@assistant-ui/store 0.0.6 → 0.1.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/README.md +13 -13
- package/dist/{AssistantIf.d.ts → AuiIf.d.ts} +4 -4
- package/dist/AuiIf.d.ts.map +1 -0
- package/dist/AuiIf.js +8 -0
- package/dist/AuiIf.js.map +1 -0
- package/dist/Derived.d.ts +2 -2
- package/dist/Derived.d.ts.map +1 -1
- package/dist/Derived.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/tapClientList.d.ts.map +1 -1
- package/dist/tapClientList.js +16 -10
- package/dist/tapClientList.js.map +1 -1
- package/dist/tapClientLookup.d.ts +3 -3
- package/dist/tapClientLookup.d.ts.map +1 -1
- package/dist/tapClientLookup.js +28 -16
- package/dist/tapClientLookup.js.map +1 -1
- package/dist/tapClientResource.d.ts +6 -2
- package/dist/tapClientResource.d.ts.map +1 -1
- package/dist/tapClientResource.js +11 -5
- package/dist/tapClientResource.js.map +1 -1
- package/dist/types/client.d.ts +4 -2
- package/dist/types/client.d.ts.map +1 -1
- package/dist/useAui.d.ts +20 -0
- package/dist/useAui.d.ts.map +1 -0
- package/dist/{useAssistantClient.js → useAui.js} +65 -35
- package/dist/useAui.js.map +1 -0
- package/dist/useAuiEvent.d.ts +3 -0
- package/dist/useAuiEvent.d.ts.map +1 -0
- package/dist/{useAssistantEvent.js → useAuiEvent.js} +4 -4
- package/dist/useAuiEvent.js.map +1 -0
- package/dist/{useAssistantState.d.ts → useAuiState.d.ts} +4 -4
- package/dist/useAuiState.d.ts.map +1 -0
- package/dist/{useAssistantState.js → useAuiState.js} +6 -6
- package/dist/useAuiState.js.map +1 -0
- package/dist/utils/NotificationManager.d.ts +1 -1
- package/dist/utils/NotificationManager.d.ts.map +1 -1
- package/dist/utils/NotificationManager.js +3 -2
- package/dist/utils/NotificationManager.js.map +1 -1
- package/dist/utils/StoreResource.d.ts +1 -1
- package/dist/utils/StoreResource.d.ts.map +1 -1
- package/dist/utils/StoreResource.js +2 -4
- package/dist/utils/StoreResource.js.map +1 -1
- package/dist/utils/react-assistant-context.d.ts +5 -5
- package/dist/utils/react-assistant-context.d.ts.map +1 -1
- package/dist/utils/react-assistant-context.js +6 -6
- package/dist/utils/react-assistant-context.js.map +1 -1
- package/dist/utils/splitClients.d.ts +2 -20
- package/dist/utils/splitClients.d.ts.map +1 -1
- package/dist/utils/splitClients.js +13 -1
- package/dist/utils/splitClients.js.map +1 -1
- package/dist/utils/tap-assistant-context.d.ts.map +1 -1
- package/dist/utils/tap-assistant-context.js +3 -3
- package/dist/utils/tap-assistant-context.js.map +1 -1
- package/dist/utils/tap-client-stack-context.js +3 -3
- package/dist/utils/tap-client-stack-context.js.map +1 -1
- package/dist/wrapperResource.d.ts +3 -0
- package/dist/wrapperResource.d.ts.map +1 -0
- package/dist/wrapperResource.js +11 -0
- package/dist/wrapperResource.js.map +1 -0
- package/package.json +2 -2
- package/src/AuiIf.tsx +17 -0
- package/src/Derived.ts +1 -1
- package/src/index.ts +5 -5
- package/src/tapClientList.ts +27 -14
- package/src/tapClientLookup.ts +53 -33
- package/src/tapClientResource.ts +12 -6
- package/src/types/client.ts +2 -2
- package/src/{useAssistantClient.tsx → useAui.tsx} +95 -52
- package/src/{useAssistantEvent.ts → useAuiEvent.ts} +3 -3
- package/src/{useAssistantState.tsx → useAuiState.tsx} +5 -7
- package/src/utils/NotificationManager.ts +3 -2
- package/src/utils/StoreResource.ts +3 -5
- package/src/utils/react-assistant-context.tsx +9 -8
- package/src/utils/splitClients.ts +22 -7
- package/src/utils/tap-assistant-context.ts +5 -6
- package/src/utils/tap-client-stack-context.ts +4 -4
- package/src/wrapperResource.ts +17 -0
- package/dist/AssistantIf.d.ts.map +0 -1
- package/dist/AssistantIf.js +0 -8
- package/dist/AssistantIf.js.map +0 -1
- package/dist/useAssistantClient.d.ts +0 -17
- package/dist/useAssistantClient.d.ts.map +0 -1
- package/dist/useAssistantClient.js.map +0 -1
- package/dist/useAssistantEvent.d.ts +0 -3
- package/dist/useAssistantEvent.d.ts.map +0 -1
- package/dist/useAssistantEvent.js.map +0 -1
- package/dist/useAssistantState.d.ts.map +0 -1
- package/dist/useAssistantState.js.map +0 -1
- package/src/AssistantIf.tsx +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/store",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Tap-based state management for @assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state-management",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"sideEffects": false,
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@assistant-ui/tap": "^0.
|
|
31
|
+
"@assistant-ui/tap": "^0.4.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@types/react": "*",
|
package/src/AuiIf.tsx
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { FC, PropsWithChildren } from "react";
|
|
4
|
+
import { useAuiState } from "./useAuiState";
|
|
5
|
+
import type { AssistantState } from "./types/client";
|
|
6
|
+
|
|
7
|
+
export namespace AuiIf {
|
|
8
|
+
export type Props = PropsWithChildren<{ condition: AuiIf.Condition }>;
|
|
9
|
+
export type Condition = (state: AssistantState) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const AuiIf: FC<AuiIf.Props> = ({ children, condition }) => {
|
|
13
|
+
const result = useAuiState(condition);
|
|
14
|
+
return result ? children : null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
AuiIf.displayName = "AuiIf";
|
package/src/Derived.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// hooks
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
2
|
+
export { useAui } from "./useAui";
|
|
3
|
+
export { useAuiState } from "./useAuiState";
|
|
4
|
+
export { useAuiEvent } from "./useAuiEvent";
|
|
5
5
|
|
|
6
6
|
// components
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
7
|
+
export { AuiIf } from "./AuiIf";
|
|
8
|
+
export { AuiProvider } from "./utils/react-assistant-context";
|
|
9
9
|
|
|
10
10
|
// resources
|
|
11
11
|
export { Derived } from "./Derived";
|
package/src/tapClientList.ts
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import { tapState } from "@assistant-ui/tap";
|
|
1
|
+
import { tapConst, tapState, withKey } from "@assistant-ui/tap";
|
|
2
2
|
import type { ContravariantResource } from "@assistant-ui/tap";
|
|
3
3
|
import { tapClientLookup } from "./tapClientLookup";
|
|
4
4
|
import type { ClientMethods, ClientOutputOf } from "./types/client";
|
|
5
5
|
|
|
6
|
+
type DataHandle<TData> = { data: TData | undefined; hasData: boolean };
|
|
7
|
+
|
|
6
8
|
const createProps = <TData>(
|
|
7
9
|
key: string,
|
|
8
|
-
data: TData
|
|
10
|
+
data: DataHandle<TData>,
|
|
9
11
|
remove: () => void,
|
|
10
12
|
): tapClientList.ResourceProps<TData> => {
|
|
11
|
-
let initialData: { data: TData } | undefined = { data };
|
|
12
13
|
return {
|
|
13
14
|
key,
|
|
14
15
|
getInitialData: () => {
|
|
15
|
-
if (!
|
|
16
|
-
throw new Error(
|
|
16
|
+
if (!data.hasData) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"getInitialData may only be called during initial render",
|
|
19
|
+
);
|
|
17
20
|
}
|
|
18
|
-
|
|
19
|
-
initialData = undefined;
|
|
20
|
-
return data;
|
|
21
|
+
return data.data!;
|
|
21
22
|
},
|
|
22
23
|
remove,
|
|
23
24
|
};
|
|
@@ -34,13 +35,16 @@ export const tapClientList = <TData, TState, TMethods extends ClientMethods>(
|
|
|
34
35
|
|
|
35
36
|
type Props = tapClientList.ResourceProps<TData>;
|
|
36
37
|
|
|
38
|
+
const initialDataHandles: DataHandle<TData>[] = tapConst(() => [], []);
|
|
39
|
+
|
|
37
40
|
const [items, setItems] = tapState<Record<string, Props>>(() => {
|
|
38
41
|
const entries: [string, Props][] = [];
|
|
39
42
|
for (const data of initialValues) {
|
|
40
43
|
const key = getKey(data);
|
|
44
|
+
const handle = { data, hasData: true };
|
|
41
45
|
entries.push([
|
|
42
46
|
key,
|
|
43
|
-
createProps(key,
|
|
47
|
+
createProps(key, handle, () => {
|
|
44
48
|
setItems((items) => {
|
|
45
49
|
const newItems = { ...items };
|
|
46
50
|
delete newItems[key];
|
|
@@ -48,16 +52,22 @@ export const tapClientList = <TData, TState, TMethods extends ClientMethods>(
|
|
|
48
52
|
});
|
|
49
53
|
}),
|
|
50
54
|
]);
|
|
55
|
+
initialDataHandles.push(handle);
|
|
51
56
|
}
|
|
52
57
|
return Object.fromEntries(entries);
|
|
53
58
|
});
|
|
54
59
|
|
|
55
|
-
const lookup = tapClientLookup<TState, TMethods
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
[Resource],
|
|
60
|
+
const lookup = tapClientLookup<TState, TMethods>(
|
|
61
|
+
() =>
|
|
62
|
+
Object.values(items).map((props) => withKey(props.key, Resource(props))),
|
|
63
|
+
[items, Resource],
|
|
59
64
|
);
|
|
60
65
|
|
|
66
|
+
initialDataHandles.forEach((handle) => {
|
|
67
|
+
handle.data = undefined;
|
|
68
|
+
handle.hasData = false;
|
|
69
|
+
});
|
|
70
|
+
|
|
61
71
|
const add = (data: TData) => {
|
|
62
72
|
const key = getKey(data);
|
|
63
73
|
setItems((items) => {
|
|
@@ -67,9 +77,12 @@ export const tapClientList = <TData, TState, TMethods extends ClientMethods>(
|
|
|
67
77
|
);
|
|
68
78
|
}
|
|
69
79
|
|
|
80
|
+
const handle = { data, hasData: true };
|
|
81
|
+
initialDataHandles.push(handle);
|
|
82
|
+
|
|
70
83
|
return {
|
|
71
84
|
...items,
|
|
72
|
-
[key]: createProps(key,
|
|
85
|
+
[key]: createProps(key, handle, () => {
|
|
73
86
|
setItems((items) => {
|
|
74
87
|
const newItems = { ...items };
|
|
75
88
|
delete newItems[key];
|
package/src/tapClientLookup.ts
CHANGED
|
@@ -1,56 +1,76 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
tapInlineResource,
|
|
3
|
+
tapMemo,
|
|
4
|
+
tapResources,
|
|
5
|
+
type ResourceElement,
|
|
6
|
+
} from "@assistant-ui/tap";
|
|
2
7
|
import type { ClientMethods, ClientOutputOf } from "./types/client";
|
|
3
8
|
import { ClientResource } from "./tapClientResource";
|
|
9
|
+
import { wrapperResource } from "./wrapperResource";
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
TState,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const ClientResourceWithKey = wrapperResource(
|
|
12
|
+
<TState, TMethods extends ClientMethods>(
|
|
13
|
+
el: ResourceElement<ClientOutputOf<TState, TMethods>>,
|
|
14
|
+
) => {
|
|
15
|
+
if (el.key === undefined) {
|
|
16
|
+
throw new Error("tapClientResource: Element has no key");
|
|
17
|
+
}
|
|
18
|
+
return tapInlineResource(ClientResource(el)) as ClientOutputOf<
|
|
19
|
+
TState,
|
|
20
|
+
TMethods
|
|
21
|
+
> & { key: string | number };
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export function tapClientLookup<TState, TMethods extends ClientMethods>(
|
|
26
|
+
getElements: () => readonly ResourceElement<
|
|
27
|
+
ClientOutputOf<TState, TMethods>
|
|
28
|
+
>[],
|
|
29
|
+
getElementsDeps: readonly unknown[],
|
|
16
30
|
): {
|
|
17
31
|
state: TState[];
|
|
18
|
-
get: (lookup: { index: number } | { key:
|
|
19
|
-
}
|
|
32
|
+
get: (lookup: { index: number } | { key: string }) => TMethods;
|
|
33
|
+
} {
|
|
20
34
|
const resources = tapResources(
|
|
21
|
-
map,
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
() => getElements().map((el) => ClientResourceWithKey(el)),
|
|
36
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: getElementsDeps is passed through from caller
|
|
37
|
+
getElementsDeps,
|
|
24
38
|
);
|
|
25
|
-
|
|
39
|
+
|
|
40
|
+
const keys = tapMemo(() => Object.keys(resources), [resources]);
|
|
41
|
+
|
|
42
|
+
// For arrays, track element key -> index mapping
|
|
43
|
+
const keyToIndex = tapMemo(() => {
|
|
44
|
+
return resources.reduce(
|
|
45
|
+
(acc, resource, index) => {
|
|
46
|
+
acc[resource.key] = index;
|
|
47
|
+
return acc;
|
|
48
|
+
},
|
|
49
|
+
{} as Record<string, number>,
|
|
50
|
+
);
|
|
51
|
+
}, [resources]);
|
|
26
52
|
|
|
27
53
|
const state = tapMemo(() => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
result[i] = resources[keys[i]!].state;
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}, [keys, resources]);
|
|
54
|
+
return resources.map((r) => r.state);
|
|
55
|
+
}, [resources]);
|
|
34
56
|
|
|
35
57
|
return {
|
|
36
58
|
state,
|
|
37
|
-
get: (lookup: { index: number } | { key:
|
|
59
|
+
get: (lookup: { index: number } | { key: string }) => {
|
|
38
60
|
if ("index" in lookup) {
|
|
39
61
|
if (lookup.index < 0 || lookup.index >= keys.length) {
|
|
40
62
|
throw new Error(
|
|
41
63
|
`tapClientLookup: Index ${lookup.index} out of bounds (length: ${keys.length})`,
|
|
42
64
|
);
|
|
43
65
|
}
|
|
44
|
-
return resources[
|
|
66
|
+
return resources[lookup.index]!.methods;
|
|
45
67
|
}
|
|
46
68
|
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
throw new Error(
|
|
50
|
-
`tapClientLookup: Key "${String(lookup.key)}" not found`,
|
|
51
|
-
);
|
|
69
|
+
const index = keyToIndex[lookup.key];
|
|
70
|
+
if (index === undefined) {
|
|
71
|
+
throw new Error(`tapClientLookup: Key "${lookup.key}" not found`);
|
|
52
72
|
}
|
|
53
|
-
return
|
|
73
|
+
return resources[index]!.methods;
|
|
54
74
|
},
|
|
55
75
|
};
|
|
56
|
-
}
|
|
76
|
+
}
|
package/src/tapClientResource.ts
CHANGED
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
tapRef,
|
|
5
5
|
type ResourceElement,
|
|
6
6
|
tapResource,
|
|
7
|
-
resource,
|
|
8
7
|
tapInlineResource,
|
|
9
8
|
} from "@assistant-ui/tap";
|
|
10
9
|
import type { ClientMethods, ClientOutputOf } from "./types/client";
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
BaseProxyHandler,
|
|
18
17
|
handleIntrospectionProp,
|
|
19
18
|
} from "./utils/BaseProxyHandler";
|
|
19
|
+
import { wrapperResource } from "./wrapperResource";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Symbol used internally to get state from ClientProxy.
|
|
@@ -57,6 +57,8 @@ function getOrCreateProxyFn(prop: string | symbol) {
|
|
|
57
57
|
const method = this[SYMBOL_GET_OUTPUT].methods[prop];
|
|
58
58
|
if (!method)
|
|
59
59
|
throw new Error(`Method "${String(prop)}" is not implemented.`);
|
|
60
|
+
if (typeof method !== "function")
|
|
61
|
+
throw new Error(`"${String(prop)}" is not a function.`);
|
|
60
62
|
return method(...args);
|
|
61
63
|
};
|
|
62
64
|
fieldAccessFns.set(prop, template);
|
|
@@ -82,7 +84,9 @@ class ClientProxyHandler
|
|
|
82
84
|
if (prop === SYMBOL_CLIENT_INDEX) return this.index;
|
|
83
85
|
const introspection = handleIntrospectionProp(prop, "ClientProxy");
|
|
84
86
|
if (introspection !== false) return introspection;
|
|
85
|
-
|
|
87
|
+
const value = this.outputRef.current.methods[prop];
|
|
88
|
+
if (typeof value === "function") return getOrCreateProxyFn(prop);
|
|
89
|
+
return value;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
ownKeys(): ArrayLike<string | symbol> {
|
|
@@ -114,10 +118,12 @@ class ClientProxyHandler
|
|
|
114
118
|
* });
|
|
115
119
|
* ```
|
|
116
120
|
*/
|
|
117
|
-
export const ClientResource =
|
|
121
|
+
export const ClientResource = wrapperResource(
|
|
118
122
|
<TState, TMethods extends ClientMethods>(
|
|
119
123
|
element: ResourceElement<ClientOutputOf<TState, TMethods>>,
|
|
120
|
-
): ClientOutputOf<TState, TMethods>
|
|
124
|
+
): ClientOutputOf<TState, TMethods> & {
|
|
125
|
+
key: string | number | undefined;
|
|
126
|
+
} => {
|
|
121
127
|
const valueRef = tapRef(
|
|
122
128
|
null as unknown as ClientOutputOf<TState, TMethods>,
|
|
123
129
|
);
|
|
@@ -129,7 +135,7 @@ export const ClientResource = resource(
|
|
|
129
135
|
{} as TMethods,
|
|
130
136
|
new ClientProxyHandler(valueRef, index),
|
|
131
137
|
),
|
|
132
|
-
[],
|
|
138
|
+
[index],
|
|
133
139
|
);
|
|
134
140
|
|
|
135
141
|
const value = tapWithClientStack(methods, () => tapResource(element));
|
|
@@ -141,7 +147,7 @@ export const ClientResource = resource(
|
|
|
141
147
|
valueRef.current = value;
|
|
142
148
|
});
|
|
143
149
|
|
|
144
|
-
return { methods, state: value.state };
|
|
150
|
+
return { methods, state: value.state, key: element.key };
|
|
145
151
|
},
|
|
146
152
|
);
|
|
147
153
|
|
package/src/types/client.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
* Base type for methods that can be called on a client.
|
|
10
10
|
*/
|
|
11
11
|
export interface ClientMethods {
|
|
12
|
-
[key: string | symbol]: (...args: any[]) => any;
|
|
12
|
+
[key: string | symbol]: ((...args: any[]) => any) | ClientMethods;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
type ClientMetaType = { source: ClientNames; query: Record<string, unknown> };
|
|
@@ -170,7 +170,7 @@ export type AssistantClientAccessor<K extends ClientNames> =
|
|
|
170
170
|
| ClientMeta<K>
|
|
171
171
|
| { source: "root"; query: Record<string, never> }
|
|
172
172
|
| { source: null; query: null }
|
|
173
|
-
);
|
|
173
|
+
) & { name: K };
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
176
|
* The assistant client type with all registered clients.
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
tapEffect,
|
|
11
11
|
tapRef,
|
|
12
12
|
tapResource,
|
|
13
|
+
withKey,
|
|
13
14
|
} from "@assistant-ui/tap";
|
|
14
15
|
import type {
|
|
15
16
|
AssistantClient,
|
|
@@ -28,7 +29,7 @@ import {
|
|
|
28
29
|
import {
|
|
29
30
|
DerivedClients,
|
|
30
31
|
RootClients,
|
|
31
|
-
|
|
32
|
+
tapSplitClients,
|
|
32
33
|
} from "./utils/splitClients";
|
|
33
34
|
import {
|
|
34
35
|
normalizeEventSelector,
|
|
@@ -59,7 +60,7 @@ const RootClientResource = resource(
|
|
|
59
60
|
{ clientRef, emit },
|
|
60
61
|
() => tapClientResource(element),
|
|
61
62
|
);
|
|
62
|
-
return tapMemo(() => ({ methods }), [state]);
|
|
63
|
+
return tapMemo(() => ({ state, methods }), [methods, state]);
|
|
63
64
|
},
|
|
64
65
|
);
|
|
65
66
|
|
|
@@ -68,10 +69,12 @@ const RootClientAccessorResource = resource(
|
|
|
68
69
|
element,
|
|
69
70
|
notifications,
|
|
70
71
|
clientRef,
|
|
72
|
+
name,
|
|
71
73
|
}: {
|
|
72
74
|
element: ClientElement<K>;
|
|
73
75
|
notifications: NotificationManager;
|
|
74
76
|
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
77
|
+
name: K;
|
|
75
78
|
}): AssistantClientAccessor<K> => {
|
|
76
79
|
const store = tapInlineResource(
|
|
77
80
|
StoreResource(
|
|
@@ -84,17 +87,33 @@ const RootClientAccessorResource = resource(
|
|
|
84
87
|
}, [store, notifications]);
|
|
85
88
|
|
|
86
89
|
return tapMemo(() => {
|
|
87
|
-
const clientFunction = () => store.
|
|
88
|
-
clientFunction
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const clientFunction = () => store.getValue().methods;
|
|
91
|
+
Object.defineProperties(clientFunction, {
|
|
92
|
+
source: {
|
|
93
|
+
value: "root" as const,
|
|
94
|
+
writable: false,
|
|
95
|
+
},
|
|
96
|
+
query: {
|
|
97
|
+
value: {} as Record<string, never>,
|
|
98
|
+
writable: false,
|
|
99
|
+
},
|
|
100
|
+
name: {
|
|
101
|
+
value: name,
|
|
102
|
+
configurable: true,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
return clientFunction as AssistantClientAccessor<K>;
|
|
106
|
+
}, [store, name]);
|
|
92
107
|
},
|
|
93
108
|
);
|
|
94
109
|
|
|
95
110
|
const NoOpRootClientsAccessorsResource = resource(() => {
|
|
96
111
|
return tapMemo(
|
|
97
|
-
() => ({
|
|
112
|
+
() => ({
|
|
113
|
+
clients: [] as AssistantClientAccessor<ClientNames>[],
|
|
114
|
+
subscribe: undefined,
|
|
115
|
+
on: undefined,
|
|
116
|
+
}),
|
|
98
117
|
[],
|
|
99
118
|
);
|
|
100
119
|
});
|
|
@@ -115,14 +134,19 @@ const RootClientsAccessorsResource = resource(
|
|
|
115
134
|
);
|
|
116
135
|
|
|
117
136
|
const results = tapResources(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
() =>
|
|
138
|
+
Object.keys(inputClients).map((key) =>
|
|
139
|
+
withKey(
|
|
140
|
+
key,
|
|
141
|
+
RootClientAccessorResource({
|
|
142
|
+
element: inputClients[key as keyof typeof inputClients]!,
|
|
143
|
+
notifications,
|
|
144
|
+
clientRef,
|
|
145
|
+
name: key as keyof typeof inputClients,
|
|
146
|
+
}),
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
[inputClients, notifications, clientRef],
|
|
126
150
|
);
|
|
127
151
|
|
|
128
152
|
return tapMemo(() => {
|
|
@@ -136,7 +160,7 @@ const RootClientsAccessorsResource = resource(
|
|
|
136
160
|
) {
|
|
137
161
|
if (!this) {
|
|
138
162
|
throw new Error(
|
|
139
|
-
"const { on } =
|
|
163
|
+
"const { on } = useAui() is not supported. Use aui.on() instead.",
|
|
140
164
|
);
|
|
141
165
|
}
|
|
142
166
|
|
|
@@ -203,9 +227,11 @@ const DerivedClientAccessorResource = resource(
|
|
|
203
227
|
<K extends ClientNames>({
|
|
204
228
|
element,
|
|
205
229
|
clientRef,
|
|
230
|
+
name,
|
|
206
231
|
}: {
|
|
207
232
|
element: DerivedElement<K>;
|
|
208
233
|
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
234
|
+
name: K;
|
|
209
235
|
}) => {
|
|
210
236
|
const get = tapEffectEvent(() => element.props);
|
|
211
237
|
|
|
@@ -219,9 +245,13 @@ const DerivedClientAccessorResource = resource(
|
|
|
219
245
|
query: {
|
|
220
246
|
get: () => getMeta(get(), clientRef, metaMemo).query,
|
|
221
247
|
},
|
|
248
|
+
name: {
|
|
249
|
+
value: name,
|
|
250
|
+
configurable: true,
|
|
251
|
+
},
|
|
222
252
|
});
|
|
223
|
-
return clientFunction
|
|
224
|
-
}, [clientRef]);
|
|
253
|
+
return clientFunction as AssistantClientAccessor<K>;
|
|
254
|
+
}, [clientRef, name]);
|
|
225
255
|
},
|
|
226
256
|
);
|
|
227
257
|
|
|
@@ -234,13 +264,18 @@ const DerivedClientsAccessorsResource = resource(
|
|
|
234
264
|
clientRef: { parent: AssistantClient; current: AssistantClient | null };
|
|
235
265
|
}) => {
|
|
236
266
|
return tapResources(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
267
|
+
() =>
|
|
268
|
+
Object.keys(clients).map((key) =>
|
|
269
|
+
withKey(
|
|
270
|
+
key,
|
|
271
|
+
DerivedClientAccessorResource({
|
|
272
|
+
element: clients[key as keyof typeof clients]!,
|
|
273
|
+
clientRef,
|
|
274
|
+
name: key as keyof typeof clients,
|
|
275
|
+
}),
|
|
276
|
+
),
|
|
277
|
+
),
|
|
278
|
+
[clients, clientRef],
|
|
244
279
|
);
|
|
245
280
|
},
|
|
246
281
|
);
|
|
@@ -250,19 +285,26 @@ const DerivedClientsAccessorsResource = resource(
|
|
|
250
285
|
*/
|
|
251
286
|
export const AssistantClientResource = resource(
|
|
252
287
|
({
|
|
253
|
-
|
|
288
|
+
parent,
|
|
254
289
|
clients,
|
|
255
290
|
}: {
|
|
256
|
-
|
|
257
|
-
clients:
|
|
291
|
+
parent: AssistantClient;
|
|
292
|
+
clients: useAui.Props;
|
|
258
293
|
}): AssistantClient => {
|
|
259
|
-
const { rootClients, derivedClients } =
|
|
294
|
+
const { rootClients, derivedClients } = tapSplitClients(clients, parent);
|
|
260
295
|
|
|
261
296
|
const clientRef = tapRef({
|
|
262
|
-
parent:
|
|
297
|
+
parent: parent,
|
|
263
298
|
current: null as AssistantClient | null,
|
|
264
299
|
}).current;
|
|
265
300
|
|
|
301
|
+
tapEffect(() => {
|
|
302
|
+
// if (clientRef.current && clientRef.current !== client)
|
|
303
|
+
// throw new Error("clientRef.current !== client");
|
|
304
|
+
|
|
305
|
+
clientRef.current = client;
|
|
306
|
+
});
|
|
307
|
+
|
|
266
308
|
const rootFields = tapResource(
|
|
267
309
|
Object.keys(rootClients).length > 0
|
|
268
310
|
? RootClientsAccessorsResource({ clients: rootClients, clientRef })
|
|
@@ -276,46 +318,47 @@ export const AssistantClientResource = resource(
|
|
|
276
318
|
const client = tapMemo(() => {
|
|
277
319
|
// Swap DefaultAssistantClient -> createRootAssistantClient at root to change error message
|
|
278
320
|
const proto =
|
|
279
|
-
|
|
321
|
+
parent === DefaultAssistantClient
|
|
280
322
|
? createRootAssistantClient()
|
|
281
|
-
:
|
|
323
|
+
: parent;
|
|
324
|
+
|
|
282
325
|
const client = Object.create(proto) as AssistantClient;
|
|
283
|
-
Object.assign(client,
|
|
284
|
-
subscribe: rootFields.subscribe ??
|
|
285
|
-
on: rootFields.on ??
|
|
326
|
+
Object.assign(client, {
|
|
327
|
+
subscribe: rootFields.subscribe ?? parent.subscribe,
|
|
328
|
+
on: rootFields.on ?? parent.on,
|
|
286
329
|
[PROXIED_ASSISTANT_STATE_SYMBOL]: createProxiedAssistantState(client),
|
|
287
330
|
});
|
|
331
|
+
|
|
332
|
+
for (const field of rootFields.clients) {
|
|
333
|
+
(client as any)[field.name] = field;
|
|
334
|
+
}
|
|
335
|
+
for (const field of derivedFields) {
|
|
336
|
+
(client as any)[field.name] = field;
|
|
337
|
+
}
|
|
338
|
+
|
|
288
339
|
return client;
|
|
289
|
-
}, [
|
|
340
|
+
}, [parent, rootFields, derivedFields]);
|
|
290
341
|
|
|
291
342
|
if (clientRef.current === null) {
|
|
292
343
|
clientRef.current = client;
|
|
293
344
|
}
|
|
294
345
|
|
|
295
|
-
tapEffect(() => {
|
|
296
|
-
clientRef.current = client;
|
|
297
|
-
});
|
|
298
|
-
|
|
299
346
|
return client;
|
|
300
347
|
},
|
|
301
348
|
);
|
|
302
349
|
|
|
303
|
-
export namespace
|
|
350
|
+
export namespace useAui {
|
|
304
351
|
export type Props = {
|
|
305
352
|
[K in ClientNames]?: ClientElement<K> | DerivedElement<K>;
|
|
306
353
|
};
|
|
307
354
|
}
|
|
308
355
|
|
|
309
|
-
export function
|
|
310
|
-
export function
|
|
311
|
-
|
|
312
|
-
)
|
|
313
|
-
export function useAssistantClient(
|
|
314
|
-
clients?: useAssistantClient.Props,
|
|
315
|
-
): AssistantClient {
|
|
316
|
-
const baseClient = useAssistantContextValue();
|
|
356
|
+
export function useAui(): AssistantClient;
|
|
357
|
+
export function useAui(clients: useAui.Props): AssistantClient;
|
|
358
|
+
export function useAui(clients?: useAui.Props): AssistantClient {
|
|
359
|
+
const parent = useAssistantContextValue();
|
|
317
360
|
if (clients) {
|
|
318
|
-
return useResource(AssistantClientResource({
|
|
361
|
+
return useResource(AssistantClientResource({ parent: parent, clients }));
|
|
319
362
|
}
|
|
320
|
-
return
|
|
363
|
+
return parent;
|
|
321
364
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useEffectEvent } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useAui } from "./useAui";
|
|
3
3
|
import type {
|
|
4
4
|
AssistantEventName,
|
|
5
5
|
AssistantEventCallback,
|
|
@@ -7,11 +7,11 @@ import type {
|
|
|
7
7
|
} from "./types/events";
|
|
8
8
|
import { normalizeEventSelector } from "./types/events";
|
|
9
9
|
|
|
10
|
-
export const
|
|
10
|
+
export const useAuiEvent = <TEvent extends AssistantEventName>(
|
|
11
11
|
selector: AssistantEventSelector<TEvent>,
|
|
12
12
|
callback: AssistantEventCallback<TEvent>,
|
|
13
13
|
) => {
|
|
14
|
-
const aui =
|
|
14
|
+
const aui = useAui();
|
|
15
15
|
const callbackRef = useEffectEvent(callback);
|
|
16
16
|
|
|
17
17
|
const { scope, event } = normalizeEventSelector(selector);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSyncExternalStore, useDebugValue } from "react";
|
|
2
2
|
import type { AssistantState } from "./types/client";
|
|
3
|
-
import {
|
|
3
|
+
import { useAui } from "./useAui";
|
|
4
4
|
import { getProxiedAssistantState } from "./utils/proxied-assistant-state";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -11,17 +11,15 @@ import { getProxiedAssistantState } from "./utils/proxied-assistant-state";
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```typescript
|
|
14
|
-
* const aui =
|
|
14
|
+
* const aui = useAui({
|
|
15
15
|
* foo: RootScope({ ... }),
|
|
16
16
|
* });
|
|
17
17
|
*
|
|
18
|
-
* const bar =
|
|
18
|
+
* const bar = useAuiState((state) => state.foo.bar);
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
): T => {
|
|
24
|
-
const aui = useAssistantClient();
|
|
21
|
+
export const useAuiState = <T,>(selector: (state: AssistantState) => T): T => {
|
|
22
|
+
const aui = useAui();
|
|
25
23
|
const proxiedState = getProxiedAssistantState(aui);
|
|
26
24
|
|
|
27
25
|
const slice = useSyncExternalStore(
|