Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,20 @@ jobs:
run: ./gradlew :colorpicker-material3:linkDebugFrameworkIosSimulatorArm64
- name: Run iOS simulator tests
run: ./gradlew :colorpicker-foundation:iosSimulatorArm64Test :colorpicker-material3:iosSimulatorArm64Test :color:iosSimulatorArm64Test :color-compose:iosSimulatorArm64Test
# A release is the first time publish.yml runs, and what it uploads to Maven Central cannot be replaced.
# Publishing locally builds the same publications here, where only macOS builds all six of each module:
# the POMs, the sources and the Dokka javadoc jars. Nothing is signed without the key.
- name: Publish every module locally
run: ./gradlew publishToMavenLocal
- name: Check each module published its six targets
run: |
VERSION="$(sed -n 's/^VERSION_NAME=//p' gradle.properties)"
for module in color color-compose colorpicker-foundation colorpicker-material3; do
for suffix in "" -android -jvm -wasm-js -iosarm64 -iossimulatorarm64; do
pom="$HOME/.m2/repository/codes/side/$module$suffix/$VERSION/$module$suffix-$VERSION.pom"
if [ ! -f "$pom" ]; then
echo "::error::$module$suffix $VERSION was not published"
exit 1
fi
done
done
8 changes: 8 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ jobs:
permissions:
contents: write
steps:
# A release goes out from its tag, which the step below checks against VERSION_NAME. Run by hand from a
# branch with snapshot unticked, this workflow would otherwise release whatever VERSION_NAME says, with no
# tag and no GitHub Release.
- name: Refuse a release from anything but a tag
if: inputs.snapshot != true && !startsWith(github.ref, 'refs/tags/v')
run: |
echo "::error::A release runs from a v* tag, and $GITHUB_REF is not one. Tick snapshot, or push the tag."
exit 1
- uses: actions/checkout@v7
with:
# The API removal check reads the dumps at the last release tag.
Expand Down
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
- **`codes.side:colorpicker` stops at 1.2.1.** 2.0 is `codes.side:colorpicker-material3`, which brings `codes.side:colorpicker-foundation`: the state, the `Basic*` components and the strings, with no Material dependency, for an app on another design system.
- **The Material components, `ColorPickerTheme`, `ColorPickerDefaults` and the theme classes are in `codes.side.colorpicker.material3`,** one package as `androidx.compose.material3` is, where 1.x had `codes.side.colorpicker.ui` and `codes.side.colorpicker.theme`.
- **A color is a `ColorValue`.** The `model`, `conversion` and `util` packages are gone: `HslColor`, `RgbColor`, `CmykColor`, `LabColor`, `OklabColor`, `OklchColor`, `OkhslColor`, `OkhsvColor`, `PickerColor`, their conversions and hex functions, and `randomHslColor`. A `ColorValue` is a color in one of fifteen spaces, in CSS's units, so HSL's saturation and lightness run 0–100 rather than 0–1.
- **`ColorPickerState` holds a `ColorValue`.** It is built from a `ColorValue` or a Compose `Color`, with no default. `state.value`, `state[channel]` and fifteen typed views (`state.hsl`, `state.okLch`, …) replace the eight typed getters, `pickerColor` and `argbInt`, and `state[channel] = x` and `state.set(view)` replace the thirty `update…` functions. Writing NaN or a value outside a channel's limit throws where 1.x ignored or clamped it.
- **`ColorPickerState` holds a `ColorValue`.** It is built from a `ColorValue` or a Compose `Color`, with no default. `state.value`, `state[channel]` and fifteen typed views (`state.hsl`, `state.oklch`, …) replace the eight typed getters, `pickerColor` and `argbInt`, and `state[channel] = x` and `state.set(view)` replace the thirty `update…` functions. Writing NaN or a value outside a channel's limit throws where 1.x ignored or clamped it.
- **The 21 channel sliders and the three planes are gone.** `ChannelSlider(state, channel)` and `ChannelPlane(state, x, y)` take any channel of any space.
- **The pickers' value forms are fully controlled.** They take a `ColorValue` or a Compose `Color` in place of 1.x's color classes. A change reaches the callback in the same event, and the picker draws only what the caller passes back, where 1.x applied the caller's value when the gesture ended.
- **A picker's slots are `plane`, `channelSlider` and `alphaSlider`,** in place of one slot per slider. The plane's is handed its axes as well as the state, and `null` leaves the plane or alpha out, in place of `showAlpha = false`, on the pickers and the dialog alike.
- **A picker's slots are `plane`, `channelSlider` and `alphaSlider`,** in place of one slot per slider. Each is handed a part, `PlanePart`, `ChannelSliderPart` or `AlphaSliderPart`, holding the state and the plane's axes or the slider's channel, and `null` leaves the plane or alpha out, in place of `showAlpha = false`, on the pickers and the dialog alike.
- **`ColorPickerDialog` takes a `ColorValue` or a Compose `Color`, and switches between `spaces`,** Okhsl, OkLCh, HSV and RGB by default, where 1.x's was fixed to HSL. `onDismiss` is `onDismissRequest`, as Material's dialogs name it, and the title and buttons are slots in place of `title`, `confirmText` and `dismissText`.
- **State saved by 1.x is not restored.** It starts again from its initial value.
- **Numbers follow the device's locale.** Values and spoken descriptions read `40 %` in French, `%40` in Turkish and `٤٠٪` in Egyptian Arabic, where 1.x wrote `40%` with a `.` separator everywhere.
Expand All @@ -38,7 +38,7 @@
- **`LocalPlaneRendering`** chooses how planes are built: `PlaneRendering.Fast`, the default, or `PlaneRendering.Canonical`, the reference it is tested against.
- **`codes.side:color-compose`,** `ColorValue.toComposeColor()` and `Color.toColorValue()`. A Compose color in Display P3 or another of Compose's RGB spaces keeps its space.
- **`ColorPicker(state, space)`,** a picker for any space: a plane when the space has one hue and two other channels, a slider for each channel, and alpha.
- **Five more named pickers,** `HsvColorPicker`, `HwbColorPicker`, `LchColorPicker`, `OklabColorPicker` and `OkLchColorPicker`, beside the six 1.x had. Each comes over a `ColorPickerState`, a `ColorValue` and a Compose `Color`.
- **Five more named pickers,** `HsvColorPicker`, `HwbColorPicker`, `LchColorPicker`, `OklabColorPicker` and `OklchColorPicker`, beside the six 1.x had. Each comes over a `ColorPickerState`, a `ColorValue` and a Compose `Color`.
- **`ChannelSlider` and `ChannelPlane`.** Arrow keys and screen readers step by each channel's own unit: a degree on a hue, 1/255 on an RGB channel, 0.001 on OkLCh chroma. A value past the end of a track, such as OkLCh chroma 0.5, pins the thumb while the label keeps its true number.
- **`AlphaSlider` takes `onValueChangeFinished`.**
- **`ColorPickerState.Saver(knownSpaces)`,** for saving a state wherever Compose takes a `Saver`. It and `rememberSaveableColorPickerState(…, knownSpaces)` restore a value in a space the app defines.
Expand All @@ -52,7 +52,8 @@
- **`BasicColorPlane` and `BasicChannelPlane`,** the planes with no look and no size of their own. The `thumb` slot reads the position, and on a channel plane the channels and the opaque color under it, from `ColorPlaneScope` and `ChannelPlaneScope`.
- **`BasicColorPicker`,** over a state, a `ColorValue` or a Compose `Color`, laying out whatever plane, channel sliders and alpha slider it is given, stacked or side by side (`orientation`), with `null` leaving the plane or alpha out.
- **`ColorPickerDefaults.SliderThumb` and `ColorPickerDefaults.PlaneThumb`,** the default slider and plane thumbs, for a `thumb` slot that draws them beside something of its own.
- **`ColorPickerDefaults.plane()`, `channelSlider()` and `alphaSlider()`,** the slots a picker draws by default, for a slot that wraps one.
- **`ColorPickerDefaults.Plane(part)`,** the plane a picker draws unless given another, for a plane slot that wraps it.
- **A replaced part inherits the picker's settings.** A library slider or plane in a slot takes the picker's `thumb`, `coloringMode` and `enabled`, and reports to its `onValueChangeFinished` as well as to its own, without the slot forwarding any of them. `ColoringMode.current(channel)` is the coloring a slider takes there.
- **`orientation` and `dimensions` on every picker.** `Orientation.Horizontal` puts the plane beside the sliders.
- **`LocalColorPickerEnabled`,** false inside a disabled `BasicColorPicker`: for a label or frame of your own, outside every slot's scope, that should look disabled with the picker.
- **`rememberCheckerboardBrush(light, dark)`,** the checkerboard `Modifier.checkerboard` draws, as a `Brush` for a shape of your own.
Expand Down
Loading
Loading