Skip to content

Commit

Permalink
feat(Modal): update Modal styles to phase 2 AI spec (#15727)
Browse files Browse the repository at this point in the history
* feat(Modal): update Modal styles to phase 2 AI spec

* test(snapshot): update snapshots

* feat(Modal): add overflow effect

* refactor(Modal): adjust mask so that focus, scroll bar are not masked

* chore(Modal): fix storybook control, adjust mask-image values
  • Loading branch information
tw15egan committed Feb 14, 2024
1 parent 1ca2ae7 commit de4793c
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 21 deletions.
Expand Up @@ -16,6 +16,7 @@ Array [
"aiGradientStart01",
"aiGradientStart02",
"aiInnerShadow",
"aiOverlay",
"background",
"backgroundActive",
"backgroundBrand",
Expand Down
88 changes: 77 additions & 11 deletions packages/react/src/components/Slug/Slug-examples.stories.js
Expand Up @@ -276,25 +276,50 @@ export const _Combobox = {
};

export const _ComposedModal = {
args: {
showButtons: true,
hasScrollingContent: false,
},
argTypes: {
slug: {
description:
'**Experimental**: Provide a `Slug` component to be rendered inside the component',
},
hasScrollingContent: {
description: 'Add scrolling content indicator',
},
showButtons: {
description: 'Show or hide the Modal buttons',
},
},
render: () => {
render: (args) => {
const [open, setOpen] = useState(true); // eslint-disable-line
return (
<div className="slug-modal">
<Button onClick={() => setOpen(true)}>Launch composed modal</Button>
<ComposedModal open={open} onClose={() => setOpen(false)} slug={slug}>
<ModalHeader label="Account resources" title="Add a custom domain" />
<ModalBody>
<ModalBody hasScrollingContent={args.hasScrollingContent}>
<p style={{ marginBottom: '1rem' }}>
Custom domains direct requests for your apps in this Cloud Foundry
organization to a URL that you own. A custom domain can be a
shared domain, a shared subdomain, or a shared domain and host.
</p>
<p style={{ marginBottom: '1rem' }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
eu nibh odio. Nunc a consequat est, id porttitor sapien. Proin
vitae leo vitae orci tincidunt auctor eget eget libero. Ut
tincidunt ultricies fringilla. Aliquam erat volutpat. Aenean arcu
odio, elementum vel vehicula vitae, porttitor ac lorem. Sed
viverra elit ac risus tincidunt fermentum. Ut sollicitudin nibh id
risus ornare ornare. Etiam gravida orci ut lectus dictum, quis
ultricies felis mollis. Mauris nec commodo est, nec faucibus nibh.
Nunc commodo ante quis pretium consectetur. Ut ac nisl vitae mi
mattis vulputate a at elit. Nullam porttitor ex eget mi feugiat
mattis. Nunc non sodales magna. Proin ornare tellus quis hendrerit
egestas. Donec pharetra leo nec molestie sollicitudin.
</p>

<TextInput
data-modal-primary-focus
id="text-input-1"
Expand All @@ -306,14 +331,29 @@ export const _ComposedModal = {
<SelectItem value="us-south" text="US South" />
<SelectItem value="us-east" text="US East" />
</Select>
<p style={{ marginBlock: '1rem' }}>
Custom domains direct requests for your apps in this Cloud Foundry
organization to a URL that you own. A custom domain can be a
shared domain, a shared subdomain, or a shared domain and host.
</p>
<TextInput
data-modal-primary-focus
id="text-input-1"
labelText="Domain name"
placeholder="e.g. github.com"
style={{ marginBottom: '1rem' }}
/>
</ModalBody>
<ModalFooter
primaryButtonText="Add"
secondaryButtons={[
{ buttonText: 'Keep both' },
{ buttonText: 'Rename' },
]}
/>

{args.showButtons && (
<ModalFooter
primaryButtonText="Add"
secondaryButtons={[
{ buttonText: 'Keep both' },
{ buttonText: 'Rename' },
]}
/>
)}
</ComposedModal>
</div>
);
Expand Down Expand Up @@ -380,13 +420,23 @@ export const _FilterableMultiselect = {
};

export const _Modal = {
args: {
showButtons: true,
hasScrollingContent: false,
},
argTypes: {
slug: {
description:
'**Experimental**: Provide a `Slug` component to be rendered inside the component',
},
hasScrollingContent: {
description: 'Add scrolling content indicator',
},
showButtons: {
description: 'Show or hide the Modal buttons',
},
},
render: () => {
render: (args) => {
const [open, setOpen] = useState(true); // eslint-disable-line
return (
<div className="slug-modal">
Expand All @@ -398,12 +448,28 @@ export const _Modal = {
modalLabel="Account resources"
primaryButtonText="Add"
secondaryButtonText="Cancel"
passiveModal={!args.showButtons}
hasScrollingContent={args.hasScrollingContent}
slug={slug}>
<p>
<p style={{ marginBottom: '1rem' }}>
Custom domains direct requests for your apps in this Cloud Foundry
organization to a URL that you own. A custom domain can be a shared
domain, a shared subdomain, or a shared domain and host.
</p>
<p style={{ marginBottom: '1rem' }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
eu nibh odio. Nunc a consequat est, id porttitor sapien. Proin vitae
leo vitae orci tincidunt auctor eget eget libero. Ut tincidunt
ultricies fringilla. Aliquam erat volutpat. Aenean arcu odio,
elementum vel vehicula vitae, porttitor ac lorem. Sed viverra elit
ac risus tincidunt fermentum. Ut sollicitudin nibh id risus ornare
ornare. Etiam gravida orci ut lectus dictum, quis ultricies felis
mollis. Mauris nec commodo est, nec faucibus nibh. Nunc commodo ante
quis pretium consectetur. Ut ac nisl vitae mi mattis vulputate a at
elit. Nullam porttitor ex eget mi feugiat mattis. Nunc non sodales
magna. Proin ornare tellus quis hendrerit egestas. Donec pharetra
leo nec molestie sollicitudin.
</p>
<TextInput
data-modal-primary-focus
id="text-input-1"
Expand Down
1 change: 1 addition & 0 deletions packages/styles/scss/__tests__/theme-test.js
Expand Up @@ -162,6 +162,7 @@ describe('@carbon/styles/scss/theme', () => {
"ai-border-start",
"ai-border-end",
"ai-drop-shadow",
"ai-overlay",
"slug-callout-caret-center",
"slug-callout-caret-bottom",
"slug-callout-caret-bottom-background",
Expand Down
43 changes: 33 additions & 10 deletions packages/styles/scss/components/modal/_modal.scss
Expand Up @@ -450,21 +450,25 @@
}

// Slug styles
.#{$prefix}--modal--slug.#{$prefix}--modal {
background-color: $ai-overlay;
}

.#{$prefix}--modal--slug .#{$prefix}--modal-container {
@include callout-gradient();
@include callout-gradient('default', 0, 'layer');

border: 1px solid transparent;
background-color: $layer;
box-shadow: inset 0 -80px 70px -65px $ai-inner-shadow,
0 4px 10px 2px $ai-drop-shadow;
}

// Start the gradient 64px from bottom only when two buttons are present
.#{$prefix}--modal--slug
.#{$prefix}--modal-container:has(
.#{$prefix}--btn-set:not(.#{$prefix}--modal-footer--three-button)
> button:not(:only-child)
) {
@include callout-gradient('default', 64px);
.#{$prefix}--modal-container:has(.#{$prefix}--modal-footer) {
@include callout-gradient('default', 64px, 'layer');

background-color: $layer;
box-shadow: inset 0 -80px 0 -16px $layer,
inset 0 -160px 70px -65px $ai-inner-shadow, 0 4px 10px 2px $ai-drop-shadow;
}

.#{$prefix}--modal--slug .#{$prefix}--slug {
Expand All @@ -473,6 +477,19 @@
inset-inline-end: 0;
}

.#{$prefix}--modal--slug
.#{$prefix}--modal-content.#{$prefix}--modal-scroll-content {
mask-image: linear-gradient(
to bottom,
$layer calc(100% - 80px),
transparent calc(100% - 48px),
transparent 100%
),
linear-gradient(to left, $layer 0, 16px, transparent 16px),
linear-gradient(to right, $layer 0, 2px, transparent 2px),
linear-gradient(to top, $layer 0, 2px, transparent 2px);
}

.#{$prefix}--modal-header
> .#{$prefix}--slug:has(+ .#{$prefix}--modal-close-button),
.#{$prefix}--modal-header
Expand All @@ -484,14 +501,20 @@
inset-inline-end: convert.to-rem(48px);
}

.#{$prefix}--modal--slug
.#{$prefix}--modal-content--overflow-indicator::before,
.#{$prefix}--modal--slug .#{$prefix}--modal-content--overflow-indicator {
display: none;
}

// Windows HCM fix
/* stylelint-disable */
/* stylelint-disable no-duplicate-selectors */
.#{$prefix}--modal-close__icon {
@include high-contrast-mode('icon-fill');
}

.#{$prefix}--modal-close:focus {
@include high-contrast-mode('focus');
}
/* stylelint-enable */
/* stylelint-enable no-duplicate-selectors */
}
1 change: 1 addition & 0 deletions packages/styles/scss/utilities/_ai-gradient.scss
Expand Up @@ -124,6 +124,7 @@
} @else {
background: linear-gradient(
to top,
$background $start,
theme.$ai-aura-start $start,
theme.$ai-aura-end 50%
)
Expand Down
4 changes: 4 additions & 0 deletions packages/themes/src/g10.js
Expand Up @@ -13,6 +13,7 @@ import {
blue40,
blue60,
blue70,
blue100,

// CoolGray
coolGray10,
Expand Down Expand Up @@ -232,6 +233,9 @@ export const aiAuraHoverEnd = rgba(white, 0);
export const slugCalloutShadowOuter01 = rgba(blue70, 0.25);
export const slugCalloutShadowOuter02 = rgba(black, 0.1);

// AI Modal tokens
export const aiOverlay = rgba(blue100, 0.5);

//// Not used in phase 2 / possibly remove?
export const slugCalloutGradientTop = rgba(gray10, 0.85);
export const slugCalloutGradientBottom = rgba(gray20, 0.85);
Expand Down
4 changes: 4 additions & 0 deletions packages/themes/src/g100.js
Expand Up @@ -13,6 +13,7 @@ import {
blue60,
blue70,
blue80,
blue100,

// Gray
gray10,
Expand Down Expand Up @@ -237,6 +238,9 @@ export const aiAuraHoverEnd = rgba(black, 0);
export const slugCalloutShadowOuter01 = rgba(blue80, 0.25);
export const slugCalloutShadowOuter02 = rgba(black, 0.65);

// AI Modal tokens
export const aiOverlay = rgba(blue100, 0.5);

//// Not used in phase 2 / possibly remove?
export const slugCalloutGradientTop = rgba(gray100, 0.85);
export const slugCalloutGradientBottom = rgba(gray90, 0.85);
Expand Down
4 changes: 4 additions & 0 deletions packages/themes/src/g90.js
Expand Up @@ -13,6 +13,7 @@ import {
blue60,
blue70,
blue80,
blue100,

// Gray
gray10,
Expand Down Expand Up @@ -238,6 +239,9 @@ export const aiAuraHoverEnd = rgba(black, 0);
export const slugCalloutShadowOuter01 = rgba(blue80, 0.25);
export const slugCalloutShadowOuter02 = rgba(black, 0.65);

// AI Modal tokens
export const aiOverlay = rgba(blue100, 0.5);

//// Not used in phase 2 / possibly remove?
export const slugCalloutGradientTop = rgba(gray100, 0.85);
export const slugCalloutGradientBottom = rgba(gray90, 0.85);
Expand Down
Expand Up @@ -273,6 +273,7 @@ Array [
"ai-border-start",
"ai-border-end",
"ai-drop-shadow",
"ai-overlay",
"slug-callout-caret-center",
"slug-callout-caret-bottom",
"slug-callout-caret-bottom-background",
Expand Down
4 changes: 4 additions & 0 deletions packages/themes/src/tokens/__tests__/metadata-test.js
Expand Up @@ -1065,6 +1065,10 @@ test('metadata', () => {
"name": "ai-drop-shadow",
"type": "color",
},
Object {
"name": "ai-overlay",
"type": "color",
},
Object {
"name": "slug-callout-caret-center",
"type": "color",
Expand Down
1 change: 1 addition & 0 deletions packages/themes/src/tokens/v11TokenGroup.js
Expand Up @@ -382,6 +382,7 @@ export const ai = TokenGroup.create({
'ai-border-start',
'ai-border-end',
'ai-drop-shadow',
'ai-overlay',
// Caret tokens
'slug-callout-caret-center',
'slug-callout-caret-bottom',
Expand Down
4 changes: 4 additions & 0 deletions packages/themes/src/white.js
Expand Up @@ -13,6 +13,7 @@ import {
blue40,
blue60,
blue70,
blue100,

// CoolGray
coolGray10,
Expand Down Expand Up @@ -232,6 +233,9 @@ export const aiAuraHoverEnd = rgba(white, 0);
export const slugCalloutShadowOuter01 = rgba(blue70, 0.25);
export const slugCalloutShadowOuter02 = rgba(black, 0.1);

// AI Modal tokens
export const aiOverlay = rgba(blue100, 0.5);

//// Not used in phase 2 / possibly remove?
export const slugCalloutGradientTop = rgba(gray10, 0.85);
export const slugCalloutGradientBottom = rgba(gray20, 0.85);
Expand Down

0 comments on commit de4793c

Please sign in to comment.