Skip to content

Commit c18a391

Browse files
committed
docs: polish README, add CONTRIBUTING and CoC, TypeDoc config, generate API docs, docs workflow; move tests/
1 parent 3a7fcab commit c18a391

19 files changed

Lines changed: 702 additions & 29 deletions

.github/workflows/docs.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Docs
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'src/**'
8+
- 'typedoc.json'
9+
- 'package.json'
10+
11+
jobs:
12+
build-docs:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 20
19+
cache: 'pnpm'
20+
- uses: pnpm/action-setup@v4
21+
with:
22+
version: 10
23+
- run: pnpm install --frozen-lockfile=false
24+
- run: pnpm docs:build
25+
- uses: actions/upload-pages-artifact@v3
26+
with:
27+
path: docs/api
28+
deploy:
29+
needs: build-docs
30+
permissions:
31+
pages: write
32+
id-token: write
33+
environment:
34+
name: github-pages
35+
url: ${{ steps.deployment.outputs.page_url }}
36+
runs-on: ubuntu-latest
37+
steps:
38+
- id: deployment
39+
uses: actions/deploy-pages@v4
40+
41+

CODE_OF_CONDUCT.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Code of Conduct
2+
3+
We are committed to a welcoming and inclusive community. Be respectful.
4+
5+
- Be kind and patient.
6+
- Be considerate.
7+
- Be respectful of differing viewpoints and experiences.
8+
- Gracefully accept constructive criticism.
9+
- Focus on what is best for the community.
10+
11+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting the maintainers.

CONTRIBUTING.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Contributing
2+
3+
Thanks for your interest in contributing!
4+
5+
## Development setup
6+
7+
```bash
8+
pnpm install
9+
pnpm test
10+
pnpm dev # build in watch via tsup
11+
```
12+
13+
- Tests: Vitest + jsdom in `tests/`
14+
- Lint/format: `pnpm lint` / `pnpm format`
15+
- Type-check: `pnpm typecheck`
16+
17+
## Commit and release
18+
19+
- Conventional commits are appreciated (e.g., `feat:`, `fix:`)
20+
- Use Changesets for versioning:
21+
- `pnpm changeset` to add a changeset
22+
- `pnpm version-packages` to bump versions
23+
- `pnpm publish-packages` to publish
24+
25+
## Pull requests
26+
27+
- Include tests for changes
28+
- Update docs/README when API changes
29+
- Keep diffs focused and small when possible
30+
31+
## Code style
32+
33+
- TypeScript strict, avoid `any`
34+
- Prefer explicit names and early returns
35+
36+
## Getting help
37+
38+
Open an issue if you’re unsure about an approach before investing time.

README.md

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
# use-query-state
22

3-
A tiny React hook for typed URL query string state.
3+
Tiny, typed React URL query state. Co-locate state with your components and keep it in sync with the URL for shareable, deep‑linkable UIs.
4+
5+
[![npm version](https://img.shields.io/npm/v/use-query-state.svg)](https://www.npmjs.com/package/use-query-state)
6+
[![CI](https://github.com/gawryco/use-query-state/actions/workflows/ci.yml/badge.svg)](https://github.com/gawryco/use-query-state/actions/workflows/ci.yml)
7+
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8+
9+
## Features
10+
11+
- Typed builders: number, string, boolean, date, enum, json, custom
12+
- One-liner setup per key; React‑style setters with URL sync
13+
- Back/forward navigation support via `popstate`
14+
- Tiny API, framework‑agnostic URL handling, SSR‑safe guards
15+
- ESM+CJS builds with type declarations
416

517
## Install
618

@@ -12,32 +24,87 @@ npm i use-query-state
1224
yarn add use-query-state
1325
```
1426

15-
## Usage
27+
Peer dependency: `react >= 17`.
28+
29+
## Quick start
1630

1731
```tsx
1832
import { useQueryState } from 'use-query-state';
1933

20-
export function Example() {
21-
const [page, setPage] = useQueryState<number>('page', {
22-
parse: (v) => (v ? Number(v) : undefined),
23-
serialize: (v) => (v == null ? null : String(v)),
24-
defaultValue: 1,
25-
history: 'push',
26-
});
27-
28-
return (
29-
<button onClick={() => setPage((p) => (p ?? 1) + 1)}>Page: {page}</button>
30-
);
34+
export function Counter() {
35+
const [n, setN] = useQueryState('n').number(0);
36+
return <button onClick={() => setN((v) => v + 1)}>Count: {n}</button>;
3137
}
3238
```
3339

34-
## API
40+
- Initializes from `?n=...` if present; otherwise seeds the URL with the default.
41+
- Calling the setter updates both state and the URL.
42+
43+
## API overview
44+
45+
`useQueryState(key)` returns a set of builder methods. Each returns `[value, setValue]`.
46+
47+
- `number(defaultValue, opts?)`
48+
- `opts`: `{ min?: number; max?: number; step?: number }`
49+
- `string(defaultValue, opts?)`
50+
- `opts`: `{ minLength?: number; maxLength?: number }`
51+
- `boolean(defaultValue)`
52+
- Stored as `'1' | '0'` and accepts common truthy/falsy strings
53+
- `date(defaultValue, opts?)`
54+
- Format `yyyy-MM-dd` (UTC); `{ min?: Date; max?: Date }`
55+
- `enum(allowed, defaultValue)`
56+
- `allowed: readonly string[]`
57+
- `json(defaultValue, opts?)`
58+
- `opts`: `{ validate?, omitEmpty?, stringify?, parse? }`
59+
- `custom(defaultValue, parse, format)`
60+
- Bring your own parsing/formatting logic
61+
62+
See full JSDoc/API in `docs/`.
63+
64+
## Examples
65+
66+
```tsx
67+
// String
68+
const [q, setQ] = useQueryState('q').string('');
69+
70+
// Boolean
71+
const [open, setOpen] = useQueryState('open').boolean(false);
72+
73+
// Date (UTC yyyy-MM-dd)
74+
const [start, setStart] = useQueryState('start').date(new Date('2024-01-01'));
75+
76+
// Enum
77+
type Theme = 'light' | 'dark';
78+
const [t, setT] = useQueryState('t').enum<Theme>(['light', 'dark'], 'light');
79+
80+
// JSON with omitEmpty
81+
const [filters, setFilters] = useQueryState('f').json({ q: '' }, {
82+
omitEmpty: (v) => v.q === '',
83+
});
84+
```
85+
86+
## SSR and environments
87+
88+
The hook guards access to `window`/`document`. During SSR it returns the default value and no URL edits occur until hydration.
89+
90+
## Navigation and events
91+
92+
- Listens for `popstate` and re-parses the URL to update state.
93+
- Dispatches a `CustomEvent` named `qs:changed` on `window` with `{ key, prev, next, params, source, ts }` for diagnostics.
94+
95+
## Type safety
96+
97+
The builders are typed. For advanced types use `custom` or `json` with a type guard.
98+
99+
## Docs
100+
101+
- API docs: `docs/api/` (generated from JSDoc)
102+
- Overview: `docs/README.md`
103+
104+
## Contributing
35105

36-
- `useQueryState(key, options)` returns `[value, setValue]`.
37-
- `options.parse` and `options.serialize` let you adapt non-string types.
38-
- `options.history`: `'replace' | 'push'` (default `'replace'`).
39-
- `options.defaultValue`: used when param is absent.
106+
See [CONTRIBUTING.md](CONTRIBUTING.md). Please note our [Code of Conduct](CODE_OF_CONDUCT.md).
40107

41108
## License
42109

43-
MIT
110+
MIT — Copyright (c) 2025 Gawry & Co

docs/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# use-query-state Docs
2+
3+
This folder contains the documentation for use-query-state.
4+
5+
- Overview: see the project README for a high-level introduction.
6+
- API: generated from JSDoc into `docs/api/`.
7+
8+
## Local development
9+
10+
- Update code comments (JSDoc) in `src/`.
11+
- Regenerate docs with the scripts in `package.json`.

docs/api/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
**use-query-state**
2+
3+
***
4+
5+
# use-query-state
6+
7+
## Functions
8+
9+
- [useQueryState](functions/useQueryState.md)

0 commit comments

Comments
 (0)