Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/add-layer-dialog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/kumo": minor
---

Add LayerDialog component
1 change: 1 addition & 0 deletions packages/kumo-docs-astro/src/components/SidebarNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const componentItems: NavItem[] = [
{ label: "InputGroup", href: "/components/input-group" },
{ label: "Label", href: "/components/label" },
{ label: "Layer Card", href: "/components/layer-card" },
{ label: "Layer Dialog", href: "/components/layer-dialog" },
{ label: "Link", href: "/components/link" },
{ label: "Loader", href: "/components/loader" },
{ label: "MenuBar", href: "/components/menu-bar" },
Expand Down
186 changes: 186 additions & 0 deletions packages/kumo-docs-astro/src/components/demos/LayerDialogDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {
LayerDialog,
Button,
Input,
Select,
Radio,
Banner,
} from "@cloudflare/kumo";

/**
* Basic LayerDialog with a title and body content.
*/
export function LayerDialogBasicDemo() {
return (
<LayerDialog>
<LayerDialog.Trigger render={<Button>Open dialog</Button>} />
<LayerDialog.Content className="max-w-lg">
<LayerDialog.Body>
<LayerDialog.Title>Remove Database</LayerDialog.Title>
<p className="text-base">
Are you sure you want to remove this database. This is permanently
delete
</p>
</LayerDialog.Body>
<LayerDialog.Footer className="justify-between">
<LayerDialog.Close render={<Button variant="ghost">Close</Button>} />
<Button variant="destructive">Confirm</Button>
</LayerDialog.Footer>
</LayerDialog.Content>
</LayerDialog>
);
}

const REGION_OPTIONS = [
{
label: "Asia-Pacific (APAC)",
value: "apac",
},
{
label: "Eastern Europe (EEUR)",
value: "eeur",
},
{
label: "Eastern North America (ENAM)",
value: "enam",
},
{
label: "Oceania (OC)",
value: "oc",
},
{
label: "Western Europe (WEUR)",
value: "weur",
},
{
label: "Western North America (WNAM)",
value: "wnam",
},
];

/**
* LayerDialog with footer actions for confirmation flows.
*/
export function LayerDialogWithForm() {
return (
<LayerDialog>
<LayerDialog.Trigger render={<Button>Open dialog</Button>} />
<LayerDialog.Content className="max-w-lg">
<LayerDialog.Body>
<LayerDialog.Title>Create Bucket</LayerDialog.Title>
<LayerDialog.Description>
High-performance storage for files and objects with zero egress
charges.
</LayerDialog.Description>

<div className="space-y-4 mt-4">
<Input label="Bucket name" placeholder="bucket-name" />
<Select
value={"apac"}
items={REGION_OPTIONS}
className="w-full"
label="Region"
placeholder="Region"
/>
<Radio.Group
legend="Choose a plan"
appearance="card"
orientation="horizontal"
value="Standard"
>
<Radio.Item
label="Standard"
value="Standard"
description="Recommended for objects that will be accessed at least once a month."
/>
<Radio.Item
label="Infrequent Access"
value="Infrequent Access"
description="Recommended for objects that will be accessed less than once a month."
/>
</Radio.Group>
</div>
</LayerDialog.Body>
<LayerDialog.Footer className="justify-between">
<LayerDialog.Close render={<Button variant="ghost">Close</Button>} />
<Button variant="primary">Create</Button>
</LayerDialog.Footer>
</LayerDialog.Content>
</LayerDialog>
);
}

/**
* LayerDialog showing an inline error Banner for validation feedback.
*/
export function LayerDialogWithForm2() {
return (
<LayerDialog>
<LayerDialog.Trigger render={<Button>Open dialog</Button>} />
<LayerDialog.Content className="max-w-lg">
<LayerDialog.Body>
<LayerDialog.Title>Create Bucket</LayerDialog.Title>
<LayerDialog.Description>
High-performance storage for files and objects with zero egress
charges.
</LayerDialog.Description>

<div className="space-y-4 mt-4">
<Input label="Bucket name" placeholder="bucket-name" />

<Banner variant="error">
You do not have permission to create bucket in this region
</Banner>
</div>
</LayerDialog.Body>
<LayerDialog.Footer className="justify-between">
<LayerDialog.Close render={<Button variant="ghost">Close</Button>} />
<Button variant="primary">Create</Button>
</LayerDialog.Footer>
</LayerDialog.Content>
</LayerDialog>
);
}

/**
* LayerDialog with a Separator to divide content sections.
*/
export function LayerDialogWithForm3() {
return (
<LayerDialog>
<LayerDialog.Trigger render={<Button>Open dialog</Button>} />
<LayerDialog.Content className="max-w-lg">
<LayerDialog.Body>
<LayerDialog.Title>Domain Registration</LayerDialog.Title>
<LayerDialog.Description>
At-cost domain registration and renewal. Securely register,
transfer, consolidate, and manage your domain portfolios — without
add-on fees or inflated renewal costs.
</LayerDialog.Description>

<div className="space-y-4 mt-4">
<div className="grid grid-cols-2 gap-4">
<Input label="First name" placeholder="Matt" />
<Input label="Last name" placeholder="Flare" />
</div>
<Input label="Address" placeholder="Address" />
</div>

<LayerDialog.Separator />
<LayerDialog.Description>
This information is required for domain ownership records and to
ensure we can contact you regarding your registration
</LayerDialog.Description>
<div className="space-y-4 mt-2">
<Input label="Email" placeholder="example@example.com" />
<Input label="Phone Number" placeholder="bucket-name" />
</div>
</LayerDialog.Body>
<LayerDialog.Footer className="justify-between">
<LayerDialog.Close render={<Button variant="ghost">Close</Button>} />
<Button variant="primary">Register</Button>
</LayerDialog.Footer>
</LayerDialog.Content>
</LayerDialog>
);
}
185 changes: 185 additions & 0 deletions packages/kumo-docs-astro/src/pages/components/layer-dialog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
layout: ~/layouts/MdxDocLayout.astro
title: "Layer Dialog"
description: "A dialog component built on top of LayerCard for a distinctive layered modal appearance."
sourceFile: "components/layer-dialog"
baseUIComponent: "dialog"
---

import ComponentExample from "~/components/docs/ComponentExample.astro";
import ComponentSection from "~/components/docs/ComponentSection.astro";
import CodeBlock from "~/components/docs/CodeBlock.astro";
import PropsTable from "~/components/docs/PropsTable.astro";
import {
LayerDialogBasicDemo,
LayerDialogWithForm,
LayerDialogWithForm2,
LayerDialogWithForm3,
} from "~/components/demos/LayerDialogDemo";

{/* Hero Demo */}

<ComponentSection>
<ComponentExample demo="LayerDialogWithForm">
<LayerDialogWithForm client:load />
</ComponentExample>
</ComponentSection>

{/* Installation */}

<ComponentSection>

## Installation

### Barrel

<CodeBlock code={`import { LayerDialog } from "@cloudflare/kumo";`} lang="tsx" />

### Granular

<CodeBlock
code={`import { LayerDialog } from "@cloudflare/kumo/components/layer-dialog";`}
lang="tsx"
/>
</ComponentSection>

{/* Usage */}

<ComponentSection>

## Usage

```tsx
import { LayerDialog, Button } from "@cloudflare/kumo";

export default function Example() {
return (
<LayerDialog>
<LayerDialog.Trigger render={<Button>Open</Button>} />
<LayerDialog.Content>
<LayerDialog.Body>
<LayerDialog.Title>Dialog Title</LayerDialog.Title>
<LayerDialog.Description>
A short description of the dialog content.
</LayerDialog.Description>
</LayerDialog.Body>
<LayerDialog.Footer>
<LayerDialog.Close
render={<Button variant="secondary">Cancel</Button>}
/>
<Button variant="primary">Confirm</Button>
</LayerDialog.Footer>
</LayerDialog.Content>
</LayerDialog>
);
}
```

</ComponentSection>

{/* Examples */}

<ComponentSection>

## Examples

### Basic Dialog

<p>
A simple confirmation dialog with a title, description, and footer actions.
Use <code>LayerDialog.Close</code> to provide a dismiss action.
</p>

<ComponentExample demo="LayerDialogBasicDemo">
<LayerDialogBasicDemo client:load />
</ComponentExample>

### With Form

<p>
A dialog containing a form with various inputs. The
<code>LayerDialog.Description</code> component provides context above the form
fields.
</p>

<ComponentExample demo="LayerDialogWithForm">
<LayerDialogWithForm client:load />
</ComponentExample>

### With Error Banner

<p>
Display inline validation or error states inside a dialog using the Banner
component. Keep the dialog open so users can correct the issue.
</p>

<ComponentExample demo="LayerDialogWithForm2">
<LayerDialogWithForm2 client:load />
</ComponentExample>

### With Separator

<p>
Use <code>LayerDialog.Separator</code> to visually divide related content
sections within the dialog body.
</p>

<ComponentExample demo="LayerDialogWithForm3">
<LayerDialogWithForm3 client:load />
</ComponentExample>

</ComponentSection>


{/* API Reference */}

<ComponentSection>

## API Reference

### LayerDialog

<p>The root component that controls the dialog state. Doesn't render its own HTML element.</p>
<PropsTable component="LayerDialog" />

### LayerDialog.Trigger

<p>A button that opens the dialog when clicked.</p>
<PropsTable component="LayerDialog.Trigger" />

### LayerDialog.Content

<p>Renders the portal, backdrop, and popup wrapped in a LayerCard.</p>
<PropsTable component="LayerDialog.Content" />

### LayerDialog.Body

<p>The primary content area of the dialog, rendered as LayerCard.Primary with padding.</p>
<PropsTable component="LayerDialog.Body" />

### LayerDialog.Footer

<p>The secondary action area of the dialog, rendered as LayerCard.Secondary with padding.</p>
<PropsTable component="LayerDialog.Footer" />

### LayerDialog.Title

<p>A heading that labels the dialog for accessibility.</p>
<PropsTable component="LayerDialog.Title" />

### LayerDialog.Description

<p>A paragraph providing additional context about the dialog.</p>
<PropsTable component="LayerDialog.Description" />

### LayerDialog.Close

<p>A button that closes the dialog when clicked.</p>
<PropsTable component="LayerDialog.Close" />

### LayerDialog.Separator

<p>A horizontal divider to separate content sections within the dialog body.</p>
<PropsTable component="LayerDialog.Separator" />

</ComponentSection>
4 changes: 4 additions & 0 deletions packages/kumo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
"types": "./dist/src/components/layer-card/index.d.ts",
"import": "./dist/components/layer-card.js"
},
"./components/layer-dialog": {
"types": "./dist/src/components/layer-dialog/index.d.ts",
"import": "./dist/components/layer-dialog.js"
},
"./components/label": {
"types": "./dist/src/components/label/index.d.ts",
"import": "./dist/components/label.js"
Expand Down
1 change: 1 addition & 0 deletions packages/kumo/src/components/layer-dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { LayerDialog } from "./layer-dialog";
Loading
Loading