Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Widgetize flashbar #3334

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
{
"path": "lib/components/internal/widget-exports.js",
"brotli": false,
"limit": "750 kB"
"limit": "820 kB"
}
],
"browserslist": [
Expand Down
11 changes: 7 additions & 4 deletions src/flashbar/collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ import { Transition } from '../internal/components/transition';
import { getVisualContextClassname } from '../internal/components/visual-context';
import customCssProps from '../internal/generated/custom-css-properties';
import { useEffectOnUpdate } from '../internal/hooks/use-effect-on-update';
import { useMergeRefs } from '../internal/hooks/use-merge-refs';
import { useUniqueId } from '../internal/hooks/use-unique-id';
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
import { scrollElementIntoView } from '../internal/utils/scrollable-containers';
import { throttle } from '../internal/utils/throttle';
import { GeneratedAnalyticsMetadataFlashbarExpand } from './analytics-metadata/interfaces';
import { getComponentsAnalyticsMetadata, getItemAnalyticsMetadata } from './analytics-metadata/utils';
import { useFlashbar } from './common';
import { Flash, focusFlashById } from './flash';
import { FlashbarProps } from './interfaces';
import { FlashbarProps, InternalFlashbarProps } from './interfaces';
import { counterTypes, getFlashTypeCount, getItemColor, getVisibleCollapsedItems, StackableItem } from './utils';

import styles from './styles.css.js';
Expand All @@ -33,10 +35,11 @@ const maxNonCollapsibleItems = 1;

const resizeListenerThrottleDelay = 100;

export default function CollapsibleFlashbar({ items, ...restProps }: FlashbarProps) {
export default function CollapsibleFlashbar({ __internalRootRef, items, ...restProps }: InternalFlashbarProps) {
const [enteringItems, setEnteringItems] = useState<ReadonlyArray<FlashbarProps.MessageDefinition>>([]);
const [exitingItems, setExitingItems] = useState<ReadonlyArray<FlashbarProps.MessageDefinition>>([]);
const [isFlashbarStackExpanded, setIsFlashbarStackExpanded] = useState(false);
const isVisualRefresh = useVisualRefresh();

const getElementsToAnimate = useCallback(() => {
const flashElements = isFlashbarStackExpanded ? expandedItemRefs.current : collapsedItemRefs.current;
Expand All @@ -48,7 +51,7 @@ export default function CollapsibleFlashbar({ items, ...restProps }: FlashbarPro
setInitialAnimationState(rects);
}, [getElementsToAnimate]);

const { baseProps, breakpoint, isReducedMotion, isVisualRefresh, mergedRef, ref } = useFlashbar({
const { baseProps, breakpoint, isReducedMotion, mergedRef, ref } = useFlashbar({
items,
...restProps,
onItemsAdded: newItems => {
Expand Down Expand Up @@ -308,7 +311,7 @@ export default function CollapsibleFlashbar({ items, ...restProps }: FlashbarPro
isFlashbarStackExpanded && styles.expanded,
isVisualRefresh && styles['visual-refresh']
)}
ref={mergedRef}
ref={useMergeRefs(mergedRef, __internalRootRef)}
{...getAnalyticsMetadataAttribute(getComponentsAnalyticsMetadata(items.length, true, isFlashbarStackExpanded))}
>
{isFlashbarStackExpanded && renderList()}
Expand Down
9 changes: 1 addition & 8 deletions src/flashbar/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { useReducedMotion, warnOnce } from '@cloudscape-design/component-toolkit

import { getBaseProps } from '../internal/base-component';
import { useContainerBreakpoints } from '../internal/hooks/container-queries';
import useBaseComponent from '../internal/hooks/use-base-component';
import { useMergeRefs } from '../internal/hooks/use-merge-refs';
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
import { isDevelopment } from '../internal/is-development';
import { focusFlashById } from './flash';
import { FlashbarProps } from './interfaces';
Expand All @@ -25,16 +23,12 @@ export function useFlashbar({
onItemsRemoved?: (items: FlashbarProps.MessageDefinition[]) => void;
onItemsChanged?: (options?: { allItemsHaveId?: boolean; isReducedMotion?: boolean }) => void;
}) {
const { __internalRootRef } = useBaseComponent('Flashbar', {
props: { stackItems: restProps.stackItems },
});
Comment on lines -28 to -30
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved it into the flashbar/index.tsx file to make this hook run before the widget loaded

const allItemsHaveId = useMemo(() => items.every(item => 'id' in item), [items]);
const baseProps = getBaseProps(restProps);
const ref = useRef<HTMLDivElement | null>(null);
const [breakpoint, breakpointRef] = useContainerBreakpoints(['xs']);
const mergedRef = useMergeRefs(ref, breakpointRef, __internalRootRef);
const mergedRef = useMergeRefs(ref, breakpointRef);
const isReducedMotion = useReducedMotion(ref);
const isVisualRefresh = useVisualRefresh();
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved isVisualRefresh from the hook directly into component code to make DCE work for ALWAYS_VISUAL_REFRESH mode

const [previousItems, setPreviousItems] = useState<ReadonlyArray<FlashbarProps.MessageDefinition>>(items);
const [nextFocusId, setNextFocusId] = useState<string | null>(null);

Expand Down Expand Up @@ -76,7 +70,6 @@ export function useFlashbar({
baseProps,
breakpoint,
isReducedMotion,
isVisualRefresh,
mergedRef,
ref,
};
Expand Down
18 changes: 18 additions & 0 deletions src/flashbar/implementation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';

import { createWidgetizedComponent } from '../internal/widgets';
import CollapsibleFlashbar from './collapsible-flashbar';
import { InternalFlashbarProps } from './interfaces';
import NonCollapsibleFlashbar from './non-collapsible-flashbar';

export function FlashbarImplementation(props: InternalFlashbarProps) {
if (props.stackItems) {
return <CollapsibleFlashbar {...props} />;
} else {
return <NonCollapsibleFlashbar {...props} />;
}
}

export const createWidgetizedFlashbar = createWidgetizedComponent(FlashbarImplementation);
13 changes: 6 additions & 7 deletions src/flashbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
import React from 'react';

import useBaseComponent from '../internal/hooks/use-base-component';
import { applyDisplayName } from '../internal/utils/apply-display-name';
import CollapsibleFlashbar from './collapsible-flashbar';
import { FlashbarProps } from './interfaces';
import NonCollapsibleFlashbar from './non-collapsible-flashbar';
import { InternalFlashbar } from './internal';

export { FlashbarProps };

export default function Flashbar(props: FlashbarProps) {
if (props.stackItems) {
return <CollapsibleFlashbar {...props} />;
} else {
return <NonCollapsibleFlashbar {...props} />;
}
const { __internalRootRef } = useBaseComponent('Flashbar', {
props: { stackItems: props.stackItems },
});
return <InternalFlashbar __internalRootRef={__internalRootRef} {...props} />;
}

applyDisplayName(Flashbar, 'Flashbar');
3 changes: 3 additions & 0 deletions src/flashbar/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';

import { ButtonProps } from '../button/interfaces';
import { BaseComponentProps } from '../internal/base-component';
import { InternalBaseComponentProps } from '../internal/hooks/use-base-component';

export namespace FlashbarProps {
export interface MessageDefinition {
Expand Down Expand Up @@ -99,3 +100,5 @@ export interface FlashbarProps extends BaseComponentProps {
*/
i18nStrings?: FlashbarProps.I18nStrings;
}

export type InternalFlashbarProps = FlashbarProps & InternalBaseComponentProps;
5 changes: 5 additions & 0 deletions src/flashbar/internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { createWidgetizedFlashbar } from './implementation';

export const InternalFlashbar = createWidgetizedFlashbar();
16 changes: 12 additions & 4 deletions src/flashbar/non-collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ import { getAnalyticsMetadataAttribute } from '@cloudscape-design/component-tool

import { useInternalI18n } from '../i18n/context';
import { Transition } from '../internal/components/transition';
import { useMergeRefs } from '../internal/hooks/use-merge-refs';
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
import { getComponentsAnalyticsMetadata, getItemAnalyticsMetadata } from './analytics-metadata/utils';
import { useFlashbar } from './common';
import { TIMEOUT_FOR_ENTERING_ANIMATION } from './constant';
import { Flash } from './flash';
import { FlashbarProps } from './interfaces';
import { FlashbarProps, InternalFlashbarProps } from './interfaces';

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

export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProps }: FlashbarProps) {
const { allItemsHaveId, baseProps, breakpoint, isReducedMotion, isVisualRefresh, mergedRef } = useFlashbar({
export default function NonCollapsibleFlashbar({
__internalRootRef,
items,
i18nStrings,
...restProps
}: InternalFlashbarProps) {
const isVisualRefresh = useVisualRefresh();
const { allItemsHaveId, baseProps, breakpoint, isReducedMotion, mergedRef } = useFlashbar({
items,
...restProps,
});
Expand Down Expand Up @@ -125,7 +133,7 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProp
<div
{...baseProps}
className={clsx(baseProps.className, styles.flashbar, styles[`breakpoint-${breakpoint}`])}
ref={mergedRef}
ref={useMergeRefs(mergedRef, __internalRootRef)}
>
{renderFlatItemsWithTransitions()}
{renderFlatItemsWithoutTransitions()}
Expand Down
1 change: 1 addition & 0 deletions src/internal/widget-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ export { AppLayoutToolbarImplementation as AppLayoutToolbar } from '../app-layou
export { SplitPanelImplementation as SplitPanel } from '../split-panel/implementation';
export { BreadcrumbGroupImplementation as BreadcrumbGroup } from '../breadcrumb-group/implementation';
export { DrawerImplementation as Drawer } from '../drawer/implementation';
export { FlashbarImplementation as Flashbar } from '../flashbar/implementation';
export { SideNavigationImplementation as SideNavigation } from '../side-navigation/implementation';
export { HelpPanelImplementation as HelpPanel } from '../help-panel/implementation';
Loading