From 2539c483979a87debb4bee444a6d8c80ebb4b392 Mon Sep 17 00:00:00 2001 From: Lucas Reichert Date: Fri, 26 Mar 2021 12:55:58 -0300 Subject: [PATCH 1/7] modal --- src/components.d.ts | 30 +++ src/components/tec-modal/readme.md | 31 ++++ src/components/tec-modal/tec-modal.scss | 174 ++++++++++++++++++ .../tec-modal/tec-modal.stories.tsx | 146 +++++++++++++++ src/components/tec-modal/tec-modal.tsx | 112 +++++++++++ src/components/tec-modal/tec.modal.model.ts | 7 + .../tec-modal/test/tec-modal.e2e.ts | 11 ++ .../tec-modal/test/tec-modal.spec.tsx | 104 +++++++++++ src/index.html | 24 ++- 9 files changed, 638 insertions(+), 1 deletion(-) create mode 100644 src/components/tec-modal/readme.md create mode 100644 src/components/tec-modal/tec-modal.scss create mode 100644 src/components/tec-modal/tec-modal.stories.tsx create mode 100644 src/components/tec-modal/tec-modal.tsx create mode 100644 src/components/tec-modal/tec.modal.model.ts create mode 100644 src/components/tec-modal/test/tec-modal.e2e.ts create mode 100644 src/components/tec-modal/test/tec-modal.spec.tsx diff --git a/src/components.d.ts b/src/components.d.ts index 8531f88..c56a412 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -60,6 +60,16 @@ export namespace Components { "status": TecStatus; "theme": TecnologiaTheme; } + interface TecModal { + "backDrop": boolean; + "closeOnEscape": boolean; + "fullWidth": boolean; + "modalTitle": string; + "opened": boolean; + "showCloseIcon": boolean; + "size": TecButtonSize; + "theme": TecnologiaTheme; + } interface TecProductHeader { /** * Use to make a bar fixed on top @@ -92,6 +102,12 @@ declare global { prototype: HTMLTecButtonElement; new (): HTMLTecButtonElement; }; + interface HTMLTecModalElement extends Components.TecModal, HTMLStencilElement { + } + var HTMLTecModalElement: { + prototype: HTMLTecModalElement; + new (): HTMLTecModalElement; + }; interface HTMLTecProductHeaderElement extends Components.TecProductHeader, HTMLStencilElement { } var HTMLTecProductHeaderElement: { @@ -101,6 +117,7 @@ declare global { interface HTMLElementTagNameMap { "my-component": HTMLMyComponentElement; "tec-button": HTMLTecButtonElement; + "tec-modal": HTMLTecModalElement; "tec-product-header": HTMLTecProductHeaderElement; } } @@ -160,6 +177,17 @@ declare namespace LocalJSX { "status"?: TecStatus; "theme"?: TecnologiaTheme; } + interface TecModal { + "backDrop"?: boolean; + "closeOnEscape"?: boolean; + "fullWidth"?: boolean; + "modalTitle"?: string; + "onHidden"?: (event: CustomEvent) => void; + "opened"?: boolean; + "showCloseIcon"?: boolean; + "size"?: TecButtonSize; + "theme"?: TecnologiaTheme; + } interface TecProductHeader { /** * Emitted when the title was clicked @@ -186,6 +214,7 @@ declare namespace LocalJSX { interface IntrinsicElements { "my-component": MyComponent; "tec-button": TecButton; + "tec-modal": TecModal; "tec-product-header": TecProductHeader; } } @@ -195,6 +224,7 @@ declare module "@stencil/core" { interface IntrinsicElements { "my-component": LocalJSX.MyComponent & JSXBase.HTMLAttributes; "tec-button": LocalJSX.TecButton & JSXBase.HTMLAttributes; + "tec-modal": LocalJSX.TecModal & JSXBase.HTMLAttributes; "tec-product-header": LocalJSX.TecProductHeader & JSXBase.HTMLAttributes; } } diff --git a/src/components/tec-modal/readme.md b/src/components/tec-modal/readme.md new file mode 100644 index 0000000..fc8033d --- /dev/null +++ b/src/components/tec-modal/readme.md @@ -0,0 +1,31 @@ +# tec-modal + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| --------------- | --------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- | --------------------- | +| `backDrop` | `backdrop` | | `boolean` | `true` | +| `closeOnEscape` | `closeonescape` | | `boolean` | `true` | +| `fullWidth` | `fullwidth` | | `boolean` | `false` | +| `modalTitle` | `modaltitle` | | `string` | `undefined` | +| `opened` | `opened` | | `boolean` | `false` | +| `showCloseIcon` | `showcloseicon` | | `boolean` | `true` | +| `size` | `size` | | `TecButtonSize.giant \| TecButtonSize.large \| TecButtonSize.medium \| TecButtonSize.small \| TecButtonSize.tiny` | `TecButtonSize.small` | +| `theme` | `theme` | | `TecnologiaTheme.dark \| TecnologiaTheme.light` | `defaultTheme` | + + +## Events + +| Event | Description | Type | +| -------- | ----------- | ---------------------- | +| `hidden` | | `CustomEvent` | + + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/tec-modal/tec-modal.scss b/src/components/tec-modal/tec-modal.scss new file mode 100644 index 0000000..b6ef823 --- /dev/null +++ b/src/components/tec-modal/tec-modal.scss @@ -0,0 +1,174 @@ +:host { + display: block; +} + +:host([theme='light']) { + .modal{ + .modal-content { + background: #ffffff; + color: #333; + } + } +} + +:host([theme='dark']) { + .modal { + .modal-content { + background: #{$color-base-blue-gray-900}; + color: #{$color-base-blue-gray-100}; + border: none; + + .modal-title { + border-bottom: 1px solid #353535 !important; + + h1 { + color: #{$color-base-blue-gray-100} !important; + } + } + + .footer { + border-top: 1px solid #353535 !important; + } + } + } +} + +:host([size='tiny']) .modal-content { + width: 20%; +} + +:host([size='small']) .modal-content { + width: 30%; +} + +:host([size='medium']) .modal-content { + width: 40%; +} + +:host([size='large']) .modal-content { + width: 50%; +} + +:host([size='giant']) .modal-content { + width: 60%; +} + +.modal { + display: block; + position: fixed; + z-index: 100; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.6); + + &.remove-background { + animation: remove-brackground 600ms forwards; + } + + &.show-background { + animation: show-background 600ms forwards; + } +} + +.modal-content { + border-radius: 5px; + background-color: #fefefe; + margin: 15% auto; + border: 1px solid #888; + width: 30%; + + &.full-width { + width: 100% !important; + } + + &.open-animation { + animation: open-fade 600ms forwards; + } + + &.close-animation { + animation: close-fade 600ms forwards; + } + + .modal-title { + display: flex; + align-items: center; + border-bottom: 1px solid #d9d9d9; + padding: .4rem 1rem; + + h1 { + font-size: 16px; + color: #333; + } + + .close { + color: #aaa; + margin-left: auto; + font-size: 20px; + font-weight: bold; + transition: 200ms; + } + + .close:hover, + .close:focus { + color: #888; + text-decoration: none; + cursor: pointer; + } + } + + .content { + padding: 1rem; + } + + .footer { + padding: .7rem 1rem; + border-top: 1px solid #d9d9d9; + } +} + +@keyframes open-fade { + from { + transform: scale(0); + opacity: 0; + z-index: 1; + } to { + transform: scale(1); + opacity: 1; + z-index: 101; + } +} + +@keyframes close-fade { + from { + transform: scale(1); + opacity: 1; + z-index: 101; + } to { + transform: scale(0); + opacity: 0; + z-index: 1; + } +} + +@keyframes remove-brackground { + from { + opacity: 1; + } to { + display: none; + opacity: 0; + } +} + +@keyframes show-background { + from { + display: none; + opacity: 0; + } to { + display: hidden; + opacity: 1; + } +} diff --git a/src/components/tec-modal/tec-modal.stories.tsx b/src/components/tec-modal/tec-modal.stories.tsx new file mode 100644 index 0000000..0655747 --- /dev/null +++ b/src/components/tec-modal/tec-modal.stories.tsx @@ -0,0 +1,146 @@ +import { withActions } from '@storybook/addon-actions'; +import { withTests } from '@storybook/addon-jest'; +import results from '../../../.jest-test-results.json'; +import { TecnologiaTheme } from '../interfaces'; +import readme from './readme.md'; +import { TecModalSize } from './tec.modal.model'; + +export default { + title: 'Components/Modal', + decorators: [ + Modal => { + return ` +
+ ${Modal()} + +

Hello World

+
+ `; + }, + withTests({ results }), + withActions('clicked'), + ], + parameters: { + notes: { + markdown: readme, + }, + jest: ['tec-modal.spec.tsx'], + }, + argTypes: { + theme: { + control: { + type: 'select', + options: Object.keys(TecnologiaTheme), + }, + defaultValue: TecnologiaTheme.light, + }, + opened: { + control: 'boolean', + description: 'Show or hide modal', + defaultValue: true, + }, + modalTitle: { + control: 'text', + description: 'Modal title', + defaultValue: 'Modal Title', + }, + showCloseIcon: { + control: 'boolean', + description: 'Show close icon', + defaultValue: true, + }, + backDrop: { + control: 'boolean', + description: 'Close modal when click outside', + defaultValue: true, + }, + size: { + control: { + type: 'select', + options: Object.keys(TecModalSize), + }, + defaultValue: TecModalSize.small, + }, + fullWidth: { + control: 'boolean', + description: 'Set modal width 100%', + defaultValue: false, + }, + closeOnEscape: { + control: 'boolean', + description: 'Close modal when press Escape', + defaultValue: true, + }, + }, +}; + +const Template = ({ theme, opened, modalTitle, showCloseIcon, backDrop, size, fullWidth = false, closeOnEscape }) => + ` +
+ content here +
+
+ +
+
`; + +export const Default = Template.bind({}); + +export const DarkMode = Template.bind({}); +DarkMode.args = { + theme: 'dark', +}; + +export const FullWidth = Template.bind({}); +FullWidth.args = { + fullWidth: true, +}; + +export const RemoveCloseIcon = Template.bind({}); +RemoveCloseIcon.args = { + showCloseIcon: false, +}; + +export const TinyModal = Template.bind({}); +TinyModal.args = { + size: TecModalSize.tiny, +}; + +export const SmallModal = Template.bind({}); +SmallModal.args = { + size: TecModalSize.small, +}; + +export const MediumModal = Template.bind({}); +MediumModal.args = { + size: TecModalSize.medium, +}; + +export const LargeModal = Template.bind({}); +LargeModal.args = { + size: TecModalSize.large, +}; + +export const GiantModal = Template.bind({}); +GiantModal.args = { + size: TecModalSize.giant, +}; + +export const RemoveCloseOnClickOut = Template.bind({}); +RemoveCloseOnClickOut.args = { + backDrop: false, +}; + +export const RemoveCloseOnPressEscape = Template.bind({}); +RemoveCloseOnPressEscape.args = { + closeOnEscape: false, +}; diff --git a/src/components/tec-modal/tec-modal.tsx b/src/components/tec-modal/tec-modal.tsx new file mode 100644 index 0000000..aefb0a3 --- /dev/null +++ b/src/components/tec-modal/tec-modal.tsx @@ -0,0 +1,112 @@ +import { Component, Host, h, Prop, Event, EventEmitter, Element, Watch, State } from '@stencil/core'; +import { defaultTheme } from '../../defaultTheme'; +import { TecnologiaTheme } from '../interfaces'; +import { TecButtonSize } from '../tec-button/tec-button.model'; + +@Component({ + tag: 'tec-modal', + styleUrl: 'tec-modal.scss', + shadow: true, +}) +export class TecModal { + private clickWasInside = false; + private hasFooterContent = false; + @State() private openedAuxiliary = false; + + @Element() hostElement: HTMLElement; + + @Event({ + bubbles: true, + composed: true, + }) + hidden: EventEmitter; + + @Prop({ reflect: true }) theme: TecnologiaTheme = defaultTheme; + + @Prop({ attribute: 'opened', mutable: true }) + opened = false; + + @Prop({ attribute: 'modalTitle', mutable: true }) + modalTitle: string; + + @Prop({ attribute: 'showCloseIcon', mutable: true }) + showCloseIcon = true; + + @Prop({ attribute: 'backDrop' }) + backDrop = true; + + @Prop({ attribute: 'size', mutable: true }) + size = TecButtonSize.small; + + @Prop({ attribute: 'fullWidth', mutable: true }) + fullWidth = false; + + @Prop({ attribute: 'closeOnEscape' }) + closeOnEscape = true; + + @Watch('opened') + watchOpened(newValue: boolean) { + if (!newValue) { + setTimeout(() => { + this.openedAuxiliary = false; + }, 400); + } else { + this.openedAuxiliary = true; + } + } + + handleClick(event) { + if (!this.clickWasInside && this.backDrop) this.closeModal(event); + + this.clickWasInside = false + } + + closeModal(event?: MouseEvent) { + this.opened = false; + this.hidden.emit(event); + } + + componentWillLoad() { + this.openedAuxiliary = this.opened; + if (this.closeOnEscape) + document.addEventListener('keydown', event => { + if (this.opened && event.key === 'Escape') this.closeModal(); + }); + } + + render() { + this.hasFooterContent = !!this.hostElement.querySelector('[slot="footer"]'); + + return ( + this.openedAuxiliary && ( + +
this.handleClick(event)}> +
this.clickWasInside = true} + > + + +
+ +
+ + {this.hasFooterContent && ( + + )} +
+
+
+ ) + ); + } +} diff --git a/src/components/tec-modal/tec.modal.model.ts b/src/components/tec-modal/tec.modal.model.ts new file mode 100644 index 0000000..b1edbbc --- /dev/null +++ b/src/components/tec-modal/tec.modal.model.ts @@ -0,0 +1,7 @@ +export enum TecModalSize { + tiny = 'tiny', + small = 'small', + medium = 'medium', + large = 'large', + giant = 'giant', +} diff --git a/src/components/tec-modal/test/tec-modal.e2e.ts b/src/components/tec-modal/test/tec-modal.e2e.ts new file mode 100644 index 0000000..3970cf9 --- /dev/null +++ b/src/components/tec-modal/test/tec-modal.e2e.ts @@ -0,0 +1,11 @@ +import { newE2EPage } from '@stencil/core/testing'; + +describe('tec-modal', () => { + it('renders', async () => { + const page = await newE2EPage(); + await page.setContent(''); + + const element = await page.find('tec-modal'); + expect(element).toHaveClass('hydrated'); + }); +}); diff --git a/src/components/tec-modal/test/tec-modal.spec.tsx b/src/components/tec-modal/test/tec-modal.spec.tsx new file mode 100644 index 0000000..bcd33e2 --- /dev/null +++ b/src/components/tec-modal/test/tec-modal.spec.tsx @@ -0,0 +1,104 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { TecModal } from '../tec-modal'; + +describe('tec-modal', () => { + it('closed', async () => { + const page = await newSpecPage({ + components: [TecModal], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + `); + }); + + it('opened', async () => { + const page = await newSpecPage({ + components: [TecModal], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + + + `); + }); + + it('dark', async () => { + const page = await newSpecPage({ + components: [TecModal], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + + + `); + }); + + it('remove close icon', async () => { + const page = await newSpecPage({ + components: [TecModal], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + + + `); + }); + + it('use fullWidth', async () => { + const page = await newSpecPage({ + components: [TecModal], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + + + `); + }); + +}); diff --git a/src/index.html b/src/index.html index c1b7e63..2e28158 100644 --- a/src/index.html +++ b/src/index.html @@ -15,6 +15,28 @@ - + + + + + +
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown + printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, + remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop + publishing software like Aldus PageMaker including versions of Lorem Ipsum. +
+
+ +
+
+ + From f9d693828262fa44323e15152ca7f6a1018d5b24 Mon Sep 17 00:00:00 2001 From: Lucas Reichert Date: Fri, 26 Mar 2021 12:56:48 -0300 Subject: [PATCH 2/7] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8103b1b..5636968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Created `bottom-bar` component. - Created `tec-button` component. +- Created `tec-modal` component. ### Fixes From 370997de7c36f788dfb0fd568627a41c4c72b3d9 Mon Sep 17 00:00:00 2001 From: Lucas Reichert Date: Mon, 29 Mar 2021 09:43:18 -0300 Subject: [PATCH 3/7] pr changes --- CHANGELOG.md | 11 ++- src/components.d.ts | 11 ++- src/components/tec-button/readme.md | 30 ++++---- src/components/tec-button/tec-button.tsx | 2 +- .../tec-button/test/tec-button.spec.tsx | 6 +- src/components/tec-modal/readme.md | 21 +++--- src/components/tec-modal/tec-modal.scss | 49 ++++++++---- .../tec-modal/tec-modal.stories.tsx | 48 ++++++------ src/components/tec-modal/tec-modal.tsx | 74 +++++++++++++------ .../tec-modal/test/tec-modal.spec.tsx | 26 +++---- src/index.html | 18 ++--- .../size.model.ts} | 2 +- 12 files changed, 180 insertions(+), 118 deletions(-) rename src/{components/tec-modal/tec.modal.model.ts => models/size.model.ts} (78%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d2521..f2655a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Release notes +## Unreleased + +### Features + +- Created `tec-modal` component. + +### Fixes + +- Set `reflect` `true` on button component. + ## 0.4.1 ### Fixes @@ -12,7 +22,6 @@ - Created `bottom-bar` component. - Created `tec-button` component. -- Created `tec-modal` component. ### Fixes diff --git a/src/components.d.ts b/src/components.d.ts index 9335945..5131f1d 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -9,6 +9,7 @@ import { TecnologiaTheme } from "./components/interfaces"; import { ButtonPosition } from "./components/bottom-bar/bottom-bar.model"; import { TecStatus } from "./models/status.model"; import { TecButtonColor, TecButtonIconMode, TecButtonMode, TecButtonSize } from "./components/tec-button/tec-button.model"; +import { TecSize } from "./models/size.model"; export namespace Components { interface TecBottomBar { "buttonPosition": ButtonPosition; @@ -65,13 +66,14 @@ export namespace Components { "theme": TecnologiaTheme; } interface TecModal { - "backDrop": boolean; + "blockScroll": boolean; "closeOnEscape": boolean; + "dimissOnBackdrop": boolean; "fullWidth": boolean; "modalTitle": string; "opened": boolean; "showCloseIcon": boolean; - "size": TecButtonSize; + "size": TecSize; "theme": TecnologiaTheme; } interface TecProductHeader { @@ -185,14 +187,15 @@ declare namespace LocalJSX { "theme"?: TecnologiaTheme; } interface TecModal { - "backDrop"?: boolean; + "blockScroll"?: boolean; "closeOnEscape"?: boolean; + "dimissOnBackdrop"?: boolean; "fullWidth"?: boolean; "modalTitle"?: string; "onHidden"?: (event: CustomEvent) => void; "opened"?: boolean; "showCloseIcon"?: boolean; - "size"?: TecButtonSize; + "size"?: TecSize; "theme"?: TecnologiaTheme; } interface TecProductHeader { diff --git a/src/components/tec-button/readme.md b/src/components/tec-button/readme.md index 2618884..dcdf4ed 100644 --- a/src/components/tec-button/readme.md +++ b/src/components/tec-button/readme.md @@ -7,21 +7,21 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| -------------------- | ----------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | ------------------------ | -| `buttonId` | `buttonid` | Optional ID to be attached on button | `string` | `undefined` | -| `color` | `color` | Colors of button (like gradient) | `TecButtonColor.basic \| TecButtonColor.gradient \| TecButtonColor.outline \| TecButtonColor.solid` | `TecButtonColor.solid` | -| `disabled` | `disabled` | Boolean to indicate if button is disabled | `boolean` | `false` | -| `fullWidth` | `fullwidth` | If `true` button use `width: 100%` | `boolean` | `false` | -| `icon` | `icon` | Icon class from FontAwesome 5 Free Allows to use: brands, regular, solid Example: 'far fa-paper-plane' | `string` | `undefined` | -| `iconMode` | `iconmode` | Position of icon | `TecButtonIconMode.left \| TecButtonIconMode.right` | `TecButtonIconMode.left` | -| `label` _(required)_ | `label` | Text to show inside button | `string` | `undefined` | -| `loading` | `loading` | | `boolean` | `false` | -| `mode` | `mode` | Mode of button (like square or rounded) | `TecButtonMode.radius \| TecButtonMode.rounded \| TecButtonMode.square` | `TecButtonMode.rounded` | -| `onlyIcon` | `onlyicon` | If `true` button removes label | `boolean` | `false` | -| `size` | `size` | Size of button | `TecButtonSize.giant \| TecButtonSize.large \| TecButtonSize.medium \| TecButtonSize.small \| TecButtonSize.tiny` | `TecButtonSize.small` | -| `status` | `status` | The status of button (color) | `TecStatus.danger \| TecStatus.info \| TecStatus.primary \| TecStatus.secondary \| TecStatus.success \| TecStatus.warn` | `TecStatus.primary` | -| `theme` | `theme` | | `TecnologiaTheme.dark \| TecnologiaTheme.light` | `defaultTheme` | +| Property | Attribute | Description | Type | Default | +| -------------------- | ------------ | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `buttonId` | `buttonid` | Optional ID to be attached on button | `string` | `undefined` | +| `color` | `color` | Colors of button (like gradient) | `TecButtonColor.basic \| TecButtonColor.gradient \| TecButtonColor.outline \| TecButtonColor.solid` | `TecButtonColor.solid` | +| `disabled` | `disabled` | Boolean to indicate if button is disabled | `boolean` | `false` | +| `fullWidth` | `full-width` | If `true` button use `width: 100%` | `boolean` | `false` | +| `icon` | `icon` | Icon class from FontAwesome 5 Free Allows to use: brands, regular, solid Example: 'far fa-paper-plane' | `string` | `undefined` | +| `iconMode` | `iconmode` | Position of icon | `TecButtonIconMode.left \| TecButtonIconMode.right` | `TecButtonIconMode.left` | +| `label` _(required)_ | `label` | Text to show inside button | `string` | `undefined` | +| `loading` | `loading` | | `boolean` | `false` | +| `mode` | `mode` | Mode of button (like square or rounded) | `TecButtonMode.radius \| TecButtonMode.rounded \| TecButtonMode.square` | `TecButtonMode.rounded` | +| `onlyIcon` | `onlyicon` | If `true` button removes label | `boolean` | `false` | +| `size` | `size` | Size of button | `TecButtonSize.giant \| TecButtonSize.large \| TecButtonSize.medium \| TecButtonSize.small \| TecButtonSize.tiny` | `TecButtonSize.small` | +| `status` | `status` | The status of button (color) | `TecStatus.danger \| TecStatus.info \| TecStatus.primary \| TecStatus.secondary \| TecStatus.success \| TecStatus.warn` | `TecStatus.primary` | +| `theme` | `theme` | | `TecnologiaTheme.dark \| TecnologiaTheme.light` | `defaultTheme` | ## Events diff --git a/src/components/tec-button/tec-button.tsx b/src/components/tec-button/tec-button.tsx index 5686852..22b92b0 100644 --- a/src/components/tec-button/tec-button.tsx +++ b/src/components/tec-button/tec-button.tsx @@ -68,7 +68,7 @@ export class TecButton { /** * If `true` button use `width: 100%` */ - @Prop({ attribute: 'fullWidth' }) + @Prop({ reflect: true }) fullWidth = false; /** diff --git a/src/components/tec-button/test/tec-button.spec.tsx b/src/components/tec-button/test/tec-button.spec.tsx index 3b3a519..163c2cc 100644 --- a/src/components/tec-button/test/tec-button.spec.tsx +++ b/src/components/tec-button/test/tec-button.spec.tsx @@ -58,13 +58,13 @@ describe('tec-button', () => { `); }); - it('renders with fullWidth', async () => { + it('renders with full-width', async () => { const page = await newSpecPage({ components: [TecButton], - html: ``, + html: ``, }); expect(page.root).toEqualHtml(` - + diff --git a/src/components/tec-modal/readme.md b/src/components/tec-modal/readme.md index fc8033d..200c070 100644 --- a/src/components/tec-modal/readme.md +++ b/src/components/tec-modal/readme.md @@ -7,16 +7,17 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| --------------- | --------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- | --------------------- | -| `backDrop` | `backdrop` | | `boolean` | `true` | -| `closeOnEscape` | `closeonescape` | | `boolean` | `true` | -| `fullWidth` | `fullwidth` | | `boolean` | `false` | -| `modalTitle` | `modaltitle` | | `string` | `undefined` | -| `opened` | `opened` | | `boolean` | `false` | -| `showCloseIcon` | `showcloseicon` | | `boolean` | `true` | -| `size` | `size` | | `TecButtonSize.giant \| TecButtonSize.large \| TecButtonSize.medium \| TecButtonSize.small \| TecButtonSize.tiny` | `TecButtonSize.small` | -| `theme` | `theme` | | `TecnologiaTheme.dark \| TecnologiaTheme.light` | `defaultTheme` | +| Property | Attribute | Description | Type | Default | +| ------------------ | -------------------- | ----------- | ----------------------------------------------------------------------------------- | --------------- | +| `blockScroll` | `block-scroll` | | `boolean` | `true` | +| `closeOnEscape` | `close-on-escape` | | `boolean` | `true` | +| `dimissOnBackdrop` | `dimiss-on-backdrop` | | `boolean` | `true` | +| `fullWidth` | `full-width` | | `boolean` | `false` | +| `modalTitle` | `modal-title` | | `string` | `undefined` | +| `opened` | `opened` | | `boolean` | `false` | +| `showCloseIcon` | `show-close-icon` | | `boolean` | `true` | +| `size` | `size` | | `TecSize.giant \| TecSize.large \| TecSize.medium \| TecSize.small \| TecSize.tiny` | `TecSize.small` | +| `theme` | `theme` | | `TecnologiaTheme.dark \| TecnologiaTheme.light` | `defaultTheme` | ## Events diff --git a/src/components/tec-modal/tec-modal.scss b/src/components/tec-modal/tec-modal.scss index b6ef823..0dd6e3f 100644 --- a/src/components/tec-modal/tec-modal.scss +++ b/src/components/tec-modal/tec-modal.scss @@ -1,7 +1,15 @@ +@import '../../scss/includes/components'; + :host { display: block; } +:host { + body { + overflow: hidden !important; + } +} + :host([theme='light']) { .modal{ .modal-content { @@ -19,7 +27,7 @@ border: none; .modal-title { - border-bottom: 1px solid #353535 !important; + border-bottom: 1px solid #{$color-base-blue-gray-800} !important; h1 { color: #{$color-base-blue-gray-100} !important; @@ -27,7 +35,7 @@ } .footer { - border-top: 1px solid #353535 !important; + border-top: 1px solid #{$color-base-blue-gray-800} !important; } } } @@ -54,7 +62,10 @@ } .modal { - display: block; + display: flex; + align-items: center; + justify-content: center; + align-items: center; position: fixed; z-index: 100; left: 0; @@ -66,42 +77,41 @@ background-color: rgba(0,0,0,0.6); &.remove-background { - animation: remove-brackground 600ms forwards; + animation: remove-brackground 400ms forwards; } &.show-background { - animation: show-background 600ms forwards; + animation: show-background 400ms forwards; } } .modal-content { border-radius: 5px; background-color: #fefefe; - margin: 15% auto; - border: 1px solid #888; + border: 1px solid #{$color-base-gray-600}; width: 30%; &.full-width { width: 100% !important; + border: none !important; } &.open-animation { - animation: open-fade 600ms forwards; + animation: open-fade 400ms forwards; } &.close-animation { - animation: close-fade 600ms forwards; + animation: close-fade 400ms forwards; } .modal-title { display: flex; align-items: center; - border-bottom: 1px solid #d9d9d9; - padding: .4rem 1rem; + border-bottom: 1px solid #{$color-base-gray-300}; + padding: 0 1rem; h1 { - font-size: 16px; - color: #333; + color: #{$color-base-gray-900}; } .close { @@ -125,20 +135,27 @@ } .footer { + display: flex; padding: .7rem 1rem; - border-top: 1px solid #d9d9d9; + border-top: 1px solid #{$color-base-gray-300}; + + .footer-content { + margin-left: auto; + } } } @keyframes open-fade { from { + top: -2rem; transform: scale(0); opacity: 0; z-index: 1; } to { + top: inherit; transform: scale(1); opacity: 1; - z-index: 101; + z-index: 100; } } @@ -146,7 +163,7 @@ from { transform: scale(1); opacity: 1; - z-index: 101; + z-index: 100; } to { transform: scale(0); opacity: 0; diff --git a/src/components/tec-modal/tec-modal.stories.tsx b/src/components/tec-modal/tec-modal.stories.tsx index 0655747..f687938 100644 --- a/src/components/tec-modal/tec-modal.stories.tsx +++ b/src/components/tec-modal/tec-modal.stories.tsx @@ -1,9 +1,9 @@ import { withActions } from '@storybook/addon-actions'; import { withTests } from '@storybook/addon-jest'; import results from '../../../.jest-test-results.json'; +import { TecSize } from '../../models/size.model'; import { TecnologiaTheme } from '../interfaces'; import readme from './readme.md'; -import { TecModalSize } from './tec.modal.model'; export default { title: 'Components/Modal', @@ -49,7 +49,7 @@ export default { description: 'Show close icon', defaultValue: true, }, - backDrop: { + dimissOnBackdrop: { control: 'boolean', description: 'Close modal when click outside', defaultValue: true, @@ -57,9 +57,9 @@ export default { size: { control: { type: 'select', - options: Object.keys(TecModalSize), + options: Object.keys(TecSize), }, - defaultValue: TecModalSize.small, + defaultValue: TecSize.small, }, fullWidth: { control: 'boolean', @@ -71,19 +71,25 @@ export default { description: 'Close modal when press Escape', defaultValue: true, }, + blockScroll: { + control: 'boolean', + description: 'Block scroll', + defaultValue: true, + }, }, }; -const Template = ({ theme, opened, modalTitle, showCloseIcon, backDrop, size, fullWidth = false, closeOnEscape }) => +const Template = ({ theme, opened, modalTitle, showCloseIcon, dimissOnBackdrop, size, fullWidth = false, closeOnEscape, blockScroll}) => `
content here @@ -95,11 +101,6 @@ const Template = ({ theme, opened, modalTitle, showCloseIcon, backDrop, size, fu export const Default = Template.bind({}); -export const DarkMode = Template.bind({}); -DarkMode.args = { - theme: 'dark', -}; - export const FullWidth = Template.bind({}); FullWidth.args = { fullWidth: true, @@ -112,35 +113,40 @@ RemoveCloseIcon.args = { export const TinyModal = Template.bind({}); TinyModal.args = { - size: TecModalSize.tiny, + size: TecSize.tiny, }; export const SmallModal = Template.bind({}); SmallModal.args = { - size: TecModalSize.small, + size: TecSize.small, }; export const MediumModal = Template.bind({}); MediumModal.args = { - size: TecModalSize.medium, + size: TecSize.medium, }; export const LargeModal = Template.bind({}); LargeModal.args = { - size: TecModalSize.large, + size: TecSize.large, }; export const GiantModal = Template.bind({}); GiantModal.args = { - size: TecModalSize.giant, + size: TecSize.giant, }; export const RemoveCloseOnClickOut = Template.bind({}); RemoveCloseOnClickOut.args = { - backDrop: false, + dimissOnBackdrop: false, }; export const RemoveCloseOnPressEscape = Template.bind({}); RemoveCloseOnPressEscape.args = { closeOnEscape: false, }; + +export const DarkMode = Template.bind({}); +DarkMode.args = { + theme: 'dark', +}; diff --git a/src/components/tec-modal/tec-modal.tsx b/src/components/tec-modal/tec-modal.tsx index aefb0a3..f99054c 100644 --- a/src/components/tec-modal/tec-modal.tsx +++ b/src/components/tec-modal/tec-modal.tsx @@ -1,7 +1,17 @@ -import { Component, Host, h, Prop, Event, EventEmitter, Element, Watch, State } from '@stencil/core'; +import { + Component, + Host, + h, + Prop, + Event, + EventEmitter, + Element, + Watch, + State, +} from '@stencil/core'; import { defaultTheme } from '../../defaultTheme'; +import { TecSize } from '../../models/size.model'; import { TecnologiaTheme } from '../interfaces'; -import { TecButtonSize } from '../tec-button/tec-button.model'; @Component({ tag: 'tec-modal', @@ -15,35 +25,35 @@ export class TecModal { @Element() hostElement: HTMLElement; - @Event({ - bubbles: true, - composed: true, - }) + @Event({ bubbles: true, composed: true }) hidden: EventEmitter; @Prop({ reflect: true }) theme: TecnologiaTheme = defaultTheme; - @Prop({ attribute: 'opened', mutable: true }) + @Prop({ mutable: true }) opened = false; - @Prop({ attribute: 'modalTitle', mutable: true }) + @Prop({ mutable: true }) modalTitle: string; - @Prop({ attribute: 'showCloseIcon', mutable: true }) + @Prop({ mutable: true }) showCloseIcon = true; - @Prop({ attribute: 'backDrop' }) - backDrop = true; + @Prop() + dimissOnBackdrop = true; - @Prop({ attribute: 'size', mutable: true }) - size = TecButtonSize.small; + @Prop({ mutable: true }) + size: TecSize = TecSize.small; - @Prop({ attribute: 'fullWidth', mutable: true }) + @Prop({ mutable: true }) fullWidth = false; - @Prop({ attribute: 'closeOnEscape' }) + @Prop() closeOnEscape = true; + @Prop() + blockScroll = true; + @Watch('opened') watchOpened(newValue: boolean) { if (!newValue) { @@ -51,22 +61,26 @@ export class TecModal { this.openedAuxiliary = false; }, 400); } else { + this.handleParentOverflow(); this.openedAuxiliary = true; } } handleClick(event) { - if (!this.clickWasInside && this.backDrop) this.closeModal(event); + if (!this.clickWasInside && this.dimissOnBackdrop) this.closeModal(event); - this.clickWasInside = false + this.clickWasInside = false; } closeModal(event?: MouseEvent) { this.opened = false; + this.handleParentOverflow(); this.hidden.emit(event); } componentWillLoad() { + this.hasFooterContent = !!this.hostElement.querySelector('[slot="footer"]'); + if (this.opened) this.handleParentOverflow(); this.openedAuxiliary = this.opened; if (this.closeOnEscape) document.addEventListener('keydown', event => { @@ -74,19 +88,29 @@ export class TecModal { }); } - render() { - this.hasFooterContent = !!this.hostElement.querySelector('[slot="footer"]'); + handleParentOverflow() { + const property = this.opened && this.blockScroll ? 'hidden' : 'inherit'; + this.hostElement.parentElement.style.overflow = property; + } + render() { return ( this.openedAuxiliary && ( -
this.handleClick(event)}> +
this.handleClick(event)} + >
this.clickWasInside = true} + class={`modal-content ${this.fullWidth && 'full-width'} ${ + this.opened && 'open-animation' + } ${!this.opened && 'close-animation'}`} + onClick={() => (this.clickWasInside = true)} > diff --git a/src/components/tec-modal/test/tec-modal.spec.tsx b/src/components/tec-modal/test/tec-modal.spec.tsx index bcd33e2..003e6fc 100644 --- a/src/components/tec-modal/test/tec-modal.spec.tsx +++ b/src/components/tec-modal/test/tec-modal.spec.tsx @@ -17,14 +17,14 @@ describe('tec-modal', () => { it('opened', async () => { const page = await newSpecPage({ components: [TecModal], - html: ``, + html: ``, }); expect(page.root).toEqualHtml(` - +