Skip to content

Commit 345c857

Browse files
authored
CRAFT-1734: Add Dialog component (#428)
* refactor(dialog): migrate Dialog component to use Modal base - Replaced Dialog components with Modal components in the AppNavBarCreateButton and AppNavBarSearch components for consistency and improved functionality. - Updated Dialog imports to LegacyDialog in the navigation components. - Added new Modal component and its related types, slots, and stories to enhance the modal functionality. - Updated documentation to reflect the changes in the Dialog and Modal components. All tests pass, ensuring no breaking changes introduced. * refactor(dialog): replace LegacyDialog with Modal in navigation components - Updated AppNavBarCreateButton and AppNavBarSearch components to utilize the new Modal component, enhancing consistency and functionality. - Adjusted imports and component structure to reflect the transition from LegacyDialog to Modal. - Ensured all related functionality remains intact with no breaking changes introduced. All tests pass successfully. * refactor(modal): streamline component structure and enhance accessibility - Consolidated imports and improved formatting across various modal components for better readability and consistency. - Updated Modal and Drawer components to utilize new conditions for state management, enhancing animation handling. - Refactored stories and documentation to reflect the latest changes in component structure and accessibility features. - Ensured all components maintain proper accessibility standards and functionality. All tests pass successfully, confirming no breaking changes introduced. * feat(intl): integrate IntlProvider for internationalization support - Added IntlProvider to the App component to enable internationalization features. - Updated AppNavBarCreateButton and AppNavBarSearch components to utilize the new Modal structure with improved accessibility. - Refactored ModalTrigger to support asChild prop for better component flexibility. All tests pass successfully, ensuring no breaking changes introduced. * refactor(dialog): transition Modal components to Dialog structure - Removed the Modal component and its related files, transitioning to a Dialog-based architecture for improved accessibility and consistency. - Updated Dialog components to utilize new slot-based structure, enhancing flexibility and maintainability. - Refactored stories and documentation to reflect the changes in component structure and accessibility features. - Ensured all components maintain proper accessibility standards and functionality. All tests pass successfully, confirming no breaking changes introduced. * refactor(search): replace Modal with Dialog components in AppNavBarSearch * chore(settings): remove deprecated settings.json file * refactor(dialog): update Dialog components to use local refs and improve structure - Refactored Dialog components to replace forwardRef with local refs, enhancing clarity and maintainability. - Consolidated imports and improved formatting across various dialog components for better readability. - Updated stories to reflect changes in component structure and ensure proper accessibility standards. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): simplify Dialog component structure and remove size variants - Updated Dialog components to eliminate the size prop, enhancing simplicity and usability. - Changed DialogCloseTrigger from a button to a div for better positioning control. - Refactored stories to align with the new component structure and removed unnecessary size-related examples. - Ensured all components maintain accessibility standards and functionality. All tests pass successfully, confirming no breaking changes introduced. * feat(dialog): add ButtonAsTrigger story for custom button integration - Introduced a new story, ButtonAsTrigger, demonstrating how to trigger the Dialog component using a custom Button instead of the default trigger. - Enhanced the dialog's functionality by maintaining the Button's styling while providing dialog trigger capabilities. - Included interaction tests for opening and closing the dialog, as well as footer button interactions to ensure proper functionality. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): implement Dialog context for improved configuration management - Introduced DialogContext to manage configuration for Dialog components, enhancing the ability to pass props down to child components. - Updated Dialog.Root to utilize the new context, simplifying prop management and improving component structure. - Refactored Dialog.Content to extract configuration from context instead of props, streamlining the component's API. - Adjusted stories to reflect the new context-based structure and ensure proper functionality. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): remove motion presets and streamline dialog configuration - Eliminated the motionPreset prop and related configurations from Dialog components, simplifying the API and enhancing usability. - Updated dialog stories to reflect the removal of motion presets, ensuring clarity in usage examples. - Refactored dialog components to improve structure and maintainability, while ensuring all components adhere to accessibility standards. All tests pass successfully, confirming no breaking changes introduced. * feat(heading): enhance Heading component with Chakra integration and context support - Introduced a new Heading component that integrates Chakra UI's Heading while utilizing the HeadingContext for improved prop management. - Defined HeadingProps interface to extend ChakraHeadingProps, adding support for ref and slot attributes. - Updated the component to handle context properties and ensure proper rendering with accessibility in mind. All tests pass successfully, confirming no breaking changes introduced. * feat(dialog): add backdrop filter to dialog slot recipe * refactor(dialog): remove Dialog.Description component and update related documentation - Eliminated the Dialog.Description component to streamline the dialog API, enhancing usability and reducing complexity. - Updated documentation to reflect the removal of the description prop and adjusted examples accordingly. - Refactored Dialog stories to remove references to the description, ensuring clarity in usage examples. - Improved the Dialog component structure by consolidating props and enhancing accessibility features. All tests pass successfully, confirming no breaking changes introduced. * feat(dialog): enhance Dialog.Body with scroll behavior support - Integrated useDialogRootContext to manage scroll behavior within Dialog.Body. - Added tabIndex property to enable keyboard navigation when scrollBehavior is set to "inside". - Updated DialogBodySlot to utilize new defaultProps for improved accessibility and user experience. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): replace backdrop with modal overlay and update dialog structure - Removed the Dialog.Backdrop component and replaced it with a modal overlay for improved functionality and clarity. - Updated dialog slot recipes to reflect the new modal and modalOverlay slots, enhancing the dialog's configuration. - Refactored Dialog.Content to utilize the new modal overlay, streamlining the component's API. - Adjusted stories to demonstrate the updated dialog structure and ensure proper functionality. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): enhance modal overlay with improved styling and animations - Updated modalOverlay and modal styles to utilize new properties for better responsiveness and visual effects. - Introduced backdrop filter and animation effects for entering and exiting states, enhancing user experience. - Adjusted dimensions and positioning to ensure consistent behavior across different screen sizes. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): enhance dialog component with size variations and improved dismissal scenarios - Added new SizeVariations story to demonstrate different dialog sizes and their usage. - Updated ComplexDismissalScenarios story to illustrate various dismissal behaviors, including keyboard and backdrop interactions. - Refactored existing stories for clarity and consistency, ensuring proper functionality and accessibility. - Removed deprecated properties and streamlined dialog types for better maintainability. All tests pass successfully, confirming no breaking changes introduced. * refactor(drawer): remove Drawer component and related files for simplification - Deleted the Drawer component along with its associated files, including documentation, stories, and types, to streamline the codebase. - This removal enhances maintainability and reduces complexity, as the Drawer functionality is no longer required. - All tests pass successfully, confirming no breaking changes introduced. * refactor(app-nav-bar-search): update search component for improved functionality and clarity * refactor(dialog): remove Dialog.Backdrop component and update documentation - Eliminated the Dialog.Backdrop component from the dialog structure to streamline the API and enhance clarity. - Updated related documentation to reflect the removal of the backdrop, ensuring accurate usage examples. - Adjusted dialog stories to demonstrate the updated component structure without the backdrop. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): update dialog component structure and types - Refactored Dialog stories to improve readability and maintainability by restructuring the render method. - Enhanced dialog types with new properties for dismissibility and keyboard handling, ensuring clearer API usage. - Simplified Dialog.Context by removing unnecessary properties, streamlining the context management. - Adjusted Dialog.Root to conditionally render the DialogTrigger for better integration with React Aria. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): simplify dialog close trigger and context types - Removed unused import of RaButton from dialog.close-trigger component to streamline the code. - Changed DialogContextValue from interface to type for improved clarity and consistency in type definitions. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): update DialogCloseTriggerProps to extend IconButtonProps * refactor(dialog): enhance dialog component with improved structure and accessibility - Updated Dialog.Content to support custom width and improved layout. - Introduced Separator component for better visual separation within dialog content. - Enhanced Dialog stories to demonstrate new features, including size variations and scroll behavior. - Refactored Dialog.CloseTrigger and related components for better integration and clarity. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): clean up imports in dialog stories * refactor(app-nav-bar-create-button): enhance button dialog structure and styling * refactor(app): rearrange IntlProvider and RouterProvider for improved structure * refactor(app): add locale prop to NimbusProvider for improved internationalization support * refactor(dialog): adjust modalOverlay background colors for improved visibility * refactor(dialog): streamline dialog component props and improve structure - Consolidated padding properties in dialog recipe for consistency. - Updated button event handler from onClick to onPress for better accessibility. - Enhanced dialog types by extending slot props and adding ref attributes for improved component integration. - Simplified component implementations by removing unnecessary local refs and merging with forwarded refs. All tests pass successfully, confirming no breaking changes introduced. * refactor(dialog): enhance documentation and structure of dialog components - Removed redundant type re-exports from dialog index file for clarity. - Added comprehensive documentation comments for each dialog component, detailing usage and examples. - Streamlined component implementations by removing unnecessary comments and improving readability. All tests pass successfully, confirming no breaking changes introduced. * feat(dialog): add new Dialog component for enhanced user interaction * feat(dialog): add internationalization support for dialog close trigger - Introduced a new i18n file for dialog messages, defining the aria-label for the close trigger button. - Updated DialogCloseTrigger component to utilize internationalized messages for accessibility.
1 parent a64a858 commit 345c857

25 files changed

+2373
-240
lines changed

.changeset/fancy-swans-beam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@commercetools/nimbus": minor
3+
---
4+
5+
Dialog component added

apps/docs/src/components/navigation/app-nav-bar/components/app-nav-bar-create-button.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { Info, Add } from "@commercetools/nimbus-icons";
2-
import { Button, Dialog, TextInput, Stack, Text } from "@commercetools/nimbus";
2+
import {
3+
Button,
4+
Dialog,
5+
TextInput,
6+
Stack,
7+
Flex,
8+
Text,
9+
Icon,
10+
} from "@commercetools/nimbus";
311
import { useCreateDocument } from "@/hooks/useCreateDocument";
412

513
/**
@@ -21,25 +29,20 @@ export const AppNavBarCreateButton = () => {
2129
} = useCreateDocument();
2230

2331
return (
24-
<Dialog.Root open={isOpen} onEscapeKeyDown={() => setIsOpen(false)}>
25-
<Dialog.Backdrop />
32+
<Dialog.Root isOpen={isOpen} onOpenChange={setIsOpen}>
2633
<Dialog.Trigger asChild>
27-
<Button
28-
colorPalette="primary"
29-
size="xs"
30-
variant="ghost"
31-
onPress={() => setIsOpen(true)}
32-
>
34+
<Button colorPalette="primary" size="xs" variant="ghost">
3335
<Add />
3436
New document
3537
</Button>
3638
</Dialog.Trigger>
3739
<Dialog.Content divideY="1px">
3840
<Dialog.Header>
3941
<Dialog.Title>Create New Document</Dialog.Title>
40-
<Dialog.Description>
42+
<Text color="neutral.11" textStyle="sm">
4143
Fill in the details to create a new document.
42-
</Dialog.Description>
44+
</Text>
45+
<Dialog.CloseTrigger />
4346
</Dialog.Header>
4447
<Dialog.Body>
4548
{!isLoading ? (
@@ -80,23 +83,20 @@ export const AppNavBarCreateButton = () => {
8083
placeholder="What people will click, no pressure."
8184
autoComplete="off"
8285
/>
83-
<Stack
86+
<Flex
8487
colorPalette="info"
8588
direction="row"
86-
alignItems="center"
8789
bg="colorPalette.3"
8890
p="400"
8991
gap="400"
90-
mt="200"
92+
borderRadius="200"
9193
>
92-
<Text color="colorPalette.11">
93-
<Info size="2em" />
94-
</Text>
94+
<Icon fontSize="1.5em" as={Info} color="colorPalette.11" />
9595
<Text color="colorPalette.11">
9696
The new document item will become a child of the current
9797
document.
9898
</Text>
99-
</Stack>
99+
</Flex>
100100
</Stack>
101101
</Stack>
102102
) : (

apps/docs/src/components/navigation/app-nav-bar/components/app-nav-bar-search/app-nav-bar-search.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Box,
44
useHotkeys,
55
Dialog,
6+
Separator,
67
TextInput,
78
Text,
89
Kbd,
@@ -40,20 +41,18 @@ export const AppNavBarSearch = () => {
4041
if (selectedItem) {
4142
setOpen(false);
4243
setActiveRoute(selectedItem.route);
44+
setQuery("");
4345
}
4446
};
4547

4648
return (
4749
<Flex grow="1">
4850
<Dialog.Root
49-
open={open}
51+
isOpen={open}
5052
placement="top"
51-
motionPreset="slide-in-bottom"
5253
onOpenChange={() => setOpen(!open)}
53-
scrollBehavior="outside"
54-
size="xl"
54+
scrollBehavior="inside"
5555
>
56-
<Dialog.Backdrop />
5756
<Dialog.Trigger>
5857
<Box position="relative">
5958
<TextInput
@@ -70,12 +69,12 @@ export const AppNavBarSearch = () => {
7069
</Box>
7170
</Box>
7271
</Dialog.Trigger>
73-
<Dialog.Content divideY="1px" backdropBlur="5px">
72+
<Dialog.Content width="3xl">
7473
<Dialog.Header>
75-
<Dialog.Title fontWeight="600">
76-
Search the Documentation
77-
</Dialog.Title>
74+
<Dialog.Title>Search the Documentation</Dialog.Title>
75+
<Dialog.CloseTrigger />
7876
</Dialog.Header>
77+
<Separator />
7978
<Dialog.Body>
8079
<ComboBox
8180
inputValue={query}
@@ -99,10 +98,11 @@ export const AppNavBarSearch = () => {
9998
asChild
10099
>
101100
{/** TODO: TextInput should actually work here, try again once it's fixed*/}
102-
<Input placeholder="Type to search..." />
101+
<Input autoFocus placeholder="Type to search..." />
103102
</Box>
104103
</Flex>
105-
<Box mx="-600" borderTop="1px solid" borderColor="neutral.6">
104+
<Box mx="-600">
105+
<Separator />
106106
<ListBox items={results} selectionMode="single">
107107
{(item) => (
108108
<Flex

packages/nimbus/src/components/data-table/data-table.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ type ModalState = {
5555

5656
const InfoModal = ({ isOpen, onClose, title, children }: ModalState) => (
5757
<Dialog.Root
58-
open={isOpen}
59-
onOpenChange={({ open }) => !open && onClose && onClose()}
58+
isOpen={isOpen}
59+
onOpenChange={(open) => !open && onClose && onClose()}
6060
>
6161
<Dialog.Content>
6262
<Dialog.Header>
@@ -135,8 +135,8 @@ const ProductDetailsModal = ({
135135
};
136136

137137
return (
138-
<Dialog.Root open={isOpen}>
139-
<Dialog.Content maxWidth="600px">
138+
<Dialog.Root isOpen={isOpen}>
139+
<Dialog.Content>
140140
<Dialog.Header>
141141
<Dialog.Title>{formData.name as string}</Dialog.Title>
142142
</Dialog.Header>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { DialogBodySlot } from "../dialog.slots";
2+
import type { DialogBodyProps } from "../dialog.types";
3+
import { useDialogRootContext } from "./dialog.context";
4+
5+
export const DialogBody = (props: DialogBodyProps) => {
6+
const { ref: forwardedRef, children, ...restProps } = props;
7+
const { scrollBehavior } = useDialogRootContext();
8+
9+
const defaultProps = {
10+
/**
11+
* if scrollBehavior is set to "inside", set tabIndex to 0 to allow the body to
12+
* receive focus, effectively enabling scrolling via keyboard
13+
* arrow keys.
14+
*/
15+
tabIndex: scrollBehavior === "inside" ? 0 : undefined,
16+
};
17+
18+
return (
19+
<DialogBodySlot ref={forwardedRef} {...defaultProps} {...restProps}>
20+
{children}
21+
</DialogBodySlot>
22+
);
23+
};
24+
25+
DialogBody.displayName = "Dialog.Body";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Close } from "@commercetools/nimbus-icons";
2+
import { DialogCloseTriggerSlot } from "../dialog.slots";
3+
import type { DialogCloseTriggerProps } from "../dialog.types";
4+
import { IconButton } from "@/components";
5+
import { messages } from "../dialog.i18n";
6+
import { useIntl } from "react-intl";
7+
8+
export const DialogCloseTrigger = (props: DialogCloseTriggerProps) => {
9+
const { ref: forwardedRef, "aria-label": ariaLabel, ...restProps } = props;
10+
const intl = useIntl();
11+
12+
return (
13+
<DialogCloseTriggerSlot>
14+
<IconButton
15+
ref={forwardedRef}
16+
slot="close"
17+
size="xs"
18+
variant="ghost"
19+
aria-label={ariaLabel || intl.formatMessage(messages.closeTrigger)}
20+
{...restProps}
21+
>
22+
<Close />
23+
</IconButton>
24+
</DialogCloseTriggerSlot>
25+
);
26+
};
27+
28+
DialogCloseTrigger.displayName = "Dialog.CloseTrigger";
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {
2+
Modal as RaModal,
3+
ModalOverlay as RaModalOverlay,
4+
Dialog as RaDialog,
5+
} from "react-aria-components";
6+
import {
7+
DialogModalOverlaySlot,
8+
DialogModalSlot,
9+
DialogContentSlot,
10+
} from "../dialog.slots";
11+
import type { DialogContentProps } from "../dialog.types";
12+
import { extractStyleProps } from "@/utils/extractStyleProps";
13+
import { useDialogRootContext } from "./dialog.context";
14+
15+
export const DialogContent = (props: DialogContentProps) => {
16+
const { ref: forwardedRef, children, ...restProps } = props;
17+
18+
// Get recipe configuration from context instead of props
19+
const {
20+
defaultOpen,
21+
isDismissable,
22+
isKeyboardDismissDisabled,
23+
shouldCloseOnInteractOutside,
24+
isOpen,
25+
onOpenChange,
26+
} = useDialogRootContext();
27+
28+
const modalProps = {
29+
defaultOpen,
30+
isDismissable,
31+
isKeyboardDismissDisabled,
32+
shouldCloseOnInteractOutside,
33+
isOpen,
34+
onOpenChange,
35+
};
36+
37+
const [styleProps] = extractStyleProps(restProps);
38+
39+
return (
40+
<DialogModalOverlaySlot asChild>
41+
<RaModalOverlay {...modalProps}>
42+
<DialogModalSlot asChild>
43+
<RaModal>
44+
<DialogContentSlot asChild {...styleProps}>
45+
<RaDialog ref={forwardedRef}>{children}</RaDialog>
46+
</DialogContentSlot>
47+
</RaModal>
48+
</DialogModalSlot>
49+
</RaModalOverlay>
50+
</DialogModalOverlaySlot>
51+
);
52+
};
53+
54+
DialogContent.displayName = "Dialog.Content";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { createContext, useContext } from "react";
2+
import type { DialogRootProps } from "../dialog.types";
3+
4+
/**
5+
* Context value containing dialog configuration passed from Root to child components
6+
*/
7+
export type DialogContextValue = DialogRootProps;
8+
9+
export const DialogContext = createContext<DialogContextValue | undefined>(
10+
undefined
11+
);
12+
13+
/**
14+
* Hook to access dialog configuration from DialogContext
15+
* @returns Dialog configuration from context
16+
* @throws Error if used outside of Dialog.Root
17+
*/
18+
export const useDialogRootContext = (): DialogContextValue => {
19+
const context = useContext(DialogContext);
20+
if (!context) {
21+
throw new Error("useDialogContext must be used within Dialog.Root");
22+
}
23+
return context;
24+
};
25+
26+
/**
27+
* Provider component that passes dialog configuration down to child components
28+
*/
29+
export const DialogProvider = ({
30+
children,
31+
value,
32+
}: {
33+
children: React.ReactNode;
34+
value: DialogContextValue;
35+
}) => {
36+
return <DialogContext value={value}>{children}</DialogContext>;
37+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { DialogFooterSlot } from "../dialog.slots";
2+
import type { DialogFooterProps } from "../dialog.types";
3+
4+
export const DialogFooter = (props: DialogFooterProps) => {
5+
const { ref: forwardedRef, children, ...restProps } = props;
6+
7+
return (
8+
<DialogFooterSlot ref={forwardedRef} {...restProps}>
9+
{children}
10+
</DialogFooterSlot>
11+
);
12+
};
13+
14+
DialogFooter.displayName = "Dialog.Footer";
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { DialogHeaderSlot } from "../dialog.slots";
2+
import type { DialogHeaderProps } from "../dialog.types";
3+
4+
export const DialogHeader = (props: DialogHeaderProps) => {
5+
const { ref: forwardedRef, children, ...restProps } = props;
6+
7+
return (
8+
<DialogHeaderSlot ref={forwardedRef} {...restProps}>
9+
{children}
10+
</DialogHeaderSlot>
11+
);
12+
};
13+
14+
DialogHeader.displayName = "Dialog.Header";

0 commit comments

Comments
 (0)