Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const permutations = createPermutations<ExpandableSectionProps>([
],
headerInfo: [undefined, headerInfo],
headerActions: [undefined, headerActions],
footer: ['Expandable section footer value', undefined],
disableContentPaddings: [true, false],
},
{
headerCounter: ['(5)'],
Expand Down
47 changes: 36 additions & 11 deletions src/container/internal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useRef } from 'react';
import { CSSTransition } from 'react-transition-group';
import clsx from 'clsx';

import { useMergeRefs, useUniqueId } from '@cloudscape-design/component-toolkit/internal';
Expand Down Expand Up @@ -39,6 +40,8 @@ export interface InternalContainerProps extends Omit<ContainerProps, 'variant'>,
*/
variant?: ContainerProps['variant'] | 'embedded' | 'full-page' | 'cards';

__expanded?: boolean;
__usedAsExpandableSection?: boolean;
__funnelSubStepProps?: ReturnType<typeof useFunnelSubStep>['funnelSubStepProps'];
__subStepRef?: ReturnType<typeof useFunnelSubStep>['subStepRef'];
}
Expand Down Expand Up @@ -78,6 +81,8 @@ export default function InternalContainer({
__disableStickyMobile = true,
__funnelSubStepProps,
__subStepRef,
__expanded = false,
__usedAsExpandableSection = false,
...restProps
}: InternalContainerProps) {
const isMobile = useMobile();
Expand Down Expand Up @@ -108,6 +113,36 @@ export default function InternalContainer({
const hasMedia = !!media?.content;
const mediaPosition = media?.position ?? 'top';

const footerDisplay = __usedAsExpandableSection
? footer && (
<CSSTransition in={__expanded} timeout={30} classNames={{ enter: styles['expandable-container-footer-enter'] }}>
<div
className={clsx(
styles['expandable-container-footer'],
{
[styles['with-divider']]: !__disableFooterDivider,
[styles['with-paddings']]: !disableFooterPaddings,
},
__expanded && styles['expandable-container-footer-expanded']
)}
style={getFooterStyles(style)}
>
{footer}
</div>
</CSSTransition>
)
: footer && (
<div
className={clsx(styles.footer, {
[styles['with-divider']]: !__disableFooterDivider,
[styles['with-paddings']]: !disableFooterPaddings,
})}
style={getFooterStyles(style)}
>
{footer}
</div>
);

return (
<div
{...baseProps}
Expand Down Expand Up @@ -188,17 +223,7 @@ export default function InternalContainer({
{children}
</div>
</div>
{footer && (
<div
className={clsx(styles.footer, {
[styles['with-divider']]: !__disableFooterDivider,
[styles['with-paddings']]: !disableFooterPaddings,
})}
style={getFooterStyles(style)}
>
{footer}
</div>
)}
{footerDisplay}
</div>
</div>
);
Expand Down
16 changes: 16 additions & 0 deletions src/container/motion.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

@use '../internal/styles' as styles;
@use '../internal/styles/tokens' as tokens;

.expandable-container-footer {
&-enter {
@include styles.with-motion {
animation: awsui-motion-fade-in tokens.$motion-duration-show-paced tokens.$motion-easing-show-paced;
@include styles.animation-fade-in;
}
}
}
19 changes: 19 additions & 0 deletions src/container/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@use '../internal/styles' as styles;
@use './shared' as shared;

@use './motion';

.root {
@include styles.styles-reset;
word-wrap: break-word;
Expand Down Expand Up @@ -283,3 +285,20 @@
@include shared.divider;
}
}

.expandable-container-footer {
display: none;

&.with-paddings {
padding-block: awsui.$space-scaled-s;
padding-inline: awsui.$space-container-horizontal;
}

&.with-divider {
@include shared.divider;
}

&-expanded {
display: block;
}
}
6 changes: 6 additions & 0 deletions src/expandable-section/expandable-section-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface ExpandableSectionContainerProps extends InternalBaseComponentProps {
className?: string;
header: React.ReactNode;
children?: React.ReactNode;
footer?: React.ReactNode;
variant: InternalVariant;
expanded: boolean | undefined;
disableContentPaddings: boolean | undefined;
Expand All @@ -30,6 +31,7 @@ export const ExpandableSectionContainer = ({
className,
children,
header,
footer,
variant,
expanded,
disableContentPaddings,
Expand Down Expand Up @@ -59,10 +61,14 @@ export const ExpandableSectionContainer = ({
className={className}
header={header}
variant={variant === 'stacked' ? 'stacked' : 'default'}
footer={footer}
disableContentPaddings={disableContentPaddings || !expanded}
disableFooterPaddings={disableContentPaddings || !expanded}
disableHeaderPaddings={true}
__hiddenContent={!expanded}
__internalRootRef={__internalRootRef}
__expanded={expanded}
__usedAsExpandableSection={true}
{...metadataAttribute}
>
{children}
Expand Down
5 changes: 5 additions & 0 deletions src/expandable-section/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export interface ExpandableSectionProps extends BaseComponentProps {
*/
disableContentPaddings?: boolean;

/**
* Optional slot for a footer that is only available when the `container` or `stacked` variant for this component is used.
*/
footer?: React.ReactNode;

/**
* Primary content displayed in the expandable section element.
*/
Expand Down
Loading