Skip to content

Commit 6449b13

Browse files
committed
docs(docs): polish oss readme and recipe demos
1 parent 550ebad commit 6449b13

33 files changed

+1161
-426
lines changed

README.md

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,52 @@
11
# @crup/react-timer-hook
22

3-
> Deterministic React timer primitives for countdowns, stopwatches, clocks, schedules, and many independent timers.
3+
> Reliable React timer hooks for countdowns, stopwatches, clocks, polling schedules, and many independent timer lifecycles.
44
55
[![npm alpha](https://img.shields.io/npm/v/%40crup%2Freact-timer-hook/alpha?label=npm%20alpha&color=00b894)](https://www.npmjs.com/package/@crup/react-timer-hook?activeTab=versions)
66
[![npm downloads](https://img.shields.io/npm/dm/%40crup%2Freact-timer-hook?color=0f766e)](https://www.npmjs.com/package/@crup/react-timer-hook)
77
[![CI](https://github.com/crup/react-timer-hook/actions/workflows/ci.yml/badge.svg)](https://github.com/crup/react-timer-hook/actions/workflows/ci.yml)
88
[![Docs](https://github.com/crup/react-timer-hook/actions/workflows/docs.yml/badge.svg)](https://github.com/crup/react-timer-hook/actions/workflows/docs.yml)
99
[![Size](https://github.com/crup/react-timer-hook/actions/workflows/size.yml/badge.svg)](https://github.com/crup/react-timer-hook/actions/workflows/size.yml)
1010
[![license](https://img.shields.io/npm/l/%40crup%2Freact-timer-hook?color=111827)](./LICENSE)
11-
[![types](https://img.shields.io/npm/types/%40crup%2Freact-timer-hook?color=2563eb)](./dist/index.d.ts)
11+
[![types](https://img.shields.io/npm/types/%40crup%2Freact-timer-hook?color=2563eb)](https://www.npmjs.com/package/@crup/react-timer-hook)
12+
[![React](https://img.shields.io/npm/dependency-version/%40crup%2Freact-timer-hook/peer/react?label=react&color=149eca)](https://react.dev/)
1213

13-
📚 Docs: https://crup.github.io/react-timer-hook/
14+
📚 Docs and live examples: https://crup.github.io/react-timer-hook/
1415

15-
## Docs and live examples
16+
## Why this exists
1617

17-
The documentation site is built with Docusaurus and includes live React playgrounds for 15 recipes:
18+
Timer hooks look simple until real apps need pause/resume semantics, Strict Mode cleanup, async callbacks, polling that does not overlap, and lists with dozens of independent timers.
1819

19-
- Basic: clock, stopwatch, absolute countdown, pausable countdown, manual controls
20-
- Intermediate: once-only `onEnd`, polling, poll-and-cancel, backend events, debug logs
21-
- Advanced: many display timers, timer groups, global controls, per-item polling, dynamic items
20+
`@crup/react-timer-hook` keeps the API small and lets your app decide what time means:
2221

23-
Open: https://crup.github.io/react-timer-hook/
24-
25-
## Why it is different
26-
27-
Most timer libraries mix scheduling, lifecycle, formatting, and app behavior. This package keeps the core small:
28-
29-
- ⏱️ `useTimer()` for one lifecycle.
22+
- ⏱️ `useTimer()` for one lifecycle: stopwatch, countdown, clock, schedule, or custom flow.
3023
- 🧭 `useTimerGroup()` for many keyed lifecycles with one shared scheduler.
31-
- 🧩 `durationParts()` for display-friendly duration math.
32-
- 🧼 No timezone, locale, or formatting opinions.
33-
- 🧪 Built around React Strict Mode, rerenders, async callbacks, and cleanup.
34-
- 🤖 AI-friendly docs via `llms.txt`, `llms-full.txt`, and a tiny local MCP docs utility.
24+
- 🧩 `durationParts()` for display math without locale or timezone opinions.
25+
- 🧼 No formatting, timezone, audio, retry, cache, or data-fetching policy baked in.
26+
- 🧪 Built for rerenders, Strict Mode, async callbacks, cleanup, and many timers.
27+
- 🤖 Agent-friendly docs through hosted `llms.txt`, `llms-full.txt`, and an optional MCP docs helper.
3528

3629
## Install
3730

38-
Alpha is the only intended release channel until stable publishing is explicitly unlocked.
31+
The project is currently in alpha while the API receives feedback.
3932

4033
```sh
4134
npm install @crup/react-timer-hook@alpha
4235
pnpm add @crup/react-timer-hook@alpha
4336
```
4437

45-
```ts
38+
```tsx
4639
import { durationParts, useTimer, useTimerGroup } from '@crup/react-timer-hook';
4740
```
4841

42+
## Live recipes
43+
44+
Each recipe has a live playground and a focused code sample:
45+
46+
- Basic: [wall clock](https://crup.github.io/react-timer-hook/recipes/basic/wall-clock/), [stopwatch](https://crup.github.io/react-timer-hook/recipes/basic/stopwatch/), [absolute countdown](https://crup.github.io/react-timer-hook/recipes/basic/absolute-countdown/), [pausable countdown](https://crup.github.io/react-timer-hook/recipes/basic/pausable-countdown/), [manual controls](https://crup.github.io/react-timer-hook/recipes/basic/manual-controls/)
47+
- Intermediate: [once-only onEnd](https://crup.github.io/react-timer-hook/recipes/intermediate/once-only-on-end/), [polling schedule](https://crup.github.io/react-timer-hook/recipes/intermediate/polling-schedule/), [poll and cancel](https://crup.github.io/react-timer-hook/recipes/intermediate/poll-and-cancel/), [backend event stop](https://crup.github.io/react-timer-hook/recipes/intermediate/backend-event-stop/), [debug logs](https://crup.github.io/react-timer-hook/recipes/intermediate/debug-logs/)
48+
- Advanced: [many display countdowns](https://crup.github.io/react-timer-hook/recipes/advanced/many-display-countdowns/), [timer group](https://crup.github.io/react-timer-hook/recipes/advanced/timer-group/), [group controls](https://crup.github.io/react-timer-hook/recipes/advanced/group-controls/), [per-item polling](https://crup.github.io/react-timer-hook/recipes/advanced/per-item-polling/), [dynamic items](https://crup.github.io/react-timer-hook/recipes/advanced/dynamic-items/)
49+
4950
## Quick examples
5051

5152
### Stopwatch
@@ -58,17 +59,17 @@ export function Stopwatch() {
5859

5960
return (
6061
<>
61-
<output>{Math.floor(timer.elapsedMilliseconds / 1000)}s</output>
62-
<button onClick={timer.start}>Start</button>
63-
<button onClick={timer.pause}>Pause</button>
64-
<button onClick={timer.resume}>Resume</button>
62+
<output>{(timer.elapsedMilliseconds / 1000).toFixed(1)}s</output>
63+
<button disabled={!timer.isIdle} onClick={timer.start}>Start</button>
64+
<button disabled={!timer.isRunning} onClick={timer.pause}>Pause</button>
65+
<button disabled={!timer.isPaused} onClick={timer.resume}>Resume</button>
6566
<button onClick={timer.restart}>Restart</button>
6667
</>
6768
);
6869
}
6970
```
7071

71-
### Absolute countdown
72+
### Auction countdown
7273

7374
Use `now` for wall-clock deadlines from a server, auction, reservation, or job expiry.
7475

@@ -93,7 +94,7 @@ export function AuctionTimer({ auctionId, expiresAt }: {
9394
}
9495
```
9596

96-
### Polling with early cancel
97+
### Poll and cancel early
9798

9899
Schedules run while the timer is active. Slow async work is skipped by default with `overlap: 'skip'`.
99100

@@ -134,29 +135,24 @@ const timers = useTimerGroup({
134135

135136
## Bundle size
136137

137-
Current local build:
138+
Current build:
138139

139140
| File | Raw | Gzip | Brotli |
140141
| --- | ---: | ---: | ---: |
141142
| `dist/index.js` | 11.82 kB | 3.55 kB | 3.20 kB |
142143
| `dist/index.cjs` | 12.94 kB | 3.79 kB | 3.42 kB |
143144
| `dist/index.d.ts` | 3.95 kB | 992 B | 888 B |
144145

145-
CI writes a size summary to the GitHub Actions UI and posts a bundle-size comment on pull requests.
146+
CI writes a size summary to the GitHub Actions UI and posts bundle-size reports on pull requests.
146147

147-
## AI-friendly
148+
## AI-friendly docs
148149

149-
End users do not need these files. They are for coding agents, docs-aware IDEs, and MCP clients.
150+
Agents and docs-aware IDEs can use:
150151

151-
### MCP setup
152+
- https://crup.github.io/react-timer-hook/llms.txt
153+
- https://crup.github.io/react-timer-hook/llms-full.txt
152154

153-
Clone the repo, install dependencies, and point your MCP client at the local stdio server:
154-
155-
```sh
156-
git clone https://github.com/crup/react-timer-hook.git
157-
cd react-timer-hook
158-
pnpm install
159-
```
155+
Optional local MCP docs server:
160156

161157
```json
162158
{
@@ -169,37 +165,20 @@ pnpm install
169165
}
170166
```
171167

172-
The MCP server exposes:
168+
It exposes:
173169

174170
```txt
175171
react-timer-hook://package
176172
react-timer-hook://api
177173
react-timer-hook://recipes
178174
```
179175

180-
Agents can use hosted context:
181-
182-
- https://crup.github.io/react-timer-hook/llms.txt
183-
- https://crup.github.io/react-timer-hook/llms-full.txt
184-
185-
Local MCP/docs helpers:
186-
187-
```sh
188-
pnpm ai:context
189-
pnpm mcp:docs
190-
```
191-
192-
The MCP utility is repo-local and excluded from the published npm package.
193-
194-
## Release policy
176+
## Contributing
195177

196-
- Published versions must stay `0.0.1-alpha.x` until stable release is explicitly unlocked.
197-
- `@alpha` is the documented install tag right now.
198-
- Npm requires a `latest` dist-tag, so the workflow keeps `latest` pointing at the current alpha until stable publishing is unlocked.
178+
Issues, recipes, docs improvements, and focused bug reports are welcome.
199179

200-
## Links
180+
- Read the docs: https://crup.github.io/react-timer-hook/
181+
- Open an issue: https://github.com/crup/react-timer-hook/issues
182+
- See the contributing guide: ./CONTRIBUTING.md
201183

202-
- 📚 Docs: https://crup.github.io/react-timer-hook/
203-
- 📦 npm: https://www.npmjs.com/package/@crup/react-timer-hook
204-
- 🧵 Issues: https://github.com/crup/react-timer-hook/issues
205-
- 🤝 Contributing: ./CONTRIBUTING.md
184+
The package targets Node 24 for development and React 18+ as a peer dependency.

docs-site/docs/ai.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ Verify locally:
6262
printf '{"jsonrpc":"2.0","id":1,"method":"resources/list"}\n' | pnpm mcp:docs
6363
```
6464

65-
The MCP utility is repo-local and excluded from the npm package.
65+
The npm package stays runtime-focused. AI context and MCP helpers live in the source repository for contributors and coding agents.

docs-site/docs/api/use-timer.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: useTimer
3-
description: API reference for a single deterministic timer lifecycle.
3+
description: API reference for one reliable timer lifecycle.
44
---
55

66
# useTimer

docs-site/docs/index.mdx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
2-
title: Deterministic React timers
2+
title: Reliable React timers
33
slug: /
44
description: React timer primitives for countdowns, stopwatches, clocks, polling schedules, and many independent timer lifecycles.
55
---
66

77
import RecipePlayground from '@site/src/components/RecipePlayground';
88
import { StopwatchSample, AbsoluteCountdownSample, TimerGroupSample } from '../samples/recipes';
99

10-
# Deterministic React timers
10+
# Reliable React timers
1111

1212
`@crup/react-timer-hook` gives React apps a small timer lifecycle primitive instead of a formatting-heavy timer component.
1313

14-
It is built for rerenders, Strict Mode, async callbacks, cleanup, and lists of timers.
14+
It is built for Strict Mode, rerenders, async callbacks, cleanup, and pages with many independent timers.
1515

1616
```sh
1717
npm install @crup/react-timer-hook@alpha
@@ -39,3 +39,11 @@ pnpm add @crup/react-timer-hook@alpha
3939
- `durationParts()` for duration display math
4040

4141
The library owns scheduling and cleanup. Your app owns formatting, timezone, data fetching policy, and business rules.
42+
43+
## Recipe routes
44+
45+
- [Wall clock](./recipes/basic/wall-clock)
46+
- [Stopwatch](./recipes/basic/stopwatch)
47+
- [Auction countdown](./recipes/basic/absolute-countdown)
48+
- [Polling schedule](./recipes/intermediate/polling-schedule)
49+
- [Timer group](./recipes/advanced/timer-group)

docs-site/docs/recipes/advanced.mdx

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: Dynamic items
3+
description: Add and remove timer group items at runtime.
4+
---
5+
6+
import RecipePlayground from '@site/src/components/RecipePlayground';
7+
import { DynamicItemsSample } from '../../../samples/recipes';
8+
9+
# Dynamic items
10+
11+
Use group methods when timer IDs are not known at render time.
12+
13+
<RecipePlayground title="Dynamic timer items">
14+
<DynamicItemsSample />
15+
</RecipePlayground>
16+
17+
```tsx
18+
timers.add({ id, autoStart: true });
19+
timers.remove(id);
20+
timers.clear();
21+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: Group controls
3+
description: Pause, resume, and restart a whole timer group.
4+
---
5+
6+
import RecipePlayground from '@site/src/components/RecipePlayground';
7+
import { GroupControlsSample } from '../../../samples/recipes';
8+
9+
# Group controls
10+
11+
Group-level controls are useful for dashboards, task boards, and global page actions.
12+
13+
<RecipePlayground title="Group controls">
14+
<GroupControlsSample />
15+
</RecipePlayground>
16+
17+
```tsx
18+
timers.pauseAll();
19+
timers.resumeAll();
20+
timers.restartAll();
21+
```
22+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: Advanced recipes
3+
description: Many timers, independent group lifecycles, item polling, and runtime item changes.
4+
---
5+
6+
# Advanced recipes
7+
8+
Use these patterns for lists, dashboards, auctions, reservation holds, jobs, and task boards.
9+
10+
- [Many display countdowns](./many-display-countdowns)
11+
- [Timer group](./timer-group)
12+
- [Group controls](./group-controls)
13+
- [Per-item polling](./per-item-polling)
14+
- [Dynamic items](./dynamic-items)
15+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: Many display countdowns
3+
description: Drive many display-only rows from one shared timer.
4+
---
5+
6+
import RecipePlayground from '@site/src/components/RecipePlayground';
7+
import { ManyDisplayCountdownsSample } from '../../../samples/recipes';
8+
9+
# Many display countdowns
10+
11+
Use one shared `useTimer()` when rows only need countdown labels.
12+
13+
<RecipePlayground title="Many display-only countdowns">
14+
<ManyDisplayCountdownsSample />
15+
</RecipePlayground>
16+
17+
```tsx
18+
const clock = useTimer({ autoStart: true, updateIntervalMs: 1000 });
19+
const remainingMs = Math.max(0, item.expiresAt - clock.now);
20+
```
21+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
title: Per-item polling
3+
description: Give each group item its own schedule.
4+
---
5+
6+
import RecipePlayground from '@site/src/components/RecipePlayground';
7+
import { PerItemPollingSample } from '../../../samples/recipes';
8+
9+
# Per-item polling
10+
11+
Each item can define schedules with different cadence and callbacks.
12+
13+
<RecipePlayground title="Per-item polling">
14+
<PerItemPollingSample />
15+
</RecipePlayground>
16+
17+
```tsx
18+
items: jobs.map(job => ({
19+
id: job.id,
20+
autoStart: true,
21+
schedules: [{ id: 'status', everyMs: job.pollMs, callback: refresh }],
22+
}))
23+
```
24+

0 commit comments

Comments
 (0)