Contributing¶
Local Setup¶
Use JDK 17 and the checked-in Gradle wrapper.
./gradlew check
Install docs dependencies before editing MkDocs content:
python -m pip install -r requirements-docs.txt
mkdocs build --strict
Component Changes¶
- Use
AppThemetokens instead of hardcoded colors or rawdpliterals in:components. - Put reusable pure-Kotlin helpers in
:foundationand keep that module free of Android or Compose dependencies. - Keep APIs state-hoisted and slot-based.
- Add or update light/dark previews, 200% font-scale previews, tests, docs, and screenshot coverage for visible changes.
- Check accessibility: 48dp touch targets, meaningful icon descriptions, readable state text, and 200% font scale behavior.
- Prefer
:testinghelpers for repeated Compose accessibility assertions.
Reuse shared helpers and utilities before reinventing them¶
Before writing a new component or modifier, reuse the shared building blocks the repo already owns. New components should be assembled from these rather than re-inlining the same boilerplate:
Interaction modifiers (:compose-utils) — for tappable, Role.Button surfaces:
- Modifier.minimumTouchTarget(size), Modifier.minimumTouchTargetHeight(height), Modifier.minimumTouchTargetWidth(width) — the accessibility touch-target primitives.
- Modifier.buttonRole(onClick, minimumTouchTarget) — clickable(role = Role.Button) + minimum touch target in one chain. Use for single-action surfaces (pills, links, tappable rows, buttons).
- Modifier.selectableRole(selected, onClick, minimumTouchTarget) — selectable(role = Role.Button) + minimum touch target for single-choice options (filter chips, selectable rows).
- Prefer the minimumTouchTargetSize()/standardIconSize()/containerCornerRadius() metrics helpers in :components (ComponentMetrics.kt) for the canonical values.
Theme-coupled component building blocks (:components, package-internal):
- Modifier.pillSurface(containerColor, border = false) — the capsule/pill fill+clip (+ optional outline border) shared by chips, pills, badges, and compact indicators. Use it instead of repeating .clip(AppTheme.shapes.pill).background(...).
- RowScope.ListPrimaryTextBlock(...) — the title+secondary+supporting merged-semantics text block for list rows. Use it so headline/supporting layout and the single-focus-stop TalkBack behavior stay consistent.
Sample browser scaffolding (:sample):
- SamplePage(preview = { … }, controls = { … }) — the standard demo-page skeleton (live preview, divider, controls panel). Every new component demo must be a SamplePage; use the ControlSwitch/ControlSegmented/ControlSlider control helpers for its controls.
When adding a shared helper, follow the module-boundary rules from ADR 0002: theme-agnostic Modifier/utility helpers belong in :compose-utils; anything that reads AppTheme belongs in :components. Keep cross-module helpers public and documented with KDoc. Keep implementation helpers that are shared only within :components package-internal and document non-obvious behavior so later components reuse them instead of drifting.
Verification¶
Run the focused task for your change first, then the full verification before opening a PR:
./gradlew ktlintCheck detekt check :components:recordRoborazziDebug :catalog:assembleDebug :sample:assembleDebug :baselineprofile:assembleDebug
mkdocs build --strict
Releases¶
Releases are automated after CI succeeds on main, with tags matching X.Y.Z (no v prefix).
- Use Conventional Commit PR titles such as
fix:,feat:, andfeat!:so the workflow can compute the correct version bump. - The release workflow creates the tag, publishes to Maven Central, and creates the GitHub Release automatically.
- After a release, update
VERSION_NAMEandAPI_BASELINE_VERSIONingradle.propertiesonmainto match the released version. - Do not commit signing keys or Maven credentials; configure them as repository secrets.