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

Add DialogHeader to lab #4298

Merged
merged 13 commits into from
Nov 8, 2024
28 changes: 28 additions & 0 deletions .changeset/plenty-monkeys-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@salt-ds/lab": minor
---

Added `DialogHeader` component to lab. `DialogHeader`'s update follows our standardized header for container components and app regions, and it can be added to provide a structured header for dialog. The header includes a title and actions that follows our Header Block pattern.

```typescript
<Dialog open={open} onOpenChange={onOpenChange} id={id}>
<DialogHeader
header={<H2>Terms and conditions</H2>}
actions={
<Button
aria-label="Close overlay"
appearance="transparent"
sentiment="neutral"
>
<CloseIcon aria-hidden />
</Button>
}
/>
<DialogContent>
<div>
Only Chase Cards that we determine are eligible can be added to the
Wallet.
</div>
</DialogContent>
</Dialog>;
```
47 changes: 47 additions & 0 deletions packages/lab/src/dialog/DialogHeader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Styles applied to the root element */
.saltDialogHeader {
joshwooding marked this conversation as resolved.
Show resolved Hide resolved
padding-bottom: var(--salt-spacing-300);
padding-left: var(--salt-spacing-300);
padding-right: var(--salt-spacing-300);
align-items: center;
display: flex;
flex-direction: row;
gap: var(--salt-spacing-100);
box-sizing: border-box;
}

.saltDialogHeader-container {
flex-grow: 1;
margin: 0;
display: flex;
flex-direction: column;
gap: var(--salt-spacing-50);
}

.saltDialogHeader-header > .saltText {
margin: 0;
}

.saltDialogHeader-actionsContainer {
align-self: flex-start;
}

/* Styles applied to the status indicator icon overriding its default size */
.saltDialogHeader .saltStatusIndicator.saltIcon {
--icon-size: var(--salt-text-h2-lineHeight);
}

/* Styles applied to DialogHeader when accent={true} */
.saltDialogHeader-withAccent {
position: relative;
}

.saltDialogHeader-withAccent::before {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: var(--salt-spacing-300);
width: var(--salt-size-bar);
background: var(--salt-accent-background);
}
103 changes: 103 additions & 0 deletions packages/lab/src/dialog/DialogHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
StatusIndicator,
Text,
type ValidationStatus,
makePrefixer,
useDialogContext,
} from "@salt-ds/core";
import { useComponentCssInjection } from "@salt-ds/styles";
import { useWindow } from "@salt-ds/window";
import { clsx } from "clsx";
import {
type ComponentPropsWithoutRef,
type ReactNode,
forwardRef,
} from "react";
import dialogHeaderCss from "./DialogHeader.css";

const withBaseName = makePrefixer("saltDialogHeader");

export interface DialogHeaderProps extends ComponentPropsWithoutRef<"div"> {
/**
* The status of the Dialog
*/
status?: ValidationStatus | undefined;
/**
* Displays the accent bar in the Dialog Title */
disableAccent?: boolean;
/**
* Displays the header at the top of the Dialog
*/
header: ReactNode;
/**
* Displays the preheader just above the header
**/
preheader?: ReactNode;
/**
* Description text is displayed just below the header
**/
description?: ReactNode;
/**
* Actions to be displayed in header
*/
actions?: ReactNode;
}

export const DialogHeader = forwardRef<HTMLDivElement, DialogHeaderProps>(
function DialogHeader(props, ref) {
const {
className,
description,
disableAccent,
actions,
header,
preheader,
status: statusProp,
...rest
} = props;
const { status: statusContext, id } = useDialogContext();

const targetWindow = useWindow();
useComponentCssInjection({
testId: "salt-dialog-header",
css: dialogHeaderCss,
window: targetWindow,
});

const status = statusProp ?? statusContext;

return (
<div
id={id}
className={clsx(
withBaseName(),
{
[withBaseName("withAccent")]: !disableAccent && !status,
[withBaseName(status ?? "")]: !!status,
},
className,
)}
ref={ref}
{...rest}
>
{status && <StatusIndicator status={status} />}
<div className={withBaseName("container")}>
<div className={withBaseName("header")}>
{preheader && (
<Text className={withBaseName("preheader")}>{preheader}</Text>
)}
{header}
</div>
{description && (
<Text color="secondary" className={withBaseName("description")}>
{description}
</Text>
)}
</div>
{actions && (
<div className={withBaseName("actionsContainer")}>{actions}</div>
)}
</div>
);
},
);
1 change: 1 addition & 0 deletions packages/lab/src/dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./DialogHeader";
1 change: 1 addition & 0 deletions packages/lab/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export * from "./date-input";
export * from "./date-picker";
export * from "./deck-item";
export * from "./deck-layout";
export * from "./dialog";
export * from "./dropdown";
export * from "./editable-label";
export {
Expand Down
75 changes: 75 additions & 0 deletions packages/lab/stories/dialog/dialog.qa.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Dialog, H2 } from "@salt-ds/core";
import { DialogHeader } from "@salt-ds/lab";
import type { Meta, StoryFn } from "@storybook/react";
import { QAContainer, type QAContainerProps } from "docs/components";

export default {
title: "Lab /Dialog Header/Dialog Header QA",
component: Dialog,
} as Meta<typeof Dialog>;

export const DialogHeaders: StoryFn<QAContainerProps> = () => (
<QAContainer height={600} cols={1} itemPadding={5} width={1200}>
<DialogHeader
header={<H2>Terms and conditions</H2>}
style={{
width: 600,
}}
/>
<DialogHeader
style={{
width: 600,
}}
header={<H2>Terms and conditions</H2>}
preheader="Ensure you read and agree to these Terms"
/>
<DialogHeader
style={{
width: 600,
}}
header={<H2>Terms and conditions</H2>}
preheader="Ensure you read and agree to these Terms"
description="Effective date: August 29, 2024"
/>
<DialogHeader
status="info"
header={<H2>Terms and conditions</H2>}
style={{
width: 600,
}}
/>
<DialogHeader
status="info"
style={{
width: 600,
}}
header={<H2>Terms and conditions</H2>}
preheader="Ensure you read and agree to these Terms"
/>
<DialogHeader
status="info"
style={{
width: 600,
}}
header={<H2>Terms and conditions</H2>}
preheader="Ensure you read and agree to these Terms"
description="Effective date: August 29, 2024"
/>
</QAContainer>
);
DialogHeaders.parameters = {
chromatic: {
disableSnapshot: false,
modes: {
theme: {
themeNext: "disable",
},
themeNext: {
themeNext: "enable",
corner: "rounded",
accent: "teal",
// Ignore headingFont given font is not loaded
},
},
},
};
Loading
Loading