Skip to content

Commit

Permalink
Merge branch 'rucarva-applayout-navigation-panel' into dev-v3-rucarva
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruben Carvalho committed Aug 10, 2023
2 parents aa4ae9e + 60bd1ae commit bf3f7df
Show file tree
Hide file tree
Showing 25 changed files with 132 additions and 56 deletions.
3 changes: 1 addition & 2 deletions pages/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ function App() {
urlParams: { density, motionDisabled },
} = useContext(AppContext);

const isAppLayout =
pageId !== undefined && (pageId.indexOf('app-layout') > -1 || pageId.indexOf('content-layout') > -1);
const isAppLayout = pageId !== undefined && (pageId.includes('app-layout') || pageId.includes('content-layout'));
// AppLayout already contains <main>
// Also, AppLayout pages should resemble the ConsoleNav 2.0 styles
const ContentTag = isAppLayout ? 'div' : 'main';
Expand Down
9 changes: 8 additions & 1 deletion pages/cards/permutations.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ function createSimpleItems(count: number) {
}

const cardDefinition: CardsProps.CardDefinition<Item> = {
header: item => (item.number === 2 ? <Link href="#">{item.text}</Link> : item.text),
header: item =>
item.number === 2 ? (
<Link href="#" fontSize="inherit">
{item.text}
</Link>
) : (
item.text
),
sections: [
{
id: 'description',
Expand Down
2 changes: 1 addition & 1 deletion pages/cards/selection.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface Item {
const ariaLabels: CardsProps<Item>['ariaLabels'] = {
selectionGroupLabel: 'group label',
itemSelectionLabel: ({ selectedItems }, item) =>
`${item.text} is ${selectedItems.indexOf(item) < 0 ? 'not ' : ''}selected`,
`${item.text} is ${!selectedItems.includes(item) ? 'not ' : ''}selected`,
};

function createSimpleItems(count: number) {
Expand Down
2 changes: 1 addition & 1 deletion pages/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"lib": ["ES2015", "DOM"],
"lib": ["ES2020", "DOM"],
"target": "ES2015",
"declaration": false,
"declarationMap": false,
Expand Down
20 changes: 9 additions & 11 deletions src/__a11y__/run-a11y-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import useBrowser from '@cloudscape-design/browser-test-tools/use-browser';
import { findAllPages } from '../__integ__/utils';
import A11yPageObject from './a11y-page-object';

type Theme = string;
type Theme = 'default' | 'visual-refresh';
type Mode = 'light' | 'dark';

function setupTest(url: string, testFn: (page: A11yPageObject) => Promise<void>) {
Expand All @@ -19,21 +19,19 @@ function setupTest(url: string, testFn: (page: A11yPageObject) => Promise<void>)
}

function urlFormatter(inputUrl: string, theme: Theme, mode: Mode) {
return `#/${mode}/${inputUrl}?visualRefresh=${theme.indexOf('visual-refresh') !== -1 ? 'true' : 'false'}`;
return `#/${mode}/${inputUrl}?visualRefresh=${theme === 'visual-refresh' ? 'true' : 'false'}`;
}

export default function runA11yTests(theme: Theme, mode: Mode, skip: string[] = []) {
describe(`A11y checks for ${mode} ${theme}`, () => {
findAllPages().forEach(inputUrl => {
const testFunction =
[
...skip,
'theming/tokens',
// this page intentionally has issues to test the helper
'undefined-texts',
].indexOf(inputUrl) === -1
? test
: test.skip;
const skipPages = [
...skip,
'theming/tokens',
// this page intentionally has issues to test the helper
'undefined-texts',
];
const testFunction = skipPages.includes(inputUrl) ? test.skip : test;
const url = urlFormatter(inputUrl, theme, mode);
testFunction(
url,
Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/__snapshots__/documenter.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3587,7 +3587,7 @@ add a meaningful description to the whole selection.",
Object {
"description": " Defines what to display in each card. It has the following properties:
* \`header\` ((item) => ReactNode) - Responsible for displaying the card header. You receive the current item as an argument.
Use \`fontSize=\\"heading-m\\"\` on [link](/components/link/) components inside card header.
Use \`fontSize=\\"inherit\\"\` on [link](/components/link/) components inside card header.
* \`sections\` (array) - Responsible for displaying the card content. Cards can have many sections in their
body. Each entry in the array is responsible for displaying a section. An entry has the following properties:
* \`id\`: (string) - A unique identifier for the section. The property is used as a [keys](https://reactjs.org/docs/lists-and-keys.html#keys)
Expand Down Expand Up @@ -6522,6 +6522,7 @@ A flash message object contains the following properties:
When a user clicks on this button the \`onDismiss\` handler is called.
* \`dismissLabel\` (string) - Specifies an \`aria-label\` for to the dismiss icon button for improved accessibility.
* \`statusIconAriaLabel\` (string) - Specifies an \`aria-label\` for to the status icon for improved accessibility.
If not provided, \`i18nStrings.{type}IconAriaLabel\` will be used as a fallback.
* \`ariaRole\` (string) - For flash messages added after page load, specifies how this message is communicated to assistive
technology. Use \\"status\\" for status updates or informational content. Use \\"alert\\" for important messages that need the
user's attention.
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/form-field-controls-integration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ formFieldControlComponents.forEach(({ componentName, findNativeElement }) => {
}

describe(`${componentName}`, () => {
const isGroupComponent = ['radio-group', 'tiles'].indexOf(componentName) !== -1;
const isGroupComponent = ['radio-group', 'tiles'].includes(componentName);
if (!isGroupComponent) {
describe('controlId', () => {
test('applies controlId from FormField when controlId is not set on itself', () => {
Expand Down
8 changes: 8 additions & 0 deletions src/app-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ const OldAppLayout = React.forwardRef(
}
};

useEffect(() => {
// We forcely close the navigation on mobile on the initial load
if (isMobile) {
onNavigationToggle(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const navigationVisible = !navigationHide && navigationOpen;
const toolsVisible = !toolsHide && toolsOpen;

Expand Down
8 changes: 8 additions & 0 deletions src/app-layout/visual-refresh/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ export const AppLayoutInternalsProvider = React.forwardRef(
{ componentName: 'AppLayout', controlledProp: 'navigationOpen', changeHandler: 'onNavigationChange' }
);

useEffect(() => {
// We forcely close the navigation on mobile on the initial load
if (isMobile) {
handleNavigationClick(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const { refs: navigationRefs, setFocus: focusNavButtons } = useFocusControl(isNavigationOpen);

const handleNavigationClick = useCallback(
Expand Down
2 changes: 1 addition & 1 deletion src/cards/interfaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export interface CardsProps<T = any> extends BaseComponentProps {
/**
* Defines what to display in each card. It has the following properties:
* * `header` ((item) => ReactNode) - Responsible for displaying the card header. You receive the current item as an argument.
* Use `fontSize="heading-m"` on [link](/components/link/) components inside card header.
* Use `fontSize="inherit"` on [link](/components/link/) components inside card header.
* * `sections` (array) - Responsible for displaying the card content. Cards can have many sections in their
* body. Each entry in the array is responsible for displaying a section. An entry has the following properties:
* * `id`: (string) - A unique identifier for the section. The property is used as a [keys](https://reactjs.org/docs/lists-and-keys.html#keys)
Expand Down
2 changes: 1 addition & 1 deletion src/container/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
&.with-paddings {
padding: shared.$header-padding;
&.header-variant-cards {
padding: awsui.$space-scaled-s awsui.$space-container-horizontal;
padding: awsui.$space-container-header-top awsui.$space-container-horizontal;
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/expandable-section/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ $icon-total-space-medium: calc(#{$icon-width-medium} + #{$icon-margin-left} + #{
padding-bottom: awsui.$space-container-header-bottom;
padding-right: container.$header-padding-horizontal;

&:not(.wrapper-expanded) {
// Equal top and bottom padding so standalone header has vertical symmetry.
padding-bottom: awsui.$space-container-header-top;
}
&.header-deprecated {
padding-left: container.$header-padding-horizontal;
}
Expand Down
25 changes: 25 additions & 0 deletions src/flashbar/__tests__/collapsible.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,31 @@ describe('Collapsible Flashbar', () => {
expect(innerCounter!.querySelector(`[title="${ariaLabel}"]`)).toBeTruthy();
}
});

test.each([['success'], ['error'], ['info'], ['warning'], ['in-progress']] as FlashbarProps.Type[][])(
'item icon has aria-label from i18nStrings when no statusIconAriaLabel provided: type %s',
type => {
const wrapper = renderFlashbar({
i18nStrings: {
successIconAriaLabel: 'success',
errorIconAriaLabel: 'error',
infoIconAriaLabel: 'info',
warningIconAriaLabel: 'warning',
inProgressIconAriaLabel: 'in-progress',
},
items: [
{
header: 'The header',
content: 'The content',
type: type === 'in-progress' ? 'info' : type,
loading: type === 'in-progress',
},
],
});

expect(wrapper.findItems()[0].find('[role="img"]')?.getElement()).toHaveAccessibleName(type);
}
);
});

describe('Sticky', () => {
Expand Down
35 changes: 30 additions & 5 deletions src/flashbar/__tests__/flashbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ describe('Flashbar component', () => {
});

test('icon has an aria-label when statusIconAriaLabel is provided', () => {
const iconLabel = 'Warning';
const iconLabel = 'Info';
const wrapper = createFlashbarWrapper(
<Flashbar
items={[
Expand All @@ -357,12 +357,37 @@ describe('Flashbar component', () => {
/>
);

expect(wrapper.findItems()[0].find(`:scope [aria-label]`)?.getElement()).toHaveAttribute(
'aria-label',
iconLabel
);
expect(wrapper.findItems()[0].find('[role="img"]')?.getElement()).toHaveAccessibleName(iconLabel);
});

test.each([['success'], ['error'], ['info'], ['warning'], ['in-progress']] as FlashbarProps.Type[][])(
'icon has aria-label from i18nStrings when no statusIconAriaLabel provided: type %s',
type => {
const wrapper = createFlashbarWrapper(
<Flashbar
i18nStrings={{
successIconAriaLabel: 'success',
errorIconAriaLabel: 'error',
infoIconAriaLabel: 'info',
warningIconAriaLabel: 'warning',
inProgressIconAriaLabel: 'in-progress',
}}
items={[
{
header: 'The header',
content: 'The content',
action: <Button>Click me</Button>,
type: type === 'in-progress' ? 'info' : type,
loading: type === 'in-progress',
},
]}
/>
);

expect(wrapper.findItems()[0].find('[role="img"]')?.getElement()).toHaveAccessibleName(type);
}
);

describe('Accessibility', () => {
test('renders items in an unordered list', () => {
const flashbar = createFlashbarWrapper(
Expand Down
1 change: 1 addition & 0 deletions src/flashbar/collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ export default function CollapsibleFlashbar({ items, ...restProps }: FlashbarPro
key={getItemId(item)}
ref={shouldUseStandardAnimation(item, index) ? transitionRootElement : undefined}
transitionState={shouldUseStandardAnimation(item, index) ? state : undefined}
i18nStrings={iconAriaLabels}
{...item}
/>
)}
Expand Down
7 changes: 6 additions & 1 deletion src/flashbar/flash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const focusFlashById = throttle(
export interface FlashProps extends FlashbarProps.MessageDefinition {
className: string;
transitionState?: string;
i18nStrings?: FlashbarProps.I18nStrings;
}

export const Flash = React.forwardRef(
Expand All @@ -87,6 +88,7 @@ export const Flash = React.forwardRef(
className,
transitionState,
ariaRole,
i18nStrings,
type = 'info',
}: FlashProps,
ref: React.Ref<HTMLDivElement>
Expand Down Expand Up @@ -153,7 +155,10 @@ export const Flash = React.forwardRef(
<div
className={clsx(styles['flash-icon'], styles['flash-text'])}
role="img"
aria-label={statusIconAriaLabel}
aria-label={
statusIconAriaLabel ||
i18nStrings?.[`${loading || type === 'in-progress' ? 'inProgress' : type}IconAriaLabel`]
}
>
{icon}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/flashbar/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface FlashbarProps extends BaseComponentProps {
* When a user clicks on this button the `onDismiss` handler is called.
* * `dismissLabel` (string) - Specifies an `aria-label` for to the dismiss icon button for improved accessibility.
* * `statusIconAriaLabel` (string) - Specifies an `aria-label` for to the status icon for improved accessibility.
* If not provided, `i18nStrings.{type}IconAriaLabel` will be used as a fallback.
* * `ariaRole` (string) - For flash messages added after page load, specifies how this message is communicated to assistive
* technology. Use "status" for status updates or informational content. Use "alert" for important messages that need the
* user's attention.
Expand Down
8 changes: 8 additions & 0 deletions src/flashbar/non-collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProp

const i18n = useInternalI18n('flashbar');
const ariaLabel = i18n('i18nStrings.ariaLabel', i18nStrings?.ariaLabel);
const iconAriaLabels = {
errorIconAriaLabel: i18n('i18nStrings.errorIconAriaLabel', i18nStrings?.errorIconAriaLabel),
inProgressIconAriaLabel: i18n('i18nStrings.inProgressIconAriaLabel', i18nStrings?.inProgressIconAriaLabel),
infoIconAriaLabel: i18n('i18nStrings.infoIconAriaLabel', i18nStrings?.infoIconAriaLabel),
successIconAriaLabel: i18n('i18nStrings.successIconAriaLabel', i18nStrings?.successIconAriaLabel),
warningIconAriaLabel: i18n('i18nStrings.warningIconAriaLabel', i18nStrings?.warningIconAriaLabel),
};

/**
* All the flash items should have ids so we can identify which DOM element is being
Expand Down Expand Up @@ -99,6 +106,7 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProp
key={key}
ref={transitionRootElement}
transitionState={transitionState}
i18nStrings={iconAriaLabels}
{...item}
/>
);
Expand Down
9 changes: 1 addition & 8 deletions src/header/internal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,7 @@ export default function InternalHeader({
ref={__internalRootRef}
>
<div className={clsx(styles.main, styles[`main-variant-${variantOverride}`], isRefresh && styles.refresh)}>
<div
className={clsx(
styles.title,
styles[`title-variant-${variantOverride}`],
isRefresh && styles.refresh,
description && [styles[`root-has-description`]]
)}
>
<div className={clsx(styles.title, styles[`title-variant-${variantOverride}`], isRefresh && styles.refresh)}>
<HeadingTag className={clsx(styles.heading, styles[`heading-variant-${variantOverride}`])}>
<span
{...{ [DATA_ATTR_FUNNEL_KEY]: FUNNEL_KEY_SUBSTEP_NAME }}
Expand Down
15 changes: 10 additions & 5 deletions src/header/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
@use '../internal/styles/tokens' as awsui;
@use '../internal/styles' as styles;

@function space-heading-button-diff($heading-height) {
@return calc((#{awsui.$size-vertical-input} - #{$heading-height}) / 2);
}

.root {
@include styles.styles-reset();
cursor: inherit;
Expand Down Expand Up @@ -44,7 +48,7 @@
&.refresh {
display: flex;
flex-direction: column;
// Can't use justify-content: center because it won't align with configurable dashboard handle icon
// Can't use justify-content: center because it won't align with configurable dashboard fixed handle icon
}

&-variant-h1 {
Expand Down Expand Up @@ -106,22 +110,23 @@

&-variant-h1 {
font-size: awsui.$font-heading-xl-size;
// Use padding rather than center align so that all headers of the same size start at the same height in the container,
// Use padding rather than center align with min height to avoid having extra bottom space when no actions are present.
// Having top padding always present ensures that all headers of the same variant start at the same height in the container,
// whether there are buttons present or not; otherwise configurable dashboard handles are misaligned.
&.refresh {
padding-top: calc((#{awsui.$size-vertical-input} - #{awsui.$font-heading-xl-line-height}) / 2);
padding-top: space-heading-button-diff(awsui.$font-heading-xl-line-height);
}
}
&-variant-h2 {
font-size: awsui.$font-heading-l-size;
&.refresh {
padding-top: calc((#{awsui.$size-vertical-input} - #{awsui.$font-heading-l-line-height}) / 2);
padding-top: space-heading-button-diff(awsui.$font-heading-l-line-height);
}
}
&-variant-h3 {
font-size: awsui.$font-heading-m-size;
&.refresh {
padding-top: calc((#{awsui.$size-vertical-input} - #{awsui.$font-heading-m-line-height}) / 2);
padding-top: space-heading-button-diff(awsui.$font-heading-m-line-height);
}
}
&-variant-h2:not(.refresh),
Expand Down
Loading

0 comments on commit bf3f7df

Please sign in to comment.