Bottom sheet
사용자가 현재 맥락과 밀접한 관련이 있는 범위가 정해진 작업을 수행할 수 있도록 돕는 요소입니다. 모바일 화면 하단에 오버레이되어 추가적인 사항이나 액션을 표시합니다. 메인 콘텐츠에 대한 접근성을 유지하면서 임시적으로 간단한 정보를 쉽게 접근할 수 있게 해줍니다.
Bottom sheet를 표시합니다.
breakpoint에 따라 variant를 override 하여 Popup 과 쉽게 통합할 수 있습니다.
import {
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
ModalTrigger,
} from '@montage-ui/core';
const Demo = () => {
return (
<Modal>
<ModalTrigger>
<Button>Open</Button>
</ModalTrigger>
<ModalContainer variant="bottom" handle>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;Bottom sheet 는 여러 컴포넌트를 조합해서 사용합니다.
ModalTrigger, ModalNavigation 은 선택적으로 사용할 수 있습니다.
기본 구성은 아래와 같습니다.
1가지 사이즈만 사용합니다.
- medium
import {
FlexBox,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
ModalTrigger,
} from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexWrap="wrap">
<Modal>
<ModalTrigger>
<Button>Medium</Button>
</ModalTrigger>
<ModalContainer variant="bottom" size="medium" handle>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
</FlexBox>
)
}
export default Demo;resize 옵션을 사용하면 Bottom sheet가 차지하는 높이를 조정할 수 있습니다.
hug(default) — 컨텐츠 크기에 맞춥니다.fixed—size별 고정 높이를 사용합니다.fill— 화면이 허용하는 최대 높이까지 시트를 채웁니다.flexible— 최대 높이의 절반(half)만 노출되며, 위로 끌어올리면 최대 높이(full)까지 확장됩니다. Flexible usage
import {
FlexBox,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalNavigation,
ModalHeading,
ModalSummary,
ModalTrigger,
} from '@montage-ui/core';
const Demo = () => {
return (
<FlexBox gap="12px" flexWrap="wrap">
<Modal>
<ModalTrigger>
<Button>Hug</Button>
</ModalTrigger>
<ModalContainer variant="bottom" resize="hug">
<ModalNavigation>
Hug
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
<Modal>
<ModalTrigger>
<Button>Fixed</Button>
</ModalTrigger>
<ModalContainer variant="bottom" resize="fixed">
<ModalNavigation>
Fixed
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
<Modal>
<ModalTrigger>
<Button>Fill</Button>
</ModalTrigger>
<ModalContainer variant="bottom" resize="fill">
<ModalNavigation>
Fill
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
</FlexBox>
)
}
export default Demo;Bottom sheet의 상단에 핸들을 표시하여 드래그로 숨기고 열 수 있는 옵션을 사용할 수 있습니다.
- true
- false (default)
peekHeight 옵션을 0보다 큰 값으로 설정하면 handle로 조작 혹은 dimmer 영역 클릭 시 닫히지 않고 아래로 숨겨집니다.
이 때 숨겨지는 영역의 높이는 peekHeight 값을 사용합니다.
import {
FlexBox,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
ModalTrigger,
} from '@montage-ui/core';
import { useState } from 'react';
const Demo = () => {
const [open, setOpen] = useState(false);
return (
<Modal open={open} onOpenChange={setOpen}>
<ModalTrigger>
<Button>Peek height</Button>
</ModalTrigger>
<ModalContainer variant="bottom" handle peekHeight={76}>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton onClick={() => setOpen(false)} variant="alternative">
Close sheet
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;resize="flexible" 옵션은 처음에는 최대 높이의 50%(half)만 노출되었다가, 핸들을 위로 끌어올리거나 시트 내부에서 위로 스와이프하면 최대 높이(full)까지 확장되는 동작을 제공합니다.
- 해당 옵션을 사용하면 자동으로
handle={true}로 간주합니다. - 초기 스냅을
full로 시작하려면defaultSnap="full"을 사용합니다. - 스냅이 변경될 때마다
onSnapChange(snap)콜백이 호출됩니다. ('peek' (peekHeight가 있을 때만) | 'half' | 'full')
import {
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
ModalTrigger,
} from '@montage-ui/core';
const Demo = () => {
return (
<Modal>
<ModalTrigger>
<Button>Flexible</Button>
</ModalTrigger>
<ModalContainer variant="bottom" resize="flexible" handle>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>핸들을 위로 끌어올리거나 컨텐츠를 위로 스와이프하면 full로 확장됩니다.</ModalSummary>
<ModalDescription>
{Array.from({ length: 30 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>핸들을 위로 끌어올리거나 컨텐츠를 위로 스와이프하면 full로 확장됩니다.</ModalSummary>
<ModalDescription>
{Array.from({ length: 30 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>핸들을 위로 끌어올리거나 컨텐츠를 위로 스와이프하면 full로 확장됩니다.</ModalSummary>
<ModalDescription>
{Array.from({ length: 30 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;resize="flexible" 인 시트에서 스냅('peek' | 'half' | 'full')이 변경될 때마다 onSnapChange 콜백이 호출됩니다.
현재 스냅에 따라 외부 상태를 동기화하거나, 특정 스냅에서 부가 UI를 표시할 때 사용합니다.
defaultSnap 으로 초기 스냅을 지정할 수 있으며 ('half' 가 기본값), peekHeight 와 함께 사용하면 peek ↔ half ↔ full 3단 스냅이 활성화됩니다.
import { useState } from 'react';
import {
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalTrigger,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
} from '@montage-ui/core';
const Demo = () => {
const [open, setOpen] = useState(false);
const [snap, setSnap] = useState('half');
return (
<Modal open={open} onOpenChange={setOpen}>
<ModalTrigger>
<Button>Snap change</Button>
</ModalTrigger>
<ModalContainer
variant="bottom"
resize="flexible"
defaultSnap="half"
peekHeight={72}
handle
onSnapChange={setSnap}
>
<ModalContent>
<ModalContentItem>
<ModalHeading>현재 스냅: {snap}</ModalHeading>
<ModalSummary>핸들을 끌어올리거나 컨텐츠를 위로 스와이프해보세요.</ModalSummary>
<ModalDescription>
{Array.from({ length: 30 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton onClick={() => setOpen(false)} variant="alternative">
Close sheet
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;largestUndimmedSnap 은 dimmer가 꺼지는 스냅을 지정합니다. 지정한 스냅 이하의 모든 스냅에서는 dimmer가 표시되지 않고, 시트 뒤 콘텐츠로 포인터 이벤트가 통과합니다.
iOS의 largestUndimmedDetentIdentifier 와 같은 역할을 합니다.
'peek'(기본값):peek만 undimmed.half/full에서는 dimmer가 표시됩니다.'half':peek과half모두 undimmed.full에서만 dimmer가 표시됩니다. (resize="flexible"에서만 유효)
지도 위에 시트를 띄우고 half 상태에서도 지도를 조작 가능하게 하는 등의 UX 에 사용합니다.
import { useState } from 'react';
import {
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalTrigger,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
} from '@montage-ui/core';
const Demo = () => {
const [open, setOpen] = useState(false);
return (
<Modal open={open} onOpenChange={setOpen}>
<ModalTrigger>
<Button>Largest undimmed = half</Button>
</ModalTrigger>
<ModalContainer
variant="bottom"
resize="flexible"
defaultSnap="half"
peekHeight={96}
largestUndimmedSnap="half"
handle
>
<ModalContent>
<ModalContentItem>
<ModalHeading>Half 까지 undimmed</ModalHeading>
<ModalSummary>full 로 끌어올렸을 때만 dimmer 가 표시됩니다.</ModalSummary>
<ModalDescription>
{Array.from({ length: 30 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton onClick={() => setOpen(false)} variant="alternative">
Close sheet
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;enableHalfSnapScroll 은 half 스냅 + 스크롤 가능한 콘텐츠가 함께 있을 때의 제스처 라우팅 정책을 토글합니다.
false(default): half 에서의 viewport 드래그는 항상 시트를 움직입니다. 시트가 정책상 우선이므로 본문 스크롤은 발생하지 않습니다. 짧은 콘텐츠 또는 시트 자체가 주된 인터랙션인 경우 적합합니다.true: half 상태에서 스크롤 가능한 콘텐츠가 있으면 본문 스크롤이 먼저 동작합니다.
full 스냅에서는 이 옵션과 무관하게 항상 본문 스크롤이 우선으로 동작합니다.
import { useState } from 'react';
import {
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalTrigger,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalSummary,
} from '@montage-ui/core';
const Demo = () => {
const [open, setOpen] = useState(false);
return (
<Modal open={open} onOpenChange={setOpen}>
<ModalTrigger>
<Button>Half snap scroll</Button>
</ModalTrigger>
<ModalContainer
variant="bottom"
resize="flexible"
defaultSnap="half"
peekHeight={96}
enableHalfSnapScroll
handle
>
<ModalContent>
<ModalContentItem>
<ModalHeading>Scroll → 경계 → 시트 축소</ModalHeading>
<ModalSummary>half 에서 스크롤하다 맨 위에 닿으면 ↓ 드래그가 시트를 닫는 제스처로 자동 전환됩니다.</ModalSummary>
<ModalDescription>
{Array.from({ length: 60 }).map((_, i) => (
<span key={i} style={{ display: 'block' }}>Scrollable line #{i + 1}</span>
))}
</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton onClick={() => setOpen(false)} variant="alternative">
Close sheet
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;내부 콘텐츠는 ModalContent 로 감싸서 사용하는 것을 권장하며, verticalPadding, horizontalPadding, gap 옵션을 사용하여 내부 여백을 조정할 수 있습니다.
verticalPadding
- none
- top-only (default)
- bottom-only
- both
horizontalPadding
- none
- both (default)
import {
FlexBox,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalNavigation,
ModalSummary,
ModalTrigger,
Typography,
SegmentedControl,
SegmentedControlItem,
addOpacity,
} from '@montage-ui/core';
import { useState } from 'react';
const Control = ({ label, value, onValueChange, options }) => (
<FlexBox flexDirection="column" gap="8px" sx={{ width: '100%', maxWidth: 400 }}>
<Typography variant="label1" weight="medium" color="semantic.foreground.neutral.secondary">
{label}
</Typography>
<SegmentedControl size="small" value={value} onValueChange={onValueChange}>
{options.map((option) => (
<SegmentedControlItem key={option} value={option}>
{option}
</SegmentedControlItem>
))}
</SegmentedControl>
</FlexBox>
);
const Demo = () => {
const [verticalPadding, setVerticalPadding] = useState('top-only');
const [horizontalPadding, setHorizontalPadding] = useState('both');
return (
<FlexBox gap="12px" flexWrap="wrap">
<Modal>
<ModalTrigger>
<Button>Open</Button>
</ModalTrigger>
<ModalContainer variant="bottom" handle>
<ModalContent verticalPadding={verticalPadding} horizontalPadding={horizontalPadding}>
<ModalContentItem>
<FlexBox
flexDirection="column"
gap="12px"
alignItems="center"
justifyContent="center"
sx={theme => ({
width: '100%',
height: '400px',
background: addOpacity(theme.semantic.surface.accent.violetOpaque, 0.08),
})}
>
<Control
label="verticalPadding"
value={verticalPadding}
onValueChange={setVerticalPadding}
options={['none', 'top-only', 'bottom-only', 'both']}
/>
<Control
label="horizontalPadding"
value={horizontalPadding}
onValueChange={setHorizontalPadding}
options={['none', 'both']}
/>
</FlexBox>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
</FlexBox>
)
}
export default Demo;3가지 variant의 Navigation을 사용할 수 있습니다.
- emphasized (default)
- floating
- search
Navigation을 표시할 때는 handle={false} 로 사용하는 것을 권장합니다.
또한 ModalNavigation 의 leadingContent, trailingContent로 콘텐츠를 추가할 수 있으며 ModalNavigationButton 으로 사용합니다.
import {
FlexBox,
Box,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalNavigation,
ModalNavigationButton,
ModalTrigger,
SearchField,
SegmentedControl,
SegmentedControlItem,
Typography,
} from '@montage-ui/core';
import { useState } from 'react';
const Control = ({ label, value, onValueChange, options }) => (
<FlexBox flexDirection="column" gap="8px" sx={{ width: '100%', maxWidth: 400 }}>
<Typography variant="label1" weight="medium" color="semantic.foreground.neutral.secondary">
{label}
</Typography>
<SegmentedControl size="small" value={value} onValueChange={onValueChange}>
{options.map((option) => (
<SegmentedControlItem key={option} value={option}>
{option}
</SegmentedControlItem>
))}
</SegmentedControl>
</FlexBox>
);
const Demo = () => {
const [navigationVariant, setNavigationVariant] = useState('emphasized');
const [buttonVariant, setButtonVariant] = useState('icon-button');
const [leading, setLeading] = useState('on');
const [trailing, setTrailing] = useState('on');
const [background, setBackground] = useState('off');
// background only applies to icon buttons in a floating navigation
const supportsBackground = navigationVariant === 'floating' && buttonVariant === 'icon-button';
const iconButtonBackground = supportsBackground ? background === 'on' : undefined;
const leadingContent = leading === 'on' ? (
<ModalNavigationButton variant={buttonVariant === 'icon-button' ? 'back-button' : buttonVariant} background={iconButtonBackground}>
{buttonVariant === 'text-button' ? '뒤로' : undefined}
</ModalNavigationButton>
) : null;
const trailingContent = trailing === 'on' ? (
<ModalNavigationButton variant={buttonVariant === 'icon-button' ? 'close-button' : buttonVariant} background={iconButtonBackground}>
{buttonVariant === 'text-button' ? '닫기' : undefined}
</ModalNavigationButton>
) : null;
const getNavigationContent = () => {
switch (navigationVariant) {
case 'search':
return <SearchField placeholder="Enter search keyword." />;
case 'floating':
return null;
case 'emphasized':
return 'Emphasized';
}
};
return (
<FlexBox flexDirection="column" alignItems="center" gap="24px" sx={{ width: '100%' }}>
<Control
label="variant"
value={navigationVariant}
onValueChange={setNavigationVariant}
options={['emphasized', 'floating', 'search']}
/>
<Control
label="button variant"
value={buttonVariant}
onValueChange={setButtonVariant}
options={['icon-button', 'text-button']}
/>
<Control label="leadingContent" value={leading} onValueChange={setLeading} options={['on', 'off']} />
<Control label="trailingContent" value={trailing} onValueChange={setTrailing} options={['on', 'off']} />
{supportsBackground && (
<Control
label="button background"
value={background}
onValueChange={setBackground}
options={['on', 'off']}
/>
)}
<Modal>
<ModalTrigger>
<Button>Open</Button>
</ModalTrigger>
<ModalContainer variant="bottom">
<ModalNavigation
variant={navigationVariant}
leadingContent={leadingContent}
trailingContent={trailingContent}
>
{getNavigationContent()}
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<Box
sx={theme => ({
width: '100%',
height: '800px',
background: theme.semantic.surface.accent.violetOpaque,
opacity: 0.08
})}
/>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
</FlexBox>
)
}
export default Demo;variant="full" 옵션을 사용하면 전체 화면 모달 형태로 표시할 수 있습니다.
Popup Navigation 과 동일하게 Navigation을 사용할 수 있습니다.
import {
Button,
Modal,
ModalTrigger,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalDescription,
ModalHeading,
ModalNavigation,
ModalSummary,
} from '@montage-ui/core';
const Demo = () => {
return (
<Modal>
<ModalTrigger>
<Button>Full modal</Button>
</ModalTrigger>
<ModalContainer variant="full">
<ModalNavigation>
Title
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<ModalHeading>Heading</ModalHeading>
<ModalSummary>Summary</ModalSummary>
<ModalDescription>Description</ModalDescription>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Main action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
)
}
export default Demo;full variant에서는 normal variant가 추가된 4가지 variant의 Navigation을 사용할 수 있습니다.
- normal (default)
- emphasized
- floating
- search
import {
FlexBox,
Box,
Button,
Modal,
ActionArea,
ActionAreaButton,
ModalContainer,
ModalContent,
ModalContentItem,
ModalNavigation,
ModalNavigationButton,
ModalTrigger,
SearchField,
SegmentedControl,
SegmentedControlItem,
Typography,
} from '@montage-ui/core';
import { useState } from 'react';
const Control = ({ label, value, onValueChange, options }) => (
<FlexBox flexDirection="column" gap="8px" sx={{ width: '100%', maxWidth: 400 }}>
<Typography variant="label1" weight="medium" color="semantic.foreground.neutral.secondary">
{label}
</Typography>
<SegmentedControl size="small" value={value} onValueChange={onValueChange}>
{options.map((option) => (
<SegmentedControlItem key={option} value={option}>
{option}
</SegmentedControlItem>
))}
</SegmentedControl>
</FlexBox>
);
const Demo = () => {
const [navigationVariant, setNavigationVariant] = useState('normal');
const [buttonVariant, setButtonVariant] = useState('icon-button');
const [leading, setLeading] = useState('on');
const [trailing, setTrailing] = useState('on');
const [background, setBackground] = useState('off');
// background only applies to icon buttons in a floating navigation
const supportsBackground = navigationVariant === 'floating' && buttonVariant === 'icon-button';
const iconButtonBackground = supportsBackground ? background === 'on' : undefined;
const leadingContent = leading === 'on' ? (
<ModalNavigationButton variant={buttonVariant === 'icon-button' ? 'back-button' : buttonVariant} background={iconButtonBackground}>
{buttonVariant === 'text-button' ? '뒤로' : undefined}
</ModalNavigationButton>
) : null;
const trailingContent = trailing === 'on' ? (
<ModalNavigationButton variant={buttonVariant === 'icon-button' ? 'close-button' : buttonVariant} background={iconButtonBackground}>
{buttonVariant === 'text-button' ? '닫기' : undefined}
</ModalNavigationButton>
) : null;
const getNavigationContent = () => {
switch (navigationVariant) {
case 'search':
return <SearchField placeholder="Enter search keyword." />;
case 'floating':
return null;
case 'emphasized':
return 'Emphasized';
case 'normal':
return 'Normal';
}
};
return (
<FlexBox flexDirection="column" alignItems="center" gap="24px" sx={{ width: '100%' }}>
<Control
label="variant"
value={navigationVariant}
onValueChange={setNavigationVariant}
options={['normal', 'emphasized', 'floating', 'search']}
/>
<Control
label="button variant"
value={buttonVariant}
onValueChange={setButtonVariant}
options={['icon-button', 'text-button']}
/>
<Control label="leadingContent" value={leading} onValueChange={setLeading} options={['on', 'off']} />
<Control label="trailingContent" value={trailing} onValueChange={setTrailing} options={['on', 'off']} />
{supportsBackground && (
<Control
label="button background"
value={background}
onValueChange={setBackground}
options={['on', 'off']}
/>
)}
<Modal>
<ModalTrigger>
<Button>Open</Button>
</ModalTrigger>
<ModalContainer variant="full">
<ModalNavigation
variant={navigationVariant}
leadingContent={leadingContent}
trailingContent={trailingContent}
>
{getNavigationContent()}
</ModalNavigation>
<ModalContent>
<ModalContentItem>
<Box
sx={theme => ({
width: '100%',
height: '800px',
background: theme.semantic.surface.accent.violetOpaque,
opacity: 0.08
})}
/>
</ModalContentItem>
</ModalContent>
<ActionArea>
<ActionAreaButton>
Action
</ActionAreaButton>
</ActionArea>
</ModalContainer>
</Modal>
</FlexBox>
)
}
export default Demo;FlexBox 와 동일한 Props를 사용합니다.
Typography 와 동일한 Props를 사용합니다.
Typography 와 동일한 Props를 사용합니다.
Typography 와 동일한 Props를 사용합니다.
