@assistant-ui/store 0.2.2 → 0.2.4
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/RenderChildrenWithAccessor.d.ts +23 -0
- package/dist/RenderChildrenWithAccessor.d.ts.map +1 -0
- package/dist/RenderChildrenWithAccessor.js +53 -0
- package/dist/RenderChildrenWithAccessor.js.map +1 -0
- package/dist/attachTransformScopes.d.ts +1 -1
- package/dist/attachTransformScopes.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/splitClients.js +2 -2
- package/dist/utils/splitClients.js.map +1 -1
- package/package.json +6 -6
- package/src/RenderChildrenWithAccessor.tsx +73 -0
- package/src/attachTransformScopes.ts +1 -1
- package/src/index.ts +1 -0
- package/src/utils/splitClients.ts +2 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AssistantClient } from "./types/client.js";
|
|
3
|
+
export declare const useGetItemAccessor: <T>(getItemState: (aui: AssistantClient) => T) => () => T;
|
|
4
|
+
/**
|
|
5
|
+
* Component that sets up a lazy item accessor and memoizes propless children.
|
|
6
|
+
*
|
|
7
|
+
* For the common pattern where children returns a component without props
|
|
8
|
+
* (e.g. `<Foo />`), the output is memoized and not re-created on parent re-renders.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <RenderChildrenWithAccessor
|
|
13
|
+
* getItemState={(aui) => aui.fooList().foo({ index }).getState()}
|
|
14
|
+
* >
|
|
15
|
+
* {() => <Foo />}
|
|
16
|
+
* </RenderChildrenWithAccessor>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function RenderChildrenWithAccessor<T>({ getItemState, children, }: {
|
|
20
|
+
getItemState: (aui: AssistantClient) => T;
|
|
21
|
+
children: (getItem: () => T) => ReactNode;
|
|
22
|
+
}): ReactNode;
|
|
23
|
+
//# sourceMappingURL=RenderChildrenWithAccessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RenderChildrenWithAccessor.d.ts","sourceRoot":"","sources":["../src/RenderChildrenWithAccessor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,0BAAuB;AAItD,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,cAAc,CAAC,GAAG,EAAE,eAAe,KAAK,CAAC,YAkB1C,CAAC;AAIF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,EAC5C,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC;CAC3C,GAAG,SAAS,CAGZ"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo, useRef } from "react";
|
|
3
|
+
import { useAuiState } from "./useAuiState.js";
|
|
4
|
+
import { useAui } from "./useAui.js";
|
|
5
|
+
export const useGetItemAccessor = (getItemState) => {
|
|
6
|
+
const aui = useAui();
|
|
7
|
+
// if the consumer never accesses the item, do not trigger rerenders
|
|
8
|
+
const cacheRef = useRef(undefined);
|
|
9
|
+
useAuiState(() => {
|
|
10
|
+
if (cacheRef.current === undefined) {
|
|
11
|
+
cacheRef.current = getItemState(aui);
|
|
12
|
+
}
|
|
13
|
+
return cacheRef.current;
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
cacheRef.current = undefined; // clear the cache (rerender on next state change)
|
|
17
|
+
return getItemState(aui);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
const EMPTY_OBJECT = Object.freeze({});
|
|
21
|
+
/**
|
|
22
|
+
* Component that sets up a lazy item accessor and memoizes propless children.
|
|
23
|
+
*
|
|
24
|
+
* For the common pattern where children returns a component without props
|
|
25
|
+
* (e.g. `<Foo />`), the output is memoized and not re-created on parent re-renders.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <RenderChildrenWithAccessor
|
|
30
|
+
* getItemState={(aui) => aui.fooList().foo({ index }).getState()}
|
|
31
|
+
* >
|
|
32
|
+
* {() => <Foo />}
|
|
33
|
+
* </RenderChildrenWithAccessor>
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function RenderChildrenWithAccessor({ getItemState, children, }) {
|
|
37
|
+
const getItem = useGetItemAccessor(getItemState);
|
|
38
|
+
return useMemoizedProplessComponent(children(getItem));
|
|
39
|
+
}
|
|
40
|
+
const useMemoizedProplessComponent = (node) => {
|
|
41
|
+
const el = typeof node === "object" && node != null && "type" in node ? node : null;
|
|
42
|
+
const resultType = el?.type;
|
|
43
|
+
const resultKey = el?.key;
|
|
44
|
+
const resultProps = typeof el?.props === "object" &&
|
|
45
|
+
el.props != null &&
|
|
46
|
+
Object.entries(el.props).length === 0
|
|
47
|
+
? EMPTY_OBJECT
|
|
48
|
+
: el?.props;
|
|
49
|
+
return (
|
|
50
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: optimization
|
|
51
|
+
useMemo(() => el, [resultType, resultKey, resultProps]) ?? node);
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=RenderChildrenWithAccessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RenderChildrenWithAccessor.js","sourceRoot":"","sources":["../src/RenderChildrenWithAccessor.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAkB,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,MAAM,EAAE,oBAAiB;AAElC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,YAAyC,EACzC,EAAE;IACF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IAErB,oEAAoE;IACpE,MAAM,QAAQ,GAAG,MAAM,CAAgB,SAAS,CAAC,CAAC;IAClD,WAAW,CAAC,GAAG,EAAE;QACf,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,EAAE;QACV,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,kDAAkD;QAEhF,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,0BAA0B,CAAI,EAC5C,YAAY,EACZ,QAAQ,GAIT;IACC,MAAM,OAAO,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACjD,OAAO,4BAA4B,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,4BAA4B,GAAG,CAAC,IAAe,EAAE,EAAE;IACvD,MAAM,EAAE,GACN,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,MAAM,UAAU,GAAG,EAAE,EAAE,IAAI,CAAC;IAC5B,MAAM,SAAS,GAAG,EAAE,EAAE,GAAG,CAAC;IAC1B,MAAM,WAAW,GACf,OAAO,EAAE,EAAE,KAAK,KAAK,QAAQ;QAC7B,EAAE,CAAC,KAAK,IAAI,IAAI;QAChB,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC;QACnC,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC;IAEhB,OAAO;IACL,wEAAwE;IACxE,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,IAAI,IAAI,CAChE,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -4,7 +4,7 @@ import type { DerivedElement } from "./Derived.js";
|
|
|
4
4
|
export type ScopesConfig = {
|
|
5
5
|
[K in ClientNames]?: ClientElement<K> | DerivedElement<K>;
|
|
6
6
|
};
|
|
7
|
-
type TransformScopesFn = (scopes: ScopesConfig, parent: AssistantClient) =>
|
|
7
|
+
type TransformScopesFn = (scopes: ScopesConfig, parent: AssistantClient) => void;
|
|
8
8
|
export declare function attachTransformScopes<T extends (...args: any[]) => ResourceElement<any>>(resource: T, transform: TransformScopesFn): void;
|
|
9
9
|
export declare function getTransformScopes<T extends (...args: any[]) => ResourceElement<any>>(resource: T): TransformScopesFn | undefined;
|
|
10
10
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachTransformScopes.d.ts","sourceRoot":"","sources":["../src/attachTransformScopes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,WAAW,EACZ,0BAAuB;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAkB;AAIhD,MAAM,MAAM,YAAY,GAAG;KACxB,CAAC,IAAI,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;CAC1D,CAAC;AAEF,KAAK,iBAAiB,GAAG,CACvB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,eAAe,KACpB,
|
|
1
|
+
{"version":3,"file":"attachTransformScopes.d.ts","sourceRoot":"","sources":["../src/attachTransformScopes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,WAAW,EACZ,0BAAuB;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAkB;AAIhD,MAAM,MAAM,YAAY,GAAG;KACxB,CAAC,IAAI,WAAW,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;CAC1D,CAAC;AAEF,KAAK,iBAAiB,GAAG,CACvB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,eAAe,KACpB,IAAI,CAAC;AAMV,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,eAAe,CAAC,GAAG,CAAC,EAClD,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAMjD;AAED,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,eAAe,CAAC,GAAG,CAAC,EAClD,QAAQ,EAAE,CAAC,GAAG,iBAAiB,GAAG,SAAS,CAE5C"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { useAui } from "./useAui.js";
|
|
2
2
|
export { useAuiState } from "./useAuiState.js";
|
|
3
3
|
export { useAuiEvent } from "./useAuiEvent.js";
|
|
4
|
+
export { RenderChildrenWithAccessor } from "./RenderChildrenWithAccessor.js";
|
|
4
5
|
export { AuiIf } from "./AuiIf.js";
|
|
5
6
|
export { AuiProvider } from "./utils/react-assistant-context.js";
|
|
6
7
|
export { Derived } from "./Derived.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,oBAAiB;AAClC,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,WAAW,EAAE,yBAAsB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,oBAAiB;AAClC,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,0BAA0B,EAAE,wCAAqC;AAG1E,OAAO,EAAE,KAAK,EAAE,mBAAgB;AAChC,OAAO,EAAE,WAAW,EAAE,2CAAwC;AAG9D,OAAO,EAAE,OAAO,EAAE,qBAAkB;AACpC,OAAO,EAAE,qBAAqB,EAAE,mCAAgC;AAChE,YAAY,EAAE,YAAY,EAAE,mCAAgC;AAG5D,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GACjB,yCAAsC;AACvC,OAAO,EAAE,iBAAiB,EAAE,+BAA4B;AACxD,OAAO,EAAE,eAAe,EAAE,6BAA0B;AACpD,OAAO,EAAE,aAAa,EAAE,2BAAwB;AAGhD,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,eAAe,EACf,cAAc,GACf,0BAAuB;AACxB,OAAO,EACL,sBAAsB,EACtB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,GACzB,0BAAuB"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { useAui } from "./useAui.js";
|
|
3
3
|
export { useAuiState } from "./useAuiState.js";
|
|
4
4
|
export { useAuiEvent } from "./useAuiEvent.js";
|
|
5
|
+
export { RenderChildrenWithAccessor } from "./RenderChildrenWithAccessor.js";
|
|
5
6
|
// components
|
|
6
7
|
export { AuiIf } from "./AuiIf.js";
|
|
7
8
|
export { AuiProvider } from "./utils/react-assistant-context.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,oBAAiB;AAClC,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,WAAW,EAAE,yBAAsB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,oBAAiB;AAClC,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAC5C,OAAO,EAAE,0BAA0B,EAAE,wCAAqC;AAE1E,aAAa;AACb,OAAO,EAAE,KAAK,EAAE,mBAAgB;AAChC,OAAO,EAAE,WAAW,EAAE,2CAAwC;AAE9D,YAAY;AACZ,OAAO,EAAE,OAAO,EAAE,qBAAkB;AACpC,OAAO,EAAE,qBAAqB,EAAE,mCAAgC;AAGhE,YAAY;AACZ,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GACjB,yCAAsC;AACvC,OAAO,EAAE,iBAAiB,EAAE,+BAA4B;AACxD,OAAO,EAAE,eAAe,EAAE,6BAA0B;AACpD,OAAO,EAAE,aAAa,EAAE,2BAAwB;AAiBhD,OAAO,EACL,sBAAsB,GAMvB,0BAAuB"}
|
|
@@ -7,7 +7,7 @@ import { tapMemo } from "@assistant-ui/tap";
|
|
|
7
7
|
*/
|
|
8
8
|
function splitClients(clients, baseClient) {
|
|
9
9
|
// 1. Collect transforms from root elements and run them iteratively
|
|
10
|
-
|
|
10
|
+
const scopes = { ...clients };
|
|
11
11
|
const visited = new Set();
|
|
12
12
|
let changed = true;
|
|
13
13
|
while (changed) {
|
|
@@ -20,7 +20,7 @@ function splitClients(clients, baseClient) {
|
|
|
20
20
|
visited.add(clientElement.type);
|
|
21
21
|
const transform = getTransformScopes(clientElement.type);
|
|
22
22
|
if (transform) {
|
|
23
|
-
|
|
23
|
+
transform(scopes, baseClient);
|
|
24
24
|
changed = true;
|
|
25
25
|
break; // restart iteration since scopes may have new root elements
|
|
26
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"splitClients.js","sourceRoot":"","sources":["../../src/utils/splitClients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,sBAAmB;AAMrD,OAAO,EAAE,kBAAkB,EAAE,oCAAiC;AAE9D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAS5C;;;GAGG;AACH,SAAS,YAAY,CAAC,OAAqB,EAAE,UAA2B;IACtE,oEAAoE;IACpE,
|
|
1
|
+
{"version":3,"file":"splitClients.js","sourceRoot":"","sources":["../../src/utils/splitClients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,sBAAmB;AAMrD,OAAO,EAAE,kBAAkB,EAAE,oCAAiC;AAE9D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAS5C;;;GAGG;AACH,SAAS,YAAY,CAAC,OAAqB,EAAE,UAA2B;IACtE,oEAAoE;IACpE,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAG1B,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEnD,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,OAAO,OAAO,EAAE,CAAC;QACf,OAAO,GAAG,KAAK,CAAC;QAChB,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,aAAa,CAAC,IAAI,KAAM,OAAmB;gBAAE,SAAS;YAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC9C,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAEhC,MAAM,SAAS,GAAG,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;gBAC9B,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,4DAA4D;YACrE,CAAC;QACH,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,MAAM,WAAW,GAAgB,EAAE,CAAC;IACpC,MAAM,cAAc,GAAmB,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAGrD,EAAE,CAAC;QACJ,IAAI,aAAa,CAAC,IAAI,KAAM,OAAmB,EAAE,CAAC;YAChD,cAAc,CAAC,GAAG,CAAC,GAAG,aAA4C,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,GAAG,CAAC,GAAG,aAA2C,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,oBAAoB,GAAG,CAAmB,MAAS,EAAE,EAAE;IAC3D,wEAAwE;IACxE,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,OAAqB,EACrB,UAA2B,EAC3B,EAAE;IACF,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAE1E,OAAO;QACL,WAAW,EAAE,oBAAoB,CAAC,WAAW,CAAC;QAC9C,cAAc,EAAE,oBAAoB,CAAC,cAAc,CAAC;KACrD,CAAC;AACJ,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/store",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Tap-based state management for @assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state-management",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"use-effect-event": "^2.0.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@assistant-ui/tap": "^0.5.
|
|
34
|
+
"@assistant-ui/tap": "^0.5.4",
|
|
35
35
|
"@types/react": "*",
|
|
36
36
|
"react": "^18 || ^19"
|
|
37
37
|
},
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"@testing-library/react": "^16.3.2",
|
|
45
45
|
"@types/react": "^19.2.14",
|
|
46
46
|
"@types/react-dom": "^19.2.3",
|
|
47
|
-
"jsdom": "^
|
|
47
|
+
"jsdom": "^29.0.1",
|
|
48
48
|
"react": "^19.2.4",
|
|
49
|
-
"vitest": "^4.0
|
|
50
|
-
"@assistant-ui/tap": "0.5.
|
|
51
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
49
|
+
"vitest": "^4.1.0",
|
|
50
|
+
"@assistant-ui/tap": "0.5.4",
|
|
51
|
+
"@assistant-ui/x-buildutils": "0.0.3"
|
|
52
52
|
},
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type ReactNode, useMemo, useRef } from "react";
|
|
4
|
+
import type { AssistantClient } from "./types/client";
|
|
5
|
+
import { useAuiState } from "./useAuiState";
|
|
6
|
+
import { useAui } from "./useAui";
|
|
7
|
+
|
|
8
|
+
export const useGetItemAccessor = <T,>(
|
|
9
|
+
getItemState: (aui: AssistantClient) => T,
|
|
10
|
+
) => {
|
|
11
|
+
const aui = useAui();
|
|
12
|
+
|
|
13
|
+
// if the consumer never accesses the item, do not trigger rerenders
|
|
14
|
+
const cacheRef = useRef<T | undefined>(undefined);
|
|
15
|
+
useAuiState(() => {
|
|
16
|
+
if (cacheRef.current === undefined) {
|
|
17
|
+
cacheRef.current = getItemState(aui);
|
|
18
|
+
}
|
|
19
|
+
return cacheRef.current;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
cacheRef.current = undefined; // clear the cache (rerender on next state change)
|
|
24
|
+
|
|
25
|
+
return getItemState(aui);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const EMPTY_OBJECT = Object.freeze({});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Component that sets up a lazy item accessor and memoizes propless children.
|
|
33
|
+
*
|
|
34
|
+
* For the common pattern where children returns a component without props
|
|
35
|
+
* (e.g. `<Foo />`), the output is memoized and not re-created on parent re-renders.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <RenderChildrenWithAccessor
|
|
40
|
+
* getItemState={(aui) => aui.fooList().foo({ index }).getState()}
|
|
41
|
+
* >
|
|
42
|
+
* {() => <Foo />}
|
|
43
|
+
* </RenderChildrenWithAccessor>
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function RenderChildrenWithAccessor<T>({
|
|
47
|
+
getItemState,
|
|
48
|
+
children,
|
|
49
|
+
}: {
|
|
50
|
+
getItemState: (aui: AssistantClient) => T;
|
|
51
|
+
children: (getItem: () => T) => ReactNode;
|
|
52
|
+
}): ReactNode {
|
|
53
|
+
const getItem = useGetItemAccessor(getItemState);
|
|
54
|
+
return useMemoizedProplessComponent(children(getItem));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const useMemoizedProplessComponent = (node: ReactNode) => {
|
|
58
|
+
const el =
|
|
59
|
+
typeof node === "object" && node != null && "type" in node ? node : null;
|
|
60
|
+
const resultType = el?.type;
|
|
61
|
+
const resultKey = el?.key;
|
|
62
|
+
const resultProps =
|
|
63
|
+
typeof el?.props === "object" &&
|
|
64
|
+
el.props != null &&
|
|
65
|
+
Object.entries(el.props).length === 0
|
|
66
|
+
? EMPTY_OBJECT
|
|
67
|
+
: el?.props;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: optimization
|
|
71
|
+
useMemo(() => el, [resultType, resultKey, resultProps]) ?? node
|
|
72
|
+
);
|
|
73
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type DerivedClients = Partial<
|
|
|
21
21
|
*/
|
|
22
22
|
function splitClients(clients: useAui.Props, baseClient: AssistantClient) {
|
|
23
23
|
// 1. Collect transforms from root elements and run them iteratively
|
|
24
|
-
|
|
24
|
+
const scopes = { ...clients } as Record<
|
|
25
25
|
string,
|
|
26
26
|
ClientElement<ClientNames> | DerivedElement<ClientNames>
|
|
27
27
|
>;
|
|
@@ -37,7 +37,7 @@ function splitClients(clients: useAui.Props, baseClient: AssistantClient) {
|
|
|
37
37
|
|
|
38
38
|
const transform = getTransformScopes(clientElement.type);
|
|
39
39
|
if (transform) {
|
|
40
|
-
|
|
40
|
+
transform(scopes, baseClient);
|
|
41
41
|
changed = true;
|
|
42
42
|
break; // restart iteration since scopes may have new root elements
|
|
43
43
|
}
|