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 KotlinTestCommons helpers (
assertMinimumTouchTarget,ThemedComposeRule,advanceFrames, wait helpers) for repeated Compose test code;:testingkeeps only design-system-specific helpers (see ADR 0008).
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
Published API compatibility¶
:<module>:binaryCompatibilityCheck compares each Android library's release AAR
against API_BASELINE_VERSION from Maven Central. Its baseline guard checks the
persisted AAR so the comparison still runs when the download is up to date or the
configuration cache is reused. An unpublished baseline (HTTP 404) is logged and
skipped; report that as unverified compatibility.
Compiler-generated classes containing $$inlined$ are excluded because their names
can change after internal edits without changing the library API. Public nested
classes and public component methods remain checked. Reports are written to
<module>/build/reports/binary-compatibility/japicmp.txt.
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.