@barefootjs/client 0.15.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/query-href.d.ts +39 -0
- package/dist/query-href.d.ts.map +1 -0
- package/dist/reactive.d.ts +8 -19
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +42 -4
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +18 -2
- package/dist/runtime/standalone.js +58 -4
- package/package.json +2 -2
- package/src/index.ts +8 -4
- package/src/query-href.ts +50 -0
- package/src/reactive.ts +96 -18
- package/src/runtime/index.ts +8 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export { createSignal, createEffect, createDisposableEffect, createMemo, createRoot, onCleanup, onMount, untrack, batch, setProfilerSink, beginTurn, endTurn, __bfReportOutput,
|
|
1
|
+
export { createSignal, createEffect, createDisposableEffect, createMemo, createRoot, onCleanup, onMount, untrack, batch, setProfilerSink, beginTurn, endTurn, __bfReportOutput, createSearchParams, type SearchParamsInit, __bfSetServerEnvReader, type Reactive, type Signal, type Memo, type CleanupFn, type EffectFn, type ProfilerEventSink, type SubscriberKind, } from '@barefootjs/client/reactive';
|
|
2
2
|
export { createRecordingSink, type ProfilerEvent, type ProfilerEventType, type RecordingSink, } from './profiler-events.ts';
|
|
3
3
|
export { splitProps } from './split-props.ts';
|
|
4
4
|
export { __slot, type SlotMarker } from './slot.ts';
|
|
5
5
|
export { forwardProps } from './forward-props.ts';
|
|
6
6
|
export { unwrap } from './unwrap.ts';
|
|
7
|
+
export { queryHref, type QueryParams, type QueryParamValue } from './query-href.ts';
|
|
7
8
|
export { createContext, type Context } from './context.ts';
|
|
8
9
|
export { useContext, provideContext, createPortal, isSSRPortal, findSiblingSlot, cleanupPortalPlaceholder, type Portal, type PortalChildren, type PortalOptions, type Renderable, } from './shims.ts';
|
|
9
10
|
export { Async, Region, type AsyncProps, type RegionProps, } from './builtins.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,eAAe,EACf,SAAS,EACT,OAAO,EACP,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,eAAe,EACf,SAAS,EACT,OAAO,EACP,gBAAgB,EAMhB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EACL,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEnF,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAE1D,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAA;AAKnB,OAAO,EACL,KAAK,EACL,MAAM,EACN,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
beginTurn,
|
|
14
14
|
endTurn,
|
|
15
15
|
__bfReportOutput,
|
|
16
|
-
|
|
16
|
+
createSearchParams,
|
|
17
17
|
__bfSetServerEnvReader
|
|
18
18
|
} from "@barefootjs/client/reactive";
|
|
19
19
|
|
|
@@ -146,6 +146,21 @@ function forwardProps(source, overrides, excludeKeys) {
|
|
|
146
146
|
function unwrap(prop) {
|
|
147
147
|
return typeof prop === "function" ? prop() : prop;
|
|
148
148
|
}
|
|
149
|
+
// src/query-href.ts
|
|
150
|
+
function queryHref(base, params) {
|
|
151
|
+
const u = new URLSearchParams;
|
|
152
|
+
for (const [key, value] of Object.entries(params)) {
|
|
153
|
+
if (Array.isArray(value)) {
|
|
154
|
+
for (const member of value)
|
|
155
|
+
if (member)
|
|
156
|
+
u.append(key, member);
|
|
157
|
+
} else if (value) {
|
|
158
|
+
u.set(key, value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const qs = u.toString();
|
|
162
|
+
return qs ? `${base}?${qs}` : base;
|
|
163
|
+
}
|
|
149
164
|
// src/context.ts
|
|
150
165
|
function createContext(defaultValue) {
|
|
151
166
|
return {
|
|
@@ -194,7 +209,7 @@ export {
|
|
|
194
209
|
untrack,
|
|
195
210
|
splitProps,
|
|
196
211
|
setProfilerSink,
|
|
197
|
-
|
|
212
|
+
queryHref,
|
|
198
213
|
provideContext,
|
|
199
214
|
onMount,
|
|
200
215
|
onCleanup,
|
|
@@ -203,6 +218,7 @@ export {
|
|
|
203
218
|
findSiblingSlot,
|
|
204
219
|
endTurn,
|
|
205
220
|
createSignal,
|
|
221
|
+
createSearchParams,
|
|
206
222
|
createRoot,
|
|
207
223
|
createRecordingSink,
|
|
208
224
|
createPortal,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `queryHref` — build a URL from a base path plus query params, omitting falsy
|
|
3
|
+
* values. The functional counterpart to `searchParams()` (the reactive *reader*):
|
|
4
|
+
* instead of imperatively mutating a `URLSearchParams`, pass a params object.
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const href = queryHref(base, {
|
|
8
|
+
* sort: sort !== 'date' ? sort : undefined, // conditional include via the value
|
|
9
|
+
* tag, // included only when truthy
|
|
10
|
+
* })
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Each entry is included iff its value is a **non-empty string** — `''` /
|
|
14
|
+
* `undefined` / `null` are omitted — so a conditional include folds into the
|
|
15
|
+
* value as `cond ? value : undefined`. Returns the bare `base` when no params
|
|
16
|
+
* survive. Values are encoded with `URLSearchParams` (form-encoding, spaces →
|
|
17
|
+
* `+`).
|
|
18
|
+
*
|
|
19
|
+
* A value may also be a **`string[]`**, which appends one entry per non-empty
|
|
20
|
+
* member (`{ tag: ['a', 'b'] }` → `?tag=a&tag=b`), i.e. `URLSearchParams.append`
|
|
21
|
+
* rather than `set`. Empty / falsy members are skipped (same truthy-omit as a
|
|
22
|
+
* scalar), so an empty array — or one whose members are all empty — contributes
|
|
23
|
+
* nothing.
|
|
24
|
+
*
|
|
25
|
+
* Values are **strings** (`QueryParamValue`). Number / boolean aren't accepted:
|
|
26
|
+
* JS truthiness would omit `0` / `false`, which the SSR adapters' string guard
|
|
27
|
+
* can't model without per-value type info — so keeping values string-only
|
|
28
|
+
* guarantees the server-rendered URL matches this client output byte-for-byte.
|
|
29
|
+
* Stringify other types at the call site (`String(n)`), choosing the omit rule
|
|
30
|
+
* explicitly (`n > 0 ? String(n) : undefined`).
|
|
31
|
+
*
|
|
32
|
+
* This is a pure function with no reactivity. The SSR adapters lower a
|
|
33
|
+
* `queryHref(base, { … })` call to their query helper (go-template: `bf_query`),
|
|
34
|
+
* which is why the params object must be a plain object literal at the call site.
|
|
35
|
+
*/
|
|
36
|
+
export type QueryParamValue = string | string[] | null | undefined;
|
|
37
|
+
export type QueryParams = Record<string, QueryParamValue>;
|
|
38
|
+
export declare function queryHref(base: string, params: QueryParams): string;
|
|
39
|
+
//# sourceMappingURL=query-href.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-href.d.ts","sourceRoot":"","sources":["../src/query-href.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAA;AAClE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;AAEzD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAWnE"}
|
package/dist/reactive.d.ts
CHANGED
|
@@ -235,23 +235,12 @@ export declare function createMemo<T>(fn: () => T, __bfId?: string): Memo<T>;
|
|
|
235
235
|
* resolves per-request.
|
|
236
236
|
*/
|
|
237
237
|
export declare function __bfSetServerEnvReader(reader: ((key: string) => string | undefined) | null): void;
|
|
238
|
-
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
* `@barefootjs/router` updates this signal and the URL **without a swap or
|
|
247
|
-
* re-hydration**. On the server it reflects the current request's query.
|
|
248
|
-
*
|
|
249
|
-
* Reactivity is **router-driven**: the signal is seeded once on first read and
|
|
250
|
-
* thereafter updated only through the `window.__bf_pushSearch` seam, which
|
|
251
|
-
* `startRouter()` drives (including on `popstate`). Without the router running
|
|
252
|
-
* — or after a non-router `history` change — the value is read-once; the seam
|
|
253
|
-
* name is shared with `@barefootjs/router` via `BF_SEAM_PUSH_SEARCH`, so the
|
|
254
|
-
* installer (here) and the pusher agree by construction.
|
|
255
|
-
*/
|
|
256
|
-
export declare const searchParams: Reactive<() => URLSearchParams>;
|
|
238
|
+
/** Accepted inputs for `setSearchParams` — a raw query string (with or without
|
|
239
|
+
* a leading `?`), a `URLSearchParams`, or a plain record (array = multi-value,
|
|
240
|
+
* form-encoded like the client `queryHref`, cf. #2048). */
|
|
241
|
+
export type SearchParamsInit = string | URLSearchParams | Record<string, string | readonly string[]>;
|
|
242
|
+
export declare function createSearchParams(): readonly [
|
|
243
|
+
Reactive<() => URLSearchParams>,
|
|
244
|
+
(next: SearchParamsInit) => void
|
|
245
|
+
];
|
|
257
246
|
//# sourceMappingURL=reactive.d.ts.map
|
package/dist/reactive.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"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"}
|
package/dist/reactive.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// ../shared/src/markers.ts
|
|
2
2
|
var BF_SEAM_PUSH_SEARCH = "__bf_pushSearch";
|
|
3
|
+
var BF_SEAM_NAV_SEARCH = "__bf_navSearch";
|
|
3
4
|
// ../shared/src/dom-prop.ts
|
|
4
5
|
var BOOLEAN_ATTRS = new Set([
|
|
5
6
|
"checked",
|
|
@@ -374,7 +375,7 @@ function resolveServerEnv(key) {
|
|
|
374
375
|
const seam = globalThis.__bf_serverEnvReader;
|
|
375
376
|
return typeof seam === "function" ? seam(key) : undefined;
|
|
376
377
|
}
|
|
377
|
-
function createEnvSignal(key, readClient, parse, pushSeam) {
|
|
378
|
+
function createEnvSignal(key, readClient, parse, pushSeam, navSeam) {
|
|
378
379
|
let getRaw = null;
|
|
379
380
|
function ensureClientSignal() {
|
|
380
381
|
if (!getRaw) {
|
|
@@ -387,22 +388,59 @@ function createEnvSignal(key, readClient, parse, pushSeam) {
|
|
|
387
388
|
}
|
|
388
389
|
return getRaw();
|
|
389
390
|
}
|
|
390
|
-
|
|
391
|
+
const getter = () => {
|
|
391
392
|
if (typeof window === "undefined") {
|
|
392
393
|
return parse(resolveServerEnv(key) ?? "");
|
|
393
394
|
}
|
|
394
395
|
return parse(ensureClientSignal());
|
|
395
396
|
};
|
|
397
|
+
const setter = (nextRaw) => {
|
|
398
|
+
if (typeof window === "undefined")
|
|
399
|
+
return;
|
|
400
|
+
const w = window;
|
|
401
|
+
const nav = w[navSeam];
|
|
402
|
+
if (typeof nav === "function") {
|
|
403
|
+
nav(nextRaw);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
window.location.search = nextRaw;
|
|
407
|
+
};
|
|
408
|
+
return [getter, setter];
|
|
409
|
+
}
|
|
410
|
+
function toSearchString(next) {
|
|
411
|
+
let usp;
|
|
412
|
+
if (next instanceof URLSearchParams) {
|
|
413
|
+
usp = next;
|
|
414
|
+
} else if (typeof next === "string") {
|
|
415
|
+
usp = new URLSearchParams(next.startsWith("?") ? next.slice(1) : next);
|
|
416
|
+
} else {
|
|
417
|
+
usp = new URLSearchParams;
|
|
418
|
+
for (const [k, v] of Object.entries(next)) {
|
|
419
|
+
if (Array.isArray(v)) {
|
|
420
|
+
for (const item of v)
|
|
421
|
+
usp.append(k, item);
|
|
422
|
+
} else {
|
|
423
|
+
usp.append(k, v);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const s = usp.toString();
|
|
428
|
+
return s ? `?${s}` : "";
|
|
429
|
+
}
|
|
430
|
+
var [searchParamsGetter, setSearchParamsRaw] = createEnvSignal("search", () => window.location.search, (raw) => new URLSearchParams(raw), BF_SEAM_PUSH_SEARCH, BF_SEAM_NAV_SEARCH);
|
|
431
|
+
var setSearchParams = (next) => setSearchParamsRaw(toSearchString(next));
|
|
432
|
+
var searchParamsTuple = [searchParamsGetter, setSearchParams];
|
|
433
|
+
function createSearchParams() {
|
|
434
|
+
return searchParamsTuple;
|
|
396
435
|
}
|
|
397
|
-
var searchParams = createEnvSignal("search", () => window.location.search, (raw) => new URLSearchParams(raw), BF_SEAM_PUSH_SEARCH);
|
|
398
436
|
export {
|
|
399
437
|
untrack,
|
|
400
438
|
setProfilerSink,
|
|
401
|
-
searchParams,
|
|
402
439
|
onMount,
|
|
403
440
|
onCleanup,
|
|
404
441
|
endTurn,
|
|
405
442
|
createSignal,
|
|
443
|
+
createSearchParams,
|
|
406
444
|
createRoot,
|
|
407
445
|
createMemo,
|
|
408
446
|
createEffect,
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export { createSignal, createEffect, createDisposableEffect, createMemo, createRoot, onCleanup, onMount, untrack, batch, setProfilerSink, beginTurn, endTurn, __bfReportOutput,
|
|
1
|
+
export { createSignal, createEffect, createDisposableEffect, createMemo, createRoot, onCleanup, onMount, untrack, batch, setProfilerSink, beginTurn, endTurn, __bfReportOutput, createSearchParams, type SearchParamsInit, __bfSetServerEnvReader, type Reactive, type Signal, type Memo, type CleanupFn, type EffectFn, type ProfilerEventSink, type SubscriberKind, } from '@barefootjs/client/reactive';
|
|
2
2
|
export { createRecordingSink, type ProfilerEvent, type ProfilerEventType, type RecordingSink, } from '../profiler-events.ts';
|
|
3
3
|
export { splitProps } from '../split-props.ts';
|
|
4
4
|
export { __slot, type SlotMarker } from '../slot.ts';
|
|
5
5
|
export { forwardProps } from '../forward-props.ts';
|
|
6
6
|
export { unwrap } from '../unwrap.ts';
|
|
7
|
+
export { queryHref, type QueryParams, type QueryParamValue } from '../query-href.ts';
|
|
7
8
|
export { createContext, useContext, provideContext, setCurrentScope, type Context, } from './context.ts';
|
|
8
9
|
export { createPortal, isSSRPortal, findSiblingSlot, cleanupPortalPlaceholder, type Portal, type PortalOptions, type Renderable, type PortalChildren, } from './portal.ts';
|
|
9
10
|
export { reconcileList, type RenderItemFn } from './list.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,eAAe,EACf,SAAS,EACT,OAAO,EACP,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
beginTurn,
|
|
14
14
|
endTurn,
|
|
15
15
|
__bfReportOutput as __bfReportOutput2,
|
|
16
|
-
|
|
16
|
+
createSearchParams,
|
|
17
17
|
__bfSetServerEnvReader
|
|
18
18
|
} from "@barefootjs/client/reactive";
|
|
19
19
|
|
|
@@ -146,6 +146,21 @@ function forwardProps(source, overrides, excludeKeys) {
|
|
|
146
146
|
function unwrap(prop) {
|
|
147
147
|
return typeof prop === "function" ? prop() : prop;
|
|
148
148
|
}
|
|
149
|
+
// src/query-href.ts
|
|
150
|
+
function queryHref(base, params) {
|
|
151
|
+
const u = new URLSearchParams;
|
|
152
|
+
for (const [key, value] of Object.entries(params)) {
|
|
153
|
+
if (Array.isArray(value)) {
|
|
154
|
+
for (const member of value)
|
|
155
|
+
if (member)
|
|
156
|
+
u.append(key, member);
|
|
157
|
+
} else if (value) {
|
|
158
|
+
u.set(key, value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const qs = u.toString();
|
|
162
|
+
return qs ? `${base}?${qs}` : base;
|
|
163
|
+
}
|
|
149
164
|
// ../shared/src/markers.ts
|
|
150
165
|
var BF_SCOPE = "bf-s";
|
|
151
166
|
var BF_SLOT = "bf";
|
|
@@ -2556,7 +2571,6 @@ export {
|
|
|
2556
2571
|
setupStreaming,
|
|
2557
2572
|
setProfilerSink,
|
|
2558
2573
|
setCurrentScope,
|
|
2559
|
-
searchParams,
|
|
2560
2574
|
renderChild,
|
|
2561
2575
|
render,
|
|
2562
2576
|
rehydrateScope,
|
|
@@ -2565,6 +2579,7 @@ export {
|
|
|
2565
2579
|
registerComponent,
|
|
2566
2580
|
reconcileList,
|
|
2567
2581
|
reconcileElements,
|
|
2582
|
+
queryHref,
|
|
2568
2583
|
qsaItem,
|
|
2569
2584
|
qsaChildScopes,
|
|
2570
2585
|
qsaChildScope,
|
|
@@ -2599,6 +2614,7 @@ export {
|
|
|
2599
2614
|
disposeScope,
|
|
2600
2615
|
cssEscape,
|
|
2601
2616
|
createSignal2 as createSignal,
|
|
2617
|
+
createSearchParams,
|
|
2602
2618
|
createRoot3 as createRoot,
|
|
2603
2619
|
createRecordingSink,
|
|
2604
2620
|
createPortal,
|
|
@@ -31,6 +31,7 @@ var BF_SEAM_HYDRATE = "__bf_hydrate";
|
|
|
31
31
|
var BF_SEAM_HYDRATE_WITHIN = "__bf_hydrate_within";
|
|
32
32
|
var BF_SEAM_DISPOSE_WITHIN = "__bf_dispose_within";
|
|
33
33
|
var BF_SEAM_PUSH_SEARCH = "__bf_pushSearch";
|
|
34
|
+
var BF_SEAM_NAV_SEARCH = "__bf_navSearch";
|
|
34
35
|
// ../shared/src/dom-prop.ts
|
|
35
36
|
var BOOLEAN_ATTRS = new Set([
|
|
36
37
|
"checked",
|
|
@@ -473,7 +474,7 @@ function resolveServerEnv(key) {
|
|
|
473
474
|
const seam = globalThis.__bf_serverEnvReader;
|
|
474
475
|
return typeof seam === "function" ? seam(key) : undefined;
|
|
475
476
|
}
|
|
476
|
-
function createEnvSignal(key, readClient, parse, pushSeam) {
|
|
477
|
+
function createEnvSignal(key, readClient, parse, pushSeam, navSeam) {
|
|
477
478
|
let getRaw = null;
|
|
478
479
|
function ensureClientSignal() {
|
|
479
480
|
if (!getRaw) {
|
|
@@ -486,14 +487,51 @@ function createEnvSignal(key, readClient, parse, pushSeam) {
|
|
|
486
487
|
}
|
|
487
488
|
return getRaw();
|
|
488
489
|
}
|
|
489
|
-
|
|
490
|
+
const getter = () => {
|
|
490
491
|
if (typeof window === "undefined") {
|
|
491
492
|
return parse(resolveServerEnv(key) ?? "");
|
|
492
493
|
}
|
|
493
494
|
return parse(ensureClientSignal());
|
|
494
495
|
};
|
|
496
|
+
const setter = (nextRaw) => {
|
|
497
|
+
if (typeof window === "undefined")
|
|
498
|
+
return;
|
|
499
|
+
const w = window;
|
|
500
|
+
const nav = w[navSeam];
|
|
501
|
+
if (typeof nav === "function") {
|
|
502
|
+
nav(nextRaw);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
window.location.search = nextRaw;
|
|
506
|
+
};
|
|
507
|
+
return [getter, setter];
|
|
508
|
+
}
|
|
509
|
+
function toSearchString(next) {
|
|
510
|
+
let usp;
|
|
511
|
+
if (next instanceof URLSearchParams) {
|
|
512
|
+
usp = next;
|
|
513
|
+
} else if (typeof next === "string") {
|
|
514
|
+
usp = new URLSearchParams(next.startsWith("?") ? next.slice(1) : next);
|
|
515
|
+
} else {
|
|
516
|
+
usp = new URLSearchParams;
|
|
517
|
+
for (const [k, v] of Object.entries(next)) {
|
|
518
|
+
if (Array.isArray(v)) {
|
|
519
|
+
for (const item of v)
|
|
520
|
+
usp.append(k, item);
|
|
521
|
+
} else {
|
|
522
|
+
usp.append(k, v);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const s = usp.toString();
|
|
527
|
+
return s ? `?${s}` : "";
|
|
528
|
+
}
|
|
529
|
+
var [searchParamsGetter, setSearchParamsRaw] = createEnvSignal("search", () => window.location.search, (raw) => new URLSearchParams(raw), BF_SEAM_PUSH_SEARCH, BF_SEAM_NAV_SEARCH);
|
|
530
|
+
var setSearchParams = (next) => setSearchParamsRaw(toSearchString(next));
|
|
531
|
+
var searchParamsTuple = [searchParamsGetter, setSearchParams];
|
|
532
|
+
function createSearchParams() {
|
|
533
|
+
return searchParamsTuple;
|
|
495
534
|
}
|
|
496
|
-
var searchParams = createEnvSignal("search", () => window.location.search, (raw) => new URLSearchParams(raw), BF_SEAM_PUSH_SEARCH);
|
|
497
535
|
// src/profiler-events.ts
|
|
498
536
|
function createRecordingSink() {
|
|
499
537
|
const events = [];
|
|
@@ -623,6 +661,21 @@ function forwardProps(source, overrides, excludeKeys) {
|
|
|
623
661
|
function unwrap(prop) {
|
|
624
662
|
return typeof prop === "function" ? prop() : prop;
|
|
625
663
|
}
|
|
664
|
+
// src/query-href.ts
|
|
665
|
+
function queryHref(base, params) {
|
|
666
|
+
const u = new URLSearchParams;
|
|
667
|
+
for (const [key, value] of Object.entries(params)) {
|
|
668
|
+
if (Array.isArray(value)) {
|
|
669
|
+
for (const member of value)
|
|
670
|
+
if (member)
|
|
671
|
+
u.append(key, member);
|
|
672
|
+
} else if (value) {
|
|
673
|
+
u.set(key, value);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const qs = u.toString();
|
|
677
|
+
return qs ? `${base}?${qs}` : base;
|
|
678
|
+
}
|
|
626
679
|
// src/context.ts
|
|
627
680
|
function createContext(defaultValue) {
|
|
628
681
|
return {
|
|
@@ -2841,7 +2894,6 @@ export {
|
|
|
2841
2894
|
setupStreaming,
|
|
2842
2895
|
setProfilerSink,
|
|
2843
2896
|
setCurrentScope,
|
|
2844
|
-
searchParams,
|
|
2845
2897
|
renderChild,
|
|
2846
2898
|
render,
|
|
2847
2899
|
rehydrateScope,
|
|
@@ -2850,6 +2902,7 @@ export {
|
|
|
2850
2902
|
registerComponent,
|
|
2851
2903
|
reconcileList,
|
|
2852
2904
|
reconcileElements,
|
|
2905
|
+
queryHref,
|
|
2853
2906
|
qsaItem,
|
|
2854
2907
|
qsaChildScopes,
|
|
2855
2908
|
qsaChildScope,
|
|
@@ -2884,6 +2937,7 @@ export {
|
|
|
2884
2937
|
disposeScope,
|
|
2885
2938
|
cssEscape,
|
|
2886
2939
|
createSignal,
|
|
2940
|
+
createSearchParams,
|
|
2887
2941
|
createRoot,
|
|
2888
2942
|
createRecordingSink,
|
|
2889
2943
|
createPortal,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "BarefootJS client package: reactive primitives (SSR-safe) plus browser runtime under the `/runtime` subpath (compiler target)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/client"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.
|
|
58
|
+
"@barefootjs/shared": "0.17.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0"
|
package/src/index.ts
CHANGED
|
@@ -16,10 +16,12 @@ export {
|
|
|
16
16
|
endTurn,
|
|
17
17
|
__bfReportOutput,
|
|
18
18
|
// Request-scoped reactive environment signals (spec/router.md "The wedge").
|
|
19
|
-
// `
|
|
20
|
-
// the `/runtime` entry resolve to ONE signal instance. `createEnvSignal`
|
|
21
|
-
// internal; `__bfSetServerEnvReader` is the keyed adapter/host hook for
|
|
22
|
-
|
|
19
|
+
// `createSearchParams` lives in the shared reactive module too, so this entry
|
|
20
|
+
// and the `/runtime` entry resolve to ONE signal instance. `createEnvSignal`
|
|
21
|
+
// stays internal; `__bfSetServerEnvReader` is the keyed adapter/host hook for
|
|
22
|
+
// SSR.
|
|
23
|
+
createSearchParams,
|
|
24
|
+
type SearchParamsInit,
|
|
23
25
|
__bfSetServerEnvReader,
|
|
24
26
|
type Reactive,
|
|
25
27
|
type Signal,
|
|
@@ -45,6 +47,8 @@ export { forwardProps } from './forward-props.ts'
|
|
|
45
47
|
|
|
46
48
|
export { unwrap } from './unwrap.ts'
|
|
47
49
|
|
|
50
|
+
export { queryHref, type QueryParams, type QueryParamValue } from './query-href.ts'
|
|
51
|
+
|
|
48
52
|
export { createContext, type Context } from './context.ts'
|
|
49
53
|
|
|
50
54
|
export {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `queryHref` — build a URL from a base path plus query params, omitting falsy
|
|
3
|
+
* values. The functional counterpart to `searchParams()` (the reactive *reader*):
|
|
4
|
+
* instead of imperatively mutating a `URLSearchParams`, pass a params object.
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const href = queryHref(base, {
|
|
8
|
+
* sort: sort !== 'date' ? sort : undefined, // conditional include via the value
|
|
9
|
+
* tag, // included only when truthy
|
|
10
|
+
* })
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Each entry is included iff its value is a **non-empty string** — `''` /
|
|
14
|
+
* `undefined` / `null` are omitted — so a conditional include folds into the
|
|
15
|
+
* value as `cond ? value : undefined`. Returns the bare `base` when no params
|
|
16
|
+
* survive. Values are encoded with `URLSearchParams` (form-encoding, spaces →
|
|
17
|
+
* `+`).
|
|
18
|
+
*
|
|
19
|
+
* A value may also be a **`string[]`**, which appends one entry per non-empty
|
|
20
|
+
* member (`{ tag: ['a', 'b'] }` → `?tag=a&tag=b`), i.e. `URLSearchParams.append`
|
|
21
|
+
* rather than `set`. Empty / falsy members are skipped (same truthy-omit as a
|
|
22
|
+
* scalar), so an empty array — or one whose members are all empty — contributes
|
|
23
|
+
* nothing.
|
|
24
|
+
*
|
|
25
|
+
* Values are **strings** (`QueryParamValue`). Number / boolean aren't accepted:
|
|
26
|
+
* JS truthiness would omit `0` / `false`, which the SSR adapters' string guard
|
|
27
|
+
* can't model without per-value type info — so keeping values string-only
|
|
28
|
+
* guarantees the server-rendered URL matches this client output byte-for-byte.
|
|
29
|
+
* Stringify other types at the call site (`String(n)`), choosing the omit rule
|
|
30
|
+
* explicitly (`n > 0 ? String(n) : undefined`).
|
|
31
|
+
*
|
|
32
|
+
* This is a pure function with no reactivity. The SSR adapters lower a
|
|
33
|
+
* `queryHref(base, { … })` call to their query helper (go-template: `bf_query`),
|
|
34
|
+
* which is why the params object must be a plain object literal at the call site.
|
|
35
|
+
*/
|
|
36
|
+
export type QueryParamValue = string | string[] | null | undefined
|
|
37
|
+
export type QueryParams = Record<string, QueryParamValue>
|
|
38
|
+
|
|
39
|
+
export function queryHref(base: string, params: QueryParams): string {
|
|
40
|
+
const u = new URLSearchParams()
|
|
41
|
+
for (const [key, value] of Object.entries(params)) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
for (const member of value) if (member) u.append(key, member)
|
|
44
|
+
} else if (value) {
|
|
45
|
+
u.set(key, value)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const qs = u.toString()
|
|
49
|
+
return qs ? `${base}?${qs}` : base
|
|
50
|
+
}
|
package/src/reactive.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Inspired by SolidJS signals.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { BF_SEAM_PUSH_SEARCH } from '@barefootjs/shared'
|
|
8
|
+
import { BF_SEAM_NAV_SEARCH, BF_SEAM_PUSH_SEARCH } from '@barefootjs/shared'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Phantom brand for compile-time reactivity detection.
|
|
@@ -665,15 +665,22 @@ function resolveServerEnv(key: string): string | undefined {
|
|
|
665
665
|
|
|
666
666
|
/**
|
|
667
667
|
* Build a request-scoped reactive environment signal, keyed by `key` — the env
|
|
668
|
-
* id the SSR reader resolves (`'search'`, …)
|
|
669
|
-
*
|
|
668
|
+
* id the SSR reader resolves (`'search'`, …) — as a `createSignal`-shaped
|
|
669
|
+
* `[getter, setter]` tuple. Internal: only concrete factories
|
|
670
|
+
* (`createSearchParams`, …) are exported.
|
|
671
|
+
*
|
|
672
|
+
* The tuple shape is deliberate (#2057): the compiler recognises the getter
|
|
673
|
+
* *structurally* — the same path as `createSignal` — so it needs no env-signal
|
|
674
|
+
* name allow-list, and the getter is pure-within-render for the block fold. The
|
|
675
|
+
* setter is the single imperative navigation path.
|
|
670
676
|
*/
|
|
671
677
|
function createEnvSignal<T>(
|
|
672
678
|
key: string,
|
|
673
679
|
readClient: () => string,
|
|
674
680
|
parse: (raw: string) => T,
|
|
675
681
|
pushSeam: string,
|
|
676
|
-
|
|
682
|
+
navSeam: string,
|
|
683
|
+
): readonly [Reactive<() => T>, (nextRaw: string) => void] {
|
|
677
684
|
let getRaw: (() => string) | null = null
|
|
678
685
|
|
|
679
686
|
function ensureClientSignal(): string {
|
|
@@ -693,7 +700,7 @@ function createEnvSignal<T>(
|
|
|
693
700
|
return getRaw()
|
|
694
701
|
}
|
|
695
702
|
|
|
696
|
-
|
|
703
|
+
const getter = (() => {
|
|
697
704
|
if (typeof window === 'undefined') {
|
|
698
705
|
// SSR: resolve per-call inside the host's request context. Never cache a
|
|
699
706
|
// module-level signal — it would be a process-wide global that races.
|
|
@@ -701,29 +708,100 @@ function createEnvSignal<T>(
|
|
|
701
708
|
}
|
|
702
709
|
return parse(ensureClientSignal())
|
|
703
710
|
}) as Reactive<() => T>
|
|
711
|
+
|
|
712
|
+
// Imperative navigation. The setter writes the new raw value through the
|
|
713
|
+
// router's nav seam (soft, same-route query navigation) when a router has
|
|
714
|
+
// installed it; otherwise it hard-navigates — "never worse than an MPA" — so
|
|
715
|
+
// the write is correct standalone. The getter is then updated by the router
|
|
716
|
+
// through `pushSeam`, keeping read reactivity in one place. On the server a
|
|
717
|
+
// setter call is a no-op (there is nothing to navigate).
|
|
718
|
+
const setter = (nextRaw: string) => {
|
|
719
|
+
if (typeof window === 'undefined') return
|
|
720
|
+
const w = window as unknown as Record<string, ((next: string) => void) | undefined>
|
|
721
|
+
const nav = w[navSeam]
|
|
722
|
+
if (typeof nav === 'function') {
|
|
723
|
+
nav(nextRaw)
|
|
724
|
+
return
|
|
725
|
+
}
|
|
726
|
+
window.location.search = nextRaw
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
return [getter, setter] as const
|
|
704
730
|
}
|
|
705
731
|
|
|
732
|
+
/** Accepted inputs for `setSearchParams` — a raw query string (with or without
|
|
733
|
+
* a leading `?`), a `URLSearchParams`, or a plain record (array = multi-value,
|
|
734
|
+
* form-encoded like the client `queryHref`, cf. #2048). */
|
|
735
|
+
export type SearchParamsInit =
|
|
736
|
+
| string
|
|
737
|
+
| URLSearchParams
|
|
738
|
+
| Record<string, string | readonly string[]>
|
|
739
|
+
|
|
740
|
+
function toSearchString(next: SearchParamsInit): string {
|
|
741
|
+
let usp: URLSearchParams
|
|
742
|
+
if (next instanceof URLSearchParams) {
|
|
743
|
+
usp = next
|
|
744
|
+
} else if (typeof next === 'string') {
|
|
745
|
+
usp = new URLSearchParams(next.startsWith('?') ? next.slice(1) : next)
|
|
746
|
+
} else {
|
|
747
|
+
usp = new URLSearchParams()
|
|
748
|
+
for (const [k, v] of Object.entries(next)) {
|
|
749
|
+
if (Array.isArray(v)) {
|
|
750
|
+
for (const item of v) usp.append(k, item)
|
|
751
|
+
} else {
|
|
752
|
+
usp.append(k, v as string)
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
const s = usp.toString()
|
|
757
|
+
return s ? `?${s}` : ''
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const [searchParamsGetter, setSearchParamsRaw] = createEnvSignal(
|
|
761
|
+
'search',
|
|
762
|
+
() => window.location.search,
|
|
763
|
+
(raw) => new URLSearchParams(raw),
|
|
764
|
+
BF_SEAM_PUSH_SEARCH,
|
|
765
|
+
BF_SEAM_NAV_SEARCH,
|
|
766
|
+
)
|
|
767
|
+
|
|
706
768
|
/**
|
|
707
|
-
*
|
|
769
|
+
* `createSearchParams()` — the request-scoped query-string env signal, returned
|
|
770
|
+
* as a `createSignal`-shaped `[getter, setter]` tuple (#2057):
|
|
708
771
|
*
|
|
709
772
|
* ```tsx
|
|
773
|
+
* const [searchParams, setSearchParams] = createSearchParams()
|
|
710
774
|
* const sort = createMemo(() => searchParams().get('sort') ?? 'recent')
|
|
775
|
+
* // …
|
|
776
|
+
* setSearchParams({ sort: 'price' }) // imperative, same-route navigation
|
|
711
777
|
* ```
|
|
712
778
|
*
|
|
713
|
-
*
|
|
779
|
+
* **Read** (`searchParams()`): the current query as `URLSearchParams`. A
|
|
780
|
+
* same-route, query-only navigation (`/list?sort=price`) driven by
|
|
714
781
|
* `@barefootjs/router` updates this signal and the URL **without a swap or
|
|
715
782
|
* re-hydration**. On the server it reflects the current request's query.
|
|
716
|
-
*
|
|
717
783
|
* Reactivity is **router-driven**: the signal is seeded once on first read and
|
|
718
784
|
* thereafter updated only through the `window.__bf_pushSearch` seam, which
|
|
719
|
-
* `startRouter()` drives (including on `popstate`).
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
785
|
+
* `startRouter()` drives (including on `popstate`).
|
|
786
|
+
*
|
|
787
|
+
* **Write** (`setSearchParams(next)`): the single imperative navigation path —
|
|
788
|
+
* a soft same-route navigation when a router is running, a hard navigation
|
|
789
|
+
* otherwise. This replaces mutating a live `URLSearchParams` reader (which only
|
|
790
|
+
* ever changed a throwaway copy), so there is exactly one way to change the
|
|
791
|
+
* query.
|
|
792
|
+
*
|
|
793
|
+
* Every call returns the same request-scoped getter/setter — there is one query
|
|
794
|
+
* per document, so the tuple is a stable view, not per-call state.
|
|
723
795
|
*/
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
() =>
|
|
727
|
-
(
|
|
728
|
-
|
|
729
|
-
|
|
796
|
+
const setSearchParams = (next: SearchParamsInit): void => setSearchParamsRaw(toSearchString(next))
|
|
797
|
+
const searchParamsTuple: readonly [
|
|
798
|
+
Reactive<() => URLSearchParams>,
|
|
799
|
+
(next: SearchParamsInit) => void,
|
|
800
|
+
] = [searchParamsGetter, setSearchParams]
|
|
801
|
+
|
|
802
|
+
export function createSearchParams(): readonly [
|
|
803
|
+
Reactive<() => URLSearchParams>,
|
|
804
|
+
(next: SearchParamsInit) => void,
|
|
805
|
+
] {
|
|
806
|
+
return searchParamsTuple
|
|
807
|
+
}
|
package/src/runtime/index.ts
CHANGED
|
@@ -23,11 +23,13 @@ export {
|
|
|
23
23
|
endTurn,
|
|
24
24
|
__bfReportOutput,
|
|
25
25
|
// Request-scoped env signal (router v0.5). The compiler emits island client JS
|
|
26
|
-
// that imports `
|
|
27
|
-
// it from the shared reactive module (same as the signal
|
|
28
|
-
// means this entry and the main `@barefootjs/client` entry
|
|
29
|
-
// signal instance — no second copy to disconnect from router
|
|
30
|
-
|
|
26
|
+
// that imports `createSearchParams` from `@barefootjs/client/runtime`;
|
|
27
|
+
// re-exporting it from the shared reactive module (same as the signal
|
|
28
|
+
// primitives above) means this entry and the main `@barefootjs/client` entry
|
|
29
|
+
// resolve to ONE signal instance — no second copy to disconnect from router
|
|
30
|
+
// pushes.
|
|
31
|
+
createSearchParams,
|
|
32
|
+
type SearchParamsInit,
|
|
31
33
|
__bfSetServerEnvReader,
|
|
32
34
|
type Reactive,
|
|
33
35
|
type Signal,
|
|
@@ -49,6 +51,7 @@ export { splitProps } from '../split-props.ts'
|
|
|
49
51
|
export { __slot, type SlotMarker } from '../slot.ts'
|
|
50
52
|
export { forwardProps } from '../forward-props.ts'
|
|
51
53
|
export { unwrap } from '../unwrap.ts'
|
|
54
|
+
export { queryHref, type QueryParams, type QueryParamValue } from '../query-href.ts'
|
|
52
55
|
|
|
53
56
|
// Context API (real DOM-bound implementations; `createContext` is the
|
|
54
57
|
// same pure function re-exported from `../context`).
|