@astryxdesign/cli 0.7.2-canary.f16dc9f → 0.7.2-canary.fe2c655
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/component/component.test.mjs +357 -184
- package/assets/templates/blocks/components/Drawer/DrawerForm.doc.mjs +24 -0
- package/assets/templates/blocks/components/Drawer/DrawerForm.tsx +62 -0
- package/assets/templates/blocks/components/Drawer/DrawerScrim.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerScrim.tsx +68 -0
- package/assets/templates/blocks/components/Drawer/DrawerShowcase.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerShowcase.tsx +41 -0
- package/assets/templates/blocks/components/Drawer/DrawerStart.doc.mjs +21 -0
- package/assets/templates/blocks/components/Drawer/DrawerStart.tsx +41 -0
- package/assets/templates/blocks/components/Drawer/DrawerWidths.doc.mjs +22 -0
- package/assets/templates/blocks/components/Drawer/DrawerWidths.tsx +54 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.tsx +73 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.doc.mjs +22 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.tsx +49 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.doc.mjs +21 -0
- package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.tsx +42 -0
- package/assets/templates/pages/detail-page/page.tsx +3 -3
- package/assets/templates/pages/table-inbox/page.tsx +10 -8
- package/authoring/doctypes/base/type.ts +6 -0
- package/authoring/doctypes/component/component.doc.mjs +2 -2
- package/clients/cli/lib/component-format.mjs +5 -1
- package/package.json +10 -10
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'Modal or non-modal (hasScrim)',
|
|
7
|
+
displayName: 'Modal or non-modal (hasScrim)',
|
|
8
|
+
description:
|
|
9
|
+
'The default modal drawer dims the page, traps focus, and closes on a scrim click. With hasScrim={false}, the drawer has no scrim or focus trap and leaves the page interactive.',
|
|
10
|
+
exampleFor: 'Drawer',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: [
|
|
14
|
+
'Drawer',
|
|
15
|
+
'Button',
|
|
16
|
+
'Layout',
|
|
17
|
+
'LayoutContent',
|
|
18
|
+
'HStack',
|
|
19
|
+
'DrawerHeader',
|
|
20
|
+
'Text',
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Separate controlled states for modal and non-modal drawers
|
|
7
|
+
* @output A comparison of hasScrim's two presentations
|
|
8
|
+
* @position Copyable Drawer example
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
14
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
15
|
+
import {HStack} from '@astryxdesign/core/Stack';
|
|
16
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
17
|
+
|
|
18
|
+
export default function DrawerScrim() {
|
|
19
|
+
const [openModal, setOpenModal] = useState(false);
|
|
20
|
+
const [openPanel, setOpenPanel] = useState(false);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
<HStack gap={2}>
|
|
25
|
+
<Button label="Open modal drawer" onClick={() => setOpenModal(true)} />
|
|
26
|
+
<Button
|
|
27
|
+
label="Open non-modal drawer"
|
|
28
|
+
onClick={() => setOpenPanel(true)}
|
|
29
|
+
/>
|
|
30
|
+
</HStack>
|
|
31
|
+
<Drawer
|
|
32
|
+
isOpen={openModal}
|
|
33
|
+
onOpenChange={setOpenModal}
|
|
34
|
+
label="Edit details">
|
|
35
|
+
<Layout
|
|
36
|
+
header={
|
|
37
|
+
<DrawerHeader title="Edit details" onOpenChange={setOpenModal} />
|
|
38
|
+
}
|
|
39
|
+
content={
|
|
40
|
+
<LayoutContent>
|
|
41
|
+
<Text type="body">
|
|
42
|
+
The scrim blocks the page behind this modal drawer.
|
|
43
|
+
</Text>
|
|
44
|
+
</LayoutContent>
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
</Drawer>
|
|
48
|
+
<Drawer
|
|
49
|
+
isOpen={openPanel}
|
|
50
|
+
onOpenChange={setOpenPanel}
|
|
51
|
+
label="Inspector"
|
|
52
|
+
hasScrim={false}>
|
|
53
|
+
<Layout
|
|
54
|
+
header={
|
|
55
|
+
<DrawerHeader title="Inspector" onOpenChange={setOpenPanel} />
|
|
56
|
+
}
|
|
57
|
+
content={
|
|
58
|
+
<LayoutContent>
|
|
59
|
+
<Text type="body">
|
|
60
|
+
The page behind this non-modal drawer stays interactive.
|
|
61
|
+
</Text>
|
|
62
|
+
</LayoutContent>
|
|
63
|
+
}
|
|
64
|
+
/>
|
|
65
|
+
</Drawer>
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'Basic',
|
|
7
|
+
displayName: 'Basic',
|
|
8
|
+
description:
|
|
9
|
+
'Open a modal drawer from a single trigger. The scrim dims the page; Escape, a scrim click, or the header close button closes it, and focus returns to the trigger.',
|
|
10
|
+
exampleFor: 'Drawer',
|
|
11
|
+
isReady: true,
|
|
12
|
+
isShowcase: true,
|
|
13
|
+
aspectRatio: 16 / 9,
|
|
14
|
+
componentsUsed: [
|
|
15
|
+
'Drawer',
|
|
16
|
+
'Button',
|
|
17
|
+
'Layout',
|
|
18
|
+
'LayoutContent',
|
|
19
|
+
'DrawerHeader',
|
|
20
|
+
'Text',
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Controlled open state for a modal Drawer
|
|
7
|
+
* @output A single-trigger drawer with a scrim and a DrawerHeader close button
|
|
8
|
+
* @position Drawer's docsite showcase and copyable CLI block
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
14
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
15
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
16
|
+
|
|
17
|
+
export default function DrawerShowcase() {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Button label="Open drawer" onClick={() => setIsOpen(true)} />
|
|
23
|
+
<Drawer
|
|
24
|
+
isOpen={isOpen}
|
|
25
|
+
onOpenChange={setIsOpen}
|
|
26
|
+
label="Details"
|
|
27
|
+
width={360}>
|
|
28
|
+
<Layout
|
|
29
|
+
header={<DrawerHeader title="Details" onOpenChange={setIsOpen} />}
|
|
30
|
+
content={
|
|
31
|
+
<LayoutContent>
|
|
32
|
+
<Text type="body">
|
|
33
|
+
Close with Escape, the scrim, or the close button.
|
|
34
|
+
</Text>
|
|
35
|
+
</LayoutContent>
|
|
36
|
+
}
|
|
37
|
+
/>
|
|
38
|
+
</Drawer>
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'Slide in from the start edge',
|
|
7
|
+
displayName: 'Slide in from the start edge',
|
|
8
|
+
description:
|
|
9
|
+
'Set side="start" to open from the inline start edge: left in LTR and right in RTL. The default end edge follows the inspector convention.',
|
|
10
|
+
exampleFor: 'Drawer',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: [
|
|
14
|
+
'Drawer',
|
|
15
|
+
'Button',
|
|
16
|
+
'Layout',
|
|
17
|
+
'LayoutContent',
|
|
18
|
+
'DrawerHeader',
|
|
19
|
+
'Text',
|
|
20
|
+
],
|
|
21
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Controlled open state and the logical start edge
|
|
7
|
+
* @output A Drawer that opens from the start side of the viewport
|
|
8
|
+
* @position Copyable Drawer example
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
14
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
15
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
16
|
+
|
|
17
|
+
export default function DrawerStart() {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Button label="Open start drawer" onClick={() => setIsOpen(true)} />
|
|
23
|
+
<Drawer
|
|
24
|
+
isOpen={isOpen}
|
|
25
|
+
onOpenChange={setIsOpen}
|
|
26
|
+
label="Navigation"
|
|
27
|
+
side="start">
|
|
28
|
+
<Layout
|
|
29
|
+
header={<DrawerHeader title="Navigation" onOpenChange={setIsOpen} />}
|
|
30
|
+
content={
|
|
31
|
+
<LayoutContent>
|
|
32
|
+
<Text type="body">
|
|
33
|
+
The start edge follows the page's writing direction.
|
|
34
|
+
</Text>
|
|
35
|
+
</LayoutContent>
|
|
36
|
+
}
|
|
37
|
+
/>
|
|
38
|
+
</Drawer>
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'Width budget: pixels or any CSS length',
|
|
7
|
+
displayName: 'Width budget: pixels or any CSS length',
|
|
8
|
+
description:
|
|
9
|
+
'Compare a numeric pixel width with rem and percentage lengths. The width budget also caps the drawer on mobile.',
|
|
10
|
+
exampleFor: 'Drawer',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: [
|
|
14
|
+
'Drawer',
|
|
15
|
+
'Button',
|
|
16
|
+
'Layout',
|
|
17
|
+
'LayoutContent',
|
|
18
|
+
'HStack',
|
|
19
|
+
'DrawerHeader',
|
|
20
|
+
'Text',
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input A pixel, rem, or percentage width and controlled open state
|
|
7
|
+
* @output A Drawer demonstrating the selected width budget
|
|
8
|
+
* @position Copyable Drawer example
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
14
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
15
|
+
import {HStack} from '@astryxdesign/core/Stack';
|
|
16
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
17
|
+
|
|
18
|
+
export default function DrawerWidths() {
|
|
19
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
20
|
+
const [width, setWidth] = useState<number | string>(320);
|
|
21
|
+
|
|
22
|
+
function openAtWidth(value: number | string) {
|
|
23
|
+
setWidth(value);
|
|
24
|
+
setIsOpen(true);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<HStack gap={2}>
|
|
30
|
+
<Button label="320px" onClick={() => openAtWidth(320)} />
|
|
31
|
+
<Button label="32rem" onClick={() => openAtWidth('32rem')} />
|
|
32
|
+
<Button label="50%" onClick={() => openAtWidth('50%')} />
|
|
33
|
+
</HStack>
|
|
34
|
+
<Drawer
|
|
35
|
+
isOpen={isOpen}
|
|
36
|
+
onOpenChange={setIsOpen}
|
|
37
|
+
label="Width budget"
|
|
38
|
+
width={width}>
|
|
39
|
+
<Layout
|
|
40
|
+
header={
|
|
41
|
+
<DrawerHeader title="Width budget" onOpenChange={setIsOpen} />
|
|
42
|
+
}
|
|
43
|
+
content={
|
|
44
|
+
<LayoutContent>
|
|
45
|
+
<Text type="body">
|
|
46
|
+
Width: {typeof width === 'number' ? `${width}px` : width}
|
|
47
|
+
</Text>
|
|
48
|
+
</LayoutContent>
|
|
49
|
+
}
|
|
50
|
+
/>
|
|
51
|
+
</Drawer>
|
|
52
|
+
</>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'DrawerHeader',
|
|
7
|
+
displayName: 'Drawer Header',
|
|
8
|
+
description:
|
|
9
|
+
'DrawerHeader provides a structured header for drawers with slots for title, subtitle, close button, and optional start or end content.',
|
|
10
|
+
exampleFor: 'DrawerHeader',
|
|
11
|
+
isReady: true,
|
|
12
|
+
isShowcase: true,
|
|
13
|
+
aspectRatio: 16 / 9,
|
|
14
|
+
componentsUsed: ['DrawerHeader', 'Layout', 'LayoutContent', 'Text'],
|
|
15
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Static header content: title, subtitle, a no-op close handler, and a divider
|
|
7
|
+
* @output The DrawerHeader row at the top of a square-cornered, drawer-width panel, visible without opening an overlay
|
|
8
|
+
* @position DrawerHeader's docsite showcase. Drawer has no inline mode
|
|
9
|
+
* like Dialog's isInline, so a plain panel stands in for the drawer; in an
|
|
10
|
+
* app, compose DrawerHeader in a Layout header slot inside a Drawer.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as stylex from '@stylexjs/stylex';
|
|
14
|
+
import {DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
15
|
+
import {
|
|
16
|
+
Layout,
|
|
17
|
+
LayoutContent,
|
|
18
|
+
overlayPaddingReset,
|
|
19
|
+
} from '@astryxdesign/core/Layout';
|
|
20
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
21
|
+
import {
|
|
22
|
+
borderVars,
|
|
23
|
+
colorVars,
|
|
24
|
+
spacingVars,
|
|
25
|
+
} from '@astryxdesign/core/theme/tokens.stylex';
|
|
26
|
+
|
|
27
|
+
const styles = stylex.create({
|
|
28
|
+
// A card-like panel with square corners, matching the drawer's own corners.
|
|
29
|
+
panel: {
|
|
30
|
+
width: 360,
|
|
31
|
+
maxWidth: '100%',
|
|
32
|
+
boxSizing: 'border-box',
|
|
33
|
+
backgroundColor: colorVars['--color-background-card'],
|
|
34
|
+
borderWidth: borderVars['--border-width'],
|
|
35
|
+
borderStyle: 'solid',
|
|
36
|
+
borderColor: colorVars['--color-border'],
|
|
37
|
+
borderRadius: 0,
|
|
38
|
+
},
|
|
39
|
+
body: {
|
|
40
|
+
padding: spacingVars['--spacing-4'],
|
|
41
|
+
backgroundColor: colorVars['--color-background-muted'],
|
|
42
|
+
borderRadius: 0,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default function DrawerHeaderShowcase() {
|
|
47
|
+
return (
|
|
48
|
+
// Like the Drawer root, the panel is a padding boundary, so the Layout
|
|
49
|
+
// regions inset by their own --spacing-4 default: the drawer's inset.
|
|
50
|
+
<div {...stylex.props(styles.panel, overlayPaddingReset.reset)}>
|
|
51
|
+
<Layout
|
|
52
|
+
height="auto"
|
|
53
|
+
header={
|
|
54
|
+
<DrawerHeader
|
|
55
|
+
title="Host details"
|
|
56
|
+
subtitle="web-prod-04"
|
|
57
|
+
onOpenChange={() => {}}
|
|
58
|
+
hasDivider
|
|
59
|
+
/>
|
|
60
|
+
}
|
|
61
|
+
content={
|
|
62
|
+
<LayoutContent>
|
|
63
|
+
<div {...stylex.props(styles.body)}>
|
|
64
|
+
<Text type="body" color="secondary">
|
|
65
|
+
Drawer body content goes here.
|
|
66
|
+
</Text>
|
|
67
|
+
</div>
|
|
68
|
+
</LayoutContent>
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
}
|
package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.doc.mjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'With subtitle and end content',
|
|
7
|
+
displayName: 'With subtitle and end content',
|
|
8
|
+
description:
|
|
9
|
+
'Add a subtitle under the title and put a status, such as a Badge, in endContent. The close button stays at the end of the row.',
|
|
10
|
+
exampleFor: 'DrawerHeader',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: [
|
|
14
|
+
'Drawer',
|
|
15
|
+
'DrawerHeader',
|
|
16
|
+
'Badge',
|
|
17
|
+
'Button',
|
|
18
|
+
'Layout',
|
|
19
|
+
'LayoutContent',
|
|
20
|
+
'Text',
|
|
21
|
+
],
|
|
22
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Controlled open state for a modal Drawer
|
|
7
|
+
* @output A DrawerHeader with a subtitle, a status badge in its end slot, and a close button
|
|
8
|
+
* @position Copyable DrawerHeader example
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Badge} from '@astryxdesign/core/Badge';
|
|
14
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
15
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
16
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
17
|
+
|
|
18
|
+
export default function DrawerHeaderSubtitleEndContent() {
|
|
19
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<Button label="Open host details" onClick={() => setIsOpen(true)} />
|
|
24
|
+
<Drawer
|
|
25
|
+
isOpen={isOpen}
|
|
26
|
+
onOpenChange={setIsOpen}
|
|
27
|
+
label="web-prod-04"
|
|
28
|
+
width={360}>
|
|
29
|
+
<Layout
|
|
30
|
+
header={
|
|
31
|
+
<DrawerHeader
|
|
32
|
+
title="web-prod-04"
|
|
33
|
+
subtitle="us-east-1"
|
|
34
|
+
endContent={<Badge label="Healthy" variant="success" />}
|
|
35
|
+
onOpenChange={setIsOpen}
|
|
36
|
+
/>
|
|
37
|
+
}
|
|
38
|
+
content={
|
|
39
|
+
<LayoutContent>
|
|
40
|
+
<Text type="body">
|
|
41
|
+
All 6 instances are passing readiness checks.
|
|
42
|
+
</Text>
|
|
43
|
+
</LayoutContent>
|
|
44
|
+
}
|
|
45
|
+
/>
|
|
46
|
+
</Drawer>
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
name: 'With close button',
|
|
7
|
+
displayName: 'With close button',
|
|
8
|
+
description:
|
|
9
|
+
'Pass onOpenChange to render a close button that calls it with false. Drawer renders no close button of its own, so this is the usual visible way to close.',
|
|
10
|
+
exampleFor: 'DrawerHeader',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: [
|
|
14
|
+
'Drawer',
|
|
15
|
+
'DrawerHeader',
|
|
16
|
+
'Button',
|
|
17
|
+
'Layout',
|
|
18
|
+
'LayoutContent',
|
|
19
|
+
'Text',
|
|
20
|
+
],
|
|
21
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @input Controlled open state for a modal Drawer
|
|
7
|
+
* @output A Drawer whose DrawerHeader renders a close button because it receives onOpenChange
|
|
8
|
+
* @position Copyable DrawerHeader example
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {useState} from 'react';
|
|
12
|
+
import {Drawer, DrawerHeader} from '@astryxdesign/core/Drawer';
|
|
13
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
14
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
15
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
16
|
+
|
|
17
|
+
export default function DrawerHeaderWithCloseButton() {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Button label="Open drawer" onClick={() => setIsOpen(true)} />
|
|
23
|
+
<Drawer
|
|
24
|
+
isOpen={isOpen}
|
|
25
|
+
onOpenChange={setIsOpen}
|
|
26
|
+
label="Details"
|
|
27
|
+
width={360}>
|
|
28
|
+
<Layout
|
|
29
|
+
header={<DrawerHeader title="Details" onOpenChange={setIsOpen} />}
|
|
30
|
+
content={
|
|
31
|
+
<LayoutContent>
|
|
32
|
+
<Text type="body">
|
|
33
|
+
Passing onOpenChange renders the close button, which calls it
|
|
34
|
+
with false.
|
|
35
|
+
</Text>
|
|
36
|
+
</LayoutContent>
|
|
37
|
+
}
|
|
38
|
+
/>
|
|
39
|
+
</Drawer>
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -600,9 +600,9 @@ export default function DetailPage2Template() {
|
|
|
600
600
|
}
|
|
601
601
|
end={!isNarrow && showSidePanel ? <RightPanel /> : undefined}
|
|
602
602
|
/>
|
|
603
|
-
{/* Mobile: the side
|
|
604
|
-
|
|
605
|
-
|
|
603
|
+
{/* Mobile: the side-panel content uses the full viewport so order details
|
|
604
|
+
are not squeezed beside narrow page chrome. Drawer remains available
|
|
605
|
+
for side-overlay flows that intentionally preserve page context. */}
|
|
606
606
|
<Dialog
|
|
607
607
|
variant="fullscreen"
|
|
608
608
|
isOpen={isNarrow && isPanelDialogOpen}
|
|
@@ -1652,8 +1652,8 @@ const COMPOSER_TOOLS: {
|
|
|
1652
1652
|
/**
|
|
1653
1653
|
* The compose sheet.
|
|
1654
1654
|
*
|
|
1655
|
-
* **`BottomSheet hasScrim={false}
|
|
1656
|
-
*
|
|
1655
|
+
* **`BottomSheet hasScrim={false}` keeps this bottom-edge composer non-modal.**
|
|
1656
|
+
* With the scrim off the sheet opens with `show()` rather than
|
|
1657
1657
|
* `showModal()`, so it never enters the top layer, never makes the page inert
|
|
1658
1658
|
* and never locks body scroll: the inbox behind it stays live. That matters
|
|
1659
1659
|
* more here than anywhere else in this template, because writing a message is
|
|
@@ -1661,12 +1661,14 @@ const COMPOSER_TOOLS: {
|
|
|
1661
1661
|
* actually said, copy an order number out of a thread. A modal composer
|
|
1662
1662
|
* answers that with "close me first".
|
|
1663
1663
|
*
|
|
1664
|
-
* The trade is
|
|
1665
|
-
* edge,
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1664
|
+
* The trade is bottom-edge geometry, and it is worth naming. A non-modal
|
|
1665
|
+
* `Drawer` keeps page context live from an inline edge, but it is a full-height
|
|
1666
|
+
* side panel; this composer intentionally rises from the bottom. A sheet's
|
|
1667
|
+
* positioner is `inset-inline: 0` with `justify-content: center`, and there is
|
|
1668
|
+
* no anchor, side or width prop. So this cannot be docked to the inline-end
|
|
1669
|
+
* corner the way a `Dialog` can be. `Dialog` takes a static `position` and would
|
|
1670
|
+
* put the window in that corner — but `Dialog` is always modal, so buying the
|
|
1671
|
+
* corner costs the live inbox.
|
|
1670
1672
|
* `ChatComposerDrawer` is a false friend: despite the name it is an in-flow
|
|
1671
1673
|
* disclosure tray for a ChatComposer's attachments, with no positioning of its
|
|
1672
1674
|
* own.
|
|
@@ -383,6 +383,12 @@ export interface ComponentPropDoc {
|
|
|
383
383
|
* ```
|
|
384
384
|
*/
|
|
385
385
|
slotElements?: ComponentSlotElement[];
|
|
386
|
+
/** Lifecycle marker for a prop outside the stable compatibility promise
|
|
387
|
+
* (spec:AST-017 FR21). Set `'experimental'` on a stable component's
|
|
388
|
+
* optional `experimental` prop object, and say in `description` that its
|
|
389
|
+
* contents may change or be removed in a patch release. Omit for stable
|
|
390
|
+
* props. */
|
|
391
|
+
stability?: 'experimental';
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
/**
|
|
@@ -56,7 +56,7 @@ export const doc = {
|
|
|
56
56
|
name: 'replaces',
|
|
57
57
|
type: 'string',
|
|
58
58
|
description:
|
|
59
|
-
|
|
59
|
+
'Integration components only: the exact `name` of the Core ComponentDoc this component takes over for unqualified lookup, so every app that loads the integration gets it from component detail, component lists, search, `swizzle <Name>`, and issue routing; `swizzle --list` keeps listing Core names. The Core original stays reachable with `--package @astryxdesign/core`. It takes effect only when the package\'s peer range starts at the release that applies it, `"@astryxdesign/cli": ">=0.6.7"` or later; without such a range the component keeps its own name and `doctor integration components` warns. Set it only to intentionally own a Core identity; give an alternative or variant its own name instead.',
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
name: 'keywords',
|
|
@@ -181,7 +181,7 @@ export const doc = {
|
|
|
181
181
|
name: 'props',
|
|
182
182
|
type: 'ComponentPropDoc[]',
|
|
183
183
|
description:
|
|
184
|
-
'SingleComponentDoc variant (required there): all public props for the one primary component. Each prop is {name, type, description, default?, required?, slotElements?}. Skip styling props like xstyle/className/style. Also present on SubComponentDoc.',
|
|
184
|
+
'SingleComponentDoc variant (required there): all public props for the one primary component. Each prop is {name, type, description, default?, required?, slotElements?, stability?}. Skip styling props like xstyle/className/style. Also present on SubComponentDoc.',
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
187
|
name: 'components',
|
|
@@ -68,8 +68,12 @@ function formatPropsTable(props) {
|
|
|
68
68
|
for (const p of props) {
|
|
69
69
|
const def = p.default ? `\`${mdCell(p.default)}\`` : '-';
|
|
70
70
|
const req = p.required ? ' **(required)**' : '';
|
|
71
|
+
// The text projection of the prop doc's `stability` field: an
|
|
72
|
+
// experimental prop is outside the stable compatibility promise.
|
|
73
|
+
const stability =
|
|
74
|
+
p.stability === 'experimental' ? ' **(experimental)**' : '';
|
|
71
75
|
lines.push(
|
|
72
|
-
`| \`${mdCell(p.name)}\` | \`${mdCell(p.type)}\` | ${def} | ${mdCell(p.description)}${req} |`,
|
|
76
|
+
`| \`${mdCell(p.name)}\` | \`${mdCell(p.type)}\` | ${def} | ${mdCell(p.description)}${req}${stability} |`,
|
|
73
77
|
);
|
|
74
78
|
}
|
|
75
79
|
return lines.join('\n');
|