Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/audio/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const App: Component = () => {
<div class="flex flex-col items-center">
<div class="flex items-center justify-center space-x-4 rounded-full bg-white p-1 shadow">
<button
class="scale-200 flex cursor-pointer border-none bg-transparent"
class="flex scale-200 cursor-pointer border-none bg-transparent"
disabled={audio.state == AudioState.ERROR}
onClick={() => setPlaying(audio.state == AudioState.PLAYING ? false : true)}
>
Expand All @@ -97,7 +97,7 @@ const App: Component = () => {
step="0.1"
max={audio.duration}
value={audio.currentTime}
class="form-range w-40 cursor-pointer appearance-none rounded-3xl bg-gray-200 transition hover:bg-gray-300 focus:outline-none focus:ring-0"
class="form-range w-40 cursor-pointer appearance-none rounded-3xl bg-gray-200 transition hover:bg-gray-300 focus:ring-0 focus:outline-none"
/>
<div class="flex px-2">
<Icon class="w-6 text-blue-600" path={speakerWave} />
Expand Down
13 changes: 13 additions & 0 deletions packages/geolocation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# @solid-primitives/geolocation

## 2.0.0

### Major Changes

- Updated to Solid.js 2.0 API and full primitive redesign:
- Added `makeGeolocation(options?)` — non-reactive one-shot query returning `[query, cleanup]` tuple, no Solid owner required
- Added `makeGeolocationWatcher(options?)` — non-reactive continuous watcher returning `[store, cleanup]` tuple, no Solid owner required
- `createGeolocation` now returns `[Accessor<GeolocationCoordinates>, refetch]` — async memo that suspends with `<Suspense>`, re-queries when reactive `options` change or `refetch()` is called. Supports `isPending()` for background re-query indicators
- `createGeolocationWatcher` now returns `{ location: Accessor<GeolocationCoordinates>, error: Accessor<GeolocationPositionError | null> }` — `location` suspends until the first GPS fix then updates reactively; `error` is a signal for recoverable in-component error handling
- Replaced `createResource` with async `createMemo` + version signal
- Replaced `createComputed` with `createEffect`
- Updated peer dependency to `solid-js@^2.0.0`

## 1.5.4

### Patch Changes
Expand Down
116 changes: 88 additions & 28 deletions packages/geolocation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,60 +20,122 @@ yarn add @solid-primitives/geolocation

## How to use it

### createGeolocation
### `makeGeolocation`

Used to fetch current geolocation data as a resource. This primitive uses `createResource` to return a location, so `loading`, `error`
A non-reactive one-shot query. No Solid owner required — can be used outside components. Returns a `[query, cleanup]` tuple.

```ts
const [location, refetch] = createGeolocation();
const [query, cleanup] = makeGeolocation({ enableHighAccuracy: true });
const coords = await query();
cleanup();
```

or with options:
#### Definition

```ts
const [location, refetch] = createGeolocation({
enableHighAccuracy: false,
maximumAge: 0,
timeout: 200,
});
makeGeolocation(
options?: PositionOptions
): [query: () => Promise<GeolocationCoordinates>, cleanup: VoidFunction]
```

---

### `makeGeolocationWatcher`

A non-reactive continuous watcher. No Solid owner required. Returns a `[store, cleanup]` tuple.

```ts
const [store, cleanup] = makeGeolocationWatcher();
console.log(store.location); // GeolocationCoordinates | null
console.log(store.error); // GeolocationPositionError | null
cleanup();
```

#### Definition

```ts
createGeolocation(
options: MaybeAccessor<PositionOptions> // these override basic defaults (see Types section)
makeGeolocationWatcher(
options?: PositionOptions
): [
location: Resource<GeolocationCoordinates | undefined>,
refetch: Accessor<void>
store: { location: GeolocationCoordinates | null; error: GeolocationPositionError | null },
cleanup: VoidFunction
]
```

### createGeolocationWatcher
---

### `createGeolocation`

A reactive one-shot query. Returns an async accessor that integrates with `<Suspense>` / `<Loading>` boundaries — the component subtree suspends until the position resolves. Re-queries automatically when reactive `options` change, or manually via `refetch()`.

```ts
const [location, refetch] = createGeolocation();
```

```tsx
// Suspends until first fix:
<Suspense fallback="Locating...">
<div>{location().latitude}, {location().longitude}</div>
</Suspense>

Creates a geolocation watcher and updates a signal with the latest coordinates. This primitive returns two reactive getters: `location` and `error`.
// Show a subtle indicator while re-querying in the background:
<Show when={isPending(() => location())}>Updating position...</Show>
```

With reactive options:

```ts
const [opts, setOpts] = createSignal<PositionOptions>({ enableHighAccuracy: false });
const [location, refetch] = createGeolocation(opts);
// Automatically re-queries when opts() changes
```

#### Definition

```ts
createGeolocation(
options?: MaybeAccessor<PositionOptions>
): [location: Accessor<GeolocationCoordinates>, refetch: VoidFunction]
```

---

### `createGeolocationWatcher`

A reactive continuous watcher. `location` suspends until the first GPS fix, then updates reactively without re-suspending. `error` is a signal accessor for recoverable in-component error handling. The watcher starts and stops reactively based on `enabled`.

```ts
const watcher = createGeolocationWatcher(true);
console.log(watcher.location);
console.log(watcher.error);
const [enabled, setEnabled] = createSignal(true);
const { location, error } = createGeolocationWatcher(enabled);
```

```tsx
// Show error inline (recoverable — no error boundary needed):
<Show when={error()}>
Permission denied — <button onClick={retry}>retry</button>
</Show>

// Suspends until first GPS fix, then updates live:
<Suspense fallback="Acquiring GPS fix...">
<Map lat={location().latitude} lng={location().longitude} />
</Suspense>
```

#### Definition

```ts
createGeolocationWatcher(
enabled: MaybeAccessor<boolean>,
options: MaybeAccessor<PositionOptions>
options?: MaybeAccessor<PositionOptions>
): {
location: GeolocationCoordinates | null,
error: GeolocationPositionError | null
location: Accessor<GeolocationCoordinates>;
error: Accessor<GeolocationPositionError | null>;
}
```

#### Types
---

The values returned in the location property are as follows:
## Types

```ts
interface GeolocationCoordinates {
Expand All @@ -87,7 +149,7 @@ interface GeolocationCoordinates {
}
```

The options property defaults to the following value unless overwritten:
Default position options (overridden by anything you pass):

```ts
const geolocationDefaults: PositionOptions = {
Expand All @@ -103,10 +165,8 @@ You may view a working example here: https://stackblitz.com/edit/vitejs-vite-dvk

## Primitive Ideas

We're always looking to enhance our primitives. Some ideas:

- `createDistance` (supply a lat/lng and reactively calculate the difference in km/m)
- `createWithinRadius` (a signal for tracking if a user is within a radius boundary)
- `createDistance` — supply a lat/lng and reactively calculate the distance in km/m
- `createWithinRadius` — a signal for tracking if a user is within a radius boundary

## Changelog

Expand Down
50 changes: 30 additions & 20 deletions packages/geolocation/dev/client.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,65 @@
import { type Component, createEffect, onMount, Show } from "solid-js";
import { createGeolocation } from "../src/index.js";
import { type Component, Suspense, Show, createEffect, onMount } from "solid-js";
import { createGeolocationWatcher } from "../src/index.js";

import * as L from "leaflet";

import "leaflet/dist/leaflet.css";

const Client: Component = () => {
let ref: HTMLDivElement;
let ref!: HTMLDivElement;
let map: L.Map;
let marker: L.Marker;
const [location] = createGeolocation({
let marker: L.Marker | undefined;

const { location, error } = createGeolocationWatcher(true, {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Number.POSITIVE_INFINITY,
});

onMount(() => {
map = L.map(ref).setView([37.0643592, -26.1593362], 1);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19,
attribution: "© OpenStreetMap",
}).addTo(map);
});

createEffect(() => {
const coordinates = location();
if (map && coordinates && !location.error) {
const latLng: L.LatLngExpression = [coordinates.latitude, coordinates.longitude];
const coords = location();
if (map && coords) {
const latLng: L.LatLngExpression = [coords.latitude, coords.longitude];
marker?.remove();
map.setView(latLng, 14);
marker = L.marker(latLng).addTo(map);
}
});

return (
<div class="box-border flex h-screen w-full items-center justify-center overflow-hidden bg-gray-900">
<div class="flex flex-col items-center">
<div class="flex flex-col items-center justify-center overflow-hidden rounded-lg bg-white/30 p-0 text-white shadow-lg">
<Show
fallback={<div class="p-4">Could not detect coordinates, check permissions.</div>}
when={!location.error}
>
<div class="flex flex-row">
fallback={
<div class="p-4">
<b>Accuracy</b>: {(location()?.accuracy || 0).toFixed(2)}
Could not detect coordinates: {error()?.message ?? "unknown error"}
</div>
}
when={!error()}
>
<Suspense fallback={<div class="p-4">Acquiring GPS fix...</div>}>
<div class="flex flex-row">
<div class="p-4">
<b>Accuracy</b>: {(location().accuracy ?? 0).toFixed(2)}
</div>
<div class="p-4">
<b>Altitude</b>: {(location().altitude ?? 0).toFixed(2)}
</div>
</div>
<div class="p-4">
<b>Altitude</b>: {(location()?.altitude || 0).toFixed(2)}
{location().latitude}, {location().longitude}
</div>
</div>
</Suspense>
</Show>
<div class="w-100 h-100" ref={el => (ref = el)} />
<div class="p-4">
{location()?.latitude}, {location()?.longitude}
</div>
<div class="h-100 w-100" ref={el => (ref = el)} />
</div>
</div>
</div>
Expand Down
8 changes: 5 additions & 3 deletions packages/geolocation/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solid-primitives/geolocation",
"version": "1.5.4",
"version": "2.0.0",
"description": "Primitives to query geolocation and observe changes.",
"author": "David Di Biase <dave@solidjs.com>",
"license": "MIT",
Expand All @@ -13,6 +13,8 @@
"name": "geolocation",
"stage": 3,
"list": [
"makeGeolocation",
"makeGeolocationWatcher",
"createGeolocation",
"createGeolocationWatcher"
],
Expand Down Expand Up @@ -50,14 +52,14 @@
"devDependencies": {
"@types/leaflet": "^1.9.8",
"leaflet": "^1.9.4",
"solid-js": "^1.9.7"
"solid-js": "^2.0.0-beta.6"
},
"dependencies": {
"@solid-primitives/static-store": "workspace:^",
"@solid-primitives/utils": "workspace:^"
},
"peerDependencies": {
"solid-js": "^1.6.12"
"solid-js": "^2.0.0-beta.6"
},
"typesVersions": {}
}
Loading
Loading