Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(modal): provides content-top and content-bottom slots #6490

Merged
merged 21 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2ca9176
feat(modal): provides content-header and content-footer slots
Elijbet Feb 16, 2023
6ab5974
WIP: styling
Elijbet Feb 16, 2023
335e439
WIP: slots story
Elijbet Feb 16, 2023
3f4d382
WIP: content header/footer visibility
Elijbet Feb 16, 2023
9309a22
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 16, 2023
7abc8d0
WIP: cleanup
Elijbet Feb 16, 2023
7e9a4aa
WIP: keys and scroll text
Elijbet Feb 16, 2023
ee67199
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 16, 2023
a29e02e
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 17, 2023
aabeff0
WIP: cleanup stories, use onSlotChange instead of the getSlotted() ut…
Elijbet Feb 18, 2023
9b4e40a
WIP: tweak hidden
Elijbet Feb 21, 2023
ad74ffd
WIP: simplify
Elijbet Feb 21, 2023
4ebe033
WIP: cleanup
Elijbet Feb 21, 2023
b41f2e0
WIP: disable stylelint rule for use-logical to prevent overriding usi…
Elijbet Feb 22, 2023
7ed1cb1
WIP: cleanup
Elijbet Feb 22, 2023
1f5fb34
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 22, 2023
91083c5
WIP: try with linter update
Elijbet Feb 22, 2023
65f9c06
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 24, 2023
4742349
WIP: cleanup, eslint prevents commit because of unused var inport
Elijbet Feb 24, 2023
146164e
Merge branch 'master' into elijbet/4800-sticky-header-footer-content-…
Elijbet Feb 26, 2023
21327a9
WIP: cleanup
Elijbet Feb 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 48 additions & 9 deletions src/components/modal/modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*
* @prop --calcite-modal-content-background: Specifies the background color of content placed in the `content` slot.
* @prop --calcite-modal-content-padding: Specifies the padding of the modal `content` slot.
* @prop --calcite-modal-content-header-padding: Specifies the padding of the modal `content-header` slot.
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
* @prop --calcite-modal-content-footer-padding: Specifies the padding of the modal `content-footer` slot.
* @prop --calcite-modal-scrim-background: Specifies the background color of the modal scrim.
* @prop --calcite-modal-width: Specifies a width of the modal, using `px`, `em`, `rem`, `vw`, or `%`. Will never exceed the width of the viewport. Will not apply if `fullscreen` if set.
* @prop --calcite-modal-height: Specifies a height of the modal, using `px`, `em`, `rem`, `vh`, or `%`. Will never exceed the height of the viewport. Will not apply if `fullscreen` if set.
Expand Down Expand Up @@ -190,7 +192,41 @@
padding-inline: var(--calcite-modal-content-padding, var(--calcite-modal-padding-internal));
}

.content--no-footer {
.content-header {
@apply bg-foreground-1
border-color-3
flex
min-w-0
max-w-full
rounded-t
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
border-0
border-b
border-solid
z-header;
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
flex: 0 0 auto;
padding-block: var(--calcite-modal-content-header-padding, var(--calcite-modal-padding-internal));
padding-inline: var(--calcite-modal-content-header-padding, var(--calcite-modal-padding-internal));
}

.content-footer {
@apply bg-foreground-1
border-color-3
mt-auto
box-border
flex
w-full
justify-between
rounded-b
border-0
border-t
border-solid
z-header;
flex: 0 0 auto;
padding-block: var(--calcite-modal-content-footer-padding, var(--calcite-modal-padding-internal));
padding-inline: var(--calcite-modal-content-footer-padding, var(--calcite-modal-padding-internal));
}

.content--no-modal-footer {
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
@apply rounded-b;
}

Expand Down Expand Up @@ -287,10 +323,10 @@ slot[name="primary"] {
}

:host([open][fullscreen]) {
.header {
border-radius: 0;
}
.footer {
.header,
.footer,
.content-header,
.content-footer {
border-radius: 0;
}
}
Expand Down Expand Up @@ -339,7 +375,8 @@ slot[name="primary"] {
.modal {
@apply border-0 border-t-4 border-solid;
}
.header {
.header,
.content-header {
@apply rounded rounded-b-none;
}
}
Expand All @@ -348,10 +385,11 @@ slot[name="primary"] {
* Tablet
*/
@media screen and (max-width: $viewport-medium) {
@include slotted("header", "*") {
@include slotted("header", "content-header", "*") {
@apply text-1;
}
.footer {
.footer,
.content-footer {
@apply sticky bottom-0;
}
}
Expand All @@ -360,7 +398,8 @@ slot[name="primary"] {
* Mobile
*/
@media screen and (max-width: $viewport-small) {
.footer {
.footer,
.content-footer {
@apply flex-col;
}
.back,
Expand Down
30 changes: 30 additions & 0 deletions src/components/modal/modal.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,36 @@ export const simple = (): string => html`
</calcite-modal>
`;

const mightyLongTextToScroll = html`
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non nisi et elit auctor aliquet ac suscipit eros. Sed nec
nibh viverra, feugiat magna ut, posuere arcu. Curabitur varius erat ut suscipit convallis. Nullam semper pellentesque
est laoreet accumsan. Aenean eget urna fermentum, porttitor dui et, tincidunt erat. Curabitur lacinia lacus in urna
lacinia, ac interdum lorem fermentum. Ut accumsan malesuada varius. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Phasellus tempus tempor magna, eu dignissim urna ornare non. Integer tempor justo blandit nunc ornare, a
interdum nisl pharetra. Sed ultricies at augue vel fermentum. Maecenas laoreet odio lorem. Aliquam in pretium turpis.
Donec quis felis a diam accumsan vehicula efficitur at orci. Donec sollicitudin gravida ultrices.
`;

export const slots = (): string => html`
<calcite-modal
${boolean("open", true)}
kind="${select("kind", ["brand", "danger", "info", "success", "warning"], "")}"
scale="${select("scale", ["s", "m", "l"], "m")}"
width="${select("width", ["s", "m", "l"], "s")}"
${boolean("fullscreen", false)}
${boolean("docked", false)}
${boolean("escape-disabled", false)}
>
<h3 slot="header">Slot for a header.</h3>
<h4 slot="content-header">Slot for a content-header.</h4>
<div slot="content" style="height: 100px">
<p>${mightyLongTextToScroll}</p>
</div>
<h4 slot="content-footer">Slot for a content-footer.</h4>
<calcite-button slot="primary" width="full">Button</calcite-button>
</calcite-modal>
`;

export const darkModeRTLCustomSizeCSSVars_TestOnly = (): string => html`
<calcite-modal
class="calcite-mode-dark"
Expand Down
48 changes: 42 additions & 6 deletions src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ import { ModalMessages } from "./assets/modal/t9n";
/**
* @slot header - A slot for adding header text.
* @slot content - A slot for adding the component's content.
* @slot contentHeader - A slot for adding the component's content header.
* @slot contentFooter - A slot for adding the component's content footer.
* @slot primary - A slot for adding a primary button.
* @slot secondary - A slot for adding a secondary button.
* @slot back - A slot for adding a back button.
Expand Down Expand Up @@ -177,6 +179,8 @@ export class Modal
this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
this.cssVarObserver?.observe(this.el, { attributeFilter: ["style"] });
this.updateFooterVisibility();
this.updateContentHeaderVisibility();
this.updateContentFooterVisibility();
this.updateSizeCssVars();
connectConditionalSlotComponent(this);
connectLocalized(this);
Expand Down Expand Up @@ -223,24 +227,26 @@ export class Modal
<slot name={CSS.header} />
</header>
</div>
{this.renderContentHeader()}
<div
class={{
[CSS.content]: true,
[CSS.contentNoFooter]: !this.hasFooter
[CSS.contentNoModalFooter]: !this.hasModalFooter
}}
ref={(el) => (this.modalContent = el)}
>
<slot name={SLOTS.content} />
</div>
{this.renderFooter()}
{this.renderContentFooter()}
{this.renderModalFooter()}
</div>
</div>
</Host>
);
}

renderFooter(): VNode {
return this.hasFooter ? (
renderModalFooter(): VNode {
return this.hasModalFooter ? (
<div class={CSS.footer} key="footer">
<span class={CSS.back}>
<slot name={SLOTS.back} />
Expand All @@ -255,6 +261,22 @@ export class Modal
) : null;
}

renderContentHeader(): VNode {
return this.hasContentHeader ? (
<div class={CSS.contentHeader} key="content-header">
<slot name={SLOTS.contentHeader} />
</div>
) : null;
}

renderContentFooter(): VNode {
return this.hasContentFooter ? (
<div class={CSS.contentFooter} key="content-footer">
<slot name={SLOTS.contentFooter} />
</div>
) : null;
}

renderCloseButton(): VNode {
return !this.closeButtonDisabled ? (
<button
Expand Down Expand Up @@ -323,6 +345,8 @@ export class Modal

private mutationObserver: MutationObserver = createObserver("mutation", () => {
this.updateFooterVisibility();
this.updateContentHeaderVisibility();
this.updateContentFooterVisibility();
});

private cssVarObserver: MutationObserver = createObserver("mutation", () => {
Expand All @@ -347,7 +371,11 @@ export class Modal

@State() cssHeight: string | number;

@State() hasFooter = true;
@State() hasModalFooter = true;

@State() hasContentHeader = true;

@State() hasContentFooter = true;

/**
* We use internal variable to make sure initially open modal can transition from closed state when rendered
Expand Down Expand Up @@ -527,7 +555,15 @@ export class Modal
}

private updateFooterVisibility = (): void => {
this.hasFooter = !!getSlotted(this.el, [SLOTS.back, SLOTS.primary, SLOTS.secondary]);
this.hasModalFooter = !!getSlotted(this.el, [SLOTS.back, SLOTS.primary, SLOTS.secondary]);
};

private updateContentHeaderVisibility = (): void => {
this.hasContentHeader = !!getSlotted(this.el, SLOTS.contentHeader);
};

private updateContentFooterVisibility = (): void => {
this.hasContentFooter = !!getSlotted(this.el, SLOTS.contentFooter);
};

private updateSizeCssVars = (): void => {
Expand Down
6 changes: 5 additions & 1 deletion src/components/modal/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export const CSS = {
overflowHidden: "overflow-hidden",
container: "container",
content: "content",
contentNoFooter: "content--no-footer",
contentNoModalFooter: "content--no-modal-footer",
contentFooter: "content-footer",
contentHeader: "content-header",
slottedInShell: "slotted-in-shell",

// these classes help apply the animation in phases to only set transform on open/close
Expand All @@ -36,6 +38,8 @@ export const ICONS = {

export const SLOTS = {
content: "content",
contentFooter: "content-footer",
contentHeader: "content-header",
header: "header",
back: "back",
secondary: "secondary",
Expand Down