Skip to content
Open
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
64 changes: 64 additions & 0 deletions pages/popover/style-api-v2.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useContext } from 'react';

import { Checkbox, KeyValuePairs, Popover } from '~components';

import AppContext, { AppContextType } from '../app/app-context';
import { SimplePage } from '../app/templates';

import styles from './style-api-v2.scss';

const brand = { popover: styles['popover-brand'], dismissButton: styles['popover-brand-dismiss'] };

type PageContext = React.Context<
AppContextType<{
renderWithPortal: boolean;
}>
>;

export default function () {
const {
urlParams: { renderWithPortal = true },
setUrlParams,
} = useContext(AppContext as PageContext);
const shared = { header: 'Popover header', content: 'Popover content', renderWithPortal };
return (
<SimplePage
title="Popover - Style API v2"
screenshotArea={{}}
settings={
<Checkbox
checked={renderWithPortal}
onChange={({ detail }) => setUrlParams({ renderWithPortal: detail.checked })}
>
renderWithPortal
</Checkbox>
}
>
<KeyValuePairs
columns={4}
items={[
{
type: 'pair',
label: 'Brand',
value: (
<Popover {...shared} {...{ styleClassNames: brand }}>
Open popover
</Popover>
),
},
{
type: 'pair',
label: 'Borderless',
value: (
<Popover {...shared} {...{ styleClassNames: { popover: styles['popover-borderless'] } }}>
Open popover
</Popover>
),
},
]}
/>
</SimplePage>
);
}
29 changes: 29 additions & 0 deletions pages/popover/style-api-v2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

@use '../style-api/palette' as palette;

.popover-brand {
--awsui-style-color: #{palette.$genai-text};
--awsui-style-background: #{palette.$genai-surface};
--awsui-style-border-color: #{palette.$genai};
--awsui-style-border-width: 3px;
--awsui-style-border-radius: 8px;
}

.popover-borderless {
--awsui-style-background: #{palette.$subtle};
--awsui-style-border-width: 0px;
--awsui-style-border-radius: 4px;
}

.popover-brand-dismiss {
--awsui-style-color: #{palette.$genai};
--awsui-style-focus-ring-color: #{palette.$genai};

&:hover {
--awsui-style-color: #{palette.$genai-hover};
}
}
36 changes: 36 additions & 0 deletions pages/tooltip/style-api-v2.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useRef, useState } from 'react';

import { Button, Tooltip } from '~components';

import { SimplePage } from '../app/templates';

import styles from './style-api-v2.scss';

export default function () {
const triggerRef = useRef<HTMLSpanElement>(null);
const [open, setOpen] = useState(false);
return (
<SimplePage title="Tooltip - Style API v2" screenshotArea={{}}>
<br />
<span
ref={triggerRef}
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onFocus={() => setOpen(true)}
onBlur={() => setOpen(false)}
>
<Button variant="icon" iconName="copy" ariaLabel="Copy" />
{open && (
<Tooltip
content="ARN Copied"
getTrack={() => triggerRef.current}
onEscape={() => setOpen(false)}
{...{ styleClassNames: { tooltip: styles['tooltip-inverted'] } }}
/>
)}
</span>
</SimplePage>
);
}
13 changes: 13 additions & 0 deletions pages/tooltip/style-api-v2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

@use '../style-api/palette' as palette;

.tooltip-inverted {
--awsui-style-color: #{palette.$text-on-accent};
--awsui-style-background: #{palette.$accent};
--awsui-style-border-color: #{palette.$accent};
--awsui-style-border-radius: 2px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,36 @@ exports[`Style API docs definition for link matches the snapshot: link 1`] = `
}
`;

exports[`Style API docs definition for popover matches the snapshot: popover 1`] = `
{
"slots": [
{
"name": "popover",
"properties": [],
"propertyDescriptions": {},
"tokenDescriptions": {
"background": "Background of the surface and arrow.",
"border-color": "Border color of the surface and arrow.",
"border-width": "Border width of the surface and arrow.",
},
"tokens": [
"background",
"border-color",
"border-width",
"border-radius",
],
},
{
"forwardsTo": {
"component": "button",
"slot": "root",
},
"name": "dismissButton",
},
],
}
`;

exports[`Style API docs definition for radio-button matches the snapshot: radio-button 1`] = `
{
"slots": [
Expand Down Expand Up @@ -237,6 +267,29 @@ exports[`Style API docs definition for toggle matches the snapshot: toggle 1`] =
}
`;

exports[`Style API docs definition for tooltip matches the snapshot: tooltip 1`] = `
{
"slots": [
{
"name": "tooltip",
"properties": [],
"propertyDescriptions": {},
"tokenDescriptions": {
"background": "Background of the surface and arrow.",
"border-color": "Border color of the surface and arrow.",
"border-width": "Border width of the surface and arrow.",
},
"tokens": [
"background",
"border-color",
"border-width",
"border-radius",
],
},
],
}
`;

exports[`Style API docs list of components with a Style API doc matches the snapshot 1`] = `
[
"alert",
Expand All @@ -245,7 +298,9 @@ exports[`Style API docs list of components with a Style API doc matches the snap
"checkbox",
"dropdown",
"link",
"popover",
"radio-button",
"toggle",
"tooltip",
]
`;
4 changes: 2 additions & 2 deletions src/internal/styles/style-api.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ $_focus-ring-carriers: toolkit.resolve($focus-ring, carrier);
}
}

@mixin docs($name, $map) {
@mixin docs($name, $tokens: null, $properties: null, $descriptions: null) {
@if enabled() {
@include toolkit.docs($name, $map);
@include toolkit.docs($name, $tokens, $properties, $descriptions);
}
}

Expand Down
40 changes: 40 additions & 0 deletions src/popover/__tests__/style-api.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { render } from '@testing-library/react';

import Popover from '../../../lib/components/popover';
import createWrapper from '../../../lib/components/test-utils/dom';

import styles from '../../../lib/components/popover/styles.css.js';

function renderOpenPopover(props: Record<string, unknown>) {
const { container } = render(<Popover content="Content" header="Header" {...props} />);
const wrapper = createWrapper(container).findPopover()!;
wrapper.findTrigger().click();
return wrapper;
}

describe('Popover Style API v2', () => {
test('applies styleClassNames to the popover container', () => {
const wrapper = renderOpenPopover({ styleClassNames: { popover: 'a', unknown: 'b' } });
expect(wrapper.findByClassName(styles.container)!.getElement()).toHaveClass('a');
expect(wrapper.find('.b')).toBeNull();
});

test('forwards the dismissButton slot to the dismiss button', () => {
const wrapper = renderOpenPopover({ styleClassNames: { dismissButton: 'a' } });
expect(wrapper.findDismissButton()!.getElement()).toHaveClass('a');
});

test('applies styleClassNames to the popover container when rendered in a portal', () => {
const wrapper = renderOpenPopover({ renderWithPortal: true, styleClassNames: { popover: 'a' } });
expect(wrapper.findContent({ renderWithPortal: true })).not.toBeNull();
expect(document.body.querySelector(`.${styles.container}`)).toHaveClass('a');
});

test('does not leak the styleClassNames prop to the DOM', () => {
renderOpenPopover({ renderWithPortal: true, styleClassNames: { popover: 'a' } });
expect(document.body.querySelector('[styleClassNames]')).toBeNull();
});
});
11 changes: 8 additions & 3 deletions src/popover/arrow.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

@use '../internal/styles' as styles;
@use '../internal/styles/tokens' as awsui;
@use '../internal/styles/style-api' as style-api;
@use './style-api' as popover-style-api;

.arrow {
// Arrow design:
Expand Down Expand Up @@ -64,19 +66,22 @@

&-outer {
&::after {
background-color: awsui.$color-border-popover;
background-color: style-api.value(popover-style-api.$tokens, border-color, awsui.$color-border-popover);
}
}

&-inner {
inset-block-start: calc(awsui.$border-width-popover + 1px);
// The inner triangle is shifted by the border width plus up to 1px so that the uncovered part of the
// outer triangle renders as the border; min() collapses the shift to 0 for a borderless popover.
$border-width: style-api.value(popover-style-api.$tokens, border-width, awsui.$border-width-popover);
inset-block-start: calc(#{$border-width} + min(#{$border-width}, 1px));

&::after {
border-start-start-radius: 1px;
border-start-end-radius: 0;
border-end-start-radius: 0;
border-end-end-radius: 0;
background-color: awsui.$color-background-popover;
background: style-api.value(popover-style-api.$tokens, background, awsui.$color-background-popover);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/popover/body.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ $header-row-margin-block-end: awsui.$space-xs;
.body {
@include styles.styles-reset;
@include styles.text-flex-wrapping;
color: awsui.$color-text-body-default;

padding-block: awsui.$space-s;
padding-inline: awsui.$space-m;
Expand Down
3 changes: 3 additions & 0 deletions src/popover/body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface PopoverBodyProps {
overflowVisible?: 'content' | 'both';

className?: string;
dismissButtonClassName?: string;
ariaLabelledby?: string;

closeAnalyticsAction?: string;
Expand All @@ -46,6 +47,7 @@ const PopoverBody = React.forwardRef(
variant,
overflowVisible,
className,
dismissButtonClassName,
ariaLabelledby,
closeAnalyticsAction,
}: PopoverBodyProps,
Expand Down Expand Up @@ -90,6 +92,7 @@ const PopoverBody = React.forwardRef(
ariaLabel={i18n('dismissAriaLabel', dismissAriaLabel)}
onClick={() => onDismiss?.('close-button')}
ref={dismissButtonRef}
styleClassNames={{ root: dismissButtonClassName }}
/>
</div>
);
Expand Down
20 changes: 13 additions & 7 deletions src/popover/container.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

@use '../internal/styles' as styles;
@use '../internal/styles/tokens' as awsui;
@use '../internal/styles/style-api' as style-api;
@use './style-api' as popover-style-api;

$arrow-height: 10px;

Expand All @@ -12,6 +14,7 @@ $arrow-height: 10px;
inset-block-start: -9999px;
inset-inline-start: -9999px;
z-index: 2000;
@include style-api.carriers(popover-style-api.$tokens);

// A little pseudoelement to extend the container to the space between the
// popover and the trigger to avoid hover-based popovers/tooltips from
Expand Down Expand Up @@ -61,15 +64,18 @@ $arrow-height: 10px;
}

.container-body {
$tokens: popover-style-api.$tokens;
@include styles.styles-reset;
border-start-start-radius: awsui.$border-radius-popover;
border-start-end-radius: awsui.$border-radius-popover;
border-end-start-radius: awsui.$border-radius-popover;
border-end-end-radius: awsui.$border-radius-popover;
background-color: awsui.$color-background-popover;
border-start-start-radius: style-api.value($tokens, border-radius, awsui.$border-radius-popover);
border-start-end-radius: style-api.value($tokens, border-radius, awsui.$border-radius-popover);
border-end-start-radius: style-api.value($tokens, border-radius, awsui.$border-radius-popover);
border-end-end-radius: style-api.value($tokens, border-radius, awsui.$border-radius-popover);
background: style-api.value($tokens, background, awsui.$color-background-popover);
box-shadow: awsui.$shadow-popover;
border-block: awsui.$border-width-popover solid awsui.$color-border-popover;
border-inline: awsui.$border-width-popover solid awsui.$color-border-popover;
$border: style-api.value($tokens, border-width, awsui.$border-width-popover) solid
style-api.value($tokens, border-color, awsui.$color-border-popover);
border-block: $border;
border-inline: $border;
}

.container-body-variant-annotation {
Expand Down
Loading
Loading