Skip to content

Commit 49417e1

Browse files
committed
library: Add a ColorPalette based on hsv color space
1 parent dcc897e commit 49417e1

File tree

13 files changed

+843
-13
lines changed

13 files changed

+843
-13
lines changed

docs/.vitepress/locales/en_US.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export default defineConfig({
8787
{ text: 'Divider', link: '/components/divider' },
8888
{ text: 'PullToRefresh', link: '/components/pulltorefresh' },
8989
{ text: 'SearchBar', link: '/components/searchbar' },
90+
{ text: 'ColorPalette', link: '/components/colorpalette' },
9091
{ text: 'ColorPicker', link: '/components/colorpicker' },
9192
{ text: 'ListPopup', link: '/components/listpopup' },
9293
]

docs/.vitepress/locales/zh_CN.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export default defineConfig({
107107
{ text: 'Divider', link: '/zh_CN/components/divider' },
108108
{ text: 'PullToRefresh', link: '/zh_CN/components/pulltorefresh' },
109109
{ text: 'SearchBar', link: '/zh_CN/components/searchbar' },
110+
{ text: 'ColorPalette', link: '/zh_CN/components/colorpalette' },
110111
{ text: 'ColorPicker', link: '/zh_CN/components/colorpicker' },
111112
{ text: 'ListPopup', link: '/zh_CN/components/listpopup' },
112113
]

docs/components/colorpalette.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# ColorPalette
2+
3+
`ColorPalette` is a HSV color grid component with a built‑in alpha slider and an optional gray column. It uses a single Canvas and minimizes recomposition during drag interactions. With real-time color preview.
4+
5+
<div style="position: relative; max-width: 700px; height: 300px; 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=colorPalette" 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+
## Import
10+
11+
```kotlin
12+
import top.yukonga.miuix.kmp.basic.ColorPalette
13+
```
14+
15+
## Basic Usage
16+
17+
```kotlin
18+
var selectedColor by remember { mutableStateOf(Color.Red) }
19+
20+
ColorPalette(
21+
initialColor = selectedColor,
22+
onColorChanged = { newColor ->
23+
selectedColor = newColor
24+
}
25+
)
26+
```
27+
28+
## Component Variants
29+
30+
### Without Color Preview
31+
32+
Hide the preview panel at the top by setting `showPreview` to `false`:
33+
34+
```kotlin
35+
ColorPalette(
36+
initialColor = selected,
37+
onColorChanged = { newColor ->
38+
selectedColor = newColor
39+
},
40+
showPreview = false
41+
)
42+
```
43+
44+
### Customize Grid Density
45+
46+
You can change the number of rows and hue columns, and toggle the gray column at the right:
47+
48+
```kotlin
49+
ColorPalette(
50+
initialColor = selected,
51+
onColorChanged = { newColor ->
52+
selectedColor = newColor
53+
},
54+
rows = 9,
55+
hueColumns = 18,
56+
includeGrayColumn = false
57+
)
58+
```
59+
60+
### Customize Shape and Indicator
61+
62+
Control the palette corner radius and the selection indicator radius:
63+
64+
```kotlin
65+
ColorPalette(
66+
initialColor = selected,
67+
onColorChanged = { newColor ->
68+
selectedColor = newColor
69+
},
70+
cornerRadius = 20.dp,
71+
indicatorRadius = 12.dp
72+
)
73+
```
74+
75+
> Note: The alpha slider is built in and currently cannot be hidden.
76+
77+
## Properties
78+
79+
| Property | Type | Description | Default | Required |
80+
| ----------------- | --------------- | ------------------------------------------------------------------ | --------- | -------- |
81+
| initialColor | Color | Initial color | - | Yes |
82+
| onColorChanged | (Color) -> Unit | Callback when selection changes | - | Yes |
83+
| modifier | Modifier | Modifier for the component | Modifier | No |
84+
| rows | Int | Grid rows (top: brighter/lower saturation → bottom: darker/higher) | 7 | No |
85+
| hueColumns | Int | Number of hue columns | 12 | No |
86+
| includeGrayColumn | Boolean | Whether to show the gray column at the right | true | No |
87+
| showPreview | Boolean | Whether to show the color preview panel | true | No |
88+
| cornerRadius | Dp | Palette corner radius | 16.dp | No |
89+
| indicatorRadius | Dp | Selection indicator radius | 10.dp | No |
90+
91+
## Advanced Usage
92+
93+
### Using in Forms
94+
95+
Combine with other inputs to build a simple color form. The example below maintains a HEX string. You may extend it to include alpha if needed.
96+
97+
```kotlin
98+
var currentColor by remember { mutableStateOf(Color(0xFF2196F3)) }
99+
var hexValue by remember(currentColor) {
100+
mutableStateOf(
101+
"#${(currentColor.red * 255).toInt().toString(16).padStart(2, '0').uppercase()}" +
102+
(currentColor.green * 255).toInt().toString(16).padStart(2, '0').uppercase() +
103+
(currentColor.blue * 255).toInt().toString(16).padStart(2, '0').uppercase()
104+
)
105+
}
106+
107+
Surface {
108+
Column(
109+
modifier = Modifier
110+
.fillMaxWidth()
111+
.padding(16.dp)
112+
) {
113+
Text(
114+
text = "Select Color",
115+
style = MiuixTheme.textStyles.title2
116+
)
117+
Spacer(modifier = Modifier.height(16.dp))
118+
ColorPalette(
119+
initialColor = currentColor,
120+
onColorChanged = {
121+
currentColor = it
122+
hexValue = "#${(it.red * 255).toInt().toString(16).padStart(2, '0').uppercase()}" +
123+
(it.green * 255).toInt().toString(16).padStart(2, '0').uppercase() +
124+
(it.blue * 255).toInt().toString(16).padStart(2, '0').uppercase()
125+
}
126+
)
127+
Spacer(modifier = Modifier.height(16.dp))
128+
TextField(
129+
value = hexValue,
130+
onValueChange = { /* Add hex parsing logic if needed */ },
131+
label = "Hex Value",
132+
modifier = Modifier.fillMaxWidth()
133+
)
134+
}
135+
}
136+
```
137+
138+
### Using with Dialog
139+
140+
Use `ColorPalette` in a dialog to select a color:
141+
142+
```kotlin
143+
var showColorDialog = remember { mutableStateOf(false) }
144+
var selectedColor by remember { mutableStateOf(Color(0xFF2196F3)) }
145+
146+
Scaffold {
147+
TextButton(
148+
text = "Select Color",
149+
onClick = { showColorDialog.value = true }
150+
)
151+
SuperDialog(
152+
title = "Select Color",
153+
show = showColorDialog,
154+
onDismissRequest = { showColorDialog.value = false } // Close dialog
155+
) {
156+
Column {
157+
ColorPalette(
158+
initialColor = selectedColor,
159+
onColorChanged = { selectedColor = it }
160+
)
161+
Spacer(modifier = Modifier.height(16.dp))
162+
Row(
163+
modifier = Modifier.fillMaxWidth(),
164+
horizontalArrangement = Arrangement.spacedBy(8.dp),
165+
) {
166+
TextButton(
167+
modifier = Modifier.weight(1f),
168+
text = "Cancel",
169+
onClick = { showColorDialog.value = false } // Close dialog
170+
)
171+
TextButton(
172+
modifier = Modifier.weight(1f),
173+
text = "Confirm",
174+
colors = ButtonDefaults.textButtonColorsPrimary(), // Use theme color
175+
onClick = {
176+
showColorDialog.value = false
177+
// Handle confirmation logic
178+
// For example: save the selected color
179+
})
180+
}
181+
}
182+
}
183+
}
184+
```

docs/components/colorpicker.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ Scaffold {
190190
SuperDialog(
191191
title = "Select Color",
192192
show = showColorDialog,
193-
onDismissRequest = { showColorDialog.value = false }
193+
onDismissRequest = { showColorDialog.value = false } // Close dialog
194194
) {
195195
Column {
196196
ColorPicker(
@@ -205,12 +205,12 @@ Scaffold {
205205
TextButton(
206206
modifier = Modifier.weight(1f),
207207
text = "Cancel",
208-
onClick = { showColorDialog.value = false }
208+
onClick = { showColorDialog.value = false } // Close dialog
209209
)
210210
TextButton(
211211
modifier = Modifier.weight(1f),
212212
text = "Confirm",
213-
colors = ButtonDefaults.textButtonColorsPrimary(),
213+
colors = ButtonDefaults.textButtonColorsPrimary(), // Use theme color
214214
onClick = {
215215
showColorDialog.value = false
216216
// Handle confirmation logic

docs/components/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The Scaffold component provides a suitable container for cross-platform popup wi
3636
| [Divider](../components/divider) | Content separator | Block separation, hierarchy division |
3737
| [PullToRefresh](../components/pulltorefresh) | Pull-down refresh operation | Data update, page refresh |
3838
| [SearchBar](../components/searchbar) | Search input field | Content search, quick find |
39+
| [ColorPalette](../components/colorpalette) | Grid palette with alpha slider | Theme settings, color selection |
3940
| [ColorPicker](../components/colorpicker) | Color selection control | Theme settings, color selection |
4041
| [ListPopup](../components/listpopup) | List popup window component | Option selection, feature list |
4142

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2025, miuix-kotlin-multiplatform 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.getValue
14+
import androidx.compose.runtime.mutableStateOf
15+
import androidx.compose.runtime.remember
16+
import androidx.compose.runtime.setValue
17+
import androidx.compose.ui.Alignment
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.Brush
20+
import androidx.compose.ui.graphics.Color
21+
import androidx.compose.ui.unit.dp
22+
import top.yukonga.miuix.kmp.basic.ColorPalette
23+
import top.yukonga.miuix.kmp.theme.MiuixTheme
24+
25+
@Composable
26+
fun ColorPaletteDemo() {
27+
Box(
28+
modifier = Modifier
29+
.fillMaxSize()
30+
.background(Brush.linearGradient(listOf(Color(0xfff77062), Color(0xfffe5196)))),
31+
contentAlignment = Alignment.Center
32+
) {
33+
Column(
34+
Modifier
35+
.padding(16.dp)
36+
.widthIn(max = 400.dp)
37+
.fillMaxWidth(),
38+
verticalArrangement = Arrangement.spacedBy(16.dp),
39+
horizontalAlignment = Alignment.CenterHorizontally
40+
) {
41+
val miuixColor = MiuixTheme.colorScheme.primary
42+
var selectedColor by remember { mutableStateOf(miuixColor) }
43+
ColorPalette(
44+
initialColor = selectedColor,
45+
onColorChanged = { selectedColor = it }
46+
)
47+
}
48+
}
49+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ private val availableComponents = listOf(
6464
AvailableComponent("PullToRefresh", "pullToRefresh") { PullToRefreshDemo() },
6565
AvailableComponent("SearchBar", "searchBar") { SearchBarDemo() },
6666
AvailableComponent("ColorPicker", "colorPicker") { ColorPickerDemo() },
67+
AvailableComponent("ColorPalette", "colorPalette") { ColorPaletteDemo() },
6768
AvailableComponent("ListPopup", "listPopup") { ListPopupDemo() },
6869
AvailableComponent("SuperArrow", "superArrow") { SuperArrowDemo() },
6970
AvailableComponent("SuperSwitch", "superSwitch") { SuperSwitchDemo() },

0 commit comments

Comments
 (0)