Skip to content

Commit 03827cf

Browse files
committed
library: Add SuperBottomSheet component
1 parent cfe4f24 commit 03827cf

File tree

12 files changed

+905
-29
lines changed

12 files changed

+905
-29
lines changed

docs/.vitepress/locales/en_US.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export default defineConfig({
102102
{ text: 'SuperDropdown', link: '/components/superdropdown' },
103103
{ text: 'SuperSpinner', link: '/components/superspinner' },
104104
{ text: 'SuperDialog', link: '/components/superdialog' },
105+
{ text: 'SuperBottomSheet', link: '/components/superbottomsheet'
105106
]
106107
},
107108
]

docs/.vitepress/locales/zh_CN.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export default defineConfig({
122122
{ text: 'SuperDropdown', link: '/zh_CN/components/superdropdown' },
123123
{ text: 'SuperSpinner', link: '/zh_CN/components/superspinner' },
124124
{ text: 'SuperDialog', link: '/zh_CN/components/superdialog' },
125+
{ text: 'SuperBottomSheet', link: '/zh_CN/components/superbottomsheet' },
125126
]
126127
},
127128
]

docs/components/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ The Scaffold component provides a suitable container for cross-platform popup wi
5050
| [SuperDropdown](../components/superdropdown) | Dropdown menu based on BasicComponent | Option selection, feature list |
5151
| [SuperSpinner](../components/superspinner) | Advanced menu based on BasicComponent | Advanced options, feature list |
5252
| [SuperDialog](../components/superdialog) | Dialog window based on BasicComponent | Prompts, action confirmation |
53+
| [SuperBottomSheet](../components/superbottomsheet) | Bottom sheet based on BasicComponent | Bottom drawer, additional options |
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# SuperBottomSheet
2+
3+
`SuperBottomSheet` is a bottom sheet component in Miuix that slides up from the bottom of the screen. The height automatically adapts to the content size, but will not cover the status bar area. Supports swipe-to-dismiss gestures and custom styling.
4+
5+
<div style="position: relative; max-width: 700px; height: 210px; border-radius: 10px; overflow: hidden; border: 1px solid #777;">
6+
<iframe id="demoIframe" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;" src="../compose/index.html?id=superBottomSheet" title="Demo" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
7+
</div>
8+
9+
::: warning
10+
`SuperBottomSheet` must be used within a `Scaffold` component!
11+
:::
12+
13+
## Import
14+
15+
```kotlin
16+
import top.yukonga.miuix.kmp.extra.SuperBottomSheet
17+
```
18+
19+
## Basic Usage
20+
21+
SuperBottomSheet component provides basic bottom sheet functionality:
22+
23+
```kotlin
24+
var showBottomSheet = remember { mutableStateOf(false) }
25+
26+
Scaffold {
27+
TextButton(
28+
text = "Show Bottom Sheet",
29+
onClick = { showBottomSheet.value = true }
30+
)
31+
32+
SuperBottomSheet(
33+
show = showBottomSheet,
34+
title = "Bottom Sheet Title",
35+
onDismissRequest = { showBottomSheet.value = false }
36+
) {
37+
Text(text = "This is the content of the bottom sheet")
38+
}
39+
}
40+
```
41+
42+
## Properties
43+
44+
### SuperBottomSheet Properties
45+
46+
| Property Name | Type | Description | Default Value | Required |
47+
| -------------------------- | ---------------------------------- | -------------------------------------------- | ------------------------------------------- | -------- |
48+
| show | MutableState\<Boolean> | State object to control bottom sheet visibility | - | Yes |
49+
| modifier | Modifier | Modifier applied to the bottom sheet | Modifier | No |
50+
| title | String? | Bottom sheet title | null | No |
51+
| backgroundColor | Color | Bottom sheet background color | SuperBottomSheetDefaults.backgroundColor() | No |
52+
| enableWindowDim | Boolean | Whether to enable dimming layer | true | No |
53+
| onDismissRequest | (() -> Unit)? | Callback when bottom sheet is closed | null | No |
54+
| outsideMargin | DpSize | Bottom sheet external margin | SuperBottomSheetDefaults.outsideMargin | No |
55+
| insideMargin | DpSize | Bottom sheet internal content margin | SuperBottomSheetDefaults.insideMargin | No |
56+
| defaultWindowInsetsPadding | Boolean | Whether to apply default window insets padding | true | No |
57+
| dragHandleColor | Color | Drag indicator color | SuperBottomSheetDefaults.dragHandleColor() | No |
58+
| content | @Composable ColumnScope.() -> Unit | Bottom sheet content | - | Yes |
59+
60+
### SuperBottomSheetDefaults Object
61+
62+
The SuperBottomSheetDefaults object provides default settings for the SuperBottomSheet component.
63+
64+
#### Properties
65+
66+
| Property Name | Type | Description |
67+
| ------------- | ------ | -------------------------------------- |
68+
| outsideMargin | DpSize | Default bottom sheet external margin |
69+
| insideMargin | DpSize | Default bottom sheet internal margin |
70+
71+
#### Functions
72+
73+
| Function Name | Return Type | Description |
74+
| ----------------- | ----------- | ------------------------------- |
75+
| backgroundColor() | Color | Get default background color |
76+
| dragHandleColor() | Color | Get default drag indicator color |
77+
78+
## Advanced Usage
79+
80+
### Custom Styled Bottom Sheet
81+
82+
```kotlin
83+
var showBottomSheet = remember { mutableStateOf(false) }
84+
85+
Scaffold {
86+
TextButton(
87+
text = "Show Custom Styled Bottom Sheet",
88+
onClick = { showBottomSheet.value = true }
89+
)
90+
91+
SuperBottomSheet(
92+
show = showBottomSheet,
93+
title = "Custom Style",
94+
backgroundColor = MiuixTheme.colorScheme.surfaceVariant,
95+
dragHandleColor = MiuixTheme.colorScheme.primary,
96+
outsideMargin = DpSize(16.dp, 0.dp),
97+
insideMargin = DpSize(32.dp, 16.dp),
98+
onDismissRequest = { showBottomSheet.value = false }
99+
) {
100+
Column {
101+
Text("Custom styled bottom sheet")
102+
Spacer(modifier = Modifier.height(16.dp))
103+
TextButton(
104+
text = "Close",
105+
onClick = { showBottomSheet.value = false },
106+
modifier = Modifier.fillMaxWidth()
107+
)
108+
}
109+
}
110+
}
111+
```
112+
113+
### Bottom Sheet with List Content
114+
115+
```kotlin
116+
var showBottomSheet = remember { mutableStateOf(false) }
117+
var selectedItem by remember { mutableStateOf("") }
118+
119+
Scaffold {
120+
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
121+
TextButton(
122+
text = "Show Selection List",
123+
onClick = { showBottomSheet.value = true }
124+
)
125+
126+
Text("Selected: $selectedItem")
127+
}
128+
129+
SuperBottomSheet(
130+
show = showBottomSheet,
131+
title = "Select Item",
132+
onDismissRequest = { showBottomSheet.value = false }
133+
) {
134+
LazyColumn {
135+
items(20) { index ->
136+
Text(
137+
text = "Item ${index + 1}",
138+
modifier = Modifier
139+
.fillMaxWidth()
140+
.clickable {
141+
selectedItem = "Item ${index + 1}"
142+
showBottomSheet.value = false
143+
}
144+
.padding(vertical = 12.dp)
145+
)
146+
}
147+
}
148+
}
149+
}
150+
```
151+
152+
### Without Dimming Layer
153+
154+
```kotlin
155+
var showBottomSheet = remember { mutableStateOf(false) }
156+
157+
Scaffold {
158+
TextButton(
159+
text = "Show Bottom Sheet Without Dim",
160+
onClick = { showBottomSheet.value = true }
161+
)
162+
163+
SuperBottomSheet(
164+
show = showBottomSheet,
165+
title = "No Dimming",
166+
enableWindowDim = false,
167+
onDismissRequest = { showBottomSheet.value = false }
168+
) {
169+
Text("This bottom sheet has no background dimming layer")
170+
Spacer(modifier = Modifier.height(16.dp))
171+
TextButton(
172+
text = "Close",
173+
onClick = { showBottomSheet.value = false },
174+
modifier = Modifier.fillMaxWidth()
175+
)
176+
}
177+
}
178+
```
179+
180+
### Bottom Sheet with Form
181+
182+
```kotlin
183+
var showBottomSheet = remember { mutableStateOf(false) }
184+
var textFieldValue by remember { mutableStateOf("") }
185+
var switchState by remember { mutableStateOf(false) }
186+
187+
Scaffold {
188+
TextButton(
189+
text = "Show Form Bottom Sheet",
190+
onClick = { showBottomSheet.value = true }
191+
)
192+
193+
SuperBottomSheet(
194+
show = showBottomSheet,
195+
title = "Settings Form",
196+
onDismissRequest = { showBottomSheet.value = false }
197+
) {
198+
Card(
199+
color = MiuixTheme.colorScheme.secondaryContainer,
200+
) {
201+
TextField(
202+
modifier = Modifier.padding(vertical = 12.dp),
203+
value = textFieldValue,
204+
label = "Enter content",
205+
maxLines = 1,
206+
onValueChange = { textFieldValue = it }
207+
)
208+
209+
SuperSwitch(
210+
title = "Switch Option",
211+
checked = switchState,
212+
onCheckedChange = { switchState = it }
213+
)
214+
}
215+
216+
Spacer(Modifier.height(12.dp))
217+
218+
Row(
219+
horizontalArrangement = Arrangement.SpaceBetween
220+
) {
221+
TextButton(
222+
text = "Cancel",
223+
onClick = { showBottomSheet.value = false },
224+
modifier = Modifier.weight(1f)
225+
)
226+
Spacer(Modifier.width(20.dp))
227+
TextButton(
228+
text = "Confirm",
229+
onClick = { showBottomSheet.value = false },
230+
modifier = Modifier.weight(1f),
231+
colors = ButtonDefaults.textButtonColorsPrimary()
232+
)
233+
}
234+
}
235+
}
236+
```
237+
238+
### Adaptive Content Height
239+
240+
```kotlin
241+
var showBottomSheet = remember { mutableStateOf(false) }
242+
243+
Scaffold {
244+
TextButton(
245+
text = "Show Adaptive Height Bottom Sheet",
246+
onClick = { showBottomSheet.value = true }
247+
)
248+
249+
SuperBottomSheet(
250+
show = showBottomSheet,
251+
title = "Adaptive Height",
252+
onDismissRequest = { showBottomSheet.value = false }
253+
) {
254+
Column(modifier = Modifier.padding(vertical = 16.dp)) {
255+
Text("The height adapts to content")
256+
Spacer(modifier = Modifier.height(16.dp))
257+
Text("Add as much content as needed")
258+
Spacer(modifier = Modifier.height(16.dp))
259+
Text("But will not cover the status bar area")
260+
Spacer(modifier = Modifier.height(16.dp))
261+
TextButton(
262+
text = "Close",
263+
onClick = { showBottomSheet.value = false },
264+
modifier = Modifier.fillMaxWidth()
265+
)
266+
}
267+
}
268+
}
269+
```

docs/demo/src/commonMain/kotlin/Demo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ private val availableComponents = listOf(
7272
AvailableComponent("SuperDropdown", "superDropdown") { SuperDropdownDemo() },
7373
AvailableComponent("SuperSpinner", "superSpinner") { SuperSpinnerDemo() },
7474
AvailableComponent("SuperDialog", "superDialog") { SuperDialogDemo() },
75+
AvailableComponent("SuperBottomSheet", "superBottomSheet") { SuperBottomSheetDemo() },
7576
)
7677

7778
@Composable
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2025, compose-miuix-ui contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.fillMaxSize
9+
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.widthIn
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.mutableStateOf
14+
import androidx.compose.runtime.remember
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.graphics.Brush
18+
import androidx.compose.ui.graphics.Color
19+
import androidx.compose.ui.unit.dp
20+
import top.yukonga.miuix.kmp.basic.Card
21+
import top.yukonga.miuix.kmp.basic.Scaffold
22+
import top.yukonga.miuix.kmp.basic.TextButton
23+
import top.yukonga.miuix.kmp.extra.SuperBottomSheet
24+
25+
@Composable
26+
fun SuperBottomSheetDemo() {
27+
Scaffold {
28+
Box(
29+
modifier = Modifier
30+
.fillMaxSize()
31+
.background(Brush.linearGradient(listOf(Color(0xfff77062), Color(0xfffe5196)))),
32+
contentAlignment = Alignment.Center
33+
) {
34+
Column(
35+
Modifier
36+
.padding(16.dp)
37+
.widthIn(max = 600.dp)
38+
.fillMaxWidth(),
39+
verticalArrangement = Arrangement.spacedBy(16.dp),
40+
horizontalAlignment = Alignment.CenterHorizontally
41+
) {
42+
val showBottomSheet = remember { mutableStateOf(false) }
43+
Card {
44+
TextButton(
45+
text = "Show a BottomSheet",
46+
onClick = { showBottomSheet.value = true }
47+
)
48+
SuperBottomSheet(
49+
title = "BottomSheet Title",
50+
show = showBottomSheet,
51+
onDismissRequest = { showBottomSheet.value = false } // Close bottom sheet
52+
) {
53+
TextButton(
54+
text = "Confirm",
55+
onClick = { showBottomSheet.value = false }, // Close bottom sheet
56+
modifier = Modifier.fillMaxWidth()
57+
)
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}

docs/zh_CN/components/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ Scaffold 组件为跨平台提供了一个合适的弹出窗口的容器。`Supe
5050
| [SuperDropdown](../components/superdropdown) | 基于 BasicComponent 的下拉菜单组件 | 选项选择、功能列表 |
5151
| [SuperSpinner](../components/superspinner) | 基于 BasicComponent 的高级菜单组件 | 进阶选项选择、功能列表 |
5252
| [SuperDialog](../components/superdialog) | 基于 BasicComponent 的对话弹窗组件 | 提示、确认操作 |
53+
| [SuperBottomSheet](../components/superbottomsheet) | 基于 BasicComponent 的底部抽屉组件 | 底部抽屉、附加选项 |

0 commit comments

Comments
 (0)