diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index bbe882a8..651e2440 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useLayoutEffect } from 'react';
import { I18nProvider } from 'react-aria-components';
import { Preview } from '@storybook/react';
import { themes } from '@storybook/theming';
@@ -44,12 +44,14 @@ export const withTheme = (Story, context) => {
const { theme } = context.globals;
const { Colors, font } = THEMES[theme];
+ useLayoutEffect(() => {
+ document.body.style.fontFamily = font;
+ }, []);
+
return (
<>
-
-
-
+
>
);
};
@@ -106,13 +108,13 @@ export const preview: Preview = {
container: props => {
const scheme = useDarkMode() ? DarkTheme : LightTheme;
const globals = props.context.store.globals.get();
- const { Colors, font } = THEMES[globals.theme];
+ const { Colors } = THEMES[globals.theme];
return (
-
+ <>
-
+ >
);
},
toc: {
diff --git a/.stylelintrc b/.stylelintrc
index 9db63eb9..e307d119 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -10,7 +10,7 @@
"rules": {
"declaration-empty-line-before": null,
"declaration-property-unit-whitelist": {
- "/.*/": ["rem", "deg", "fr", "ms", "%", "px"]
+ "/.*/": ["rem", "deg", "fr", "ms", "%", "px", "vw"]
},
"declaration-property-value-blacklist": {
"/.*/": ["(\\d+[1]+px|[^1]+px)"]
diff --git a/src/components/experimental/Backdrop/Backdrop.tsx b/src/components/experimental/Backdrop/Backdrop.tsx
new file mode 100644
index 00000000..72fb9616
--- /dev/null
+++ b/src/components/experimental/Backdrop/Backdrop.tsx
@@ -0,0 +1,38 @@
+import styled from 'styled-components';
+import { ModalOverlayProps, ModalOverlay } from 'react-aria-components';
+import { getSemanticHslValue } from '../../../essentials/experimental';
+import { Elevation } from '../../../essentials';
+
+type BackdropProps = ModalOverlayProps;
+
+const Backdrop = styled(ModalOverlay)`
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: var(--visual-viewport-height);
+ background: hsla(${getSemanticHslValue('on-surface')}, 60%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: ${Elevation.DIMMING};
+
+ &[data-entering] {
+ animation: backdrop-fade 200ms;
+ }
+
+ &[data-exiting] {
+ animation: backdrop-fade 150ms reverse ease-in;
+ }
+
+ @keyframes backdrop-fade {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+ }
+`;
+
+export { Backdrop, BackdropProps };
diff --git a/src/components/experimental/Dialog/Dialog.tsx b/src/components/experimental/Dialog/Dialog.tsx
new file mode 100644
index 00000000..1c28d029
--- /dev/null
+++ b/src/components/experimental/Dialog/Dialog.tsx
@@ -0,0 +1,69 @@
+import React, { ReactElement, ReactNode } from 'react';
+import { Heading } from 'react-aria-components';
+import styled from 'styled-components';
+import { Text, textStyles } from '../Text/Text';
+import { Modal } from '../Modal/Modal';
+import { Backdrop, BackdropProps } from '../Backdrop/Backdrop';
+import { getSemanticValue } from '../../../essentials/experimental';
+
+const Card = styled.div`
+ display: grid;
+ gap: 0.5rem;
+`;
+
+const ButtonsWrapper = styled.div`
+ padding-top: 1.5rem;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ gap: 1rem;
+`;
+
+const StyledModal = styled(Modal)`
+ width: 30rem;
+`;
+
+const HeadlineText = styled(Heading)`
+ margin: 0;
+ ${textStyles.variants.headline}
+`;
+
+const SubtitleText = styled(Text)`
+ color: ${getSemanticValue('on-surface-variant')};
+`;
+
+interface DialogProps extends Omit {
+ role?: 'dialog' | 'alertdialog';
+ headline: ReactNode;
+ subtitle: ReactNode;
+ dismissButton: ReactNode;
+ actionButton: ReactNode;
+}
+
+const Dialog = ({
+ role = 'dialog',
+ headline,
+ subtitle,
+ dismissButton,
+ actionButton,
+ ...props
+}: DialogProps): ReactElement => (
+
+
+
+ {headline}
+
+
+ {subtitle}
+
+
+
+ {dismissButton}
+ {actionButton}
+
+
+
+
+);
+
+export { Dialog, DialogProps };
diff --git a/src/components/experimental/Dialog/docs/Dialog.stories.tsx b/src/components/experimental/Dialog/docs/Dialog.stories.tsx
new file mode 100644
index 00000000..6506058f
--- /dev/null
+++ b/src/components/experimental/Dialog/docs/Dialog.stories.tsx
@@ -0,0 +1,86 @@
+import React, { useState } from 'react';
+import { DialogTrigger } from 'react-aria-components';
+import { StoryObj, Meta } from '@storybook/react';
+import { action } from '@storybook/addon-actions';
+import { Dialog } from '../Dialog';
+import { Button } from '../../Button/Button';
+import { WarningIcon } from '../../../../icons';
+
+const meta: Meta = {
+ title: 'Experimental/Components/Dialog',
+ component: Dialog,
+ parameters: {
+ layout: 'centered'
+ }
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ return (
+ <>
+
+