Skip to content

Commit 4c0997e

Browse files
committed
chore: wip
1 parent a4f1a08 commit 4c0997e

42 files changed

Lines changed: 1836 additions & 178 deletions

Some content is hidden

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

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ jobs:
113113
test -f packages/react/dist/index.js
114114
test -f packages/vue/dist/index.js
115115
test -f packages/react-native/dist/index.js
116+
test -f packages/svelte/dist/index.d.ts
117+
test -f packages/solid/dist/index.d.ts
118+
test -f packages/nuxt/dist/index.d.ts
116119
117120
publish-commit:
118121
needs: [lint, typecheck, test]

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ storage
1919
.stx
2020
pantry
2121
packages/ts-maps/bench/reports/*.json
22+
.render-check/

.vscode/settings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
"todo-tree.highlights.enabled": true,
6060
"cSpell.ignorePaths": [
6161
"node_modules",
62-
"packages/ts-maps/src/maps"
62+
"packages/ts-maps/dist",
63+
"pantry"
6364
],
6465
"cSpell.dictionaries": [
6566
"custom-dictionary"
@@ -81,8 +82,7 @@
8182
"**/*.txt"
8283
],
8384
"grammarly.files.exclude": [
84-
"**/dictionary.txt",
85-
"**/maps"
85+
"**/dictionary.txt"
8686
],
8787
"cSpell.words": [
8888
"unconfig"

CLAUDE.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ A zero-dependency, TypeScript-native interactive mapping library. Mapbox-class f
1212

1313
## Frontend
1414

15-
- Use **stx** for templating — never write vanilla JS (`var`, `document.*`, `window.*`) in stx templates
16-
- Use **crosswind** as the default CSS framework which enables standard Tailwind-like utility classes
17-
- stx `<script>` tags should only contain stx-compatible code (signals, composables, directives)
15+
- Framework bindings live under `packages/react`, `packages/vue`,
16+
`packages/svelte`, `packages/solid`, `packages/nuxt`, and
17+
`packages/react-native`. When touching one, keep them in parity:
18+
same component names, same prop shape, same event names.
19+
- `packages/ts-maps/src/core-map/` is the implementation. Everything
20+
else is a thin wrapper; avoid forking logic into bindings.
21+
- Docs are built with `@stacksjs/bunpress`; follow the file layout in
22+
`docs/`.
1823

1924
## Dependencies
2025

ROADMAP.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> _A zero-dependency, TypeScript-native, batteries-included interactive mapping library._
44
> Target: parity with Mapbox GL JS feature set, with a Leaflet-style developer experience.
5-
> Constraints: **no runtime deps**, everything in-house, tooling = bun/pickier/better-dx/stx.
5+
> Constraints: **no runtime deps**, everything in-house, tooling = bun/pickier/better-dx.
66
77
This document is the authoritative execution plan. Each phase is scoped to be
88
independently testable and shippable. Phases are **gated** — do not start a phase
@@ -374,7 +374,8 @@ so nobody is forced into a vendor account.
374374

375375
- **9.7 `MapGeocoderControl`, `MapDirectionsControl`** — drop-in UI
376376

377-
controls matching Mapbox's plugin set, built with stx.
377+
controls matching Mapbox's plugin set, built with vanilla DOM (no
378+
templating dependency).
378379

379380
**Exit:** the playground has search, turn-by-turn, reachable-within-X-min,
380381
all fully functional against OSRM+Nominatim with no API keys.
@@ -404,32 +405,32 @@ all fully functional against OSRM+Nominatim with no API keys.
404405

405406
---
406407

407-
## Phase 11 — Framework integrations (ride the existing packages)
408+
## Phase 11 — Framework integrations
408409

409-
The repo already has `packages/vue` and `packages/react`. Update + add:
410+
All six bindings ship from this repo:
410411

411-
- **11.1 `ts-maps-react`**`<Map>`, `<TileLayer>`, `<Marker>`, `<Source>`,
412-
413-
`<Layer>`, `<Popup>`, hooks (`useMap`, `useMapEvent`).
414-
415-
- **11.2 `ts-maps-vue`** — matching SFC components.
416-
- **11.3 `ts-maps-svelte`** (new).
417-
- **11.4 `ts-maps-solid`** (new).
418-
- **11.5 `ts-maps-nuxt`** module (already scaffolded; wire it).
419-
- **11.6 `ts-maps-stx`** — native components for our own stx templating.
412+
- **11.1 `@ts-maps/react`**`<Map>`, `<TileLayer>`, `<Marker>`,
413+
`<Source>`, `<Layer>`, `<Popup>`, hooks (`useMap`, `useMapEvent`).
414+
- **11.2 `@ts-maps/vue`** — matching SFC components + composables.
415+
- **11.3 `@ts-maps/svelte`**`<Map>` / `<TileLayer>` / `<Marker>` /
416+
`<Popup>` / `<Source>` / `<Layer>` Svelte components.
417+
- **11.4 `@ts-maps/solid`** — Solid JSX components with a
418+
`MapContext` / `useMap` pair.
419+
- **11.5 `ts-maps-nuxt`** — Nuxt 3 module; auto-imports the Vue
420+
bindings with a configurable component prefix.
421+
- **11.6 `@ts-maps/react-native`** — WebView-hosted `<MapView>`
422+
bridged to the full `TsMap` API for native mobile apps.
420423

421424
**Exit:** `npm create ts-maps@latest` scaffolds a demo app in any of the
422-
five frameworks.
425+
six frameworks.
423426

424427
---
425428

426429
## Phase 12 — Docs, site, ecosystem
427430

428-
- **12.1 Docs site.** Built with stx + crosswind. Hosted. API reference
429-
430-
generated from TSDoc (zero-dep custom extractor).
431-
432-
- **12.2 Examples gallery.** ~40 examples matching Mapbox's + Leaflet's.
431+
- **12.1 Docs site.** Built with `@stacksjs/bunpress`; hosted at
432+
`ts-maps.dev`. API reference generated from TSDoc.
433+
- **12.2 Examples gallery.** Runnable demos matching Mapbox's + Leaflet's.
433434
- **12.3 Style playground** (edit style JSON, see the map re-render).
434435
- **12.4 Plugin guide + public plugin registry.**
435436
- **12.5 Migration guides.** From Leaflet, from Mapbox GL JS, from MapLibre.

docs/api/TsMap.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ The root class. An instance owns one DOM container, one camera, one style docume
5757
| `setPaintProperty(id, name, value)` / `setLayoutProperty(id, name, value)` | Update a single property. |
5858
| `setFilter(id, filter)` | Update a layer's filter expression. |
5959

60+
## Feature queries
61+
62+
| Method | Summary |
63+
| ------ | ------- |
64+
| `queryRenderedFeatures(pointOrOpts?, opts?)` | Iterate every vector source on the map and return the features painted at a container-pixel point, bbox, or globally. Results carry `{ feature, layer, tile }`. Options: `{ layers, point, bbox }`. |
65+
| `querySourceFeatures(sourceId, { sourceLayer?, filter? })` | Iterate features in a given vector source across every decoded tile, regardless of whether they're rendered. Respects style-spec filter expressions. |
66+
67+
## Renderer selection
68+
69+
| Method | Summary |
70+
| ------ | ------- |
71+
| `setRenderer('canvas2d' \| 'webgl' \| 'svg')` | Switch the preferred rendering backend for every source-backed host layer on this map. Fires `rendererchange`. |
72+
| `getPreferredRenderer()` | Currently active renderer name. Note: `getRenderer(layer)` is an internal mixin used by vector overlays — don't confuse the two. |
73+
74+
## Static image export
75+
76+
| Method | Summary |
77+
| ------ | ------- |
78+
| `toCanvas()` | Composite the visible map — every nested `<canvas>` and `<img>` — onto a single `HTMLCanvasElement`. Respects `devicePixelRatio`. |
79+
| `toDataURL(type?, quality?)` | Convenience wrapper: `toCanvas().toDataURL(...)`. Forces WebGL tile renderers to repaint first so the readback is correct. |
80+
| `toBlob(type?, quality?)` | Same as above but yields a `Blob`. |
81+
6082
## Layers (OO, legacy-style)
6183

6284
| Method | Summary |

docs/plugins.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Plugins
2+
3+
`ts-maps` is designed so most extension points do not need a plugin
4+
system at all — you can drop in custom layers, custom services,
5+
or custom controls using the same APIs the built-ins use. This page is
6+
an orientation for plugin authors and a pointer to the community
7+
registry.
8+
9+
## Extension surfaces
10+
11+
### Custom layers
12+
13+
Any class that implements the `Layer` contract can be `addTo(map)`'d.
14+
For GPU-rendered overlays on top of the tile panes, prefer
15+
`CustomLayerInterface` — it hooks into the same render loop as the
16+
built-in vector-tile renderer:
17+
18+
```ts
19+
map.addCustomLayer({
20+
id: 'wind',
21+
type: 'custom',
22+
onAdd(map, gl) { /* compile shaders */ },
23+
render(gl, projectionMatrix) { /* draw frame */ },
24+
onRemove(map, gl) { /* release resources */ },
25+
})
26+
```
27+
28+
See [concepts/3d.md](./concepts/3d.md) for the full interface.
29+
30+
### Custom sources
31+
32+
For non-tile data, hook into the style-spec source registry by
33+
calling `map.addSource(id, { type: 'geojson', data: … })` or
34+
`{ type: 'vector', tiles: [...] }`. If you need a bespoke tile format,
35+
extend `GridLayer` or `TileLayer` directly — they handle the pan /
36+
zoom bookkeeping so your plugin only needs a `createTile(coords, done)`.
37+
38+
### Custom services
39+
40+
The `services` interfaces (`GeocoderProvider`, `DirectionsProvider`,
41+
`IsochroneProvider`, `MatrixProvider`) are public:
42+
43+
```ts
44+
import type { GeocoderProvider } from 'ts-maps/services'
45+
46+
class MyProvider implements GeocoderProvider {
47+
name = 'my-provider'
48+
async search(query: string) { /* ... */ }
49+
async reverse(center) { /* ... */ }
50+
}
51+
```
52+
53+
Hand the instance to whichever consumer expects a provider (e.g. your
54+
own geocoder control).
55+
56+
### Custom controls
57+
58+
Any object with `onAdd(map)` / `onRemove(map)` can be passed to
59+
`map.addControl(ctrl, position)`. The four built-in controls
60+
(`ZoomControl`, `ScaleControl`, `AttributionControl`, `LayersControl`)
61+
are reference implementations.
62+
63+
### Custom renderers
64+
65+
The WebGL path is pluggable — `map.setRenderer('webgl' | 'canvas2d' | 'svg')`
66+
picks the backend for style-spec layers. If you want an entirely
67+
different backend, subclass `Renderer` and register it via the same
68+
setter; the map will rewire source hosts on the next paint.
69+
70+
## Publishing a plugin
71+
72+
Plugins are just npm packages. Follow these conventions so they're
73+
discoverable:
74+
75+
- **Name:** `ts-maps-plugin-<name>` (unscoped) or `@<scope>/ts-maps-<name>`.
76+
- **Keywords:** include `ts-maps`, `ts-maps-plugin`, and the relevant
77+
extension surface (`geocoder`, `directions`, `layer`, `control`).
78+
- **Peer:** `"peerDependencies": { "ts-maps": "^0.2.0" }`.
79+
- **Readme:** add a "Requires" section listing any external services
80+
(tile endpoints, API keys, etc.).
81+
82+
## Plugin registry
83+
84+
Plugins that meet the naming convention above auto-surface in the npm
85+
search: <https://www.npmjs.com/search?q=ts-maps-plugin>. A curated list
86+
lives at <https://ts-maps.dev/plugins>.
87+
88+
Submissions welcome — open a PR against `docs/plugins.md` with a short
89+
description and a link to your package.
90+
91+
## Best practices
92+
93+
- **Keep runtime deps to zero** if you can. `ts-maps` core has none;
94+
plugins that inherit that discipline are easier to ship.
95+
- **Declare `ts-maps` as a peer**, not a dependency — otherwise apps
96+
end up with two copies.
97+
- **Use subpath imports** (`ts-maps/style-spec`, `ts-maps/services`, …)
98+
so bundlers only pull in the slice you actually use.
99+
- **Fail soft.** If your plugin wraps a third-party API, handle 4xx /
100+
5xx responses gracefully and surface them as a rejected Promise —
101+
don't throw synchronously from a `render()` callback.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"typecheck": "bunx tsc --noEmit",
5050
"bench:ts-maps": "cd packages/ts-maps && bun run bench",
5151
"playground:core-map": "bun --bun run playground/core-map/serve.ts",
52+
"render:check": "bun --bun scripts/verify-render.ts",
5253
"dev:docs": "bun --bun bunpress dev docs",
5354
"build:docs": "bun --bun bunpress build docs",
5455
"preview:docs": "bun --bun bunpress preview docs"
@@ -67,7 +68,6 @@
6768
},
6869
"workspaces": [
6970
"packages/**",
70-
"playground",
7171
"playground/core-map"
7272
]
7373
}

packages/nuxt/package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@
2525
],
2626
"exports": {
2727
".": {
28+
"types": "./dist/index.d.ts",
29+
"import": "./dist/index.js"
30+
},
31+
"./module": {
2832
"types": "./dist/module.d.ts",
29-
"import": "./dist/module.mjs",
30-
"require": "./dist/module.cjs"
33+
"import": "./dist/module.js"
3134
}
3235
},
33-
"main": "./dist/module.cjs",
34-
"module": "./dist/module.mjs",
35-
"types": "./dist/module.d.ts",
36+
"main": "./dist/index.js",
37+
"module": "./dist/index.js",
38+
"types": "./dist/index.d.ts",
3639
"files": [
3740
"README.md",
3841
"dist",

packages/nuxt/tsconfig.build.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
"extends": "./tsconfig.json",
33
"compilerOptions": {
44
"noEmit": false,
5-
"emitDeclarationOnly": true,
65
"declaration": true,
6+
"emitDeclarationOnly": false,
77
"outDir": "./dist",
8-
"rootDir": "./src"
8+
"rootDir": "./src",
9+
"module": "esnext",
10+
"moduleResolution": "bundler",
11+
"allowImportingTsExtensions": false
912
},
1013
"include": ["src/**/*"],
1114
"exclude": ["src/**/*.test.ts", "dist", "node_modules", "test"]

0 commit comments

Comments
 (0)