From 5d00bf4af99ada0f6b54eb28d716ad110001b9a3 Mon Sep 17 00:00:00 2001 From: Matthias Manoukian Date: Tue, 22 Oct 2019 09:16:59 +0200 Subject: [PATCH 1/6] feat(uploader): create component structure --- demo/angularjs/app.js | 8 +++++ demo/angularjs/components/uploader/demo.html | 2 ++ demo/angularjs/components/uploader/doc.md | 3 ++ .../components/uploader/partials/default.html | 1 + src/angularjs.index.js | 1 + .../uploader/angularjs/uploader.html | 1 + .../uploader/angularjs/uploader_directive.js | 33 +++++++++++++++++++ .../uploader/style/lumapps/_index.scss | 3 ++ src/core/angularjs/lumx.js | 2 ++ src/core/style/lumx-theme-lumapps.scss | 1 + 10 files changed, 55 insertions(+) create mode 100644 demo/angularjs/components/uploader/demo.html create mode 100644 demo/angularjs/components/uploader/doc.md create mode 100644 demo/angularjs/components/uploader/partials/default.html create mode 100644 src/components/uploader/angularjs/uploader.html create mode 100644 src/components/uploader/angularjs/uploader_directive.js create mode 100644 src/components/uploader/style/lumapps/_index.scss diff --git a/demo/angularjs/app.js b/demo/angularjs/app.js index 20747f4e8..ac58cf6a2 100644 --- a/demo/angularjs/app.js +++ b/demo/angularjs/app.js @@ -346,6 +346,14 @@ function AppDefaultConfig($locationProvider, $stateProvider, markedProvider) { }, }, }) + .state('app.product.components.uploader', { + url: 'uploader', + views: { + 'main@': { + template: require('./components/uploader/demo.html'), + }, + }, + }) .state('app.product.components.user-block', { url: 'user-block', views: { diff --git a/demo/angularjs/components/uploader/demo.html b/demo/angularjs/components/uploader/demo.html new file mode 100644 index 000000000..51c9b2663 --- /dev/null +++ b/demo/angularjs/components/uploader/demo.html @@ -0,0 +1,2 @@ + + diff --git a/demo/angularjs/components/uploader/doc.md b/demo/angularjs/components/uploader/doc.md new file mode 100644 index 000000000..2b8a29c2b --- /dev/null +++ b/demo/angularjs/components/uploader/doc.md @@ -0,0 +1,3 @@ +# Uploader + + diff --git a/demo/angularjs/components/uploader/partials/default.html b/demo/angularjs/components/uploader/partials/default.html new file mode 100644 index 000000000..5e2556e8e --- /dev/null +++ b/demo/angularjs/components/uploader/partials/default.html @@ -0,0 +1 @@ + diff --git a/src/angularjs.index.js b/src/angularjs.index.js index a51b1f405..b7b9185a4 100644 --- a/src/angularjs.index.js +++ b/src/angularjs.index.js @@ -59,4 +59,5 @@ import './components/text-field/angularjs/text-field_directive'; import './components/thumbnail/angularjs/thumbnail_directive'; import './components/toolbar/angularjs/toolbar_directive'; import './components/tooltip/angularjs/tooltip_directive'; +import './components/uploader/angularjs/uploader_directive'; import './components/user-block/angularjs/user-block_directive'; diff --git a/src/components/uploader/angularjs/uploader.html b/src/components/uploader/angularjs/uploader.html new file mode 100644 index 000000000..cf2a2c239 --- /dev/null +++ b/src/components/uploader/angularjs/uploader.html @@ -0,0 +1 @@ +
diff --git a/src/components/uploader/angularjs/uploader_directive.js b/src/components/uploader/angularjs/uploader_directive.js new file mode 100644 index 000000000..50f8e451a --- /dev/null +++ b/src/components/uploader/angularjs/uploader_directive.js @@ -0,0 +1,33 @@ +import { COMPONENT_PREFIX, MODULE_NAME } from 'LumX/angularjs/constants/common_constants'; + +import template from './uploader.html'; + +///////////////////////////// + +function UploaderController() { + // eslint-disable-next-line consistent-this, no-unused-vars + const lumx = this; +} + +///////////////////////////// + +function UploaderDirective() { + 'ngInject'; + + return { + bindToController: true, + controller: UploaderController, + controllerAs: 'lumx', + replace: true, + restrict: 'E', + template, + }; +} + +///////////////////////////// + +angular.module(`${MODULE_NAME}.uploader`).directive(`${COMPONENT_PREFIX}Uploader`, UploaderDirective); + +///////////////////////////// + +export { UploaderDirective }; diff --git a/src/components/uploader/style/lumapps/_index.scss b/src/components/uploader/style/lumapps/_index.scss new file mode 100644 index 000000000..fcb446049 --- /dev/null +++ b/src/components/uploader/style/lumapps/_index.scss @@ -0,0 +1,3 @@ +/* ========================================================================== + Uploader + ========================================================================== */ diff --git a/src/core/angularjs/lumx.js b/src/core/angularjs/lumx.js index 9c039677a..b1ad6640e 100644 --- a/src/core/angularjs/lumx.js +++ b/src/core/angularjs/lumx.js @@ -52,6 +52,7 @@ angular.module(`${MODULE_NAME}.theme`, []); angular.module(`${MODULE_NAME}.thumbnail`, []); angular.module(`${MODULE_NAME}.toolbar`, []); angular.module(`${MODULE_NAME}.tooltip`, []); +angular.module(`${MODULE_NAME}.uploader`, []); angular.module(`${MODULE_NAME}.user-block`, []); angular.module(MODULE_NAME, [ @@ -90,5 +91,6 @@ angular.module(MODULE_NAME, [ `${MODULE_NAME}.thumbnail`, `${MODULE_NAME}.toolbar`, `${MODULE_NAME}.tooltip`, + `${MODULE_NAME}.uploader`, `${MODULE_NAME}.user-block`, ]); diff --git a/src/core/style/lumx-theme-lumapps.scss b/src/core/style/lumx-theme-lumapps.scss index 7369d5199..44946dec4 100644 --- a/src/core/style/lumx-theme-lumapps.scss +++ b/src/core/style/lumx-theme-lumapps.scss @@ -42,4 +42,5 @@ @import '../../components/thumbnail/style/lumapps/index'; @import '../../components/toolbar/style/lumapps/index'; @import '../../components/tooltip/style/lumapps/index'; +@import '../../components/uploader/style/lumapps/index'; @import '../../components/user-block/style/lumapps/index'; From 70aa33a7142b4e2660c202f249259ad757ba5b26 Mon Sep 17 00:00:00 2001 From: Matthias Manoukian Date: Tue, 22 Oct 2019 14:56:18 +0200 Subject: [PATCH 2/6] feat(uploader): design a first experience --- demo/angularjs/app.js | 3 + .../components/uploader/controller.js | 34 +++++++++ .../components/uploader/partials/default.html | 6 +- .../uploader/angularjs/uploader.html | 14 +++- .../uploader/angularjs/uploader_directive.js | 70 ++++++++++++++++++- .../uploader/style/lumapps/_index.scss | 57 +++++++++++++++ 6 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 demo/angularjs/components/uploader/controller.js diff --git a/demo/angularjs/app.js b/demo/angularjs/app.js index ac58cf6a2..235950def 100644 --- a/demo/angularjs/app.js +++ b/demo/angularjs/app.js @@ -350,6 +350,8 @@ function AppDefaultConfig($locationProvider, $stateProvider, markedProvider) { url: 'uploader', views: { 'main@': { + controller: 'DemoUploaderController', + controllerAs: 'vm', template: require('./components/uploader/demo.html'), }, }, @@ -446,5 +448,6 @@ require('./components/table/controller.js'); require('./components/tabs/controller.js'); require('./components/text-field/controller.js'); require('./components/toolbar/controller.js'); +require('./components/uploader/controller.js'); require('./components/user-block/controller.js'); /* eslint-enable import/no-unassigned-import */ diff --git a/demo/angularjs/components/uploader/controller.js b/demo/angularjs/components/uploader/controller.js new file mode 100644 index 000000000..3f46f96a9 --- /dev/null +++ b/demo/angularjs/components/uploader/controller.js @@ -0,0 +1,34 @@ +import { mdiUpload } from 'LumX/icons'; + +///////////////////////////// + +function DemoUploaderController() { + 'ngInject'; + + const vm = this; + + ///////////////////////////// + // // + // Public attributes // + // // + ///////////////////////////// + + /** + * The icons to use in the template. + * + * @type {Object} + * @constant + * @readonly + */ + vm.icons = { + mdiUpload, + }; +} + +///////////////////////////// + +angular.module('design-system').controller('DemoUploaderController', DemoUploaderController); + +///////////////////////////// + +export { DemoUploaderController }; diff --git a/demo/angularjs/components/uploader/partials/default.html b/demo/angularjs/components/uploader/partials/default.html index 5e2556e8e..a805d48ba 100644 --- a/demo/angularjs/components/uploader/partials/default.html +++ b/demo/angularjs/components/uploader/partials/default.html @@ -1 +1,5 @@ - + + + Pick from + + diff --git a/src/components/uploader/angularjs/uploader.html b/src/components/uploader/angularjs/uploader.html index cf2a2c239..7ed3ab5ce 100644 --- a/src/components/uploader/angularjs/uploader.html +++ b/src/components/uploader/angularjs/uploader.html @@ -1 +1,13 @@ -
+
+
+ +
+
+ +
+ + {{ lumx.label }} + +
+
+
diff --git a/src/components/uploader/angularjs/uploader_directive.js b/src/components/uploader/angularjs/uploader_directive.js index 50f8e451a..a0401a622 100644 --- a/src/components/uploader/angularjs/uploader_directive.js +++ b/src/components/uploader/angularjs/uploader_directive.js @@ -1,3 +1,4 @@ +import { CSS_PREFIX } from 'LumX/core/constants'; import { COMPONENT_PREFIX, MODULE_NAME } from 'LumX/angularjs/constants/common_constants'; import template from './uploader.html'; @@ -5,8 +6,65 @@ import template from './uploader.html'; ///////////////////////////// function UploaderController() { - // eslint-disable-next-line consistent-this, no-unused-vars + 'ngInject'; + + // eslint-disable-next-line consistent-this const lumx = this; + + ///////////////////////////// + // // + // Private attributes // + // // + ///////////////////////////// + + /** + * The default props. + * + * @type {Object} + * @constant + * @readonly + */ + const _DEFAULT_PROPS = { + aspectRatio: 'horizontal', + variant: 'squared', + }; + + ///////////////////////////// + // // + // Public functions // + // // + ///////////////////////////// + + /** + * Get button classes. + * + * @return {Array} The list of button classes. + */ + function getClasses() { + const classes = []; + + if (angular.isDefined(lumx.aspectRatio) && lumx.aspectRatio) { + classes.push(`${CSS_PREFIX}-uploader--aspect-ratio-${lumx.aspectRatio}`); + } else { + classes.push(`${CSS_PREFIX}-uploader--aspect-ratio-${_DEFAULT_PROPS.aspectRatio}`); + } + + if (angular.isDefined(lumx.variant) && lumx.variant) { + classes.push(`${CSS_PREFIX}-uploader--variant-${lumx.variant}`); + } else { + classes.push(`${CSS_PREFIX}-uploader--variant-${_DEFAULT_PROPS.variant}`); + } + + if (angular.isDefined(lumx.size) && lumx.size) { + classes.push(`${CSS_PREFIX}-uploader--size-${lumx.size}`); + } + + return classes; + } + + ///////////////////////////// + + lumx.getClasses = getClasses; } ///////////////////////////// @@ -20,7 +78,17 @@ function UploaderDirective() { controllerAs: 'lumx', replace: true, restrict: 'E', + scope: { + aspectRatio: '@?lumxAspectRatio', + icon: '@?lumxIcon', + label: '@?lumxLabel', + size: '@?lumxSize', + variant: '@?lumxVariant', + }, template, + transclude: { + action: `${COMPONENT_PREFIX}UploaderAction`, + }, }; } diff --git a/src/components/uploader/style/lumapps/_index.scss b/src/components/uploader/style/lumapps/_index.scss index fcb446049..0c1df550c 100644 --- a/src/components/uploader/style/lumapps/_index.scss +++ b/src/components/uploader/style/lumapps/_index.scss @@ -1,3 +1,60 @@ /* ========================================================================== Uploader ========================================================================== */ + +.#{$lumx-base-prefix}-uploader { + position: relative; + background-color: lumx-theme-color-variant('dark', 'L5'); + + &--variant-square { + border-radius: 0; + } + + &--variant-rounded { + border-radius: $lumx-theme-border-radius; + } + + &--variant-circle { + border-radius: 50%; + } + + &__wrapper { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + &__icon { + margin-bottom: 2px; + } + + &__label { + @include lumx-typography('subtitle1'); + + margin-bottom: $lumx-spacing-unit; + } +} + +/* Uploader sizes + ========================================================================== */ + +@each $key, $size in $lumx-sizes { + .#{$lumx-base-prefix}-uploader--size-#{$key} { + width: $size; + } +} + +/* Uploader aspect ratio + ========================================================================== */ + +@each $key, $aspect-ratio in $lumx-thumbnail-aspect-ratio { + .#{$lumx-base-prefix}-uploader--aspect-ratio-#{$key} .#{$lumx-base-prefix}-uploader__background { + padding-top: $aspect-ratio; + } +} From c09dc9018c66b860bf10bd386a82f42a1f1d2026 Mon Sep 17 00:00:00 2001 From: Matthias Manoukian Date: Fri, 25 Oct 2019 14:25:26 +0200 Subject: [PATCH 3/6] feat(uploader): refine style --- .../components/uploader/controller.js | 4 +- .../components/uploader/partials/default.html | 13 ++-- .../layout/main-nav/main-nav_controller.js | 4 ++ .../uploader/angularjs/uploader.html | 6 +- .../uploader/angularjs/uploader_directive.js | 19 +++--- .../uploader/style/lumapps/_index.scss | 61 ++++++++++++++++++- 6 files changed, 86 insertions(+), 21 deletions(-) diff --git a/demo/angularjs/components/uploader/controller.js b/demo/angularjs/components/uploader/controller.js index 3f46f96a9..b710b1d55 100644 --- a/demo/angularjs/components/uploader/controller.js +++ b/demo/angularjs/components/uploader/controller.js @@ -1,4 +1,4 @@ -import { mdiUpload } from 'LumX/icons'; +import { mdiImagePlus } from 'LumX/icons'; ///////////////////////////// @@ -21,7 +21,7 @@ function DemoUploaderController() { * @readonly */ vm.icons = { - mdiUpload, + mdiImagePlus, }; } diff --git a/demo/angularjs/components/uploader/partials/default.html b/demo/angularjs/components/uploader/partials/default.html index a805d48ba..c5a92d657 100644 --- a/demo/angularjs/components/uploader/partials/default.html +++ b/demo/angularjs/components/uploader/partials/default.html @@ -1,5 +1,8 @@ - - - Pick from - - + diff --git a/demo/angularjs/layout/main-nav/main-nav_controller.js b/demo/angularjs/layout/main-nav/main-nav_controller.js index 40a01536a..8f301b142 100644 --- a/demo/angularjs/layout/main-nav/main-nav_controller.js +++ b/demo/angularjs/layout/main-nav/main-nav_controller.js @@ -157,6 +157,10 @@ function MainNavController($state) { label: 'Tooltip', state: 'app.product.components.tooltip', }, + { + label: 'Uploader', + state: 'app.product.components.uploader', + }, { label: 'User block', state: 'app.product.components.user-block', diff --git a/src/components/uploader/angularjs/uploader.html b/src/components/uploader/angularjs/uploader.html index 7ed3ab5ce..ed4908478 100644 --- a/src/components/uploader/angularjs/uploader.html +++ b/src/components/uploader/angularjs/uploader.html @@ -1,13 +1,11 @@ -
+
- +
{{ lumx.label }} - -
diff --git a/src/components/uploader/angularjs/uploader_directive.js b/src/components/uploader/angularjs/uploader_directive.js index a0401a622..5e6e1f8df 100644 --- a/src/components/uploader/angularjs/uploader_directive.js +++ b/src/components/uploader/angularjs/uploader_directive.js @@ -26,6 +26,7 @@ function UploaderController() { */ const _DEFAULT_PROPS = { aspectRatio: 'horizontal', + theme: 'light', variant: 'squared', }; @@ -49,16 +50,22 @@ function UploaderController() { classes.push(`${CSS_PREFIX}-uploader--aspect-ratio-${_DEFAULT_PROPS.aspectRatio}`); } + if (angular.isDefined(lumx.size) && lumx.size) { + classes.push(`${CSS_PREFIX}-uploader--size-${lumx.size}`); + } + + if (angular.isDefined(lumx.theme) && lumx.theme) { + classes.push(`${CSS_PREFIX}-uploader--theme-${lumx.theme}`); + } else { + classes.push(`${CSS_PREFIX}-uploader--theme-${_DEFAULT_PROPS.theme}`); + } + if (angular.isDefined(lumx.variant) && lumx.variant) { classes.push(`${CSS_PREFIX}-uploader--variant-${lumx.variant}`); } else { classes.push(`${CSS_PREFIX}-uploader--variant-${_DEFAULT_PROPS.variant}`); } - if (angular.isDefined(lumx.size) && lumx.size) { - classes.push(`${CSS_PREFIX}-uploader--size-${lumx.size}`); - } - return classes; } @@ -83,12 +90,10 @@ function UploaderDirective() { icon: '@?lumxIcon', label: '@?lumxLabel', size: '@?lumxSize', + theme: '@?lumxTheme', variant: '@?lumxVariant', }, template, - transclude: { - action: `${COMPONENT_PREFIX}UploaderAction`, - }, }; } diff --git a/src/components/uploader/style/lumapps/_index.scss b/src/components/uploader/style/lumapps/_index.scss index 0c1df550c..b2ad9de5e 100644 --- a/src/components/uploader/style/lumapps/_index.scss +++ b/src/components/uploader/style/lumapps/_index.scss @@ -3,8 +3,45 @@ ========================================================================== */ .#{$lumx-base-prefix}-uploader { + $self: &; + + @include lumx-state-transition; + position: relative; - background-color: lumx-theme-color-variant('dark', 'L5'); + cursor: pointer; + outline: none; + + &--theme-light { + @include lumx-state('state-default', 'emphasis-medium', 'dark'); + + &:hover { + @include lumx-state('state-hover', 'emphasis-medium', 'dark'); + } + + &:active { + @include lumx-state('state-active', 'emphasis-medium', 'dark'); + } + + &[data-focus-visible-added] { + @include lumx-state('state-focus', 'emphasis-medium', 'dark'); + } + } + + &--theme-dark { + @include lumx-state('state-default', 'emphasis-medium', 'light'); + + &:hover { + @include lumx-state('state-hover', 'emphasis-medium', 'light'); + } + + &:active { + @include lumx-state('state-active', 'emphasis-medium', 'light'); + } + + &[data-focus-visible-added] { + @include lumx-state('state-focus', 'emphasis-medium', 'light'); + } + } &--variant-square { border-radius: 0; @@ -28,16 +65,34 @@ flex-direction: column; align-items: center; justify-content: center; + padding: 0 $lumx-spacing-unit * 2; + user-select: none; } &__icon { - margin-bottom: 2px; + margin-bottom: $lumx-spacing-unit; + + #{$self}--theme-light & { + color: lumx-theme-color-variant('dark', 'N'); + } + + #{$self}--theme-dark & { + color: lumx-theme-color-variant('light', 'N'); + } } &__label { @include lumx-typography('subtitle1'); - margin-bottom: $lumx-spacing-unit; + text-align: center; + + #{$self}--theme-light & { + color: lumx-theme-color-variant('dark', 'N'); + } + + #{$self}--theme-dark & { + color: lumx-theme-color-variant('light', 'N'); + } } } From 1fef42de37f9256689a19b3c3e82f1d0c75f424e Mon Sep 17 00:00:00 2001 From: gcornut Date: Tue, 5 Nov 2019 10:33:36 +0100 Subject: [PATCH 4/6] refactor: deprecate `ThumbnailAspectRatio` in favor of `AspectRatio` --- CHANGELOG.react.md | 1 + demo/react/components/slideshow/default.tsx | 14 +++++------ .../doc/product/components/image-block.mdx | 10 ++++---- .../doc/product/components/thumbnail.mdx | 16 ++++++------- .../editable-media/react/EditableMedia.tsx | 4 ++-- .../image-block/react/ImageBlock.tsx | 10 ++++---- src/components/index.ts | 23 ++++++++++++++++++- src/components/post-block/react/PostBlock.tsx | 6 ++--- src/components/thumbnail/react/Thumbnail.tsx | 21 +++++++++-------- 9 files changed, 64 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.react.md b/CHANGELOG.react.md index dcdc92fba..e66b10256 100644 --- a/CHANGELOG.react.md +++ b/CHANGELOG.react.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Popover` bug that made the content be displayed on the top left corner. - Make autocomplete multiple demo remove a value upon clicking on the entire chip. +- Deprecated `ThumbnailAspectRatio` (use `AspectRatio` instead) [#208](https://github.com/lumapps/design-system/pull/208) ### Removed diff --git a/demo/react/components/slideshow/default.tsx b/demo/react/components/slideshow/default.tsx index b779db0dd..3369135d9 100644 --- a/demo/react/components/slideshow/default.tsx +++ b/demo/react/components/slideshow/default.tsx @@ -1,13 +1,13 @@ import React, { CSSProperties, ReactElement } from 'react'; import { + AspectRatio, ImageBlock, ImageBlockCaptionPosition, ImageBlockProps, Slideshow, SlideshowItem, Theme, - ThumbnailAspectRatio, } from 'LumX'; ///////////////////////////// @@ -49,14 +49,14 @@ const DemoComponent: React.FC = ({ theme }: IProps): ReactElement => ( @@ -66,7 +66,7 @@ const DemoComponent: React.FC = ({ theme }: IProps): ReactElement => ( = ({ theme }: IProps): ReactElement => ( = ({ theme }: IProps): ReactElement => ( = ({ theme }: IProps): ReactElement => ( } - aspectRatio={ThumbnailAspectRatio.horizontal} + aspectRatio={AspectRatio.horizontal} description="Lorem ipsum dolor sit amet, consectur adipiscing " tags={ @@ -89,7 +89,7 @@ A custom padding can be added. ```javascript jsx withThemeSwitcher disableGrid (theme) => ( ( ( diff --git a/demo/react/doc/product/components/thumbnail.mdx b/demo/react/doc/product/components/thumbnail.mdx index a95915f8c..585781cf1 100644 --- a/demo/react/doc/product/components/thumbnail.mdx +++ b/demo/react/doc/product/components/thumbnail.mdx @@ -1,5 +1,5 @@ ```javascript import -import { Size, Theme, Thumbnail, ThumbnailAspectRatio, ThumbnailVariant } from '@lumx/react'; +import { Size, Theme, Thumbnail, AspectRatio, ThumbnailVariant } from '@lumx/react'; ``` # Thumbnail @@ -33,10 +33,10 @@ Thumbnails come in 4 ratios: _square_, _original_, _vertical_, and _horizontal_. ```javascript jsx (theme) => ( <> - - - - + + + + ); ``` @@ -60,21 +60,21 @@ Thumbnails come in two variants: _squared_ and _rounded_ (theme) => ( <> = ({ {image && variant === 'thumbnail' && (
= ({ }), { [`${CLASSNAME}--fill-height`]: fillHeight, - [`${CLASSNAME}--format-crop`]: aspectRatio && aspectRatio !== ThumbnailAspectRatio.original, - [`${CLASSNAME}--format-original`]: !aspectRatio || aspectRatio === ThumbnailAspectRatio.original, + [`${CLASSNAME}--format-crop`]: aspectRatio && aspectRatio !== AspectRatio.original, + [`${CLASSNAME}--format-original`]: !aspectRatio || aspectRatio === AspectRatio.original, }, )} {...restProps} diff --git a/src/components/index.ts b/src/components/index.ts index 5cd2d5dbe..0b49fbe1c 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -80,6 +80,27 @@ enum Emphasis { high = 'high', } +/** + * All available aspect ratios. + */ +enum AspectRatio { + original = 'original', + horizontal = 'horizontal', + vertical = 'vertical', + square = 'square', +} + ///////////////////////////// -export { Alignment, ComplexPropDefault, Color, ColorPalette, ColorVariant, Theme, Size, Orientation, Emphasis }; +export { + Alignment, + AspectRatio, + ComplexPropDefault, + Color, + ColorPalette, + ColorVariant, + Theme, + Size, + Orientation, + Emphasis, +}; diff --git a/src/components/post-block/react/PostBlock.tsx b/src/components/post-block/react/PostBlock.tsx index 68db1f85f..477305429 100644 --- a/src/components/post-block/react/PostBlock.tsx +++ b/src/components/post-block/react/PostBlock.tsx @@ -6,7 +6,7 @@ import { COMPONENT_PREFIX } from 'LumX/core/react/constants'; import isObject from 'lodash/isObject'; -import { Orientation, Theme, Thumbnail, ThumbnailAspectRatio, ThumbnailVariant } from 'LumX'; +import { AspectRatio, Orientation, Theme, Thumbnail, ThumbnailVariant } from 'LumX'; import { IGenericProps, getRootClassName } from 'LumX/core/react/utils'; @@ -39,7 +39,7 @@ interface IPostBlockProps extends IGenericProps { /* Thumbnail image source */ thumbnail: string; /* The image aspect ratio. */ - thumbnailAspectRatio?: ThumbnailAspectRatio; + thumbnailAspectRatio?: AspectRatio; /* Post title */ title: string; /* Theme. */ @@ -79,7 +79,7 @@ const DEFAULT_PROPS: IDefaultPropsType = { orientation: Orientation.horizontal, text: undefined, theme: Theme.light, - thumbnailAspectRatio: ThumbnailAspectRatio.horizontal, + thumbnailAspectRatio: AspectRatio.horizontal, }; ///////////////////////////// diff --git a/src/components/thumbnail/react/Thumbnail.tsx b/src/components/thumbnail/react/Thumbnail.tsx index 8c592b04f..46ba846d0 100644 --- a/src/components/thumbnail/react/Thumbnail.tsx +++ b/src/components/thumbnail/react/Thumbnail.tsx @@ -2,7 +2,7 @@ import React, { CSSProperties, ReactElement } from 'react'; import classNames from 'classnames'; -import { Alignment, Size, Theme } from 'LumX'; +import { Alignment, AspectRatio, Size, Theme } from 'LumX'; import { COMPONENT_PREFIX } from 'LumX/core/react/constants'; @@ -25,13 +25,14 @@ declare module 'react' { /** * All available aspect ratios. + * @deprecated */ -enum ThumbnailAspectRatio { - original = 'original', - horizontal = 'horizontal', - vertical = 'vertical', - square = 'square', -} +const ThumbnailAspectRatio: Record = { + horizontal: AspectRatio.horizontal, + original: AspectRatio.original, + square: AspectRatio.square, + vertical: AspectRatio.vertical, +}; /** * Authorized size values. @@ -64,7 +65,7 @@ interface IThumbnailProps extends IGenericProps { /** The thumbnail alignment. */ align?: Alignment; /** The image aspect ratio. */ - aspectRatio?: ThumbnailAspectRatio; + aspectRatio?: AspectRatio; /** Whether the image has to fill its container's height. */ fillHeight?: boolean; /** Avatar image. */ @@ -108,7 +109,7 @@ const CLASSNAME: string = getRootClassName(COMPONENT_NAME); */ const DEFAULT_PROPS: IDefaultPropsType = { align: Alignment.left, - aspectRatio: ThumbnailAspectRatio.original, + aspectRatio: AspectRatio.original, fillHeight: false, loading: ImageLoading.lazy, size: undefined, @@ -155,7 +156,7 @@ const Thumbnail: React.FC = ({ onKeyDown={onEnterPressed(onClick)} {...restProps} > - {aspectRatio === ThumbnailAspectRatio.original ? ( + {aspectRatio === AspectRatio.original ? ( {alt} ) : (
From f40773af5b22e6026311182cd8b3116fdc258fc9 Mon Sep 17 00:00:00 2001 From: gcornut Date: Tue, 5 Nov 2019 10:34:10 +0100 Subject: [PATCH 5/6] feat(uploader): add react component --- CHANGELOG.react.md | 1 + .../react/doc/product/components/uploader.mdx | 48 ++++++ demo/react/layout/MainNav.tsx | 1 + .../uploader/react/Uploader.test.tsx | 120 +++++++++++++++ src/components/uploader/react/Uploader.tsx | 137 ++++++++++++++++++ .../__snapshots__/Uploader.test.tsx.snap | 14 ++ src/react.index.ts | 2 + 7 files changed, 323 insertions(+) create mode 100644 demo/react/doc/product/components/uploader.mdx create mode 100644 src/components/uploader/react/Uploader.test.tsx create mode 100644 src/components/uploader/react/Uploader.tsx create mode 100644 src/components/uploader/react/__snapshots__/Uploader.test.tsx.snap diff --git a/CHANGELOG.react.md b/CHANGELOG.react.md index e66b10256..505ba3783 100644 --- a/CHANGELOG.react.md +++ b/CHANGELOG.react.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 -   Multiple Autocomplete component [#209](https://github.com/lumapps/design-system/pull/209) -   `isHighlighted` prop for `Chip` component [#209](https://github.com/lumapps/design-system/pull/209) -   Added `isClearable` and `chips` props for Autocomplete [#209](https://github.com/lumapps/design-system/pull/209) +- Uploader component [#208](https://github.com/lumapps/design-system/pull/208) ### Changed diff --git a/demo/react/doc/product/components/uploader.mdx b/demo/react/doc/product/components/uploader.mdx new file mode 100644 index 000000000..e6aa20a85 --- /dev/null +++ b/demo/react/doc/product/components/uploader.mdx @@ -0,0 +1,48 @@ +```javascript import +import { Uploader, UploaderVariant } from '@lumx/react'; +import { mdiImagePlus } from '@lumx/icons'; +``` + +# Uploader + +## Default + +```javascript jsx withThemeSwitcher +(theme) => ( + +); +``` + +## Rounded + +```javascript jsx withThemeSwitcher +(theme) => ( + +); +``` + +## Circle + +```javascript jsx withThemeSwitcher +(theme) => ( + +); +``` + +### Properties + + diff --git a/demo/react/layout/MainNav.tsx b/demo/react/layout/MainNav.tsx index aa085c27d..b14f32989 100644 --- a/demo/react/layout/MainNav.tsx +++ b/demo/react/layout/MainNav.tsx @@ -76,6 +76,7 @@ const ITEMS: Item[] = [ 'Thumbnail', 'Toolbar', 'Tooltip', + 'Uploader', 'User block', ], }, diff --git a/src/components/uploader/react/Uploader.test.tsx b/src/components/uploader/react/Uploader.test.tsx new file mode 100644 index 000000000..ce88a037a --- /dev/null +++ b/src/components/uploader/react/Uploader.test.tsx @@ -0,0 +1,120 @@ +import React, { ReactElement } from 'react'; + +import { mount, shallow } from 'enzyme'; + +import { ICommonSetup, Wrapper, commonTestsSuite } from 'LumX/core/testing/utils.test'; +import { getBasicClass } from 'LumX/core/utils'; + +import { CLASSNAME, DEFAULT_PROPS, Uploader, UploaderProps } from './Uploader'; + +///////////////////////////// + +/** + * Define the overriding properties waited by the `setup` function. + */ +type ISetupProps = Partial; + +/** + * Defines what the `setup` function will return. + */ +interface ISetup extends ICommonSetup { + props: ISetupProps; + + /** + * [Enter the description of this wrapper]. + * [You should also probably change the name of the wrapper to something more meaningful]. + */ + wrapper: Wrapper; +} + +///////////////////////////// + +/** + * Mounts the component and returns common DOM elements / data needed in multiple tests further down. + * + * @param props The props to use to override the default props of the component. + * @param [shallowRendering=true] Indicates if we want to do a shallow or a full rendering. + * @return An object with the props, the component wrapper and some shortcut to some element inside of the component. + */ +const setup = (props: ISetupProps = {}, shallowRendering: boolean = true): ISetup => { + const renderer: (el: ReactElement) => Wrapper = shallowRendering ? shallow : mount; + + // @ts-ignore + const wrapper: Wrapper = renderer(); + + return { + props, + wrapper, + }; +}; + +describe(`<${Uploader.displayName}>`, (): void => { + // 1. Test render via snapshot (default states of component). + describe('Snapshots and structure', (): void => { + // Here is an example of a basic rendering check, with snapshot. + + it('should render correctly', (): void => { + const { wrapper } = setup(); + expect(wrapper).toMatchSnapshot(); + + expect(wrapper).toExist(); + expect(wrapper).toHaveClassName(CLASSNAME); + }); + }); + + ///////////////////////////// + + // 2. Test defaultProps value and important props custom values. + describe('Props', (): void => { + // Here are some examples of basic props check. + + it('should use default props', (): void => { + const { wrapper } = setup(); + + Object.keys(DEFAULT_PROPS).forEach((prop: string): void => { + expect(wrapper).toHaveClassName( + getBasicClass({ prefix: CLASSNAME, type: prop, value: DEFAULT_PROPS[prop] }), + ); + }); + }); + }); + + ///////////////////////////// + + // 3. Test events. + describe('Events', (): void => { + // Here is an example how to check a `onClick` event. + + const onClick: jest.Mock = jest.fn(); + + beforeEach((): void => { + onClick.mockClear(); + }); + + it('should trigger `onClick` when clicked', (): void => { + const { wrapper } = setup({ onClick }, false); + + wrapper.simulate('click'); + + expect(onClick).toHaveBeenCalled(); + }); + }); + ///////////////////////////// + + // 4. Test conditions (i.e. things that display or not in the UI based on props). + describe('Conditions', (): void => { + // Nothing to do here. + }); + + ///////////////////////////// + + // 5. Test state. + describe('State', (): void => { + // Nothing to do here. + }); + + ///////////////////////////// + + // Common tests suite. + commonTestsSuite(setup, { className: 'wrapper', prop: 'wrapper' }, { className: CLASSNAME }); +}); diff --git a/src/components/uploader/react/Uploader.tsx b/src/components/uploader/react/Uploader.tsx new file mode 100644 index 000000000..9c5fc3b31 --- /dev/null +++ b/src/components/uploader/react/Uploader.tsx @@ -0,0 +1,137 @@ +import React, { MouseEventHandler, ReactElement } from 'react'; + +import classNames from 'classnames'; + +import { AspectRatio, Icon, Size, Theme } from 'LumX'; +import { COMPONENT_PREFIX } from 'LumX/core/react/constants'; +import { handleBasicClasses } from 'LumX/core/utils'; +import { IGenericProps, getRootClassName } from 'LumX/react/utils'; + +///////////////////////////// + +enum UploaderVariant { + square = 'square', + rounded = 'rounded', + circle = 'circle', +} + +type UploaderSize = Size.xl | Size.xxl; + +/** + * Defines the props of the component. + */ +interface IUploaderProps extends IGenericProps { + /** + * Aspect ratio + */ + aspectRatio?: AspectRatio; + /** + * Icon + */ + icon?: string; + /** + * Label + */ + label?: string; + /** + * Size + */ + size?: UploaderSize; + /** + * Theme + */ + theme?: Theme; + /** + * Uploader variant + */ + variant?: UploaderVariant; + /** + * On click handler + */ + onClick?: MouseEventHandler; +} +type UploaderProps = IUploaderProps; + +///////////////////////////// + +///////////////////////////// +// // +// Public attributes // +// // +///////////////////////////// + +/** + * The display name of the component. + */ +const COMPONENT_NAME = `${COMPONENT_PREFIX}Uploader`; + +/** + * The default class name and classes prefix for this component. + */ +const CLASSNAME = getRootClassName(COMPONENT_NAME); + +/** + * The default value of props. + */ +const DEFAULT_PROPS: Partial = { + aspectRatio: AspectRatio.horizontal, + size: Size.xl, + theme: Theme.light, + variant: UploaderVariant.square, +}; + +///////////////////////////// + +/** + * [Enter the description of the component here]. + * + * @return The component. + */ +const Uploader: React.FC = (props: UploaderProps): ReactElement => { + const { + aspectRatio = DEFAULT_PROPS.aspectRatio, + className, + label, + icon, + size = DEFAULT_PROPS.size, + theme = DEFAULT_PROPS.theme, + variant = DEFAULT_PROPS.variant, + ...forwardedProps + } = props; + + // Square aspect ratio for circle variants. + const adjustedAspectRatio = variant === UploaderVariant.circle ? AspectRatio.square : aspectRatio; + + return ( +
+
+ +
+ {icon && ( +
+ +
+ )} + + {label && {label}} +
+
+ ); +}; +Uploader.displayName = COMPONENT_NAME; + +///////////////////////////// + +export { CLASSNAME, DEFAULT_PROPS, Uploader, UploaderProps, UploaderVariant }; diff --git a/src/components/uploader/react/__snapshots__/Uploader.test.tsx.snap b/src/components/uploader/react/__snapshots__/Uploader.test.tsx.snap new file mode 100644 index 000000000..c3bf65cb3 --- /dev/null +++ b/src/components/uploader/react/__snapshots__/Uploader.test.tsx.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` Snapshots and structure should render correctly 1`] = ` +
+
+
+
+`; diff --git a/src/react.index.ts b/src/react.index.ts index c2fdd4e7a..81d9f98e4 100644 --- a/src/react.index.ts +++ b/src/react.index.ts @@ -116,3 +116,5 @@ export { SideNavigationItem, SideNavigationItemProps } from 'LumX/components/sid export { Slider } from 'LumX/components/slider/react/Slider'; export { Dialog, DialogSizes } from 'LumX/components/dialog/react/Dialog'; + +export { Uploader, UploaderProps, UploaderVariant } from 'LumX/components/uploader/react/Uploader'; From 14398ede04ec6ad9ebefdf06fcd989fa52775dd5 Mon Sep 17 00:00:00 2001 From: gcornut Date: Tue, 5 Nov 2019 12:04:30 +0100 Subject: [PATCH 6/6] feat(uploader): rework angular default props --- demo/angularjs/components/uploader/doc.md | 6 +++ .../components/uploader/partials/circle.html | 8 ++++ .../components/uploader/partials/default.html | 3 -- .../uploader/angularjs/uploader_directive.js | 40 +++++++------------ src/components/uploader/react/Uploader.tsx | 2 +- 5 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 demo/angularjs/components/uploader/partials/circle.html diff --git a/demo/angularjs/components/uploader/doc.md b/demo/angularjs/components/uploader/doc.md index 2b8a29c2b..4b4d2f1c1 100644 --- a/demo/angularjs/components/uploader/doc.md +++ b/demo/angularjs/components/uploader/doc.md @@ -1,3 +1,9 @@ # Uploader +## Default + + +## Circle + + diff --git a/demo/angularjs/components/uploader/partials/circle.html b/demo/angularjs/components/uploader/partials/circle.html new file mode 100644 index 000000000..c5a92d657 --- /dev/null +++ b/demo/angularjs/components/uploader/partials/circle.html @@ -0,0 +1,8 @@ + diff --git a/demo/angularjs/components/uploader/partials/default.html b/demo/angularjs/components/uploader/partials/default.html index c5a92d657..0230e5f5b 100644 --- a/demo/angularjs/components/uploader/partials/default.html +++ b/demo/angularjs/components/uploader/partials/default.html @@ -1,8 +1,5 @@ diff --git a/src/components/uploader/angularjs/uploader_directive.js b/src/components/uploader/angularjs/uploader_directive.js index 5e6e1f8df..bc3d0ef0b 100644 --- a/src/components/uploader/angularjs/uploader_directive.js +++ b/src/components/uploader/angularjs/uploader_directive.js @@ -26,6 +26,7 @@ function UploaderController() { */ const _DEFAULT_PROPS = { aspectRatio: 'horizontal', + size: 'xl', theme: 'light', variant: 'squared', }; @@ -42,31 +43,20 @@ function UploaderController() { * @return {Array} The list of button classes. */ function getClasses() { - const classes = []; - - if (angular.isDefined(lumx.aspectRatio) && lumx.aspectRatio) { - classes.push(`${CSS_PREFIX}-uploader--aspect-ratio-${lumx.aspectRatio}`); - } else { - classes.push(`${CSS_PREFIX}-uploader--aspect-ratio-${_DEFAULT_PROPS.aspectRatio}`); - } - - if (angular.isDefined(lumx.size) && lumx.size) { - classes.push(`${CSS_PREFIX}-uploader--size-${lumx.size}`); - } - - if (angular.isDefined(lumx.theme) && lumx.theme) { - classes.push(`${CSS_PREFIX}-uploader--theme-${lumx.theme}`); - } else { - classes.push(`${CSS_PREFIX}-uploader--theme-${_DEFAULT_PROPS.theme}`); - } - - if (angular.isDefined(lumx.variant) && lumx.variant) { - classes.push(`${CSS_PREFIX}-uploader--variant-${lumx.variant}`); - } else { - classes.push(`${CSS_PREFIX}-uploader--variant-${_DEFAULT_PROPS.variant}`); - } - - return classes; + const aspectRatio = lumx.aspectRatio ? lumx.aspectRatio : _DEFAULT_PROPS.aspectRatio; + const size = lumx.size ? lumx.size : _DEFAULT_PROPS.size; + const theme = lumx.theme ? lumx.theme : _DEFAULT_PROPS.theme; + const variant = lumx.variant ? lumx.variant : _DEFAULT_PROPS.variant; + + // Adjust to square aspect ratio when using circle variants. + const adjustedAspectRatio = variant === 'circle' ? 'square' : aspectRatio; + + return [ + `${CSS_PREFIX}-uploader--aspect-ratio-${adjustedAspectRatio}`, + `${CSS_PREFIX}-uploader--size-${size}`, + `${CSS_PREFIX}-uploader--theme-${theme}`, + `${CSS_PREFIX}-uploader--variant-${variant}`, + ]; } ///////////////////////////// diff --git a/src/components/uploader/react/Uploader.tsx b/src/components/uploader/react/Uploader.tsx index 9c5fc3b31..2c19cf41c 100644 --- a/src/components/uploader/react/Uploader.tsx +++ b/src/components/uploader/react/Uploader.tsx @@ -99,7 +99,7 @@ const Uploader: React.FC = (props: UploaderProps): ReactElement = ...forwardedProps } = props; - // Square aspect ratio for circle variants. + // Adjust to square aspect ratio when using circle variants. const adjustedAspectRatio = variant === UploaderVariant.circle ? AspectRatio.square : aspectRatio; return (