Skip to content

Commit e6da2ac

Browse files
committed
feat(react): add floating panel
1 parent ce03f23 commit e6da2ac

33 files changed

+1093
-34
lines changed

bun.lockb

-2.73 KB
Binary file not shown.

packages/react/.storybook/main.css

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
1-
@import url("./styles/accordion.css");
2-
@import url("./styles/avatar.css");
3-
@import url("./styles/carousel.css");
4-
@import url("./styles/checkbox.css");
5-
@import url("./styles/collapsible.css");
6-
@import url("./styles/color-picker.css");
7-
@import url("./styles/combobox.css");
8-
@import url("./styles/date-picker.css");
9-
@import url("./styles/dialog.css");
10-
@import url("./styles/field.css");
11-
@import url("./styles/file-upload.css");
12-
@import url("./styles/hover-card.css");
13-
@import url("./styles/menu.css");
14-
@import url("./styles/number-input.css");
15-
@import url("./styles/pagination.css");
16-
@import url("./styles/pin-input.css");
17-
@import url("./styles/popover.css");
18-
@import url("./styles/progress.css");
19-
@import url("./styles/presence.css");
20-
@import url("./styles/qr-code.css");
21-
@import url("./styles/radio-group.css");
22-
@import url("./styles/select.css");
23-
@import url("./styles/segment-group.css");
24-
@import url("./styles/signature-pad.css");
25-
@import url("./styles/slider.css");
26-
@import url("./styles/splitter.css");
27-
@import url("./styles/switch.css");
28-
@import url("./styles/tabs.css");
29-
@import url("./styles/tags-input.css");
30-
@import url("./styles/toast.css");
31-
@import url("./styles/toggle-group.css");
32-
@import url("./styles/tooltip.css");
33-
@import url("./styles/tree-view.css");
1+
@import url('./styles/accordion.css');
2+
@import url('./styles/avatar.css');
3+
@import url('./styles/carousel.css');
4+
@import url('./styles/checkbox.css');
5+
@import url('./styles/collapsible.css');
6+
@import url('./styles/color-picker.css');
7+
@import url('./styles/combobox.css');
8+
@import url('./styles/date-picker.css');
9+
@import url('./styles/dialog.css');
10+
@import url('./styles/field.css');
11+
@import url('./styles/file-upload.css');
12+
@import url('./styles/floating-panel.css');
13+
@import url('./styles/hover-card.css');
14+
@import url('./styles/menu.css');
15+
@import url('./styles/number-input.css');
16+
@import url('./styles/pagination.css');
17+
@import url('./styles/pin-input.css');
18+
@import url('./styles/popover.css');
19+
@import url('./styles/progress.css');
20+
@import url('./styles/presence.css');
21+
@import url('./styles/qr-code.css');
22+
@import url('./styles/radio-group.css');
23+
@import url('./styles/select.css');
24+
@import url('./styles/segment-group.css');
25+
@import url('./styles/signature-pad.css');
26+
@import url('./styles/slider.css');
27+
@import url('./styles/splitter.css');
28+
@import url('./styles/switch.css');
29+
@import url('./styles/tabs.css');
30+
@import url('./styles/tags-input.css');
31+
@import url('./styles/toast.css');
32+
@import url('./styles/toggle-group.css');
33+
@import url('./styles/tooltip.css');
34+
@import url('./styles/tree-view.css');
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
[data-scope='floating-panel'] button {
2+
appearance: none;
3+
border: 1px solid black;
4+
margin: 0;
5+
padding: 0;
6+
}
7+
[data-scope='floating-panel'][data-part='content'] {
8+
box-shadow:
9+
rgba(0, 0, 0, 0.28) 0px 16px 18px 0px,
10+
rgba(0, 0, 0, 0.12) 0px 4px 16px 0px;
11+
outline: 0 !important;
12+
background-color: white;
13+
display: flex;
14+
flex-direction: column;
15+
16+
&[data-topmost] {
17+
z-index: 999999;
18+
}
19+
20+
&[data-behind] {
21+
opacity: 0.4;
22+
}
23+
}
24+
25+
[data-scope='floating-panel'][data-part='body'] {
26+
position: relative;
27+
overflow: auto;
28+
flex: 1 1 auto;
29+
padding-block: 16px;
30+
padding-inline: 16px;
31+
background-color: white;
32+
}
33+
34+
[data-scope='floating-panel'][data-part='header'] {
35+
padding-block: 16px;
36+
padding-inline: 16px;
37+
background-color: #f5f5f5;
38+
border-bottom: 1px solid #ebebeb;
39+
display: flex;
40+
justify-content: space-between;
41+
align-items: center;
42+
}
43+
44+
[data-scope='floating-panel'][data-part='header'] button {
45+
width: 24px;
46+
height: 24px;
47+
display: inline-flex;
48+
align-items: center;
49+
justify-content: center;
50+
font-size: 14px;
51+
padding: 0;
52+
svg {
53+
width: 1em;
54+
height: 1em;
55+
}
56+
}
57+
58+
[data-scope='floating-panel'][data-part='trigger-group'] {
59+
display: flex;
60+
align-items: center;
61+
gap: 8px;
62+
}
63+
64+
[data-scope='floating-panel'][data-part='resize-trigger'] {
65+
background-color: rgba(154, 18, 18, 0.396);
66+
67+
&[data-axis='n'],
68+
&[data-axis='s'] {
69+
height: 6px;
70+
max-width: 90%;
71+
}
72+
73+
&[data-axis='e'],
74+
&[data-axis='w'] {
75+
width: 6px;
76+
max-height: 90%;
77+
}
78+
79+
&[data-axis='ne'],
80+
&[data-axis='nw'],
81+
&[data-axis='se'],
82+
&[data-axis='sw'] {
83+
width: 10px;
84+
height: 10px;
85+
}
86+
}
87+
88+
[hidden] {
89+
display: none !important;
90+
}

packages/react/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,11 +544,12 @@
544544
"@zag-js/core": "0.60.0",
545545
"@zag-js/date-picker": "0.60.0",
546546
"@zag-js/date-utils": "0.60.0",
547-
"@zag-js/dom-query": "0.60.0",
548547
"@zag-js/dialog": "0.60.0",
548+
"@zag-js/dom-query": "0.60.0",
549549
"@zag-js/editable": "0.60.0",
550550
"@zag-js/file-upload": "0.60.0",
551551
"@zag-js/file-utils": "0.60.0",
552+
"@zag-js/floating-panel": "0.60.0",
552553
"@zag-js/hover-card": "0.60.0",
553554
"@zag-js/i18n-utils": "0.60.0",
554555
"@zag-js/menu": "0.60.0",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {
2+
FloatingPanel,
3+
FloatingPanelBody,
4+
FloatingPanelCloseTrigger,
5+
FloatingPanelContent,
6+
FloatingPanelDragTrigger,
7+
FloatingPanelHeader,
8+
FloatingPanelMaximizeTrigger,
9+
FloatingPanelMinimizeTrigger,
10+
FloatingPanelPositioner,
11+
FloatingPanelResizeTrigger,
12+
FloatingPanelRestoreTrigger,
13+
FloatingPanelTitle,
14+
FloatingPanelTrigger,
15+
Portal,
16+
} from '../..'
17+
18+
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
19+
20+
export const Basic = () => (
21+
<FloatingPanel.Root>
22+
<FloatingPanelTrigger>Toggle Panel</FloatingPanelTrigger>
23+
<FloatingPanelPositioner>
24+
<FloatingPanelContent>
25+
<FloatingPanelDragTrigger>
26+
<FloatingPanelHeader>
27+
<FloatingPanelTitle>Floating Panel</FloatingPanelTitle>
28+
<div data-scope="floating-panel" data-part="trigger-group">
29+
<FloatingPanelMinimizeTrigger>
30+
<Minus />
31+
</FloatingPanelMinimizeTrigger>
32+
<FloatingPanelMaximizeTrigger>
33+
<Maximize2 />
34+
</FloatingPanelMaximizeTrigger>
35+
<FloatingPanelRestoreTrigger>
36+
<ArrowDownLeft />
37+
</FloatingPanelRestoreTrigger>
38+
<FloatingPanelCloseTrigger>
39+
<XIcon />
40+
</FloatingPanelCloseTrigger>
41+
</div>
42+
</FloatingPanelHeader>
43+
</FloatingPanelDragTrigger>
44+
<FloatingPanelBody>
45+
<p>Some content</p>
46+
</FloatingPanelBody>
47+
48+
<FloatingPanelResizeTrigger axis="n" />
49+
<FloatingPanelResizeTrigger axis="e" />
50+
<FloatingPanelResizeTrigger axis="w" />
51+
<FloatingPanelResizeTrigger axis="s" />
52+
<FloatingPanelResizeTrigger axis="ne" />
53+
<FloatingPanelResizeTrigger axis="se" />
54+
<FloatingPanelResizeTrigger axis="sw" />
55+
<FloatingPanelResizeTrigger axis="nw" />
56+
</FloatingPanelContent>
57+
</FloatingPanelPositioner>
58+
</FloatingPanel.Root>
59+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { useState } from 'react'
2+
import {
3+
FloatingPanel,
4+
FloatingPanelBody,
5+
FloatingPanelCloseTrigger,
6+
FloatingPanelContent,
7+
FloatingPanelDragTrigger,
8+
FloatingPanelHeader,
9+
FloatingPanelMaximizeTrigger,
10+
FloatingPanelMinimizeTrigger,
11+
FloatingPanelPositioner,
12+
FloatingPanelResizeTrigger,
13+
FloatingPanelRestoreTrigger,
14+
FloatingPanelTitle,
15+
FloatingPanelTrigger,
16+
Portal,
17+
} from '../..'
18+
19+
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
20+
21+
export const Controlled = () => {
22+
const [isOpen, setIsOpen] = useState(false)
23+
24+
return (
25+
<FloatingPanel.Root open={isOpen} onOpenChange={(e) => setIsOpen(e.open)}>
26+
<FloatingPanelTrigger onClick={() => setIsOpen(true)}>Toggle Panel</FloatingPanelTrigger>
27+
<Portal>
28+
<FloatingPanelPositioner>
29+
<FloatingPanelContent>
30+
<FloatingPanelDragTrigger>
31+
<FloatingPanelHeader>
32+
<FloatingPanelTitle>Floating Panel</FloatingPanelTitle>
33+
<div data-scope="floating-panel" data-part="trigger-group">
34+
<FloatingPanelMinimizeTrigger>
35+
<Minus />
36+
</FloatingPanelMinimizeTrigger>
37+
<FloatingPanelMaximizeTrigger>
38+
<Maximize2 />
39+
</FloatingPanelMaximizeTrigger>
40+
<FloatingPanelRestoreTrigger>
41+
<ArrowDownLeft />
42+
</FloatingPanelRestoreTrigger>
43+
<FloatingPanelCloseTrigger>
44+
<XIcon />
45+
</FloatingPanelCloseTrigger>
46+
</div>
47+
</FloatingPanelHeader>
48+
</FloatingPanelDragTrigger>
49+
<FloatingPanelBody>
50+
<p>Some content</p>
51+
</FloatingPanelBody>
52+
53+
<FloatingPanelResizeTrigger axis="n" />
54+
<FloatingPanelResizeTrigger axis="e" />
55+
<FloatingPanelResizeTrigger axis="w" />
56+
<FloatingPanelResizeTrigger axis="s" />
57+
<FloatingPanelResizeTrigger axis="ne" />
58+
<FloatingPanelResizeTrigger axis="se" />
59+
<FloatingPanelResizeTrigger axis="sw" />
60+
<FloatingPanelResizeTrigger axis="nw" />
61+
</FloatingPanelContent>
62+
</FloatingPanelPositioner>
63+
</Portal>
64+
</FloatingPanel.Root>
65+
)
66+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {
2+
FloatingPanel,
3+
FloatingPanelBody,
4+
FloatingPanelCloseTrigger,
5+
FloatingPanelContent,
6+
FloatingPanelDragTrigger,
7+
FloatingPanelHeader,
8+
FloatingPanelMaximizeTrigger,
9+
FloatingPanelMinimizeTrigger,
10+
FloatingPanelPositioner,
11+
FloatingPanelResizeTrigger,
12+
FloatingPanelRestoreTrigger,
13+
FloatingPanelTitle,
14+
FloatingPanelTrigger,
15+
Portal,
16+
} from '../..'
17+
18+
import { ArrowDownLeft, Maximize2, Minus, XIcon } from 'lucide-react'
19+
20+
export const LazyMount = () => (
21+
<FloatingPanel.Root lazyMount onExitComplete={() => console.log('onExitComplete invoked')}>
22+
<FloatingPanelTrigger>Toggle Panel</FloatingPanelTrigger>
23+
<Portal>
24+
<FloatingPanelPositioner>
25+
<FloatingPanelContent>
26+
<FloatingPanelDragTrigger>
27+
<FloatingPanelHeader>
28+
<FloatingPanelTitle>Floating Panel</FloatingPanelTitle>
29+
<div data-scope="floating-panel" data-part="trigger-group">
30+
<FloatingPanelMinimizeTrigger>
31+
<Minus />
32+
</FloatingPanelMinimizeTrigger>
33+
<FloatingPanelMaximizeTrigger>
34+
<Maximize2 />
35+
</FloatingPanelMaximizeTrigger>
36+
<FloatingPanelRestoreTrigger>
37+
<ArrowDownLeft />
38+
</FloatingPanelRestoreTrigger>
39+
<FloatingPanelCloseTrigger>
40+
<XIcon />
41+
</FloatingPanelCloseTrigger>
42+
</div>
43+
</FloatingPanelHeader>
44+
</FloatingPanelDragTrigger>
45+
<FloatingPanelBody>
46+
<p>Some content</p>
47+
</FloatingPanelBody>
48+
49+
<FloatingPanelResizeTrigger axis="n" />
50+
<FloatingPanelResizeTrigger axis="e" />
51+
<FloatingPanelResizeTrigger axis="w" />
52+
<FloatingPanelResizeTrigger axis="s" />
53+
<FloatingPanelResizeTrigger axis="ne" />
54+
<FloatingPanelResizeTrigger axis="se" />
55+
<FloatingPanelResizeTrigger axis="sw" />
56+
<FloatingPanelResizeTrigger axis="nw" />
57+
</FloatingPanelContent>
58+
</FloatingPanelPositioner>
59+
</Portal>
60+
</FloatingPanel.Root>
61+
)

0 commit comments

Comments
 (0)