@phreshos/react 0.1.30 → 0.1.32

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.
@@ -10,6 +10,8 @@ export default function ContextProvider({ children, context, fallback }: Context
10
10
  }> | null>> | null;
11
11
  /** Returns the complete Client Context supplied by the nearest provider. */
12
12
  export declare function useContext(): ClientContext;
13
+ /** Read the current Context when present; explicit-handle hooks also work without it. */
14
+ export declare function useProvidedContext(): ClientContext | null;
13
15
  /** Returns the current Program once it resolves. */
14
16
  export declare function useProgram<Handle extends Program = Program>(): Handle;
15
17
  /** Returns the current Process once it resolves. */
@@ -18,6 +18,10 @@ export default function ContextProvider({ children, context, fallback = null })
18
18
  export function useContext() {
19
19
  return useValue().context;
20
20
  }
21
+ /** Read the current Context when present; explicit-handle hooks also work without it. */
22
+ export function useProvidedContext() {
23
+ return useReactContext(CurrentContext)?.context ?? null;
24
+ }
21
25
  /** Returns the current Program once it resolves. */
22
26
  export function useProgram() {
23
27
  return useResolved(useValue().program);
package/dist/main.d.ts CHANGED
@@ -9,6 +9,6 @@ export { default as useSessionState, type SessionState } from "./use-session-sta
9
9
  export { default as useEndpointState, type EndpointState } from "./use-endpoint-state.js";
10
10
  export { default as useServiceState, type ServiceState } from "./use-service-state.js";
11
11
  export { default as useWindowState } from "./use-window-state.js";
12
- export { default as useWindowPresentationState } from "./use-window-presentation-state.js";
12
+ export { default as useClientMemory } from "./use-client-memory.js";
13
13
  export { default as useSubscribeAsks, type AskSubscribable } from "./use-subscribe-asks.js";
14
14
  export { default as useSubscribeAnswers, type AnswerSubscribable } from "./use-subscribe-answers.js";
package/dist/main.js CHANGED
@@ -9,6 +9,6 @@ export { default as useSessionState } from "./use-session-state.js";
9
9
  export { default as useEndpointState } from "./use-endpoint-state.js";
10
10
  export { default as useServiceState } from "./use-service-state.js";
11
11
  export { default as useWindowState } from "./use-window-state.js";
12
- export { default as useWindowPresentationState } from "./use-window-presentation-state.js";
12
+ export { default as useClientMemory } from "./use-client-memory.js";
13
13
  export { default as useSubscribeAsks } from "./use-subscribe-asks.js";
14
14
  export { default as useSubscribeAnswers } from "./use-subscribe-answers.js";
@@ -0,0 +1,7 @@
1
+ import type { ClientMemory, JsonValue } from "@phreshos/core";
2
+ type Widen<Value extends JsonValue> = Value extends string ? string : Value extends number ? number : Value extends boolean ? boolean : Value;
3
+ type MemoryResult<Value extends JsonValue> = readonly [Value | undefined, (next: Value | ((current: Value | undefined) => Value)) => Promise<void>];
4
+ /** Reads the current Client's memory, or an explicitly supplied Client memory handle. */
5
+ export default function useClientMemory<Value extends JsonValue>(key: string, initial: Value): MemoryResult<Widen<Value>>;
6
+ export default function useClientMemory<Value extends JsonValue>(memory: ClientMemory, key: string, initial: Value): MemoryResult<Widen<Value>>;
7
+ export {};
@@ -0,0 +1,21 @@
1
+ import { useCallback, useMemo, useSyncExternalStore } from "react";
2
+ import { useProvidedContext } from "./context-provider.js";
3
+ import LiveState from "./live-state.js";
4
+ export default function useClientMemory(memoryOrKey, keyOrInitial, explicitInitial) {
5
+ const context = useProvidedContext();
6
+ const memory = typeof memoryOrKey === "string" ? context?.memory : memoryOrKey;
7
+ if (!memory)
8
+ throw new Error("useClientMemory(key, initial) requires ContextProvider");
9
+ const key = typeof memoryOrKey === "string" ? memoryOrKey : keyOrInitial;
10
+ const initial = typeof memoryOrKey === "string" ? keyOrInitial : explicitInitial;
11
+ // Initial seeds the key, but does not restart its subscription when it changes.
12
+ const state = useMemo(() => new LiveState(async () => ({ value: await memory.update(key, current => current === undefined ? initial : current) }), reduce => memory.subscribe(key, value => reduce(() => ({ value })))), [memory, key]);
13
+ const snapshot = useSyncExternalStore(state.subscribe, state.snapshot, state.snapshot);
14
+ const set = useCallback(async (next) => {
15
+ if (typeof next === "function")
16
+ await memory.update(key, next);
17
+ else
18
+ await memory.set(key, next);
19
+ }, [memory, key]);
20
+ return [snapshot?.value, set];
21
+ }
@@ -3,11 +3,9 @@ import LiveState, { combineCleanups } from "./live-state.js";
3
3
  /** Explicitly reads and follows one live Client Window while mounted. */
4
4
  export default function useWindowState(window) {
5
5
  const state = useMemo(() => new LiveState(async () => {
6
- const [title, header, surface, transaction, position, size, minimized, maximized, front, layer] = await Promise.all([
6
+ const [title, header, position, size, minimized, maximized, front, layer] = await Promise.all([
7
7
  window.title(),
8
8
  window.header(),
9
- window.surface(),
10
- window.transaction(),
11
9
  window.position(),
12
10
  window.size(),
13
11
  window.minimized(),
@@ -15,7 +13,7 @@ export default function useWindowState(window) {
15
13
  window.front(),
16
14
  window.layer()
17
15
  ]);
18
- return { title, header, surface, transaction, position, size, minimized, maximized, front, layer };
19
- }, reduce => combineCleanups(window.subscribe("move", position => reduce(current => ({ ...current, position }))), window.subscribe("resize", size => reduce(current => ({ ...current, size }))), window.subscribe("minimize", minimized => reduce(current => ({ ...current, minimized }))), window.subscribe("maximize", maximized => reduce(current => ({ ...current, maximized }))), window.subscribe("changeTitle", title => reduce(current => ({ ...current, title }))), window.subscribe("changeHeader", header => reduce(current => ({ ...current, header }))), window.subscribe("changeSurface", surface => reduce(current => ({ ...current, surface }))), window.subscribe("changeTransaction", transaction => reduce(current => ({ ...current, transaction }))), window.subscribe("front", front => reduce(current => ({ ...current, front }))))), [window]);
16
+ return { title, header, position, size, minimized, maximized, front, layer };
17
+ }, reduce => combineCleanups(window.subscribe("move", position => reduce(current => ({ ...current, position }))), window.subscribe("resize", size => reduce(current => ({ ...current, size }))), window.subscribe("minimize", minimized => reduce(current => ({ ...current, minimized }))), window.subscribe("maximize", maximized => reduce(current => ({ ...current, maximized }))), window.subscribe("changeTitle", title => reduce(current => ({ ...current, title }))), window.subscribe("changeHeader", header => reduce(current => ({ ...current, header }))), window.subscribe("front", front => reduce(current => ({ ...current, front }))))), [window]);
20
18
  return useSyncExternalStore(state.subscribe, state.snapshot, state.snapshot);
21
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/react",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "Runtime-neutral React adapters for PhreshOS contracts.",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -46,11 +46,11 @@
46
46
  "prepack": "node --run build"
47
47
  },
48
48
  "peerDependencies": {
49
- "@phreshos/core": "^0.1.58",
49
+ "@phreshos/core": "^0.1.62",
50
50
  "react": "^19.2.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@phreshos/core": "^0.1.58",
53
+ "@phreshos/core": "^0.1.62",
54
54
  "@testing-library/dom": "^10.4.1",
55
55
  "@testing-library/react": "^16.3.0",
56
56
  "@types/react": "^19.2.18",
@@ -1,3 +0,0 @@
1
- import type { WindowPresentation, WindowPresentationState } from "@phreshos/core";
2
- /** Reads and follows the values one Desktop relies on to represent a Window. */
3
- export default function useWindowPresentationState(presentation: WindowPresentation): WindowPresentationState | undefined;
@@ -1,30 +0,0 @@
1
- import { useMemo, useSyncExternalStore } from "react";
2
- import LiveState, { combineCleanups } from "./live-state.js";
3
- /** Reads and follows the values one Desktop relies on to represent a Window. */
4
- export default function useWindowPresentationState(presentation) {
5
- const state = useMemo(() => new LiveState(() => readPresentation(presentation), reduce => combineCleanups(presentation.subscribe("move", position => reduce(current => change(current, "position", position))), presentation.subscribe("resize", size => reduce(current => change(current, "size", size))), presentation.subscribe("minimize", minimized => reduce(current => change(current, "minimized", minimized))), presentation.subscribe("maximize", maximized => reduce(current => change(current, "maximized", maximized))), presentation.subscribe("changeTitle", title => reduce(current => change(current, "title", title))), presentation.subscribe("changeHeader", header => reduce(current => change(current, "header", header))), presentation.subscribe("changeSurface", surface => reduce(current => change(current, "surface", surface))), presentation.subscribe("front", front => reduce(current => change(current, "front", front))))), [presentation]);
6
- return useSyncExternalStore(state.subscribe, state.snapshot, state.snapshot);
7
- }
8
- async function readPresentation(presentation) {
9
- const layer = await presentation.layer();
10
- if (layer === "wallpaper")
11
- return { layer };
12
- const [surface, position, size, minimized, maximized, front] = await Promise.all([
13
- presentation.surface(),
14
- presentation.position(),
15
- presentation.size(),
16
- presentation.minimized(),
17
- presentation.maximized(),
18
- presentation.front()
19
- ]);
20
- if (layer === "under" || layer === "over" || layer === "shell") {
21
- return { layer, surface, position, size, minimized, maximized, front };
22
- }
23
- const [title, header] = await Promise.all([presentation.title(), presentation.header()]);
24
- return { layer, title, header, surface, position, size, minimized, maximized, front };
25
- }
26
- function change(state, property, value) {
27
- if (!(property in state))
28
- return state;
29
- return { ...state, [property]: value };
30
- }