Skip to content
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
3 changes: 3 additions & 0 deletions build-tools/utils/custom-css-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ const customCssPropertiesList = [
'stackedNotificationsDefaultBottomMargin',
// Dropdown Custom Properties
'dropdownDefaultMaxWidth',
// Modal Custom Properties
'modalCustomWidth',
'modalCustomHeight',
// Spinner Custom Properties
'spinnerRotatorFrom',
'spinnerRotatorTo',
Expand Down
140 changes: 140 additions & 0 deletions pages/modal/custom-dimensions.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';

import Button from '~components/button';
import Modal from '~components/modal';
import SpaceBetween from '~components/space-between';

export default function ModalCustomDimensionsPage() {
const [visible, setVisible] = useState(false);
const [widthVisible, setWidthVisible] = useState(false);
const [heightVisible, setHeightVisible] = useState(false);
const [bothVisible, setBothVisible] = useState(false);

return (
<SpaceBetween size="m">
<h1>Modal Custom Dimensions Demo</h1>

<SpaceBetween direction="horizontal" size="s">
<Button onClick={() => setVisible(true)}>Default Modal</Button>
<Button onClick={() => setWidthVisible(true)}>Custom Width (700px)</Button>
<Button onClick={() => setHeightVisible(true)}>Custom Height (400px)</Button>
<Button onClick={() => setBothVisible(true)}>Custom Width & Height</Button>
</SpaceBetween>

<Modal
visible={visible}
onDismiss={() => setVisible(false)}
header="Default Modal"
footer={
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={() => setVisible(false)}>
Cancel
</Button>
<Button variant="primary" onClick={() => setVisible(false)}>
Ok
</Button>
</SpaceBetween>
}
>
<p>This is a default modal without custom dimensions.</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua.
</p>
</Modal>

<Modal
visible={widthVisible}
onDismiss={() => setWidthVisible(false)}
header="Modal with Custom Width"
width={700}
footer={
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={() => setWidthVisible(false)}>
Cancel
</Button>
<Button variant="primary" onClick={() => setWidthVisible(false)}>
Ok
</Button>
</SpaceBetween>
}
>
<p>This modal has a custom width of 700px.</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</Modal>

<Modal
visible={heightVisible}
onDismiss={() => setHeightVisible(false)}
header="Modal with Custom Height"
height={400}
footer={
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={() => setHeightVisible(false)}>
Cancel
</Button>
<Button variant="primary" onClick={() => setHeightVisible(false)}>
Ok
</Button>
</SpaceBetween>
}
>
<p>This modal has a custom height of 400px. Content should be scrollable if it exceeds this height.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
<p>Laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate.</p>
<p>Velit esse cillum dolore eu fugiat nulla pariatur.</p>
<p>Excepteur sint occaecat cupidatat non proident.</p>
<p>Sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>More content to demonstrate scrolling...</p>
<p>Additional paragraph to test overflow behavior.</p>
</Modal>

<Modal
visible={bothVisible}
onDismiss={() => setBothVisible(false)}
header="Modal with Custom Width & Height"
width={800}
height={500}
footer={
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={() => setBothVisible(false)}>
Cancel
</Button>
<Button variant="primary" onClick={() => setBothVisible(false)}>
Ok
</Button>
</SpaceBetween>
}
>
<p>This modal has both custom width (800px) and height (500px).</p>
<p>The content area becomes scrollable when it exceeds the specified height.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
<p>Laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate.</p>
<p>Velit esse cillum dolore eu fugiat nulla pariatur.</p>
<p>Excepteur sint occaecat cupidatat non proident.</p>
<p>Sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
<p>Laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate.</p>
<p>Velit esse cillum dolore eu fugiat nulla pariatur.</p>
<p>More content to demonstrate the scrolling behavior with custom dimensions.</p>
<p>The footer should remain visible at the bottom of the modal.</p>
</Modal>
</SpaceBetween>
);
}
147 changes: 147 additions & 0 deletions pages/modal/playground.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';

import Box from '~components/box';
import Button from '~components/button';
import Checkbox from '~components/checkbox';
import FormField from '~components/form-field';
import Input from '~components/input';
import Modal from '~components/modal';
import Select from '~components/select';
import SpaceBetween from '~components/space-between';

export default function ModalPlayground() {
const [visible, setVisible] = useState(false);
const [size, setSize] = useState<'small' | 'medium' | 'large' | 'max'>('medium');
const [position, setPosition] = useState<'center' | 'top'>('center');
const [width, setWidth] = useState('');
const [height, setHeight] = useState('');
const [disableContentPaddings, setDisableContentPaddings] = useState(false);
const [contentLines, setContentLines] = useState(10);
const [hasFooter, setHasFooter] = useState(true);
const [headerText, setHeaderText] = useState('Modal Playground');
const [closeAriaLabel, setCloseAriaLabel] = useState('');

return (
<Box padding="l">
<SpaceBetween size="l">
<h1>Modal Playground</h1>

<SpaceBetween size="m">
<FormField label="Size">
<Select
selectedOption={{ value: size }}
onChange={({ detail }) => setSize(detail.selectedOption.value as any)}
options={[
{ value: 'small', label: 'Small' },
{ value: 'medium', label: 'Medium' },
{ value: 'large', label: 'Large' },
{ value: 'max', label: 'Max' },
]}
/>
</FormField>

<FormField label="Position">
<Select
selectedOption={{ value: position }}
onChange={({ detail }) => setPosition(detail.selectedOption.value as any)}
options={[
{ value: 'center', label: 'Center' },
{ value: 'top', label: 'Top' },
]}
/>
</FormField>

<FormField label="Header Text">
<Input value={headerText} onChange={({ detail }) => setHeaderText(detail.value)} />
</FormField>

<FormField label="Close Aria Label">
<Input
value={closeAriaLabel}
onChange={({ detail }) => setCloseAriaLabel(detail.value)}
placeholder="Default: Close modal"
/>
</FormField>

<FormField label="Custom Width (px)">
<Input
value={width}
onChange={({ detail }) => setWidth(detail.value)}
placeholder="Leave empty for default"
type="number"
/>
</FormField>

<FormField label="Custom Height (px)">
<Input
value={height}
onChange={({ detail }) => setHeight(detail.value)}
placeholder="Leave empty for default"
type="number"
/>
</FormField>

<FormField label="Content Lines">
<Input
value={String(contentLines)}
onChange={({ detail }) => setContentLines(Number(detail.value) || 10)}
type="number"
/>
</FormField>

<Checkbox
checked={disableContentPaddings}
onChange={({ detail }) => setDisableContentPaddings(detail.checked)}
>
Disable content paddings
</Checkbox>

<Checkbox checked={hasFooter} onChange={({ detail }) => setHasFooter(detail.checked)}>
Show footer
</Checkbox>

<Button variant="primary" onClick={() => setVisible(true)}>
Open Modal
</Button>
</SpaceBetween>

<Modal
visible={visible}
onDismiss={() => setVisible(false)}
size={size}
position={position}
width={width ? Number(width) : undefined}
height={height ? Number(height) : undefined}
disableContentPaddings={disableContentPaddings}
closeAriaLabel={closeAriaLabel || undefined}
header={headerText}
footer={
hasFooter ? (
<Box float="right">
<SpaceBetween direction="horizontal" size="xs">
<Button variant="link" onClick={() => setVisible(false)}>
Cancel
</Button>
<Button variant="primary" onClick={() => setVisible(false)}>
Confirm
</Button>
</SpaceBetween>
</Box>
) : undefined
}
>
<SpaceBetween size="m">
{Array.from({ length: contentLines }, (_, i) => (
<Box key={i}>
Line {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
</Box>
))}
</SpaceBetween>
</Modal>
</SpaceBetween>
</Box>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17482,6 +17482,13 @@ The function will be called when a user clicks on the trigger button.",
"optional": true,
"type": "((options: { abortSignal: AbortSignal; }) => Promise<HTMLElement>)",
},
{
"description": "Specifies the height of the modal. When provided, the modal content becomes scrollable if it exceeds the specified height.
If the specified height exceeds available viewport space, the modal will use the maximum available space.",
"name": "height",
"optional": true,
"type": "number",
},
{
"deprecatedTag": "The usage of the \`id\` attribute is reserved for internal use cases. For testing and other use cases,
use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes). If you must
Expand All @@ -17499,6 +17506,28 @@ render to an element under \`document.body\`.",
"optional": true,
"type": "HTMLElement",
},
{
"defaultValue": "'center'",
"description": "Controls the vertical positioning of the modal.

- \`center\` (default) - Modal is vertically centered in viewport and re-centers
when content height changes. Use for dialogs with static, predictable content.

- \`top\` - Modal anchors at fixed distance and grows downward
as content expands. Use when content changes dynamically to prevent disruptive
vertical repositioning that causes users to lose focus.",
"inlineType": {
"name": "ModalProps.Position",
"type": "union",
"values": [
"center",
"top",
],
},
"name": "position",
"optional": true,
"type": "string",
},
{
"description": "Use this property when \`getModalRoot\` is used to clean up the modal root
element after a user closes the dialog. The function receives the return value
Expand All @@ -17521,8 +17550,8 @@ of the most recent getModalRoot call as an argument.",
{
"defaultValue": "'medium'",
"description": "Sets the width of the modal. \`max\` uses variable width up to the
largest size allowed by the design guidelines. Other sizes
(\`small\`/\`medium\`/\`large\`) have fixed widths.",
largest size allowed by the design guidelines. Other sizes:
\`small\` (320px), \`medium\` (600px), \`large\` (820px), \`x-large\` (1024px), \`xx-large\` (1280px).",
"inlineType": {
"name": "ModalProps.Size",
"type": "union",
Expand All @@ -17531,6 +17560,8 @@ largest size allowed by the design guidelines. Other sizes
"max",
"medium",
"large",
"x-large",
"xx-large",
],
},
"name": "size",
Expand All @@ -17544,6 +17575,13 @@ Set this property to \`true\` to show them.",
"optional": false,
"type": "boolean",
},
{
"description": "Specifies the width of the modal. When provided, takes precedence over the \`size\` property.
If the specified width exceeds available viewport space, the modal will use the maximum available space.",
"name": "width",
"optional": true,
"type": "number",
},
],
"regions": [
{
Expand Down
Loading
Loading