Skip to content

Commit

Permalink
refactor(modal): update modal to follow best practices (#292)
Browse files Browse the repository at this point in the history
* add new utilities

* rewrite modal component

* update modal
  • Loading branch information
mimshins authored Dec 8, 2024
1 parent b7418fd commit df3f6a4
Show file tree
Hide file tree
Showing 11 changed files with 668 additions and 255 deletions.
4 changes: 4 additions & 0 deletions packages/web-components/src/modal/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const Slots = {
IMAGE: "image",
ACTION_BAR: "action-bar",
} as const;
25 changes: 25 additions & 0 deletions packages/web-components/src/modal/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { BaseEvent } from "../utils";

export class HideEvent extends BaseEvent<null> {
public static type = "hide";

constructor() {
super(HideEvent.type, {
composed: true,
cancelable: true,
details: null,
});
}
}

export class ShowEvent extends BaseEvent<null> {
public static type = "show";

constructor() {
super(ShowEvent.type, {
composed: true,
cancelable: true,
details: null,
});
}
}
49 changes: 13 additions & 36 deletions packages/web-components/src/modal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,24 @@ import { customElement } from "lit/decorators.js";
import { Modal } from "./modal";
import styles from "./modal.style";

export { Slots } from "./constants";
export * from "./events";

/**
* @summary A modal dialog component.
* @summary The modal component.
*
* @prop {boolean} [open=false] - Indicates whether the modal is open.
* @prop {string} [title=''] - Sets the title of the modal. If not provided, no title is displayed.
* @prop {string} [description=''] - Provides a description or content text for the modal. If empty, no description is shown.
* @prop {string} [alignment='right'] - Determines the alignment of the modal's content. Can be 'right', or 'center'.
* @prop {string} [image] - URL of an image to display within the modal. If specified, the image is shown above the content, if not pass the icon slot.
* @tag tap-modal
*
* @csspart [overlay] - The overlay background when the modal is open.
* @csspart [dialog] - The main container for the modal dialog.
* @csspart [image-container] - The container of the image element, a `div`.
* @csspart [image] - The image element, a `img`.
* @csspart [icon] - The container of the icon slot, a `div`.
* @csspart [content] - The wrapper around title and description, a `div`.
* @csspart [title] - The title element, a `span`.
* @csspart [description] - The description element, a `p`.
* @csspart [actions] - The container of the actions slot, a `div`.
* @prop {boolean} [open=false] - Indicates whether the modal is open or not.
* @prop {string} [heading=""] - Sets the title of the modal.
* @prop {string} [description=""] - Sets the description text for the modal.
* @prop {"start" | "center"} [alignment="start"] - Determines the alignment of the modal's content.
*
* @cssprop [--tap-dialog-color-surface-overlay=--tap-sys-color-surface-overlay-dark] - The background color of the overlay.
* @cssprop [--tap-dialog-color-surface-primary=--tap-sys-color-surface-primary] - The background color of the modal dialog.
* @cssprop [--tap-dialog-radius=--tap-sys-radius-6] - The border radius of the modal dialog.
* @cssprop [--tap-dialog-icon-top-margin=--tap-sys-spacing-8] - The top margin of the icon.
* @cssprop [--tap-dialog-image-container-background-color=--tap-palette-gray-100] - The background color of the image container.
* @cssprop [--tap-dialog-content-vertical-padding=--tap-sys-spacing-4] - The vertical padding of the content.
* @cssprop [--tap-dialog-content-horizontal-padding=--tap-sys-spacing-6] - The horizontal padding of the content.
* @cssprop [--tap-dialog-content-vertical-margin=--tap-sys-spacing-6] - The vertical margin of the content.
* @cssprop [--tap-dialog-content-horizontal-margin] - The horizontal margin of the content.
* @cssprop [--tap-dialog-title-font-size=--tap-sys-typography-headline-sm-size] - The font size of the title in the dialog modal.
* @cssprop [--tap-dialog-title-font-weight=--tap-sys-typography-headline-sm-weight] - The font weight of title in the dialog modal.
* @cssprop [--tap-dialog-title-line-height=--tap-sys-typography-headline-sm-height] - The line height of title in the dialog modal.
* @cssprop [--tap-dialog-description-margin] - The margin of the description in the dialog modal.
* @cssprop [--tap-dialog-description-padding-top=--tap-sys-spacing-4] - The top padding of the description in the dialog modal.
* @cssprop [--tap-dialog-description-font-size=--tap-sys-typography-body-md-size] - The font size of the description in the dialog modal.
* @cssprop [--tap-dialog-description-font-weight=--tap-sys-typography-body-md-weight] - The font weight of the description in the dialog modal.
* @cssprop [--tap-dialog-description-line-height=--tap-sys-typography-body-md-height] - The line height of the description in the dialog modal.
* @cssprop [--tap-dialog-description-color=--tap-palette-gray-500] - The color of the description in the dialog modal.
* @cssprop [--tap-dialog-actions-padding=--tap-sys-spacing-6] - The padding of the actions in the dialog modal.
* @slot imagery - The slot for imagery element.
* @slot action-bar - The slot for actionbar element.
*
* @slot [icon] - the icon slot of the modal dialog.
* @slot [actions] - the actions slot of the modal dialog.
* @fires {ShowEvent} show - Fires when the modal should be visible.
* @fires {HideEvent} hide - Fires when the modal should be hidden.
*/
@customElement("tap-modal")
export class TapModal extends Modal {
Expand Down
163 changes: 63 additions & 100 deletions packages/web-components/src/modal/modal.style.ts
Original file line number Diff line number Diff line change
@@ -1,137 +1,100 @@
import { css } from "lit";

// tokens
// --tap-dialog-color-surface-overlay
// --tap-dialog-color-surface-primary
// --tap-dialog-padding
// --tap-dialog-radius

export default css`
:host {
*,
*::before,
*::after {
box-sizing: border-box;
}
:host *,
:host *::before,
:host *::after {
box-sizing: inherit;
}
[hidden] {
display: none !important;
}
.overlay {
background-color: var(
--tap-dialog-color-surface-overlay,
var(--tap-sys-color-surface-overlay-dark)
);
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.dialog {
position: fixed;
left: var(--tap-dialog-left, var(--tap-sys-spacing-6));
right: var(--tap-dialog-right, var(--tap-sys-spacing-6));
bottom: var(--tap-dialog-bottom, var(--tap-sys-spacing-6));
background-color: var(
--tap-dialog-color-surface-primary,
var(--tap-sys-color-surface-primary)
);
font-family: var(--tap-dialog-font, var(--tap-sys-font-family));
border-radius: var(--tap-dialog-radius, var(--tap-sys-radius-6));
overflow: hidden;
.root.open {
visibility: visible;
opacity: 1;
}
.icon-container {
margin-top: var(--tap-dialog-icon-top-margin, var(--tap-sys-spacing-8));
display: flex;
justify-content: center;
.root.open .container {
transform: translateY(0);
}
.image-container {
height: 200px;
background-color: var(
--tap-dialog-image-container-background-color,
var(--tap-palette-gray-100)
);
.root.start .body {
text-align: start;
}
::slotted([slot="banner"]) {
width: 100%;
height: 100%;
.root.center {
text-align: center;
}
.content {
padding: var(
--tap-dialog-content-vertical-padding,
var(--tap-sys-spacing-4)
)
var(--tap-dialog-content-horizontal-padding, var(--tap-sys-spacing-6));
margin: var(--tap-dialog-content-vertical-margin, var(--tap-sys-spacing-6))
var(--tap-dialog-content-horizontal-margin, 0);
}
.root {
position: absolute;
top: 0;
left: 0;
.center {
text-align: center;
}
visibility: hidden;
opacity: 0;
.right {
text-align: right;
transition:
visibility 240ms ease,
opacity 240ms ease;
}
.left {
text-align: left;
.overlay {
background-color: var(--tap-sys-color-surface-overlay-dark);
position: fixed;
inset: 0;
}
.left {
text-align: left;
.container {
transform: translateY(2rem);
position: fixed;
left: var(--tap-sys-spacing-6);
right: var(--tap-sys-spacing-6);
bottom: var(--tap-sys-spacing-6);
background-color: var(--tap-sys-color-surface-primary);
font-family: var(--tap-sys-font-family);
border-radius: var(--tap-sys-radius-6);
overflow: hidden;
transition: transform 240ms ease;
}
.left {
text-align: left;
.body {
margin-top: var(--tap-sys-spacing-6);
margin-bottom: var(--tap-sys-spacing-6);
padding: var(--tap-sys-spacing-4) var(--tap-sys-spacing-6);
}
.title {
font-size: var(
--tap-dialog-title-size,
var(--tap-sys-typography-headline-sm-size)
);
font-weight: var(
--tap-dialog-title-weight,
var(--tap-sys-typography-headline-sm-weight)
);
line-height: var(
--tap-dialog-title-line-height,
var(--tap-sys-typography-headline-sm-height)
);
color: var(--tap-sys-color-content-primary);
font-size: var(--tap-sys-typography-headline-sm-size);
font-weight: var(--tap-sys-typography-headline-sm-weight);
line-height: var(--tap-sys-typography-headline-sm-height);
}
.description {
margin: var(--tap-dialog-description-margin, 0);
padding-top: var(
--tap-dialog-description-padding-top,
var(--tap-sys-spacing-4)
);
font-size: var(
--tap-dialog-description-font-size,
var(--tap-sys-typography-body-md-size)
);
font-weight: var(
--tap-dialog-description-font-weight,
var(--tap-sys-typography-body-md-weight)
);
line-height: var(
--tap-dialog-description-line-height,
var(--tap-sys-typography-body-md-height)
);
color: var(--tap-dialog-description-color, var(--tap-palette-gray-500));
color: var(--tap-sys-color-content-tertiary);
font-size: var(--tap-sys-typography-body-md-size);
font-weight: var(--tap-sys-typography-body-md-weight);
line-height: var(--tap-sys-typography-body-md-height);
}
.title + .description {
margin-top: var(--tap-sys-spacing-4);
}
.actions {
padding: var(--tap-dialog-actions-padding, var(--tap-sys-spacing-6));
padding: var(--tap-sys-spacing-6);
}
.actions ::slotted(*) {
width: 100%;
}
`;
Loading

0 comments on commit df3f6a4

Please sign in to comment.