-
-
- {!hidePreferencesButton && isOpen && (
- <>
+
+
+
+
+ {headerInfo && (
+ {headerInfo}
+ )}
+
+ {headerActions && (
+
{headerActions}
+ )}
+
+
+ {!hidePreferencesButton && isOpen && (
+ <>
+ setPreferencesOpen(true)}
+ formAction="none"
+ ariaLabel={i18nStrings.preferencesTitle}
+ ref={refs.preferences}
+ />
+
+ >
+ )}
+
+ {isOpen ? (
setPreferencesOpen(true)}
+ onClick={onToggle}
formAction="none"
- ariaLabel={i18nStrings.preferencesTitle}
- ref={refs.preferences}
+ ariaLabel={i18nStrings.closeButtonAriaLabel}
+ ariaExpanded={isOpen}
/>
-
- >
- )}
-
- {isOpen ? (
-
- ) : position === 'side' || closeBehavior === 'hide' ? null : (
-
- )}
+ ) : position === 'side' || closeBehavior === 'hide' ? null : (
+
+ )}
+
+
+ {showDescription && (
+
{headerDescription}
+ )}
);
@@ -230,6 +265,7 @@ export function SplitPanelImplementation({
panelHeaderId={panelHeaderId}
appLayoutMaxWidth={appLayoutMaxWidth}
closeBehavior={closeBehavior}
+ hasCustomElements={hasCustomElements}
>
{children}
diff --git a/src/split-panel/index.tsx b/src/split-panel/index.tsx
index 06ba2088f6..377030aafd 100644
--- a/src/split-panel/index.tsx
+++ b/src/split-panel/index.tsx
@@ -19,6 +19,11 @@ export default function SplitPanel({
}: SplitPanelProps) {
const { __internalRootRef } = useBaseComponent('SplitPanel', {
props: { closeBehavior, hidePreferencesButton },
+ metadata: {
+ hasHeaderActions: Boolean(restProps.headerActions),
+ hasHeaderDescription: Boolean(restProps.headerDescription),
+ hasHeaderInfo: Boolean(restProps.headerInfo),
+ },
});
const i18n = useInternalI18n('split-panel');
const i18nModal = useInternalI18n('modal');
diff --git a/src/split-panel/interfaces.ts b/src/split-panel/interfaces.ts
index 97a6b2a624..ac7c9cebc5 100644
--- a/src/split-panel/interfaces.ts
+++ b/src/split-panel/interfaces.ts
@@ -33,6 +33,21 @@ export interface SplitPanelProps extends BaseComponentProps {
* @i18n
*/
i18nStrings?: SplitPanelProps.I18nStrings;
+
+ /**
+ * Actions for the header. Available only if you specify the `header` property.
+ */
+ headerActions?: React.ReactNode;
+
+ /**
+ * Supplementary text below the heading.
+ */
+ headerDescription?: React.ReactNode;
+
+ /**
+ * The area next to the heading, used to display an Info link.
+ */
+ headerInfo?: React.ReactNode;
}
export namespace SplitPanelProps {
diff --git a/src/split-panel/styles.scss b/src/split-panel/styles.scss
index 1fd95cb935..148466557d 100644
--- a/src/split-panel/styles.scss
+++ b/src/split-panel/styles.scss
@@ -71,8 +71,9 @@ $app-layout-drawer-width: calc(#{awsui.$space-layout-toggle-diameter} + 2 * #{aw
&.drawer-closed {
overflow: hidden;
}
- &.drawer-closed:hover {
+ &.drawer-closed.drawer-clickable:hover {
background: awsui.$color-background-layout-panel-hover;
+ cursor: pointer;
}
& > .drawer-content-bottom > [aria-hidden='true'] {
display: none;
@@ -227,11 +228,6 @@ $app-layout-drawer-width: calc(#{awsui.$space-layout-toggle-diameter} + 2 * #{aw
}
.header {
- display: flex;
- flex: auto;
- flex-direction: row;
- align-items: flex-start;
- justify-content: space-between;
inline-size: 100%;
margin-block: awsui.$size-vertical-panel-icon-offset;
margin-inline: 0;
@@ -239,17 +235,60 @@ $app-layout-drawer-width: calc(#{awsui.$space-layout-toggle-diameter} + 2 * #{aw
margin-block: constants.$toolbar-vertical-panel-icon-offset;
}
+ &-main-row,
+ &-main-content {
+ display: flex;
+ }
+
+ &-main-row {
+ align-items: flex-start;
+ }
+
+ &-main-content {
+ flex: auto;
+ flex-direction: row;
+ flex-wrap: wrap;
+ column-gap: awsui.$space-scaled-xs;
+ row-gap: awsui.$space-scaled-xxs;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ &-text-and-info {
+ $vertical-margin: calc(#{awsui.$space-scaled-xxs} + 1px);
+ margin-block-start: $vertical-margin;
+ min-block-size: calc(#{awsui.$font-panel-header-line-height} + #{$vertical-margin});
+ // The line height of the header text might not be respected in non-high pixel density screens
+ // unless it is set to a smaller value in its parent container.
+ line-height: awsui.$line-height-body-s;
+ }
+
+ &-text,
+ &-info {
+ display: inline;
+ }
+
&-text {
@include styles.font-panel-header;
+ flex-grow: 1;
padding-block: 0;
padding-inline: 0;
- margin-block: 0;
margin-inline: 0;
- margin-block-start: calc(#{awsui.$space-scaled-xxs} + 1px);
+ margin-block: 0;
+ &.with-info {
+ margin-inline-end: awsui.$space-scaled-xs;
+ }
+ }
+
+ &-description {
+ color: awsui.$color-text-heading-secondary;
+ @include styles.font-body-m;
+ margin-block-start: awsui.$space-scaled-xxxs;
+ margin-block-end: 0;
}
}
-.header-actions {
+.header-buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
diff --git a/src/split-panel/test-classes/styles.scss b/src/split-panel/test-classes/styles.scss
index d977bcc68e..f2fd3e5335 100644
--- a/src/split-panel/test-classes/styles.scss
+++ b/src/split-panel/test-classes/styles.scss
@@ -4,6 +4,9 @@
*/
.root,
+.header-actions,
+.header-description,
+.header-info,
.header-text,
.open-button,
.close-button,
diff --git a/src/test-utils/dom/split-panel/index.ts b/src/test-utils/dom/split-panel/index.ts
index b7a329f368..6a0399c3c5 100644
--- a/src/test-utils/dom/split-panel/index.ts
+++ b/src/test-utils/dom/split-panel/index.ts
@@ -30,6 +30,18 @@ export default class SplitPanelWrapper extends ComponentWrapper {
return this.findByClassName(testUtilStyles.slider);
}
+ findHeaderActions() {
+ return this.findByClassName(testUtilStyles['header-actions']);
+ }
+
+ findHeaderDescription() {
+ return this.findByClassName(testUtilStyles['header-description']);
+ }
+
+ findHeaderInfo() {
+ return this.findByClassName(testUtilStyles['header-info']);
+ }
+
/**
* Returns the same panel if it's currently open in bottom position. If not, it returns null.
* Use this method to assert the panel position.