@@ -213,6 +224,7 @@ export const Flash = React.forwardRef(
ref={mergedRef}
data-itemid={id}
className={clsx(
+ styleClassNames?.item,
styles.flash,
styles[`flash-type-${effectiveType}`],
className,
@@ -243,7 +255,7 @@ export const Flash = React.forwardRef(
aria-labelledby={`${flashIconId} ${flashMessageId}`}
>
@@ -298,7 +310,8 @@ export const Flash = React.forwardRef(
dismissButtonRefObject,
id,
onDismissed,
- persistenceConfig
+ persistenceConfig,
+ styleClassNames?.dismissButton
)}
{ariaRole === 'status' && (
diff --git a/src/flashbar/internal-interfaces.ts b/src/flashbar/internal-interfaces.ts
index 33026d66512..1e077f202f7 100644
--- a/src/flashbar/internal-interfaces.ts
+++ b/src/flashbar/internal-interfaces.ts
@@ -3,4 +3,13 @@
import { InternalBaseComponentProps } from '../internal/hooks/use-base-component';
import { FlashbarProps } from './interfaces';
-export type InternalFlashbarProps = FlashbarProps & InternalBaseComponentProps;
+// Style API v2
+export interface FlashbarStyleClassNames {
+ item?: string | ((props: { item: FlashbarProps.MessageDefinition }) => string);
+ icon?: string;
+ dismissButton?: string;
+ notificationBar?: string;
+}
+
+export type InternalFlashbarProps = FlashbarProps &
+ InternalBaseComponentProps & { styleClassNames?: FlashbarStyleClassNames };
diff --git a/src/flashbar/non-collapsible-flashbar.tsx b/src/flashbar/non-collapsible-flashbar.tsx
index af15293b436..2302d8622cb 100644
--- a/src/flashbar/non-collapsible-flashbar.tsx
+++ b/src/flashbar/non-collapsible-flashbar.tsx
@@ -19,6 +19,7 @@ import { isRefObject } from './utils';
import styles from './styles.css.js';
export default function NonCollapsibleFlashbar({ items, i18nStrings, style, ...restProps }: InternalFlashbarProps) {
+ const { styleClassNames } = restProps;
const visibleItems = useFlashbarVisibility(items);
const { allItemsHaveId, baseProps, isReducedMotion, isVisualRefresh, mergedRef, flashRefs, handleFlashDismissed } =
@@ -46,6 +47,10 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, style, ...r
const animateFlash = !isReducedMotion && isVisualRefresh;
+ // Style API v2
+ const getItemClass = (item: FlashbarProps.MessageDefinition) =>
+ typeof styleClassNames?.item === 'function' ? styleClassNames.item({ item }) : styleClassNames?.item;
+
/**
* If the flashbar is flat and motion is `enabled` then the adding and removing of items
* from the flashbar will render with visual transitions.
@@ -132,6 +137,11 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, style, ...r
i18nStrings={iconAriaLabels}
style={style}
onDismissed={handleFlashDismissed}
+ styleClassNames={{
+ item: getItemClass(item),
+ icon: styleClassNames?.icon,
+ dismissButton: styleClassNames?.dismissButton,
+ }}
{...item}
/>
);
diff --git a/src/flashbar/styles.scss b/src/flashbar/styles.scss
index 788854ea259..b21d274ed73 100644
--- a/src/flashbar/styles.scss
+++ b/src/flashbar/styles.scss
@@ -8,9 +8,30 @@
@use '../internal/styles' as styles;
@use '../internal/styles/typography' as typography;
@use '../internal/styles/foundation' as foundation;
+@use '../internal/styles/style-api' as style-api;
@use './motion';
@use './collapsible';
+// Style API v2. The focus-ring tokens are registered once here, for the item slot and the notificationBar slot
+// (collapsible.scss).
+$_item-tokens: style-api.resolve(style-api.$focus-ring, carrier);
+@include style-api.register($_item-tokens);
+@include style-api.docs(
+ 'item',
+ $_item-tokens,
+ $properties: (color, background, border, border-radius, box-shadow, padding),
+ $descriptions: (
+ slot:
+ 'One flash message: its box and focus ring. Accepts a class name, or a function of `{ item }` that returns one, so each `type` can take its own class.'
+ )
+);
+@include style-api.docs(
+ 'icon',
+ $properties: (color),
+ $descriptions: (slot: 'The status icon, or the spinner for `loading`.')
+);
+@include style-api.docs-forward('dismissButton', 'button', 'root');
+
.flashbar {
position: relative;
/* stylelint-disable-next-line selector-max-type */
@@ -26,6 +47,7 @@
}
.flash {
+ @include style-api.carriers($_item-tokens);
position: relative;
display: flex;
justify-content: flex-start;
@@ -41,10 +63,6 @@
overflow-wrap: break-word;
word-wrap: break-word;
box-shadow: awsui.$shadow-flash-sticky;
-
- #{custom-props.$styleFocusRingBoxShadow}: 0 0 0
- var(#{custom-props.$styleFocusRingBorderWidth}, foundation.$box-shadow-focused-width)
- var(#{custom-props.$styleFocusRingBorderColor}, awsui.$color-border-item-focused);
}
.initial-hidden {
@@ -83,10 +101,10 @@
outline: none;
}
@include focus-visible.when-visible {
- @include styles.focus-highlight(
- $gutter: awsui.$space-button-focus-outline-gutter,
- $border-radius: var(#{custom-props.$styleFocusRingBorderRadius}, awsui.$border-radius-control-default-focus-ring),
- $box-shadow: var(#{custom-props.$styleFocusRingBoxShadow})
+ @include style-api.focus-highlight(
+ $radius: var(#{custom-props.$styleFocusRingBorderRadius}, awsui.$border-radius-control-default-focus-ring),
+ $width: var(#{custom-props.$styleFocusRingBorderWidth}, foundation.$box-shadow-focused-width),
+ $color: var(#{custom-props.$styleFocusRingBorderColor}, awsui.$color-border-item-focused)
);
}
}