Skip to content

Commit db64cc9

Browse files
authored
Merge pull request #2 from MohamedRejeb/feature/sample-rework
feat(sample): rebuild the sample as a trip planner, fix auto-scroll and glow
2 parents 6f0d302 + fa49bdb commit db64cc9

116 files changed

Lines changed: 5199 additions & 3160 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ node_modules/
2121
plans
2222
CLAUDE.md
2323
kotlin-js-store
24+
.superpowers

‎README.md‎

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,126 +2,134 @@
22

33
**Product tours and feature showcases for Compose Multiplatform.**
44

5-
[![Kotlin](https://img.shields.io/badge/kotlin-2.3.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
6-
[![Compose](https://img.shields.io/badge/compose-1.10.3-blue.svg?logo=jetpackcompose)](https://www.jetbrains.com/lp/compose-multiplatform)
5+
[![Kotlin](https://img.shields.io/badge/kotlin-2.4.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
6+
[![Compose](https://img.shields.io/badge/compose-1.12.1-blue.svg?logo=jetpackcompose)](https://www.jetbrains.com/lp/compose-multiplatform)
77
[![MohamedRejeb](https://raw.githubusercontent.com/MohamedRejeb/MohamedRejeb/main/badges/mohamedrejeb.svg)](https://github.com/MohamedRejeb)
88
[![Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0)
99
[![Maven Central](https://img.shields.io/maven-central/v/com.mohamedrejeb.waypoint/waypoint-core)](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22)
1010

11-
Waypoint is a Compose Multiplatform library for building guided product tours, onboarding flows, feature discovery, and persistent contextual hints. It ships a spotlight overlay, tooltip positioning with auto-flip, pluggable highlight styles, and a state machine for step navigation, all from a simple declarative DSL.
11+
<p align="center">
12+
<img src="docs/assets/tour.gif" width="260" alt="A spotlight tour moving between targets, then switching to dark theme" />
13+
<img src="docs/assets/hands-on.gif" width="260" alt="A hands-on step where the user types inside the highlighted field" />
14+
<img src="docs/assets/sheet.gif" width="260" alt="A tour scrolling a list and following the user into a bottom sheet" />
15+
</p>
1216

13-
Targets **Android**, **iOS**, **Desktop (JVM)**, and **Web (JS, Wasm)**.
17+
Waypoint walks your users through your app: it dims the screen, cuts a hole around the thing you want them to look at, and puts a tooltip next to it. You describe the steps in a small DSL, tag your composables with a modifier, and the library handles positioning, animation, scrolling and input blocking.
1418

15-
## Artifacts
19+
It runs on **Android**, **iOS**, **Desktop** and **Web** (JS and Wasm) from the same code.
1620

17-
| Artifact | Description | Platforms | Version |
18-
|----------|-------------|-----------|---------|
19-
| **waypoint-core** | State machine, overlay, tooltip positioning, target registration | Android, iOS, Desktop, Web (JS, Wasm) | [![Maven Central](https://img.shields.io/maven-central/v/com.mohamedrejeb.waypoint/waypoint-core)](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22%20AND%20a:%22waypoint-core%22) |
20-
| **waypoint-material3** | Material3-styled tooltip with navigation buttons and progress | Android, iOS, Desktop, Web (JS, Wasm) | [![Maven Central](https://img.shields.io/maven-central/v/com.mohamedrejeb.waypoint/waypoint-material3)](https://search.maven.org/search?q=g:%22com.mohamedrejeb.waypoint%22%20AND%20a:%22waypoint-material3%22) |
21+
## What it does
2122

22-
Pick `waypoint-core` alone for full control over the tooltip UI, or `waypoint-material3` for a ready-to-use Material3 experience. `waypoint-material3` depends on `waypoint-core` transitively.
23-
24-
## Features
25-
26-
- **Spotlight overlay** with pluggable cutout shapes (Circle, Rect, RoundedRect, Pill)
27-
- **Highlight styles**: Spotlight, Pulse, Border, Ripple, None, or fully Custom, configurable per step
28-
- **Spotlight effects**: Glow, SoftEdge, and custom draw lambdas decorate the cutout
29-
- **Tooltip positioning** with auto-flip and screen-edge clamping
30-
- **Step navigation**: `next`, `previous`, `goTo`, `stop`, `pause`, `resume`
31-
- **Conditional steps** (`showIf`) and lifecycle callbacks (`onEnter`/`onExit`)
32-
- **Interactive tutorials**: the user types and taps inside the highlighted element (`PassThrough`) while the rest of the screen is blocked
33-
- **Event-driven progression** (`advanceOn`) and async gates (`beforeShow`)
34-
- **Steps without a target**, shown as a centered card for intros and outros
35-
- **Multi-element highlight**: one tooltip, multiple targets
36-
- **Cross-hierarchy tours**: targets inside Dialog, Sheet, and Popup via `WaypointOverlayHost`
37-
- **Persistent hints**: ambient beacons that live outside of tours
38-
- **Tour sequences**: chain multiple tours with shared persistence
39-
- **Beacons** (pulse or dot) as standalone attention indicators
40-
- **Auto-scroll** targets into view through nested scroll containers
41-
- **Keyboard navigation** (arrow keys, Enter, Escape) on Desktop and Web
42-
- **Analytics**, **persistence**, **theming**, **accessibility** (live-region + RTL) built in
43-
- Survives **configuration changes** via `rememberSaveable`
23+
- **Tours**: spotlight, pulse, border or ripple highlights, with a tooltip that flips and clamps to stay on screen.
24+
- **Hands-on steps**: let the user type or tap inside the highlighted element while the rest of the screen is blocked, and move on when they have done it (`advanceOn`).
25+
- **Works where your UI is**: targets in scrolling lists are scrolled into view, and a tour can follow the user into a dialog or bottom sheet.
26+
- **Steps that wait**: hold a step until data has loaded or a screen has opened (`beforeShow`), skip steps that do not apply (`showIf`).
27+
- **Beyond tours**: persistent hints and beacons for the "new feature" dot that stays until dismissed.
28+
- **Your design or ours**: a Material3 tooltip out of the box, or draw your own with `waypoint-core`, which has no design opinions.
29+
- **The boring parts**: keyboard navigation, screen reader announcements, RTL, show-once persistence, analytics hooks, and state that survives configuration changes.
4430

4531
## Installation
4632

47-
Add the dependency to your module `build.gradle.kts`:
48-
4933
```kotlin
5034
kotlin {
5135
sourceSets {
5236
commonMain.dependencies {
53-
// Material3 tooltip (recommended)
37+
// Material3 tooltip, includes waypoint-core
5438
implementation("com.mohamedrejeb.waypoint:waypoint-material3:0.1.0")
5539

56-
// OR: core only, for custom tooltips
40+
// or core only, if you draw your own tooltip
5741
implementation("com.mohamedrejeb.waypoint:waypoint-core:0.1.0")
5842
}
5943
}
6044
}
6145
```
6246

63-
See [installation](docs/installation.md) for the version compatibility table and snapshots.
47+
Built with Kotlin 2.4.20 and Compose Multiplatform 1.12.1. See [installation](https://mohamedrejeb.github.io/compose-waypoint/installation/) for requirements and snapshots.
6448

65-
## Quick example
49+
## Quick start
50+
51+
Three things: describe the steps, tag the targets, wrap the screen in a host.
6652

6753
```kotlin
68-
enum class OnboardingTarget { SearchBar, AddButton, Profile }
54+
enum class Onboarding { Search, Add, Profile }
6955

7056
@Composable
7157
fun HomeScreen() {
72-
val tourState = rememberWaypointState {
73-
step(OnboardingTarget.SearchBar) {
58+
// 1. Describe the steps
59+
val tour = rememberWaypointState {
60+
step(Onboarding.Search) {
7461
title = "Search"
7562
description = "Find anything in your workspace."
7663
}
77-
step(OnboardingTarget.AddButton) {
64+
step(Onboarding.Add) {
7865
title = "Create"
7966
description = "Add a new item with one tap."
8067
}
81-
step(OnboardingTarget.Profile) {
68+
step(Onboarding.Profile) {
8269
title = "Your profile"
8370
description = "View and edit your account."
8471
}
8572
}
8673

87-
WaypointMaterial3Host(state = tourState) {
74+
// 3. Wrap the screen in a host
75+
WaypointMaterial3Host(state = tour) {
8876
Column {
89-
SearchBar(
90-
modifier = Modifier.waypointTarget(tourState, OnboardingTarget.SearchBar),
91-
)
92-
FloatingActionButton(
93-
onClick = { /* ... */ },
94-
modifier = Modifier.waypointTarget(tourState, OnboardingTarget.AddButton),
95-
) { Icon(Icons.Default.Add, "Add") }
96-
IconButton(
97-
onClick = { /* ... */ },
98-
modifier = Modifier.waypointTarget(tourState, OnboardingTarget.Profile),
99-
) { Icon(Icons.Default.Person, "Profile") }
77+
// 2. Tag the targets
78+
SearchBar(Modifier.waypointTarget(tour, Onboarding.Search))
79+
AddButton(Modifier.waypointTarget(tour, Onboarding.Add))
80+
ProfileButton(Modifier.waypointTarget(tour, Onboarding.Profile))
10081
}
10182
}
10283

103-
LaunchedEffect(Unit) { tourState.start() }
84+
LaunchedEffect(Unit) { tour.start() }
85+
}
86+
```
87+
88+
To turn a step into something the user does instead of something they read:
89+
90+
```kotlin
91+
step(Onboarding.Search) {
92+
title = "Try a search"
93+
description = "Type something to continue."
94+
interaction = TargetInteraction.PassThrough
95+
advanceOn { snapshotFlow { query }.first { it.isNotEmpty() } }
10496
}
10597
```
10698

99+
## Make it yours
100+
101+
<img src="docs/assets/styles.gif" width="260" align="right" alt="One tour restyled live: spotlight, glow, pulse, border and ripple" />
102+
103+
The highlight is set for the whole tour or per step:
104+
105+
```kotlin
106+
WaypointMaterial3Host(
107+
state = tour,
108+
highlightStyle = HighlightStyle.Spotlight(
109+
shape = SpotlightShape.Circle,
110+
effect = SpotlightEffect.Glow(),
111+
),
112+
) { /* ... */ }
113+
```
114+
115+
Colors, typography and dimensions of the Material3 tooltip come from `WaypointMaterial3Theme`. If that is not enough, pass your own composable as `tooltipContent` and draw whatever you like.
116+
117+
<br clear="right" />
118+
107119
## Documentation
108120

109-
- [Overview](docs/index.md)
110-
- [Installation](docs/installation.md)
111-
- [Quick Start](docs/getting-started.md)
112-
- [Highlight Styles](docs/guides/highlight-styles.md)
113-
- [Custom Tooltips](docs/guides/custom-tooltips.md)
114-
- [Interactive Tutorials](docs/guides/interactive-tutorials.md)
115-
- [Tour Sequences](docs/guides/tour-sequences.md)
116-
- [Persistent Hints](docs/guides/hints.md)
117-
- [Theming](docs/guides/theming.md)
118-
- [Analytics](docs/guides/analytics.md)
119-
- [Persistence](docs/guides/persistence.md)
120-
- [API Reference](docs/api/waypoint-state.md)
121+
The full docs are at **[mohamedrejeb.github.io/compose-waypoint](https://mohamedrejeb.github.io/compose-waypoint/)**. Good places to start:
122+
123+
- [Quick Start](https://mohamedrejeb.github.io/compose-waypoint/getting-started/)
124+
- [Highlight Styles](https://mohamedrejeb.github.io/compose-waypoint/guides/highlight-styles/)
125+
- [Interactive Tutorials](https://mohamedrejeb.github.io/compose-waypoint/guides/interactive-tutorials/)
126+
- [Tours in dialogs and sheets](https://mohamedrejeb.github.io/compose-waypoint/guides/multi-host/)
127+
- [Custom Tooltips](https://mohamedrejeb.github.io/compose-waypoint/guides/custom-tooltips/)
128+
- [Hints](https://mohamedrejeb.github.io/compose-waypoint/guides/hints/) and [Beacons](https://mohamedrejeb.github.io/compose-waypoint/guides/beacons/)
121129

122130
## Sample
123131

124-
The `:sample` module contains seven focused demos, runnable on all targets:
132+
The recordings above come from the `:sample` module, a small trip planner whose onboarding is three chained tours, plus a Lab screen for trying every highlight and tooltip option live. It runs on all targets:
125133

126134
```bash
127135
# Desktop

‎convention-plugins/src/main/kotlin/Android.kt‎

Lines changed: 0 additions & 33 deletions
This file was deleted.

‎convention-plugins/src/main/kotlin/Targets.kt‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
22

33
@Suppress("OPT_IN_USAGE")
44
fun KotlinMultiplatformExtension.applyTargets() {
5-
androidTarget {
6-
publishLibraryVariants("release")
7-
}
8-
95
jvm()
106

117
js {
@@ -18,11 +14,15 @@ fun KotlinMultiplatformExtension.applyTargets() {
1814
enabled = false
1915
}
2016
}
17+
// Compose UI tests need the webpack bundle to load Skiko, and the
18+
// Compose plugin fails the build without a declared executable.
19+
binaries.executable()
2120
}
2221

2322
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
2423
wasmJs {
2524
browser()
25+
binaries.executable()
2626
}
2727

2828
iosArm64()

‎convention-plugins/src/main/kotlin/android.library.gradle.kts‎

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
1+
import org.gradle.accessors.dm.LibrariesForLibs
12
import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
23

34
plugins {
45
id("org.jetbrains.kotlin.multiplatform")
5-
id("android.library")
6+
id("com.android.kotlin.multiplatform.library")
67
}
78

9+
val libs = the<LibrariesForLibs>()
10+
811
kotlin {
912
explicitApi()
1013
applyHierarchyTemplate()
1114
applyTargets()
1215

16+
// No host tests are declared for Android on purpose: commonTest holds Compose
17+
// UI tests, which cannot run on the local Android unit-test JVM. The same
18+
// suite runs on the jvm target.
19+
android {
20+
namespace = group.toString() + path.replace("-", "").split(":").joinToString(".")
21+
compileSdk = libs.versions.android.compileSdk.get().toInt()
22+
minSdk = libs.versions.android.minSdk.get().toInt()
23+
}
24+
1325
// Public API baseline in `api/`. `checkKotlinAbi` runs as part of `check`,
1426
// `updateKotlinAbi` re-records the dump after an intended API change.
1527
@OptIn(ExperimentalAbiValidation::class)
16-
abiValidation {
17-
enabled.set(true)
18-
}
28+
abiValidation()
1929
}
2030

2131
setJvmTarget()

‎docs/assets/effect-glow.png‎

38 KB
Loading

‎docs/assets/hands-on.gif‎

439 KB
Loading

‎docs/assets/sheet.gif‎

578 KB
Loading

‎docs/assets/style-border.png‎

30.8 KB
Loading

0 commit comments

Comments
 (0)