Skip to content

Commit f0e4d72

Browse files
[JEWEL-1029] [JEWEL-1230] Reimplement Dropdown component
1 parent 0c3ad8e commit f0e4d72

File tree

10 files changed

+887
-110
lines changed

10 files changed

+887
-110
lines changed

platform/jewel/samples/showcase/src/main/kotlin/org/jetbrains/jewel/samples/showcase/components/ComboBoxes.kt

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Spacer
1010
import androidx.compose.foundation.layout.fillMaxWidth
1111
import androidx.compose.foundation.layout.height
1212
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
1314
import androidx.compose.foundation.layout.widthIn
1415
import androidx.compose.foundation.rememberScrollState
1516
import androidx.compose.foundation.text.input.rememberTextFieldState
@@ -32,15 +33,19 @@ import org.jetbrains.jewel.ui.component.DefaultButton
3233
import org.jetbrains.jewel.ui.component.EditableComboBox
3334
import org.jetbrains.jewel.ui.component.EditableListComboBox
3435
import org.jetbrains.jewel.ui.component.GroupHeader
36+
import org.jetbrains.jewel.ui.component.Icon
3537
import org.jetbrains.jewel.ui.component.ListComboBox
38+
import org.jetbrains.jewel.ui.component.MenuComboBox
3639
import org.jetbrains.jewel.ui.component.PopupManager
3740
import org.jetbrains.jewel.ui.component.SimpleListItem
3841
import org.jetbrains.jewel.ui.component.SpeedSearchArea
3942
import org.jetbrains.jewel.ui.component.Text
4043
import org.jetbrains.jewel.ui.component.search.SpeedSearchableComboBox
44+
import org.jetbrains.jewel.ui.component.separator
4145
import org.jetbrains.jewel.ui.disabledAppearance
4246
import org.jetbrains.jewel.ui.icon.IconKey
4347
import org.jetbrains.jewel.ui.icons.AllIconsKeys
48+
import org.jetbrains.jewel.ui.theme.comboBoxStyle
4449

4550
private val stringItems =
4651
listOf(
@@ -90,6 +95,9 @@ public fun ComboBoxes(modifier: Modifier = Modifier) {
9095
GroupHeader("Custom combo box content")
9196
CustomComboBoxes()
9297

98+
GroupHeader("Menu combo box (dropdown with menu items)")
99+
MenuComboBoxes()
100+
93101
GroupHeader("Dynamic content")
94102
DynamicListComboBox()
95103

@@ -318,6 +326,135 @@ private fun CustomComboBoxes() {
318326
}
319327
}
320328

329+
@Composable
330+
private fun MenuComboBoxes() {
331+
val comboBoxStyle = JewelTheme.comboBoxStyle
332+
333+
FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
334+
Column(Modifier.weight(1f).widthIn(min = 125.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
335+
Text("Simple menu items")
336+
var selectedItem by remember { mutableIntStateOf(0) }
337+
338+
MenuComboBox(
339+
labelContent = {
340+
Text(
341+
text = stringItems[selectedItem],
342+
maxLines = 1,
343+
overflow = TextOverflow.Ellipsis,
344+
style = JewelTheme.defaultTextStyle,
345+
modifier = Modifier.padding(comboBoxStyle.metrics.contentPadding),
346+
)
347+
},
348+
modifier = Modifier.widthIn(max = 200.dp).fillMaxWidth(),
349+
content = {
350+
stringItems.forEachIndexed { index, item ->
351+
selectableItem(selected = false, onClick = { selectedItem = index }) { Text(item) }
352+
}
353+
},
354+
)
355+
}
356+
357+
Column(Modifier.weight(1f).widthIn(min = 125.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
358+
Text("With icons and separators")
359+
var selectedLanguage by remember { mutableIntStateOf(0) }
360+
361+
MenuComboBox(
362+
labelContent = {
363+
Row(
364+
modifier = Modifier.padding(comboBoxStyle.metrics.contentPadding),
365+
horizontalArrangement = Arrangement.spacedBy(6.dp),
366+
verticalAlignment = Alignment.CenterVertically,
367+
) {
368+
Icon(
369+
key = languageOptions[selectedLanguage].icon,
370+
contentDescription = languageOptions[selectedLanguage].name,
371+
modifier = Modifier.size(16.dp),
372+
)
373+
Text(
374+
text = languageOptions[selectedLanguage].name,
375+
maxLines = 1,
376+
overflow = TextOverflow.Ellipsis,
377+
)
378+
}
379+
},
380+
modifier = Modifier.widthIn(max = 200.dp).fillMaxWidth(),
381+
content = {
382+
languageOptions.take(3).forEachIndexed { index, lang ->
383+
selectableItem(selected = false, onClick = { selectedLanguage = index }, iconKey = lang.icon) {
384+
Text(lang.name)
385+
}
386+
}
387+
separator()
388+
languageOptions.drop(3).forEachIndexed { index, lang ->
389+
val actualIndex = index + 3
390+
selectableItem(
391+
selected = false,
392+
onClick = { selectedLanguage = actualIndex },
393+
iconKey = lang.icon,
394+
) {
395+
Text(lang.name)
396+
}
397+
}
398+
},
399+
)
400+
}
401+
402+
Column(Modifier.weight(1f).widthIn(min = 125.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
403+
Text("With submenu")
404+
var selectedAction by remember { mutableIntStateOf(0) }
405+
val actions = listOf("New File", "New Folder", "Copy", "Paste", "Delete")
406+
407+
MenuComboBox(
408+
labelContent = {
409+
Text(
410+
text = actions[selectedAction],
411+
maxLines = 1,
412+
overflow = TextOverflow.Ellipsis,
413+
modifier = Modifier.padding(comboBoxStyle.metrics.contentPadding),
414+
)
415+
},
416+
modifier = Modifier.widthIn(max = 200.dp).fillMaxWidth(),
417+
content = {
418+
submenu(
419+
submenu = {
420+
selectableItem(selected = false, onClick = { selectedAction = 0 }) { Text(actions[0]) }
421+
selectableItem(selected = false, onClick = { selectedAction = 1 }) { Text(actions[1]) }
422+
}
423+
) {
424+
Text("New...")
425+
}
426+
separator()
427+
selectableItem(selected = false, onClick = { selectedAction = 2 }) { Text(actions[2]) }
428+
selectableItem(selected = false, onClick = { selectedAction = 3 }) { Text(actions[3]) }
429+
separator()
430+
selectableItem(selected = false, onClick = { selectedAction = 4 }) { Text(actions[4]) }
431+
},
432+
)
433+
}
434+
435+
Column(Modifier.weight(1f).widthIn(min = 125.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
436+
Text("Disabled")
437+
438+
MenuComboBox(
439+
labelContent = {
440+
Text(
441+
text = "Disabled",
442+
maxLines = 1,
443+
overflow = TextOverflow.Ellipsis,
444+
modifier = Modifier.padding(comboBoxStyle.metrics.contentPadding),
445+
)
446+
},
447+
modifier = Modifier.widthIn(max = 200.dp).fillMaxWidth(),
448+
enabled = false,
449+
content = {
450+
selectableItem(selected = false, onClick = {}) { Text("Item 1") }
451+
selectableItem(selected = false, onClick = {}) { Text("Item 2") }
452+
},
453+
)
454+
}
455+
}
456+
}
457+
321458
@Composable
322459
private fun CustomPopupContent(onButtonClick: () -> Unit) {
323460
Column(Modifier.padding(horizontal = 16.dp, vertical = 8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {

platform/jewel/ui/api-dump-experimental.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
f:org.jetbrains.jewel.ui.component.ComboBoxKt
22
- *bsf:ComboBox-8u0NR3k(kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.ui.Modifier,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,kotlin.jvm.functions.Function0,kotlin.jvm.functions.Function0,org.jetbrains.jewel.ui.component.PopupManager,androidx.compose.runtime.Composer,I,I,I):V
3+
- *sf:ComboBox-MCfSvGQ(kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function1,Z,androidx.compose.ui.Modifier,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,kotlin.jvm.functions.Function0,kotlin.jvm.functions.Function0,org.jetbrains.jewel.ui.component.PopupManager,androidx.compose.runtime.Composer,I,I,I):V
34
- *sf:ComboBox-PlcyrME(kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.ui.Modifier,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,kotlin.jvm.functions.Function0,kotlin.jvm.functions.Function0,org.jetbrains.jewel.ui.component.PopupManager,androidx.compose.runtime.Composer,I,I,I):V
45
f:org.jetbrains.jewel.ui.component.DropdownKt
56
- *sf:Dropdown(androidx.compose.ui.Modifier,Z,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.Outline,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.DropdownStyle,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function3,androidx.compose.runtime.Composer,I,I):V
@@ -42,6 +43,8 @@ f:org.jetbrains.jewel.ui.component.LazyTreeKt
4243
f:org.jetbrains.jewel.ui.component.ListComboBoxKt
4344
- *sf:ListComboBox-pglpRAY(java.util.List,I,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,androidx.compose.ui.Modifier,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,kotlin.jvm.functions.Function1,org.jetbrains.jewel.foundation.lazy.SelectableLazyListState,kotlin.jvm.functions.Function5,androidx.compose.runtime.Composer,I,I,I):V
4445
- *bsf:ListComboBox-xKBSf-U(java.util.List,I,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,kotlin.jvm.functions.Function1,org.jetbrains.jewel.foundation.lazy.SelectableLazyListState,kotlin.jvm.functions.Function5,androidx.compose.runtime.Composer,I,I,I):V
46+
f:org.jetbrains.jewel.ui.component.MenuComboBoxKt
47+
- *sf:MenuComboBox-9xOw6hg(kotlin.jvm.functions.Function2,androidx.compose.ui.Modifier,androidx.compose.ui.Modifier,Z,org.jetbrains.jewel.ui.Outline,F,F,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.ComboBoxStyle,org.jetbrains.jewel.ui.component.styling.MenuStyle,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I,I):V
4548
*:org.jetbrains.jewel.ui.component.NodeSearchMatchState
4649
- a:getMatchResult():org.jetbrains.jewel.foundation.search.SpeedSearchMatcher$MatchResult
4750
- a:getStyle():org.jetbrains.jewel.ui.component.styling.SearchMatchStyle

platform/jewel/ui/api-dump.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ f:org.jetbrains.jewel.ui.component.ListItemState
488488
- hashCode():I
489489
- f:isActive():Z
490490
- f:isSelected():Z
491+
f:org.jetbrains.jewel.ui.component.MenuComboBoxKt
491492
org.jetbrains.jewel.ui.component.MenuController
492493
- a:clearShortcutActions():V
493494
- a:close-iuPiT84(I):Z
@@ -536,9 +537,11 @@ f:org.jetbrains.jewel.ui.component.MenuKt
536537
- sf:MenuSeparator(androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuItemMetrics,org.jetbrains.jewel.ui.component.styling.MenuItemColors,androidx.compose.runtime.Composer,I,I):V
537538
- sf:MenuSubmenuItem(androidx.compose.ui.Modifier,Z,Z,org.jetbrains.jewel.ui.icon.IconKey,androidx.compose.foundation.interaction.MutableInteractionSource,org.jetbrains.jewel.ui.component.styling.MenuStyle,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
538539
- bsf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
539-
- sf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
540+
- bsf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
540541
- bsf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.window.PopupPositionProvider,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
541-
- sf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.window.PopupPositionProvider,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
542+
- bsf:PopupMenu(kotlin.jvm.functions.Function1,androidx.compose.ui.window.PopupPositionProvider,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.MenuStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
543+
- sf:PopupMenu-_-WMjBM(kotlin.jvm.functions.Function1,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,F,org.jetbrains.jewel.ui.component.styling.MenuStyle,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
544+
- sf:PopupMenu-_-WMjBM(kotlin.jvm.functions.Function1,androidx.compose.ui.window.PopupPositionProvider,androidx.compose.ui.Modifier,F,org.jetbrains.jewel.ui.component.styling.MenuStyle,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,I,I):V
542545
- sf:items(org.jetbrains.jewel.ui.component.MenuScope,I,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function3):V
543546
- sf:items(org.jetbrains.jewel.ui.component.MenuScope,java.util.List,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function3):V
544547
- sf:separator(org.jetbrains.jewel.ui.component.MenuScope):V
@@ -566,7 +569,8 @@ f:org.jetbrains.jewel.ui.component.PopupAdKt
566569
- sf:PopupAd(androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.PopupAdStyle,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
567570
f:org.jetbrains.jewel.ui.component.PopupContainerKt
568571
- bsf:PopupContainer(kotlin.jvm.functions.Function0,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,androidx.compose.ui.window.PopupPositionProvider,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
569-
- sf:PopupContainer(kotlin.jvm.functions.Function0,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,androidx.compose.ui.window.PopupPositionProvider,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
572+
- bsf:PopupContainer(kotlin.jvm.functions.Function0,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,androidx.compose.ui.window.PopupPositionProvider,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
573+
- sf:PopupContainer-05tvjtU(kotlin.jvm.functions.Function0,androidx.compose.ui.Alignment$Horizontal,androidx.compose.ui.Modifier,Z,F,org.jetbrains.jewel.ui.component.styling.PopupContainerStyle,androidx.compose.ui.window.PopupProperties,androidx.compose.ui.window.PopupPositionProvider,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I,I):V
570574
f:org.jetbrains.jewel.ui.component.PopupKt
571575
- sf:Popup(androidx.compose.ui.window.PopupPositionProvider,androidx.compose.foundation.shape.CornerSize,kotlin.jvm.functions.Function0,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V
572576
- sf:Popup(androidx.compose.ui.window.PopupPositionProvider,kotlin.jvm.functions.Function0,androidx.compose.ui.window.PopupProperties,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function1,kotlin.jvm.functions.Function2,androidx.compose.runtime.Composer,I,I):V

platform/jewel/ui/src/main/kotlin/org/jetbrains/jewel/ui/component/Button.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ private fun SplitButtonImpl(
754754
true
755755
},
756756
horizontalAlignment = Alignment.Start,
757-
style = menuStyle,
757+
menuStyle = menuStyle,
758758
content = secondaryContentMenu,
759759
)
760760
}

0 commit comments

Comments
 (0)