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

import { ProgressBar } from '~components';

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

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

const brand = { styleClassNames: { root: styles['bar-brand'], percentage: styles['percentage-brand'] } };
const genai = { styleClassNames: { root: styles['bar-genai'], percentage: styles['percentage-genai'] } };

export default function () {
return (
<SimplePage title="Progress bar - Style API v2" screenshotArea={{}}>
<ProgressBar value={45} label="Attachments" description="Files are uploading" {...brand} />
<ProgressBar value={72} label="Attachments" additionalInfo="You can add more files at any time" {...genai} />
</SimplePage>
);
}
33 changes: 33 additions & 0 deletions pages/progress-bar/style-api-v2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

@use '~components/styling/progress-bar';
@use '../style-api/palette' as palette;

.bar-brand {
@include progress-bar.root(
$track-color: palette.$subtle,
$value-color: palette.$accent,
$bar-border-radius: 2px,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we prefix this with awsui- like $awsui-bar-border-radius, so it's clear it only accepts a single value? For example, 4px 8px wouldn't work here. According to the doc: UM9CHZ8CCdFl

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will add this change to the component toolkit part that generates css vars, docs, and mixins: every token that we pass to the style-api.docs() util will be automatically prefixed with awsui-.

$bar-block-size: 8px
);
}

.bar-genai {
@include progress-bar.root(
$track-color: palette.$genai-surface,
$value-color: palette.$genai,
$bar-border-radius: 0,
$bar-block-size: 12px
);
}

.percentage-brand {
@include progress-bar.percentage($color: palette.$accent, $font-size: 14px, $font-weight: 700);
}

.percentage-genai {
@include progress-bar.percentage($color: palette.$genai-text, $font-size: 16px, $font-weight: 600);
}
69 changes: 69 additions & 0 deletions pages/slider/style-api-v2.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';

import { KeyValuePairs, Slider } from '~components';

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

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

const styleClassNames = { root: styles.slider, handle: styles.handle };

export default function () {
const [value, setValue] = useState(40);
return (
<SimplePage title="Slider - Style API v2" screenshotArea={{}}>
<KeyValuePairs
items={[
{
type: 'pair',
label: 'With tick marks',
value: (
<Slider
value={value}
onChange={({ detail }) => setValue(detail.value)}
min={0}
max={100}
step={20}
tickMarks={true}
ariaLabel="With tick marks"
{...{ styleClassNames }}
/>
),
},
{
type: 'pair',
label: 'Disabled',
value: (
<Slider
value={value}
onChange={({ detail }) => setValue(detail.value)}
min={0}
max={100}
disabled={true}
ariaLabel="Disabled"
{...{ styleClassNames }}
/>
),
},
{
type: 'pair',
label: 'Read-only',
value: (
<Slider
value={value}
onChange={({ detail }) => setValue(detail.value)}
min={0}
max={100}
readOnly={true}
ariaLabel="Read-only"
{...{ styleClassNames }}
/>
),
},
]}
/>
</SimplePage>
);
}
39 changes: 39 additions & 0 deletions pages/slider/style-api-v2.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

@use '~components/styling/slider';
@use '../style-api/palette' as palette;

.slider {
@include slider.root($track-color: palette.$surface-alt, $value-color: palette.$accent);
}

// The handle is the native <input type="range">, so its states are regular selectors.
.handle {
@include slider.handle($fill-color: palette.$accent, $halo-color: palette.$genai, $border-radius: 4px);

&:hover {
@include slider.handle($fill-color: palette.$accent-hover);
}

&:is(:focus, :active) {
@include slider.handle($fill-color: palette.$accent-active);
}

&:disabled,
&[aria-disabled='true'] {
@include slider.handle($fill-color: palette.$control-bg-disabled, $halo-color: palette.$control-bg-disabled);
}
}

// The value fill follows the handle state through :has() on the root slot.
.slider:has(.handle:is(:focus, :active)) {
@include slider.root($value-color: palette.$accent-active);
}

// After the focus rule: a read-only slider stays focusable, and both rules have the same specificity.
.slider:has(.handle:disabled, .handle[aria-disabled='true']) {
@include slider.root($value-color: palette.$control-bg-disabled);
}
36 changes: 36 additions & 0 deletions src/progress-bar/__tests__/style-api.test.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 from 'react';
import { render } from '@testing-library/react';

import ProgressBar, { ProgressBarProps } from '../../../lib/components/progress-bar';
import createWrapper from '../../../lib/components/test-utils/dom';

function renderProgressBar(props: Partial<ProgressBarProps> & Record<string, unknown> = {}) {
const { container } = render(<ProgressBar value={40} label="Label" {...props} />);
return { container, wrapper: createWrapper(container).findProgressBar()! };
}

describe('ProgressBar Style API v2', () => {
test.each<ProgressBarProps.Variant>(['standalone', 'flash', 'key-value'])(
'applies styleClassNames (variant=%s)',
variant => {
const { wrapper } = renderProgressBar({
variant,
styleClassNames: { root: 'a', percentage: 'b', unknown: 'c' },
});
expect(wrapper.getElement()).toHaveClass('a');
expect(wrapper.getElement()).not.toHaveClass('c');

const percentage = wrapper.findPercentageText()!.getElement();
expect(percentage).not.toHaveClass('a');
expect(percentage).toHaveClass('b');
expect(percentage).not.toHaveClass('c');
}
);

test('does not leak the styleClassNames prop to the DOM', () => {
const { container } = renderProgressBar({ styleClassNames: { root: 'a', percentage: 'b' } });
expect(container.querySelector('[styleClassNames]')).toBeNull();
});
});
8 changes: 5 additions & 3 deletions src/progress-bar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { applyDisplayName } from '../internal/utils/apply-display-name';
import { joinStrings } from '../internal/utils/strings';
import InternalLiveRegion from '../live-region/internal';
import { ProgressBarProps } from './interfaces';
import { Progress, ResultState, SmallText } from './internal';
import { Progress, ResultState, SmallText, StyleClassNames } from './internal';

import styles from './styles.css.js';

Expand All @@ -41,7 +41,8 @@ export default function ProgressBar({
const { __internalRootRef } = useBaseComponent('ProgressBar', {
props: { variant },
});
const baseProps = getBaseProps(rest);
const { styleClassNames, ...restProps } = rest as typeof rest & { styleClassNames?: StyleClassNames };
const baseProps = getBaseProps(restProps);
const generatedName = useUniqueId('awsui-progress-bar-');

const labelId = `${generatedName}-label`;
Expand Down Expand Up @@ -75,7 +76,7 @@ export default function ProgressBar({
return (
<div
{...baseProps}
className={clsx(baseProps.className, styles.root, variant && styles[variant])}
className={clsx(baseProps.className, styleClassNames?.root, styles.root, variant && styles[variant])}
ref={__internalRootRef}
>
<div className={isInFlash ? styles['flash-container'] : undefined}>
Expand All @@ -101,6 +102,7 @@ export default function ProgressBar({
)}
isInFlash={isInFlash}
style={style}
styleClassNames={styleClassNames}
/>
<InternalLiveRegion hidden={true} tagName="span" delay={0}>
{label}
Expand Down
27 changes: 20 additions & 7 deletions src/progress-bar/internal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,24 @@ interface ProgressProps {
ariaLabelledby?: string;
ariaDescribedby?: string;
style?: ProgressBarProps.Style;
styleClassNames?: StyleClassNames;
}

export const Progress = ({ value, isInFlash, ariaLabel, ariaLabelledby, ariaDescribedby, style }: ProgressProps) => {
// Style API v2
export interface StyleClassNames {
root?: string;
percentage?: string;
}

export const Progress = ({
value,
isInFlash,
ariaLabel,
ariaLabelledby,
ariaDescribedby,
style,
styleClassNames,
}: ProgressProps) => {
const roundedValue = Math.round(value);
const progressValue = clamp(roundedValue, 0, MAX_VALUE);

Expand Down Expand Up @@ -56,14 +71,12 @@ export const Progress = ({ value, isInFlash, ariaLabel, ariaLabelledby, ariaDesc
}}
/>
<span aria-hidden="true" className={styles['percentage-container']}>
<InternalBox
className={styles.percentage}
variant="small"
color={isInFlash ? 'inherit' : undefined}
nativeAttributes={progressPercentageStyles ? { style: progressPercentageStyles } : undefined}
<small
className={clsx(styleClassNames?.percentage, styles.percentage, isInFlash && styles['percentage-flash'])}
style={progressPercentageStyles}
>
{`${progressValue}%`}
</InternalBox>
</small>
</span>
</div>
);
Expand Down
71 changes: 52 additions & 19 deletions src/progress-bar/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,47 @@
@use '../internal/styles/tokens' as awsui;
@use '../internal/styles' as styles;
@use '../internal/generated/custom-css-properties/index.scss' as custom-props;
@use '../internal/styles/style-api' as style-api;
@use './motion';

$progress-height: var(#{custom-props.$progressBarHeight}, 0.4 * styles.$base-size);
$progress-border-radius: var(#{custom-props.$progressBarBorderRadius}, 10px);
$progress-background-color: var(
#{custom-props.$progressBarBackgroundColor},
awsui.$color-background-progress-bar-default
$progress-bar-tokens: style-api.resolve((track-color, value-color, bar-block-size, bar-border-radius), carrier);
@include style-api.register($progress-bar-tokens);
@include style-api.docs('root', $progress-bar-tokens);
@include style-api.docs('percentage', $properties: (color, font-family, font-size, font-weight));

$progress-height: style-api.value(
$progress-bar-tokens,
bar-block-size,
var(#{custom-props.$progressBarHeight}, 0.4 * styles.$base-size)
);
$progress-border-radius: style-api.value(
$progress-bar-tokens,
bar-border-radius,
var(#{custom-props.$progressBarBorderRadius}, 10px)
);
$progress-background-color: style-api.value(
$progress-bar-tokens,
track-color,
var(#{custom-props.$progressBarBackgroundColor}, awsui.$color-background-progress-bar-default)
);
$progress-value-background-color: style-api.value(
$progress-bar-tokens,
value-color,
var(#{custom-props.$progressValueBackgroundColor}, awsui.$color-background-progress-bar-value-default)
);
$progress-value-background-color: var(
#{custom-props.$progressValueBackgroundColor},
awsui.$color-background-progress-bar-value-default
$progress-flash-background-color: style-api.value(
$progress-bar-tokens,
track-color,
var(#{custom-props.$progressBarBackgroundColor}, awsui.$color-background-progress-bar-flash)
);
$progress-flash-value-background-color: style-api.value(
$progress-bar-tokens,
value-color,
var(#{custom-props.$progressValueBackgroundColor}, awsui.$color-background-progress-bar-value-flash)
);

.root {
@include style-api.carriers($progress-bar-tokens);
@include styles.styles-reset;
}

Expand Down Expand Up @@ -79,7 +106,19 @@ $progress-value-background-color: var(
}

.percentage {
/* used in test-utils */
display: inline-block;
font-family: awsui.$font-family-base;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
line-height: awsui.$line-height-body-s;
letter-spacing: awsui.$letter-spacing-body-s;
color: awsui.$color-text-small;
font-size: awsui.$font-size-body-s;
font-weight: styles.$font-weight-normal;

&.percentage-flash {
color: currentColor;
}
}

@mixin general-progress-background-style {
Expand Down Expand Up @@ -131,22 +170,16 @@ $progress-value-background-color: var(
}

&.progress-flash {
background-color: var(#{custom-props.$progressBarBackgroundColor}, awsui.$color-background-progress-bar-flash);
background-color: $progress-flash-background-color;

&::-webkit-progress-bar {
background-color: var(#{custom-props.$progressBarBackgroundColor}, awsui.$color-background-progress-bar-flash);
background-color: $progress-flash-background-color;
}
&::-webkit-progress-value {
background-color: var(
#{custom-props.$progressValueBackgroundColor},
awsui.$color-background-progress-bar-value-flash
);
background-color: $progress-flash-value-background-color;
}
&::-moz-progress-bar {
background-color: var(
#{custom-props.$progressValueBackgroundColor},
awsui.$color-background-progress-bar-value-flash
);
background-color: $progress-flash-value-background-color;
}
}
}
Expand Down
Loading
Loading