Skip to content

Commit 1ead069

Browse files
authored
library: Add a ColorPicker based on OkLch color space (#142)
1 parent de12bce commit 1ead069

File tree

6 files changed

+430
-23
lines changed

6 files changed

+430
-23
lines changed

docs/components/colorpicker.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ ColorPicker(
6464
| showPreview | Boolean | Show color preview | true | No |
6565
| hapticEffect | SliderDefaults.SliderHapticEffect | Slider haptic feedback effect | SliderDefaults.DefaultHapticEffect | No |
6666
| modifier | Modifier | Modifier for the component | Modifier | No |
67+
| colorSpace | ColorSpace | Color space to use | ColorSpace.HSV | No |
6768

6869
## Individual Slider Components
6970

@@ -129,6 +130,24 @@ AlphaSlider(
129130

130131
## Advanced Usage
131132

133+
### Color Spaces
134+
135+
ColorPicker supports multiple color spaces via `colorSpace`:
136+
- `ColorSpace.HSV` — classic HSV sliders (Hue, Saturation, Value, Alpha).
137+
- `ColorSpace.OKHSV` — perceptual HSV variant based on OkLCH, more uniform hue steps.
138+
- `ColorSpace.OKLAB` — OkLab sliders (Lightness, a, b, Alpha) for perceptual editing.
139+
- `ColorSpace.OKLCH` — OkLCH sliders (Lightness, Chroma, Hue, Alpha). Chroma is clamped to typical sRGB gamut.
140+
141+
Example: use the OKLCH color space
142+
143+
```kotlin
144+
ColorPicker(
145+
initialColor = Color(0xFF4CAF50),
146+
onColorChanged = { /* Handle color change */ },
147+
colorSpace = ColorSpace.OKLCH
148+
)
149+
```
150+
132151
### Using in Forms
133152

134153
Combine with other input controls to create a color selection form:

docs/zh_CN/components/colorpicker.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ ColorPicker(
6464
| showPreview | Boolean | 是否显示颜色预览 | true ||
6565
| hapticEffect | SliderDefaults.SliderHapticEffect | 滑块的触觉反馈效果 | SliderDefaults.DefaultHapticEffect ||
6666
| modifier | Modifier | 应用于组件的修饰符 | Modifier ||
67+
| colorSpace | ColorSpace | 选择使用的颜色空间 | ColorSpace.HSV ||
6768

6869
## 单独使用滑块组件
6970

@@ -129,6 +130,24 @@ AlphaSlider(
129130

130131
## 进阶用法
131132

133+
### 颜色空间
134+
135+
ColorPicker 通过 `colorSpace` 支持多种颜色空间:
136+
- `ColorSpace.HSV` — 经典 HSV 滑条(色相、饱和度、明度、透明度)。
137+
- `ColorSpace.OKHSV` — 基于 OkLCH 的感知 HSV 变体,色相步进更均匀。
138+
- `ColorSpace.OKLAB` — OkLab 滑条(亮度 L、a、b、透明度),更符合人眼的感知。
139+
- `ColorSpace.OKLCH` — OkLCH 滑条(亮度 L、色度 C、色相 H、透明度)。为保证 sRGB 色域,色度会在常见范围内进行约束。
140+
141+
示例:使用 OKLCH 颜色空间
142+
143+
```kotlin
144+
ColorPicker(
145+
initialColor = Color(0xFF4CAF50),
146+
onColorChanged = { /* 处理颜色变化 */ },
147+
colorSpace = ColorSpace.OKLCH
148+
)
149+
```
150+
132151
### 在表单中使用
133152

134153
结合其他输入控件,创建颜色选择表单:

example/src/commonMain/kotlin/component/OtherComponent.kt

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ import top.yukonga.miuix.kmp.icon.icons.useful.Like
6464
import top.yukonga.miuix.kmp.theme.MiuixTheme
6565
import top.yukonga.miuix.kmp.utils.PressFeedbackType
6666
import top.yukonga.miuix.kmp.utils.toHsv
67-
import top.yukonga.miuix.kmp.utils.toOkLab
6867
import kotlin.math.round
6968

7069
fun LazyListScope.otherComponent(
@@ -590,16 +589,11 @@ fun LazyListScope.otherComponent(
590589
modifier = Modifier.padding(bottom = 12.dp),
591590
verticalAlignment = Alignment.CenterVertically
592591
) {
593-
val hsv = selectedColor.toHsv()
594592
Text(
595593
text = "HEX: #${selectedColor.toArgb().toHexString(HexFormat.UpperCase)}" +
596594
"\nRGBA: ${(selectedColor.red * 255).toInt()}, " +
597595
"${(selectedColor.green * 255).toInt()}, " +
598596
"${(selectedColor.blue * 255).toInt()}, " +
599-
"${(round(selectedColor.alpha * 100) / 100.0)}" +
600-
"\nHSVA: ${(hsv.h).toInt()}, " +
601-
"${(hsv.s).toInt()}%, " +
602-
"${(hsv.v).toInt()}%, " +
603597
"${(round(selectedColor.alpha * 100) / 100.0)}",
604598
modifier = Modifier.weight(1f)
605599
)
@@ -629,16 +623,11 @@ fun LazyListScope.otherComponent(
629623
modifier = Modifier.padding(bottom = 12.dp),
630624
verticalAlignment = Alignment.CenterVertically
631625
) {
632-
val hsv = selectedColor.toHsv()
633626
Text(
634627
text = "HEX: #${selectedColor.toArgb().toHexString(HexFormat.UpperCase)}" +
635628
"\nRGBA: ${(selectedColor.red * 255).toInt()}, " +
636629
"${(selectedColor.green * 255).toInt()}, " +
637630
"${(selectedColor.blue * 255).toInt()}, " +
638-
"${(round(selectedColor.alpha * 100) / 100.0)}" +
639-
"\nHSVA: ${(hsv.h).toInt()}, " +
640-
"${(hsv.s).toInt()}%, " +
641-
"${(hsv.v).toInt()}%, " +
642631
"${(round(selectedColor.alpha * 100) / 100.0)}",
643632
modifier = Modifier.weight(1f)
644633
)
@@ -653,7 +642,7 @@ fun LazyListScope.otherComponent(
653642
}
654643

655644
item(key = "colorPicker-okLab") {
656-
SmallTitle(text = "ColorPicker (OKLAB)")
645+
SmallTitle(text = "ColorPicker (okLab)")
657646
val miuixColor = MiuixTheme.colorScheme.primary
658647
var selectedColor by remember { mutableStateOf(miuixColor) }
659648

@@ -668,16 +657,11 @@ fun LazyListScope.otherComponent(
668657
modifier = Modifier.padding(bottom = 12.dp),
669658
verticalAlignment = Alignment.CenterVertically
670659
) {
671-
val ok = selectedColor.toOkLab()
672660
Text(
673661
text = "HEX: #${selectedColor.toArgb().toHexString(HexFormat.UpperCase)}" +
674662
"\nRGBA: ${(selectedColor.red * 255).toInt()}, " +
675663
"${(selectedColor.green * 255).toInt()}, " +
676664
"${(selectedColor.blue * 255).toInt()}, " +
677-
"${(round(selectedColor.alpha * 100) / 100.0)}" +
678-
"\nOkLab: ${((ok.l * 1000).toInt() / 1000.0)}, " +
679-
"${((ok.a * 1000).toInt() / 1000.0)}, " +
680-
"${((ok.b * 1000).toInt() / 1000.0)} / " +
681665
"${(round(selectedColor.alpha * 100) / 100.0)}",
682666
modifier = Modifier.weight(1f)
683667
)
@@ -691,6 +675,41 @@ fun LazyListScope.otherComponent(
691675
}
692676
}
693677

678+
item(key = "colorPicker-okLch") {
679+
SmallTitle(text = "ColorPicker (OkLch)")
680+
val miuixColor = MiuixTheme.colorScheme.primary
681+
var selectedColor by remember { mutableStateOf(miuixColor) }
682+
683+
Card(
684+
modifier = Modifier
685+
.fillMaxWidth()
686+
.padding(horizontal = 12.dp)
687+
.padding(bottom = 12.dp),
688+
689+
insideMargin = PaddingValues(16.dp)
690+
) {
691+
Row(
692+
modifier = Modifier.padding(bottom = 12.dp),
693+
verticalAlignment = Alignment.CenterVertically
694+
) {
695+
Text(
696+
text = "HEX: #${selectedColor.toArgb().toHexString(HexFormat.UpperCase)}" +
697+
"\nRGBA: ${(selectedColor.red * 255).toInt()}, " +
698+
"${(selectedColor.green * 255).toInt()}, " +
699+
"${(selectedColor.blue * 255).toInt()}, " +
700+
"${(round(selectedColor.alpha * 100) / 100.0)}",
701+
modifier = Modifier.weight(1f)
702+
)
703+
}
704+
ColorPicker(
705+
initialColor = selectedColor,
706+
onColorChanged = { selectedColor = it },
707+
hapticEffect = SliderDefaults.SliderHapticEffect.Step,
708+
colorSpace = ColorSpace.OKLCH
709+
)
710+
}
711+
}
712+
694713
item(key = "colorPalette") {
695714
SmallTitle(text = "ColorPalette")
696715
val miuixColor = MiuixTheme.colorScheme.primary

iosApp/iosApp/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundleShortVersionString</key>
1818
<string>1.0.5</string>
1919
<key>CFBundleVersion</key>
20-
<string>594</string>
20+
<string>595</string>
2121
<key>LSRequiresIPhoneOS</key>
2222
<true/>
2323
<key>CADisableMinimumFrameDurationOnPhone</key>

0 commit comments

Comments
 (0)