Skip to content

Settle the public API before 2.0.0 - #369

Merged
smelfungus merged 18 commits into
masterfrom
api-freeze
Sep 28, 2026
Merged

smelfungus merged 18 commits into
masterfrom
api-freeze

Conversation

@smelfungus

@smelfungus smelfungus commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

API that the 2.0.0 tag would otherwise freeze.

Defects, each with a test that fails on master:

  • ColorPickerTheme inherits what it is not given. ColorPickerTheme(dimensions = …) also fixed the colors and shapes of the MaterialTheme around it, so a MaterialTheme nested inside, such as a dark card, no longer reached the pickers under it.
  • The default slider thumb is drawn at the slider's thumb width. A wider thumbWidth opened a wide gap in the track around the 4 dp bar. Each Material slider composes its thumb with its own dimensions in force.

Contracts:

  • ColorPickerState is read and written on the main thread. Its KDoc allowed reads from any thread, but the hue memory behind displayValue is a plain map a write extends.
  • ColorPickerState.Saver says what restores as the initial value: an unknown space, components the space now refuses, or another format, 1.x's included. A space redefined under its old id reads the old components as new ones.

Surface:

  • Every set of options is an enum: PlaneRendering and EdgeSolver were abstract classes with an object per option, and ColoringMode, Exactness, AnalogousCategory, HexAlpha and CssSyntax stay enums. An app can keep an enum in rememberSaveable, where Android cannot save a class; an option added later waits for a major release.
  • Constructing a ColorChannel, a ChannelKind.Hue or a new HueFamily needs ExperimentalColorSpaceApi, as subclassing ColorSpace already did.
  • RgbGamut.peakLuminance is gone. It was always 1.0 and nothing read it.
  • DisabledAlpha and DisabledSaturation are plain vals, and ColorPickerDefaults.dimensions() is not composable.
  • ColorSlider and ColorPlane take enabled before onValueChangeFinished, which is () -> Unit = {} on every slider, plane and picker, and BasicColorPickerDialogContent takes its picker last.
  • SliderLabel and SliderValueLabel are ColorPickerDefaults.SliderLabel and SliderValueLabel, with a modifier.
  • ColoringMode is in codes.side.colorpicker.foundation, and ColorPickerDialogState in codes.side.colorpicker.state.
  • The fifteen ColorPickerState.set(view) functions are gone; state.value = x and state[channel] = x cover every write.

CONTRIBUTING gains an API conventions section recording these choices, and CHANGELOG and the README migration table cover what a 1.x user sees.

Module JVM Android host wasm
color 242 229 229
color-compose 14 14 14
colorpicker-foundation 311 155 155
colorpicker-material3 177 4 4

apiCheck, checkNoMaterial, scripts/check-api-removals.sh, the 30 screenshot baselines and the Android, desktop and web samples pass.

Its parameters defaulted to the values in force where it was called, so ColorPickerTheme(dimensions = ...) also fixed the colors and shapes of the MaterialTheme at that spot, and a MaterialTheme nested inside, such as a dark card, no longer reached the pickers under it. A parameter left null now passes on the enclosing value, or none, and each component resolves the default where it reads it.
ColorPickerDefaults.SliderThumb always drew at the 4 dp constant, so a wider thumbWidth, from a slider's dimensions or the theme, opened a wide gap in the track around a thin bar. It now takes its width from the dimensions in force, and each Material slider composes its thumb with its own dimensions in force, as the plane's default thumb already takes its diameter.
Its KDoc allowed reads from any thread, but the hue memory behind displayValue keeps the spaces it has seen in a plain map that a write on the main thread extends, so a read elsewhere can meet it half changed. Another thread takes the immutable value instead.
A const is copied into every caller when it compiles, so a library built on this one would keep 0.38 after a later release changed it, and the value could never come from the theme. As a val it is read where it is used.
It was composable though it reads no theme, only its own constants, so dimensions could not be kept in a top-level val or built in a view model. colors() and shapes() read MaterialTheme and stay composable.
A state saved before an app update can meet a space that was renamed, removed or redefined, and the saver's KDoc covered only the space that is not found. It now names every case that starts again from the initial value, and the one that does not: a space redefined under its old id reads the old components as new ones.
It was always 1.0 and nothing read it, so it promised an HDR parameter the library does not have, and once released it would bind whatever HDR design comes later to its name and meaning.
As enums, a grade or category added later would break every caller's exhaustive when, and crash one already compiled when it met the new value. Both can grow: Exactness has no grade yet for a profile-based space, and AnalogousCategory follows a CSS table that a later level may extend. HexAlpha and CssSyntax stay enums, since alpha has no fourth position in a hex string and CSS has no third syntax.
Subclassing ColorSpace already needs ExperimentalColorSpaceApi, but the parts a subclass describes itself with could be built freely, so adding a parameter to the ColorChannel constructor, or changing what a HueFamily id means, would have been a break. The factories and HueFamily's own families need no opt-in; ColorSpace.polar over a family of the app's own does.
ColorSlider and ColorPlane took onValueChangeFinished before enabled and as a nullable callback, like the basic slider and plane under them, while the channel and alpha sliders, the channel plane and every picker take enabled first and default the callback to {}. One order and one form means an argument moves between them unchanged.
The picker is the content BasicColorPickerDialogContent lays out, but it came second, before the optional parameters, so it could not be passed as a trailing lambda.
SliderLabel and SliderValueLabel were top-level functions without a modifier, the only visible components in the library to lack one, and apart from the default thumbs they sit beside in every slot a caller replaces.
Each was state.value = view.value under another name, one per space, so every space added later would have needed another. They came in as the writing half of the typed views; state.value = x and state[channel] = x now cover every write, and the views stay for reading.
…tates

ColoringMode, a display option only sliders read, sat in codes.side.colorpicker.state beside ColorPickerState, while ColorPickerDialogState, a state, sat in codes.side.colorpicker.foundation among the components. Each now lives with its kind.
The KDoc said the display, but Okhsl is fitted to sRGB, which a Display P3 screen exceeds, and it strays out of sRGB just past pure blue, as README already says.
ColoringMode is the one set of options an app is likely to keep in saved UI state, as the sample does with rememberSaveable { mutableStateOf(mode) }. Android saves an enum there and cannot save a class, so the class form the other growable sets take would crash such an app on rotation, where an enum added to later only breaks a when at compile time. It stays an enum, and a coloring added later waits for a major release.

CONTRIBUTING gains the list of API conventions this and the neighbouring changes settled, so a later type, parameter or constant is decided the same way.
Sets of options stay enums, as ColoringMode does: an app can keep an enum in saved UI state, which Android cannot do with a class, and an option added later waits for a major release instead. This reverts 5aa781b, and the API conventions in CONTRIBUTING state the rule for every such set.
They were the last sets of options written as abstract classes with an object per option, where every other set in the library is an enum, as the API conventions in CONTRIBUTING require. Callers write PlaneRendering.Fast and EdgeSolver.Iterative as before, and toString still gives the option's name.
@smelfungus
smelfungus merged commit b80f774 into master Sep 28, 2026
2 checks passed
@smelfungus
smelfungus deleted the api-freeze branch September 28, 2026 04:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant