diff --git a/package.json b/package.json index 24a44681d5..0881725b54 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ { "path": "lib/components/internal/widget-exports.js", "brotli": false, - "limit": "775 kB", + "limit": "776 kB", "ignore": "react-dom" } ], diff --git a/pages/app-layout/utils/external-widget.tsx b/pages/app-layout/utils/external-widget.tsx index 0edf5eefbd..b0137f824a 100644 --- a/pages/app-layout/utils/external-widget.tsx +++ b/pages/app-layout/utils/external-widget.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useImperativeHandle, useRef, useState } from 'react'; import ReactDOM, { unmountComponentAtNode } from 'react-dom'; +import ButtonDropdown from '~components/button-dropdown'; import Drawer from '~components/drawer'; import awsuiPlugins from '~components/internal/plugins'; @@ -153,13 +154,20 @@ awsuiPlugins.appLayout.registerDrawer({ mountContent: (container, mountContext) => { ReactDOM.render( - - global widget content circle 1 - {new Array(100).fill(null).map((_, index) => ( -
{index}
- ))} -
circle-global bottom content
-
, + Global drawer} + headerActions={ + + } + > + + global widget content circle 1 + {new Array(100).fill(null).map((_, index) => ( +
{index}
+ ))} +
circle-global bottom content
+
+
, container ); }, diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index 24b942b4a9..4b22dd5285 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -8451,6 +8451,11 @@ It should contain the only \`h2\` used in the drawer.", "isDefault": false, "name": "header", }, + { + "description": "Actions for the header. Available only if you specify the \`header\` property.", + "isDefault": false, + "name": "headerActions", + }, ], "releaseStatus": "stable", } diff --git a/src/__tests__/snapshot-tests/__snapshots__/test-utils-selectors.test.tsx.snap b/src/__tests__/snapshot-tests/__snapshots__/test-utils-selectors.test.tsx.snap index c47fe6939d..7c52e98da4 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/test-utils-selectors.test.tsx.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/test-utils-selectors.test.tsx.snap @@ -246,6 +246,7 @@ exports[`test-utils selectors 1`] = ` ], "drawer": [ "awsui_drawer_1sxt8", + "awsui_header-actions_1sxt8", "awsui_header_1sxt8", "awsui_test-utils-drawer-content_1sxt8", ], diff --git a/src/drawer/__tests__/drawer.test.tsx b/src/drawer/__tests__/drawer.test.tsx index 26b8241c23..0109d762f6 100644 --- a/src/drawer/__tests__/drawer.test.tsx +++ b/src/drawer/__tests__/drawer.test.tsx @@ -25,6 +25,22 @@ test('renders header if it is provided', () => { expect(wrapper.findContent()!.getElement()).toHaveTextContent('there is a header above'); }); +test('renders header actions if it is provided', () => { + const wrapper = renderDrawer( + Header actions}> + there is a header above + + ); + expect(wrapper.findHeader()!.getElement()).toHaveTextContent('Bla bla'); + expect(wrapper.findHeaderActions()!.getElement()).toHaveTextContent('Header actions'); + expect(wrapper.findContent()!.getElement()).toHaveTextContent('there is a header above'); +}); + +test('does not render header actions if header is not provided', () => { + const wrapper = renderDrawer(Header actions}>there is a header above); + expect(wrapper.findHeaderActions()).toBeFalsy(); +}); + test('renders loading state', () => { const { container } = render(); expect(createWrapper(container).findStatusIndicator()!.getElement()).toHaveTextContent('Loading content'); diff --git a/src/drawer/implementation.tsx b/src/drawer/implementation.tsx index 9cddc690c2..40e710242d 100644 --- a/src/drawer/implementation.tsx +++ b/src/drawer/implementation.tsx @@ -23,6 +23,7 @@ export function DrawerImplementation({ i18nStrings, disableContentPaddings, __internalRootRef, + headerActions, ...restProps }: DrawerInternalProps) { const baseProps = getBaseProps(restProps); @@ -32,6 +33,7 @@ export function DrawerImplementation({ ...baseProps, className: clsx(baseProps.className, styles.drawer, isToolbar && styles['with-toolbar']), }; + return loading ? (
) : (
- {header &&
{header}
} + {header && ( +
+ {header} + {headerActions &&
{headerActions}
} +
+ )}
& { border-color: transparent; margin-block-end: 0px; @@ -36,6 +39,17 @@ /* stylelint-enable @cloudscape-design/no-implicit-descendant, selector-max-type */ } +.header-actions { + display: inline-flex; + align-items: start; + z-index: 1; + /* + Compensate for the difference between the runtime drawer's and the drawer component's heading + to ensure the header actions are vertically aligned + */ + margin-block-start: -6px; +} + .content-with-paddings:not(:empty) { padding-block-start: awsui.$space-panel-content-top; padding-inline-start: awsui.$space-panel-side-left; diff --git a/src/test-utils/dom/drawer/index.ts b/src/test-utils/dom/drawer/index.ts index 00d4020439..7d6b009750 100644 --- a/src/test-utils/dom/drawer/index.ts +++ b/src/test-utils/dom/drawer/index.ts @@ -11,6 +11,10 @@ export default class DrawerWrapper extends ComponentWrapper { return this.findByClassName(styles.header); } + findHeaderActions(): ElementWrapper | null { + return this.findByClassName(styles['header-actions']); + } + findContent(): ElementWrapper | null { return this.findByClassName(styles['test-utils-drawer-content']); }