@vinaverse/react 0.0.0-stage → 0.1.0-alpha.11
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/LICENSE +202 -0
- package/README.md +43 -2
- package/dist/agent.cjs +174 -0
- package/dist/agent.cjs.map +1 -0
- package/dist/agent.d.cts +82 -0
- package/dist/agent.d.ts +82 -0
- package/dist/agent.js +3 -0
- package/dist/agent.js.map +1 -0
- package/dist/chunk-V4UBOVTK.js +160 -0
- package/dist/chunk-V4UBOVTK.js.map +1 -0
- package/dist/history.cjs +91 -0
- package/dist/history.cjs.map +1 -0
- package/dist/history.d.cts +55 -0
- package/dist/history.d.ts +55 -0
- package/dist/history.js +77 -0
- package/dist/history.js.map +1 -0
- package/dist/index.cjs +117 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/package.json +139 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":["createContext","copy","useMemo","textDirection","createTranslate","jsx","useContext","useSyncExternalStore","useRef","useCallback"],"mappings":";;;;;;;AAgBA,IAAM,8BAA8BA,mBAAA,CAAgC;AAAA,EAClE,MAAA,EAAQ,MAAA;AAAA,EACR,SAAA,EAAW,KAAA;AAAA,EACX,CAAA,uCAAmC,MAAS;AAC9C,CAAC,CAAA;AAEM,SAAS,aAAa,KAAA,EAIf;AACZ,EAAA,MAAM,EAAE,MAAA,QAAQC,MAAA,EAAM,QAAA,EAAS,GAAI,KAAA;AACnC,EAAA,MAAM,KAAA,GAAQC,aAAA;AAAA,IACZ,OAAO;AAAA,MACL,MAAA;AAAA,MACA,SAAA,EAAWC,mBAAc,MAAM,CAAA;AAAA,MAC/B,CAAA,EAAGC,oBAAA,CAAgB,MAAA,EAAQH,MAAI;AAAA,KACjC,CAAA;AAAA,IACA,CAAC,QAAQA,MAAI;AAAA,GACf;AACA,EAAA,uBAAOI,cAAA,CAAC,WAAA,CAAY,QAAA,EAAZ,EAAqB,OAAe,QAAA,EAAS,CAAA;AACvD;AAGO,SAAS,OAAA,GAA4B;AAC1C,EAAA,OAAOC,iBAAW,WAAW,CAAA;AAC/B;ACxBO,SAAS,gBAAgB,MAAA,EAA8C;AAC5E,EAAA,OAAOC,0BAAA;AAAA,IACL,MAAA,CAAO,SAAA;AAAA,IACP,MAAA,CAAO,WAAA;AAAA,IACP,MAAA,CAAO;AAAA,GACT;AACF;AAMO,SAAS,uBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,GAAmC,OAAO,EAAA,EACvC;AACH,EAAA,MAAM,IAAA,GAAOC,aAAoD,IAAI,CAAA;AACrE,EAAA,MAAM,MAAA,GAASA,aAAO,QAAQ,CAAA;AAC9B,EAAA,MAAA,CAAO,OAAA,GAAU,QAAA;AACjB,EAAA,MAAM,OAAA,GAAUA,aAAO,OAAO,CAAA;AAC9B,EAAA,OAAA,CAAQ,OAAA,GAAU,OAAA;AAClB,EAAA,MAAM,GAAA,GAAMC,kBAAY,MAAS;AAC/B,IAAA,MAAM,IAAA,GAAO,OAAO,WAAA,EAAY;AAChC,IAAA,MAAM,OAAO,IAAA,CAAK,OAAA;AAClB,IAAA,IAAI,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA,CAAK,KAAA;AACrC,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA;AACjC,IAAA,IAAI,QAAQ,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAO,KAAK,CAAA,EAAG;AAC9C,MAAA,IAAA,CAAK,OAAA,GAAU,EAAE,IAAA,EAAM,KAAA,EAAO,KAAK,KAAA,EAAM;AACzC,MAAA,OAAO,IAAA,CAAK,KAAA;AAAA,IACd;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,EAAE,IAAA,EAAM,KAAA,EAAM;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,OAAOF,0BAAA,CAAqB,MAAA,CAAO,SAAA,EAAW,GAAA,EAAK,GAAG,CAAA;AACxD;AAMO,SAAS,gBAAA,CACd,QACA,GAAA,EACe;AACf,EAAA,MAAM,GAAA,GAAME,kBAAY,MAAM;AAC5B,IAAA,MAAM,SAAA,GAAY,OAAO,YAAA,EAAa;AACtC,IAAA,OAAO,SAAA,EAAW,GAAA,KAAQ,GAAA,GAAM,SAAA,CAAU,IAAA,GAAO,IAAA;AAAA,EACnD,CAAA,EAAG,CAAC,MAAA,EAAQ,GAAG,CAAC,CAAA;AAChB,EAAA,OAAOF,0BAAA,CAAqB,MAAA,CAAO,kBAAA,EAAoB,GAAA,EAAK,GAAG,CAAA;AACjE","file":"index.cjs","sourcesContent":["// The copy a component tree uses, from a provider: the locale's built-in words with the tenant's overrides on top.\n\nimport {\n type CopyOverrides,\n createTranslate,\n type Translate,\n textDirection,\n} from '@vinaverse/tokens/copy';\nimport { createContext, type ReactNode, useContext, useMemo } from 'react';\n\nexport interface CopyContextValue {\n readonly locale: string | undefined;\n readonly direction: 'ltr' | 'rtl';\n readonly t: Translate;\n}\n\nconst CopyContext = /* @__PURE__ */ createContext<CopyContextValue>({\n locale: undefined,\n direction: 'ltr',\n t: /* @__PURE__ */ createTranslate(undefined),\n});\n\nexport function CopyProvider(props: {\n readonly locale?: string | undefined;\n readonly copy?: CopyOverrides | undefined;\n readonly children?: ReactNode;\n}): ReactNode {\n const { locale, copy, children } = props;\n const value = useMemo<CopyContextValue>(\n () => ({\n locale,\n direction: textDirection(locale),\n t: createTranslate(locale, copy),\n }),\n [locale, copy],\n );\n return <CopyContext.Provider value={value}>{children}</CopyContext.Provider>;\n}\n\n/** The translator, the locale and its text direction. */\nexport function useCopy(): CopyContextValue {\n return useContext(CopyContext);\n}\n","// The React bindings of the conversation store: thin by design. Every protocol rule lives in @vinaverse/client; these\n// hooks only subscribe, and re-render a component when the slice it reads changed.\n\nimport type {\n ConversationView,\n StreamingText,\n} from '@vinaverse/client/conversation';\nimport { useCallback, useRef, useSyncExternalStore } from 'react';\n\n/** What the hooks read: a conversation store, or anything with the same four members (a test's fake). */\nexport interface ConversationSource {\n getSnapshot(): ConversationView;\n subscribe(listener: () => void): () => void;\n getStreaming(): StreamingText | null;\n subscribeStreaming(listener: () => void): () => void;\n}\n\n/** The whole view; re-renders on every change of it. Prefer `useConversationSelector` in anything drawn often. */\nexport function useConversation(source: ConversationSource): ConversationView {\n return useSyncExternalStore(\n source.subscribe,\n source.getSnapshot,\n source.getSnapshot,\n );\n}\n\n/**\n * A slice of the view; re-renders only when the slice changed by `isEqual` (default `Object.is`). The view is\n * structurally shared, so selecting `items`, one item, or a field compares by identity.\n */\nexport function useConversationSelector<T>(\n source: ConversationSource,\n selector: (view: ConversationView) => T,\n isEqual: (a: T, b: T) => boolean = Object.is,\n): T {\n const last = useRef<{ view: ConversationView; value: T } | null>(null);\n const select = useRef(selector);\n select.current = selector;\n const compare = useRef(isEqual);\n compare.current = isEqual;\n const get = useCallback((): T => {\n const view = source.getSnapshot();\n const held = last.current;\n if (held?.view === view) return held.value;\n const value = select.current(view);\n if (held && compare.current(held.value, value)) {\n last.current = { view, value: held.value };\n return held.value;\n }\n last.current = { view, value };\n return value;\n }, [source]);\n return useSyncExternalStore(source.subscribe, get, get);\n}\n\n/**\n * The streamed text of the message with this `key`, or null when it is not the one streaming: only the streaming\n * bubble calls it, and only it re-renders as the reply arrives (at most once per frame).\n */\nexport function useStreamingText(\n source: ConversationSource,\n key: string,\n): string | null {\n const get = useCallback(() => {\n const streaming = source.getStreaming();\n return streaming?.key === key ? streaming.text : null;\n }, [source, key]);\n return useSyncExternalStore(source.subscribeStreaming, get, get);\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Translate, CopyOverrides } from '@vinaverse/tokens/copy';
|
|
2
|
+
export { AI_MARK, BANNED_WORDS, COPY, Copy, CopyKey, CopyOverrides, Translate, bannedWordsIn, builtInCopy, createTranslate, formatDate, formatDateTime, formatDayTime, formatMoney, formatTimeRange, textDirection } from '@vinaverse/tokens/copy';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { ConversationView, StreamingText } from '@vinaverse/client/conversation';
|
|
5
|
+
|
|
6
|
+
interface CopyContextValue {
|
|
7
|
+
readonly locale: string | undefined;
|
|
8
|
+
readonly direction: 'ltr' | 'rtl';
|
|
9
|
+
readonly t: Translate;
|
|
10
|
+
}
|
|
11
|
+
declare function CopyProvider(props: {
|
|
12
|
+
readonly locale?: string | undefined;
|
|
13
|
+
readonly copy?: CopyOverrides | undefined;
|
|
14
|
+
readonly children?: ReactNode;
|
|
15
|
+
}): ReactNode;
|
|
16
|
+
/** The translator, the locale and its text direction. */
|
|
17
|
+
declare function useCopy(): CopyContextValue;
|
|
18
|
+
|
|
19
|
+
/** What the hooks read: a conversation store, or anything with the same four members (a test's fake). */
|
|
20
|
+
interface ConversationSource {
|
|
21
|
+
getSnapshot(): ConversationView;
|
|
22
|
+
subscribe(listener: () => void): () => void;
|
|
23
|
+
getStreaming(): StreamingText | null;
|
|
24
|
+
subscribeStreaming(listener: () => void): () => void;
|
|
25
|
+
}
|
|
26
|
+
/** The whole view; re-renders on every change of it. Prefer `useConversationSelector` in anything drawn often. */
|
|
27
|
+
declare function useConversation(source: ConversationSource): ConversationView;
|
|
28
|
+
/**
|
|
29
|
+
* A slice of the view; re-renders only when the slice changed by `isEqual` (default `Object.is`). The view is
|
|
30
|
+
* structurally shared, so selecting `items`, one item, or a field compares by identity.
|
|
31
|
+
*/
|
|
32
|
+
declare function useConversationSelector<T>(source: ConversationSource, selector: (view: ConversationView) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
33
|
+
/**
|
|
34
|
+
* The streamed text of the message with this `key`, or null when it is not the one streaming: only the streaming
|
|
35
|
+
* bubble calls it, and only it re-renders as the reply arrives (at most once per frame).
|
|
36
|
+
*/
|
|
37
|
+
declare function useStreamingText(source: ConversationSource, key: string): string | null;
|
|
38
|
+
|
|
39
|
+
export { type ConversationSource, type CopyContextValue, CopyProvider, useConversation, useConversationSelector, useCopy, useStreamingText };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Translate, CopyOverrides } from '@vinaverse/tokens/copy';
|
|
2
|
+
export { AI_MARK, BANNED_WORDS, COPY, Copy, CopyKey, CopyOverrides, Translate, bannedWordsIn, builtInCopy, createTranslate, formatDate, formatDateTime, formatDayTime, formatMoney, formatTimeRange, textDirection } from '@vinaverse/tokens/copy';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { ConversationView, StreamingText } from '@vinaverse/client/conversation';
|
|
5
|
+
|
|
6
|
+
interface CopyContextValue {
|
|
7
|
+
readonly locale: string | undefined;
|
|
8
|
+
readonly direction: 'ltr' | 'rtl';
|
|
9
|
+
readonly t: Translate;
|
|
10
|
+
}
|
|
11
|
+
declare function CopyProvider(props: {
|
|
12
|
+
readonly locale?: string | undefined;
|
|
13
|
+
readonly copy?: CopyOverrides | undefined;
|
|
14
|
+
readonly children?: ReactNode;
|
|
15
|
+
}): ReactNode;
|
|
16
|
+
/** The translator, the locale and its text direction. */
|
|
17
|
+
declare function useCopy(): CopyContextValue;
|
|
18
|
+
|
|
19
|
+
/** What the hooks read: a conversation store, or anything with the same four members (a test's fake). */
|
|
20
|
+
interface ConversationSource {
|
|
21
|
+
getSnapshot(): ConversationView;
|
|
22
|
+
subscribe(listener: () => void): () => void;
|
|
23
|
+
getStreaming(): StreamingText | null;
|
|
24
|
+
subscribeStreaming(listener: () => void): () => void;
|
|
25
|
+
}
|
|
26
|
+
/** The whole view; re-renders on every change of it. Prefer `useConversationSelector` in anything drawn often. */
|
|
27
|
+
declare function useConversation(source: ConversationSource): ConversationView;
|
|
28
|
+
/**
|
|
29
|
+
* A slice of the view; re-renders only when the slice changed by `isEqual` (default `Object.is`). The view is
|
|
30
|
+
* structurally shared, so selecting `items`, one item, or a field compares by identity.
|
|
31
|
+
*/
|
|
32
|
+
declare function useConversationSelector<T>(source: ConversationSource, selector: (view: ConversationView) => T, isEqual?: (a: T, b: T) => boolean): T;
|
|
33
|
+
/**
|
|
34
|
+
* The streamed text of the message with this `key`, or null when it is not the one streaming: only the streaming
|
|
35
|
+
* bubble calls it, and only it re-renders as the reply arrives (at most once per frame).
|
|
36
|
+
*/
|
|
37
|
+
declare function useStreamingText(source: ConversationSource, key: string): string | null;
|
|
38
|
+
|
|
39
|
+
export { type ConversationSource, type CopyContextValue, CopyProvider, useConversation, useConversationSelector, useCopy, useStreamingText };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createTranslate, textDirection } from '@vinaverse/tokens/copy';
|
|
2
|
+
export { AI_MARK, BANNED_WORDS, COPY, bannedWordsIn, builtInCopy, createTranslate, formatDate, formatDateTime, formatDayTime, formatMoney, formatTimeRange, textDirection } from '@vinaverse/tokens/copy';
|
|
3
|
+
import { useMemo, useContext, useSyncExternalStore, useRef, useCallback, createContext } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/index.ts
|
|
7
|
+
var CopyContext = /* @__PURE__ */ createContext({
|
|
8
|
+
locale: void 0,
|
|
9
|
+
direction: "ltr",
|
|
10
|
+
t: /* @__PURE__ */ createTranslate(void 0)
|
|
11
|
+
});
|
|
12
|
+
function CopyProvider(props) {
|
|
13
|
+
const { locale, copy, children } = props;
|
|
14
|
+
const value = useMemo(
|
|
15
|
+
() => ({
|
|
16
|
+
locale,
|
|
17
|
+
direction: textDirection(locale),
|
|
18
|
+
t: createTranslate(locale, copy)
|
|
19
|
+
}),
|
|
20
|
+
[locale, copy]
|
|
21
|
+
);
|
|
22
|
+
return /* @__PURE__ */ jsx(CopyContext.Provider, { value, children });
|
|
23
|
+
}
|
|
24
|
+
function useCopy() {
|
|
25
|
+
return useContext(CopyContext);
|
|
26
|
+
}
|
|
27
|
+
function useConversation(source) {
|
|
28
|
+
return useSyncExternalStore(
|
|
29
|
+
source.subscribe,
|
|
30
|
+
source.getSnapshot,
|
|
31
|
+
source.getSnapshot
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
function useConversationSelector(source, selector, isEqual = Object.is) {
|
|
35
|
+
const last = useRef(null);
|
|
36
|
+
const select = useRef(selector);
|
|
37
|
+
select.current = selector;
|
|
38
|
+
const compare = useRef(isEqual);
|
|
39
|
+
compare.current = isEqual;
|
|
40
|
+
const get = useCallback(() => {
|
|
41
|
+
const view = source.getSnapshot();
|
|
42
|
+
const held = last.current;
|
|
43
|
+
if (held?.view === view) return held.value;
|
|
44
|
+
const value = select.current(view);
|
|
45
|
+
if (held && compare.current(held.value, value)) {
|
|
46
|
+
last.current = { view, value: held.value };
|
|
47
|
+
return held.value;
|
|
48
|
+
}
|
|
49
|
+
last.current = { view, value };
|
|
50
|
+
return value;
|
|
51
|
+
}, [source]);
|
|
52
|
+
return useSyncExternalStore(source.subscribe, get, get);
|
|
53
|
+
}
|
|
54
|
+
function useStreamingText(source, key) {
|
|
55
|
+
const get = useCallback(() => {
|
|
56
|
+
const streaming = source.getStreaming();
|
|
57
|
+
return streaming?.key === key ? streaming.text : null;
|
|
58
|
+
}, [source, key]);
|
|
59
|
+
return useSyncExternalStore(source.subscribeStreaming, get, get);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { CopyProvider, useConversation, useConversationSelector, useCopy, useStreamingText };
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":[],"mappings":";;;;;;AAgBA,IAAM,8BAA8B,aAAA,CAAgC;AAAA,EAClE,MAAA,EAAQ,MAAA;AAAA,EACR,SAAA,EAAW,KAAA;AAAA,EACX,CAAA,kCAAmC,MAAS;AAC9C,CAAC,CAAA;AAEM,SAAS,aAAa,KAAA,EAIf;AACZ,EAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAS,GAAI,KAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,OAAO;AAAA,MACL,MAAA;AAAA,MACA,SAAA,EAAW,cAAc,MAAM,CAAA;AAAA,MAC/B,CAAA,EAAG,eAAA,CAAgB,MAAA,EAAQ,IAAI;AAAA,KACjC,CAAA;AAAA,IACA,CAAC,QAAQ,IAAI;AAAA,GACf;AACA,EAAA,uBAAO,GAAA,CAAC,WAAA,CAAY,QAAA,EAAZ,EAAqB,OAAe,QAAA,EAAS,CAAA;AACvD;AAGO,SAAS,OAAA,GAA4B;AAC1C,EAAA,OAAO,WAAW,WAAW,CAAA;AAC/B;ACxBO,SAAS,gBAAgB,MAAA,EAA8C;AAC5E,EAAA,OAAO,oBAAA;AAAA,IACL,MAAA,CAAO,SAAA;AAAA,IACP,MAAA,CAAO,WAAA;AAAA,IACP,MAAA,CAAO;AAAA,GACT;AACF;AAMO,SAAS,uBAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,GAAmC,OAAO,EAAA,EACvC;AACH,EAAA,MAAM,IAAA,GAAO,OAAoD,IAAI,CAAA;AACrE,EAAA,MAAM,MAAA,GAAS,OAAO,QAAQ,CAAA;AAC9B,EAAA,MAAA,CAAO,OAAA,GAAU,QAAA;AACjB,EAAA,MAAM,OAAA,GAAU,OAAO,OAAO,CAAA;AAC9B,EAAA,OAAA,CAAQ,OAAA,GAAU,OAAA;AAClB,EAAA,MAAM,GAAA,GAAM,YAAY,MAAS;AAC/B,IAAA,MAAM,IAAA,GAAO,OAAO,WAAA,EAAY;AAChC,IAAA,MAAM,OAAO,IAAA,CAAK,OAAA;AAClB,IAAA,IAAI,IAAA,EAAM,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA,CAAK,KAAA;AACrC,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA;AACjC,IAAA,IAAI,QAAQ,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAO,KAAK,CAAA,EAAG;AAC9C,MAAA,IAAA,CAAK,OAAA,GAAU,EAAE,IAAA,EAAM,KAAA,EAAO,KAAK,KAAA,EAAM;AACzC,MAAA,OAAO,IAAA,CAAK,KAAA;AAAA,IACd;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,EAAE,IAAA,EAAM,KAAA,EAAM;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,OAAO,oBAAA,CAAqB,MAAA,CAAO,SAAA,EAAW,GAAA,EAAK,GAAG,CAAA;AACxD;AAMO,SAAS,gBAAA,CACd,QACA,GAAA,EACe;AACf,EAAA,MAAM,GAAA,GAAM,YAAY,MAAM;AAC5B,IAAA,MAAM,SAAA,GAAY,OAAO,YAAA,EAAa;AACtC,IAAA,OAAO,SAAA,EAAW,GAAA,KAAQ,GAAA,GAAM,SAAA,CAAU,IAAA,GAAO,IAAA;AAAA,EACnD,CAAA,EAAG,CAAC,MAAA,EAAQ,GAAG,CAAC,CAAA;AAChB,EAAA,OAAO,oBAAA,CAAqB,MAAA,CAAO,kBAAA,EAAoB,GAAA,EAAK,GAAG,CAAA;AACjE","file":"index.js","sourcesContent":["// The copy a component tree uses, from a provider: the locale's built-in words with the tenant's overrides on top.\n\nimport {\n type CopyOverrides,\n createTranslate,\n type Translate,\n textDirection,\n} from '@vinaverse/tokens/copy';\nimport { createContext, type ReactNode, useContext, useMemo } from 'react';\n\nexport interface CopyContextValue {\n readonly locale: string | undefined;\n readonly direction: 'ltr' | 'rtl';\n readonly t: Translate;\n}\n\nconst CopyContext = /* @__PURE__ */ createContext<CopyContextValue>({\n locale: undefined,\n direction: 'ltr',\n t: /* @__PURE__ */ createTranslate(undefined),\n});\n\nexport function CopyProvider(props: {\n readonly locale?: string | undefined;\n readonly copy?: CopyOverrides | undefined;\n readonly children?: ReactNode;\n}): ReactNode {\n const { locale, copy, children } = props;\n const value = useMemo<CopyContextValue>(\n () => ({\n locale,\n direction: textDirection(locale),\n t: createTranslate(locale, copy),\n }),\n [locale, copy],\n );\n return <CopyContext.Provider value={value}>{children}</CopyContext.Provider>;\n}\n\n/** The translator, the locale and its text direction. */\nexport function useCopy(): CopyContextValue {\n return useContext(CopyContext);\n}\n","// The React bindings of the conversation store: thin by design. Every protocol rule lives in @vinaverse/client; these\n// hooks only subscribe, and re-render a component when the slice it reads changed.\n\nimport type {\n ConversationView,\n StreamingText,\n} from '@vinaverse/client/conversation';\nimport { useCallback, useRef, useSyncExternalStore } from 'react';\n\n/** What the hooks read: a conversation store, or anything with the same four members (a test's fake). */\nexport interface ConversationSource {\n getSnapshot(): ConversationView;\n subscribe(listener: () => void): () => void;\n getStreaming(): StreamingText | null;\n subscribeStreaming(listener: () => void): () => void;\n}\n\n/** The whole view; re-renders on every change of it. Prefer `useConversationSelector` in anything drawn often. */\nexport function useConversation(source: ConversationSource): ConversationView {\n return useSyncExternalStore(\n source.subscribe,\n source.getSnapshot,\n source.getSnapshot,\n );\n}\n\n/**\n * A slice of the view; re-renders only when the slice changed by `isEqual` (default `Object.is`). The view is\n * structurally shared, so selecting `items`, one item, or a field compares by identity.\n */\nexport function useConversationSelector<T>(\n source: ConversationSource,\n selector: (view: ConversationView) => T,\n isEqual: (a: T, b: T) => boolean = Object.is,\n): T {\n const last = useRef<{ view: ConversationView; value: T } | null>(null);\n const select = useRef(selector);\n select.current = selector;\n const compare = useRef(isEqual);\n compare.current = isEqual;\n const get = useCallback((): T => {\n const view = source.getSnapshot();\n const held = last.current;\n if (held?.view === view) return held.value;\n const value = select.current(view);\n if (held && compare.current(held.value, value)) {\n last.current = { view, value: held.value };\n return held.value;\n }\n last.current = { view, value };\n return value;\n }, [source]);\n return useSyncExternalStore(source.subscribe, get, get);\n}\n\n/**\n * The streamed text of the message with this `key`, or null when it is not the one streaming: only the streaming\n * bubble calls it, and only it re-renders as the reply arrives (at most once per frame).\n */\nexport function useStreamingText(\n source: ConversationSource,\n key: string,\n): string | null {\n const get = useCallback(() => {\n const streaming = source.getStreaming();\n return streaming?.key === key ? streaming.text : null;\n }, [source, key]);\n return useSyncExternalStore(source.subscribeStreaming, get, get);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,142 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vinaverse/react",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0-alpha.11",
|
|
4
|
+
"description": "Vinaverse for React: hooks over the conversation store, and the copy and formatting every Vinaverse React UI shares. No react-native or DOM import.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Vinaverse, Inc.",
|
|
7
|
+
"homepage": "https://github.com/vinaverse-ai/vinaverse-js/tree/develop/packages/react#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/vinaverse-ai/vinaverse-js.git",
|
|
11
|
+
"directory": "packages/react"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/vinaverse-ai/vinaverse-js/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"vinaverse",
|
|
16
|
+
"react",
|
|
17
|
+
"hooks"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"react-native": {
|
|
24
|
+
"types": "./dist/index.d.cts",
|
|
25
|
+
"default": "./dist/index.cjs"
|
|
26
|
+
},
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/index.d.cts",
|
|
33
|
+
"default": "./dist/index.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./agent": {
|
|
37
|
+
"react-native": {
|
|
38
|
+
"types": "./dist/agent.d.cts",
|
|
39
|
+
"default": "./dist/agent.cjs"
|
|
40
|
+
},
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/agent.d.ts",
|
|
43
|
+
"default": "./dist/agent.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/agent.d.cts",
|
|
47
|
+
"default": "./dist/agent.cjs"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"./history": {
|
|
51
|
+
"react-native": {
|
|
52
|
+
"types": "./dist/history.d.cts",
|
|
53
|
+
"default": "./dist/history.cjs"
|
|
54
|
+
},
|
|
55
|
+
"import": {
|
|
56
|
+
"types": "./dist/history.d.ts",
|
|
57
|
+
"default": "./dist/history.js"
|
|
58
|
+
},
|
|
59
|
+
"require": {
|
|
60
|
+
"types": "./dist/history.d.cts",
|
|
61
|
+
"default": "./dist/history.cjs"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"./package.json": "./package.json"
|
|
65
|
+
},
|
|
66
|
+
"main": "./dist/index.cjs",
|
|
67
|
+
"module": "./dist/index.js",
|
|
68
|
+
"types": "./dist/index.d.cts",
|
|
69
|
+
"files": [
|
|
70
|
+
"dist"
|
|
71
|
+
],
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@vinaverse/client": "0.1.0-alpha.11",
|
|
74
|
+
"@vinaverse/tokens": "0.1.0-alpha.11"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"react": ">=19.1"
|
|
78
|
+
},
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public",
|
|
81
|
+
"provenance": true
|
|
82
|
+
},
|
|
83
|
+
"size-limit": [
|
|
84
|
+
{
|
|
85
|
+
"name": "@vinaverse/react (ESM, everything; react and the other @vinaverse packages excluded)",
|
|
86
|
+
"path": "dist/index.js",
|
|
87
|
+
"import": "*",
|
|
88
|
+
"ignore": [
|
|
89
|
+
"react",
|
|
90
|
+
"react/jsx-runtime",
|
|
91
|
+
"@vinaverse/client",
|
|
92
|
+
"@vinaverse/tokens/copy",
|
|
93
|
+
"@vinaverse/client/agent",
|
|
94
|
+
"@vinaverse/client/history"
|
|
95
|
+
],
|
|
96
|
+
"limit": "1.5 kB"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "@vinaverse/react/agent (ESM, everything; react and the other @vinaverse packages excluded)",
|
|
100
|
+
"path": "dist/agent.js",
|
|
101
|
+
"import": "*",
|
|
102
|
+
"ignore": [
|
|
103
|
+
"react",
|
|
104
|
+
"react/jsx-runtime",
|
|
105
|
+
"@vinaverse/client",
|
|
106
|
+
"@vinaverse/tokens/copy",
|
|
107
|
+
"@vinaverse/client/agent",
|
|
108
|
+
"@vinaverse/client/history"
|
|
109
|
+
],
|
|
110
|
+
"limit": "1.5 kB"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "@vinaverse/react/history (ESM, everything; react and the other @vinaverse packages excluded)",
|
|
114
|
+
"path": "dist/history.js",
|
|
115
|
+
"import": "*",
|
|
116
|
+
"ignore": [
|
|
117
|
+
"react",
|
|
118
|
+
"react/jsx-runtime",
|
|
119
|
+
"@vinaverse/client",
|
|
120
|
+
"@vinaverse/tokens/copy",
|
|
121
|
+
"@vinaverse/client/agent",
|
|
122
|
+
"@vinaverse/client/history"
|
|
123
|
+
],
|
|
124
|
+
"limit": "1.5 kB"
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"typesVersions": {
|
|
128
|
+
"*": {
|
|
129
|
+
"agent": [
|
|
130
|
+
"./dist/agent.d.cts"
|
|
131
|
+
],
|
|
132
|
+
"history": [
|
|
133
|
+
"./dist/history.d.cts"
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"scripts": {
|
|
138
|
+
"build": "tsup",
|
|
139
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
140
|
+
"package:check": "publint --strict && attw --pack . && size-limit"
|
|
141
|
+
}
|
|
6
142
|
}
|