@liveblocks/react-ui 2.25.0-aiprivatebeta10 → 2.25.0-aiprivatebeta12
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/components/AiChat.cjs +11 -17
- package/dist/components/AiChat.cjs.map +1 -1
- package/dist/components/AiChat.js +12 -18
- package/dist/components/AiChat.js.map +1 -1
- package/dist/components/AiTool.cjs +36 -23
- package/dist/components/AiTool.cjs.map +1 -1
- package/dist/components/AiTool.js +37 -24
- package/dist/components/AiTool.js.map +1 -1
- package/dist/components/Composer.cjs +3 -3
- package/dist/components/Composer.cjs.map +1 -1
- package/dist/components/Composer.js +3 -3
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.cjs +8 -4
- package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.js +9 -5
- package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
- package/dist/components/internal/AiChatComposer.cjs.map +1 -1
- package/dist/components/internal/AiChatComposer.js.map +1 -1
- package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatUserMessage.js.map +1 -1
- package/dist/components/internal/CodeBlock.cjs +6 -3
- package/dist/components/internal/CodeBlock.cjs.map +1 -1
- package/dist/components/internal/CodeBlock.js +6 -3
- package/dist/components/internal/CodeBlock.js.map +1 -1
- package/dist/index.d.cts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/overrides.cjs +5 -1
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.js +5 -1
- package/dist/overrides.js.map +1 -1
- package/dist/primitives/AiMessage/index.cjs +24 -19
- package/dist/primitives/AiMessage/index.cjs.map +1 -1
- package/dist/primitives/AiMessage/index.js +25 -20
- package/dist/primitives/AiMessage/index.js.map +1 -1
- package/dist/primitives/Collapsible/index.cjs +3 -3
- package/dist/primitives/Collapsible/index.cjs.map +1 -1
- package/dist/primitives/Collapsible/index.js +3 -3
- package/dist/primitives/Collapsible/index.js.map +1 -1
- package/dist/utils/use-controllable-state.cjs +25 -2
- package/dist/utils/use-controllable-state.cjs.map +1 -1
- package/dist/utils/use-controllable-state.js +25 -3
- package/dist/utils/use-controllable-state.js.map +1 -1
- package/dist/utils/use-visible.cjs +3 -1
- package/dist/utils/use-visible.cjs.map +1 -1
- package/dist/utils/use-visible.js +3 -1
- package/dist/utils/use-visible.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/src/styles/index.css +1 -1
- package/styles.css +1 -1
- package/styles.css.map +1 -1
|
@@ -24,6 +24,9 @@ const defaultMessageContentComponents = {
|
|
|
24
24
|
},
|
|
25
25
|
ToolInvocationPart: ({ children }) => children
|
|
26
26
|
};
|
|
27
|
+
function StableRenderFn(props) {
|
|
28
|
+
return props.renderFn(props.props);
|
|
29
|
+
}
|
|
27
30
|
function ToolInvocation({
|
|
28
31
|
chatId,
|
|
29
32
|
messageId,
|
|
@@ -31,53 +34,55 @@ function ToolInvocation({
|
|
|
31
34
|
}) {
|
|
32
35
|
const client = react.useClient();
|
|
33
36
|
const ai = client[core.kInternal].ai;
|
|
34
|
-
const tool = _private.useSignal(ai.signals.
|
|
37
|
+
const tool = _private.useSignal(ai.signals.getTool\u03A3(part.name, chatId));
|
|
35
38
|
const respond = react$1.useCallback(
|
|
36
39
|
(result) => {
|
|
37
40
|
if (part.status === "receiving") {
|
|
38
41
|
console.log(
|
|
39
|
-
`Ignoring respond(): tool '${part.
|
|
42
|
+
`Ignoring respond(): tool '${part.name}' (${part.invocationId}) is still receiving`
|
|
40
43
|
);
|
|
41
44
|
} else if (part.status === "executed") {
|
|
42
45
|
console.log(
|
|
43
|
-
`Ignoring respond(): tool '${part.
|
|
46
|
+
`Ignoring respond(): tool '${part.name}' (${part.invocationId}) has already executed`
|
|
44
47
|
);
|
|
45
48
|
} else {
|
|
46
49
|
ai.setToolResult(
|
|
47
50
|
chatId,
|
|
48
51
|
messageId,
|
|
49
|
-
part.
|
|
52
|
+
part.invocationId,
|
|
50
53
|
result
|
|
51
54
|
);
|
|
52
55
|
}
|
|
53
56
|
},
|
|
54
|
-
[ai, chatId, messageId, part.status, part.
|
|
57
|
+
[ai, chatId, messageId, part.status, part.name, part.invocationId]
|
|
55
58
|
);
|
|
56
|
-
|
|
59
|
+
const props = react$1.useMemo(() => {
|
|
60
|
+
const { type: _, ...rest } = part;
|
|
61
|
+
return {
|
|
62
|
+
...rest,
|
|
63
|
+
respond,
|
|
64
|
+
types: void 0,
|
|
65
|
+
[core.kInternal]: {
|
|
66
|
+
execute: tool?.execute
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}, [part, respond, tool?.execute]);
|
|
70
|
+
if (tool?.render === void 0)
|
|
57
71
|
return null;
|
|
58
|
-
const RenderFn = tool.render;
|
|
59
|
-
const { type: _, ...rest } = part;
|
|
60
|
-
const props = {
|
|
61
|
-
...rest,
|
|
62
|
-
respond,
|
|
63
|
-
types: void 0,
|
|
64
|
-
[core.kInternal]: {
|
|
65
|
-
execute: tool.execute
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
72
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary.ErrorBoundary, {
|
|
69
73
|
fallback: /* @__PURE__ */ jsxRuntime.jsxs("p", {
|
|
70
74
|
style: { color: "red" },
|
|
71
75
|
children: [
|
|
72
76
|
"Failed to render tool call result for \u2018",
|
|
73
|
-
part.
|
|
77
|
+
part.name,
|
|
74
78
|
"\u2019. See console for details."
|
|
75
79
|
]
|
|
76
80
|
}),
|
|
77
81
|
children: /* @__PURE__ */ jsxRuntime.jsx(contexts.AiToolInvocationContext.Provider, {
|
|
78
82
|
value: props,
|
|
79
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
80
|
-
|
|
83
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(StableRenderFn, {
|
|
84
|
+
renderFn: tool.render,
|
|
85
|
+
props
|
|
81
86
|
})
|
|
82
87
|
})
|
|
83
88
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../src/primitives/AiMessage/index.tsx"],"sourcesContent":["import type {\n AiToolInvocationPart,\n AiToolInvocationProps,\n JsonObject,\n MessageId,\n ToolResultData,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport { useClient } from \"@liveblocks/react\";\nimport { useSignal } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { ComponentType } from \"react\";\nimport { forwardRef, useCallback, useMemo } from \"react\";\n\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Markdown } from \"../Markdown\";\nimport { AiToolInvocationContext } from \"./contexts\";\nimport type {\n AiMessageContentComponents,\n AiMessageContentProps,\n} from \"./types\";\n\nconst AI_MESSAGE_CONTENT_NAME = \"AiMessageContent\";\n\nconst defaultMessageContentComponents: AiMessageContentComponents = {\n TextPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ReasoningPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ToolInvocationPart: ({ children }) => children,\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\n\nfunction ToolInvocation({\n chatId,\n messageId,\n part,\n}: {\n chatId: string;\n messageId: MessageId;\n part: AiToolInvocationPart;\n}) {\n const client = useClient();\n const ai = client[kInternal].ai;\n const tool = useSignal(ai.signals.getToolDefinitionΣ(chatId, part.toolName));\n\n const respond = useCallback(\n (result: ToolResultData) => {\n if (part.status === \"receiving\") {\n console.log(\n `Ignoring respond(): tool '${part.toolName}' (${part.toolCallId}) is still receiving`\n );\n } else if (part.status === \"executed\") {\n console.log(\n `Ignoring respond(): tool '${part.toolName}' (${part.toolCallId}) has already executed`\n );\n } else {\n ai.setToolResult(\n chatId,\n messageId,\n part.toolCallId,\n result\n // TODO Pass in AiGenerationOptions here?\n );\n }\n },\n [ai, chatId, messageId, part.status, part.toolName, part.toolCallId]\n );\n\n if (tool === undefined || tool.render === undefined) return null;\n const RenderFn = tool.render as ComponentType<\n AiToolInvocationProps<JsonObject, ToolResultData>\n >;\n\n const { type: _, ...rest } = part;\n const props = {\n ...rest,\n respond,\n types: undefined as never,\n [kInternal]: {\n execute: tool.execute,\n },\n };\n return (\n <ErrorBoundary\n fallback={\n <p style={{ color: \"red\" }}>\n Failed to render tool call result for ‘{part.toolName}’. See console\n for details.\n </p>\n }\n >\n <AiToolInvocationContext.Provider value={props}>\n <RenderFn {...props} />\n </AiToolInvocationContext.Provider>\n </ErrorBoundary>\n );\n}\n\n/**\n * --------------------------------------------------------------------------\n * @private The API for this component is not yet stable.\n * --------------------------------------------------------------------------\n *\n * Primitive to help display an user or assistant message’s content, which is\n * an array of parts.\n *\n * @example\n * <AiMessage.Content message={message} components={{ TextPart }} />\n */\nconst AiMessageContent = forwardRef<HTMLDivElement, AiMessageContentProps>(\n ({ message, components, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const { TextPart, ReasoningPart, ToolInvocationPart } = useMemo(\n () => ({ ...defaultMessageContentComponents, ...components }),\n [components]\n );\n\n const content = message.content ?? message.contentSoFar;\n const numParts = content.length;\n const isGenerating =\n message.role === \"assistant\" && message.status === \"generating\";\n return (\n <Component {...props} ref={forwardedRef}>\n {content.map((part, index) => {\n // A part is considered to be still \"streaming in\" if it's the last\n // part in the content array, and the message is in \"generating\"\n // state.\n const isStreaming = isGenerating && index === numParts - 1;\n const extra = { index, isStreaming };\n switch (part.type) {\n case \"text\":\n return <TextPart key={index} part={part} {...extra} />;\n case \"reasoning\":\n return <ReasoningPart key={index} part={part} {...extra} />;\n case \"tool-invocation\":\n // TODO: If the render() method doesn't exist, we should not render the ToolInvocationPart\n // or pass it no children so that it can decide to not render?\n return (\n <ToolInvocationPart key={index} part={part} {...extra}>\n <ToolInvocation\n key={index}\n part={part}\n chatId={message.chatId}\n messageId={message.id}\n />\n </ToolInvocationPart>\n );\n default:\n return null;\n }\n })}\n </Component>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n AiMessageContent.displayName = AI_MESSAGE_CONTENT_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as AiMessage.*\nexport { AiMessageContent as Content };\n"],"names":["jsx","Markdown","useClient","kInternal","useSignal","useCallback","ErrorBoundary","jsxs","AiToolInvocationContext","forwardRef","Slot","useMemo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../src/primitives/AiMessage/index.tsx"],"sourcesContent":["import type {\n AiToolInvocationPart,\n AiToolInvocationProps,\n JsonObject,\n MessageId,\n ToolResultData,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport { useClient } from \"@liveblocks/react\";\nimport { useSignal } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { FunctionComponent } from \"react\";\nimport { forwardRef, useCallback, useMemo } from \"react\";\n\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Markdown } from \"../Markdown\";\nimport { AiToolInvocationContext } from \"./contexts\";\nimport type {\n AiMessageContentComponents,\n AiMessageContentProps,\n} from \"./types\";\n\nconst AI_MESSAGE_CONTENT_NAME = \"AiMessageContent\";\n\nconst defaultMessageContentComponents: AiMessageContentComponents = {\n TextPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ReasoningPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ToolInvocationPart: ({ children }) => children,\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\n\nfunction StableRenderFn(props: {\n renderFn: FunctionComponent<\n AiToolInvocationProps<JsonObject, ToolResultData>\n >;\n props: AiToolInvocationProps<JsonObject, ToolResultData>;\n}) {\n return props.renderFn(props.props);\n}\n\nfunction ToolInvocation({\n chatId,\n messageId,\n part,\n}: {\n chatId: string;\n messageId: MessageId;\n part: AiToolInvocationPart;\n}) {\n const client = useClient();\n const ai = client[kInternal].ai;\n const tool = useSignal(ai.signals.getToolΣ(part.name, chatId));\n\n const respond = useCallback(\n (result: ToolResultData) => {\n if (part.status === \"receiving\") {\n console.log(\n `Ignoring respond(): tool '${part.name}' (${part.invocationId}) is still receiving`\n );\n } else if (part.status === \"executed\") {\n console.log(\n `Ignoring respond(): tool '${part.name}' (${part.invocationId}) has already executed`\n );\n } else {\n ai.setToolResult(\n chatId,\n messageId,\n part.invocationId,\n result\n // TODO Pass in AiGenerationOptions here?\n );\n }\n },\n [ai, chatId, messageId, part.status, part.name, part.invocationId]\n );\n\n const props = useMemo(() => {\n const { type: _, ...rest } = part;\n return {\n ...rest,\n respond,\n types: undefined as never,\n [kInternal]: {\n execute: tool?.execute,\n },\n };\n }, [part, respond, tool?.execute]);\n\n if (tool?.render === undefined) return null;\n return (\n <ErrorBoundary\n fallback={\n <p style={{ color: \"red\" }}>\n Failed to render tool call result for ‘{part.name}’. See console\n for details.\n </p>\n }\n >\n <AiToolInvocationContext.Provider value={props}>\n <StableRenderFn\n renderFn={\n tool.render as FunctionComponent<\n AiToolInvocationProps<JsonObject, ToolResultData>\n >\n }\n props={props}\n />\n </AiToolInvocationContext.Provider>\n </ErrorBoundary>\n );\n}\n\n/**\n * --------------------------------------------------------------------------\n * @private The API for this component is not yet stable.\n * --------------------------------------------------------------------------\n *\n * Primitive to help display an user or assistant message’s content, which is\n * an array of parts.\n *\n * @example\n * <AiMessage.Content message={message} components={{ TextPart }} />\n */\nconst AiMessageContent = forwardRef<HTMLDivElement, AiMessageContentProps>(\n ({ message, components, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const { TextPart, ReasoningPart, ToolInvocationPart } = useMemo(\n () => ({ ...defaultMessageContentComponents, ...components }),\n [components]\n );\n\n const content = message.content ?? message.contentSoFar;\n const numParts = content.length;\n const isGenerating =\n message.role === \"assistant\" && message.status === \"generating\";\n return (\n <Component {...props} ref={forwardedRef}>\n {content.map((part, index) => {\n // A part is considered to be still \"streaming in\" if it's the last\n // part in the content array, and the message is in \"generating\"\n // state.\n const isStreaming = isGenerating && index === numParts - 1;\n const extra = { index, isStreaming };\n switch (part.type) {\n case \"text\":\n return <TextPart key={index} part={part} {...extra} />;\n case \"reasoning\":\n return <ReasoningPart key={index} part={part} {...extra} />;\n case \"tool-invocation\":\n // TODO: If the render() method doesn't exist, we should not render the ToolInvocationPart\n // or pass it no children so that it can decide to not render?\n return (\n <ToolInvocationPart key={index} part={part} {...extra}>\n <ToolInvocation\n key={index}\n part={part}\n chatId={message.chatId}\n messageId={message.id}\n />\n </ToolInvocationPart>\n );\n default:\n return null;\n }\n })}\n </Component>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n AiMessageContent.displayName = AI_MESSAGE_CONTENT_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as AiMessage.*\nexport { AiMessageContent as Content };\n"],"names":["jsx","Markdown","useClient","kInternal","useSignal","useCallback","useMemo","ErrorBoundary","jsxs","AiToolInvocationContext","forwardRef","Slot"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { kInternal } from '@liveblocks/core';
|
|
|
3
3
|
import { useClient } from '@liveblocks/react';
|
|
4
4
|
import { useSignal } from '@liveblocks/react/_private';
|
|
5
5
|
import { Slot } from '@radix-ui/react-slot';
|
|
6
|
-
import { useCallback,
|
|
6
|
+
import { useCallback, useMemo, forwardRef } from 'react';
|
|
7
7
|
import { ErrorBoundary } from '../../utils/ErrorBoundary.js';
|
|
8
8
|
import { Markdown } from '../Markdown.js';
|
|
9
9
|
import { AiToolInvocationContext } from './contexts.js';
|
|
@@ -22,6 +22,9 @@ const defaultMessageContentComponents = {
|
|
|
22
22
|
},
|
|
23
23
|
ToolInvocationPart: ({ children }) => children
|
|
24
24
|
};
|
|
25
|
+
function StableRenderFn(props) {
|
|
26
|
+
return props.renderFn(props.props);
|
|
27
|
+
}
|
|
25
28
|
function ToolInvocation({
|
|
26
29
|
chatId,
|
|
27
30
|
messageId,
|
|
@@ -29,53 +32,55 @@ function ToolInvocation({
|
|
|
29
32
|
}) {
|
|
30
33
|
const client = useClient();
|
|
31
34
|
const ai = client[kInternal].ai;
|
|
32
|
-
const tool = useSignal(ai.signals.
|
|
35
|
+
const tool = useSignal(ai.signals.getTool\u03A3(part.name, chatId));
|
|
33
36
|
const respond = useCallback(
|
|
34
37
|
(result) => {
|
|
35
38
|
if (part.status === "receiving") {
|
|
36
39
|
console.log(
|
|
37
|
-
`Ignoring respond(): tool '${part.
|
|
40
|
+
`Ignoring respond(): tool '${part.name}' (${part.invocationId}) is still receiving`
|
|
38
41
|
);
|
|
39
42
|
} else if (part.status === "executed") {
|
|
40
43
|
console.log(
|
|
41
|
-
`Ignoring respond(): tool '${part.
|
|
44
|
+
`Ignoring respond(): tool '${part.name}' (${part.invocationId}) has already executed`
|
|
42
45
|
);
|
|
43
46
|
} else {
|
|
44
47
|
ai.setToolResult(
|
|
45
48
|
chatId,
|
|
46
49
|
messageId,
|
|
47
|
-
part.
|
|
50
|
+
part.invocationId,
|
|
48
51
|
result
|
|
49
52
|
);
|
|
50
53
|
}
|
|
51
54
|
},
|
|
52
|
-
[ai, chatId, messageId, part.status, part.
|
|
55
|
+
[ai, chatId, messageId, part.status, part.name, part.invocationId]
|
|
53
56
|
);
|
|
54
|
-
|
|
57
|
+
const props = useMemo(() => {
|
|
58
|
+
const { type: _, ...rest } = part;
|
|
59
|
+
return {
|
|
60
|
+
...rest,
|
|
61
|
+
respond,
|
|
62
|
+
types: void 0,
|
|
63
|
+
[kInternal]: {
|
|
64
|
+
execute: tool?.execute
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}, [part, respond, tool?.execute]);
|
|
68
|
+
if (tool?.render === void 0)
|
|
55
69
|
return null;
|
|
56
|
-
const RenderFn = tool.render;
|
|
57
|
-
const { type: _, ...rest } = part;
|
|
58
|
-
const props = {
|
|
59
|
-
...rest,
|
|
60
|
-
respond,
|
|
61
|
-
types: void 0,
|
|
62
|
-
[kInternal]: {
|
|
63
|
-
execute: tool.execute
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
70
|
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
67
71
|
fallback: /* @__PURE__ */ jsxs("p", {
|
|
68
72
|
style: { color: "red" },
|
|
69
73
|
children: [
|
|
70
74
|
"Failed to render tool call result for \u2018",
|
|
71
|
-
part.
|
|
75
|
+
part.name,
|
|
72
76
|
"\u2019. See console for details."
|
|
73
77
|
]
|
|
74
78
|
}),
|
|
75
79
|
children: /* @__PURE__ */ jsx(AiToolInvocationContext.Provider, {
|
|
76
80
|
value: props,
|
|
77
|
-
children: /* @__PURE__ */ jsx(
|
|
78
|
-
|
|
81
|
+
children: /* @__PURE__ */ jsx(StableRenderFn, {
|
|
82
|
+
renderFn: tool.render,
|
|
83
|
+
props
|
|
79
84
|
})
|
|
80
85
|
})
|
|
81
86
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/primitives/AiMessage/index.tsx"],"sourcesContent":["import type {\n AiToolInvocationPart,\n AiToolInvocationProps,\n JsonObject,\n MessageId,\n ToolResultData,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport { useClient } from \"@liveblocks/react\";\nimport { useSignal } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type {
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/primitives/AiMessage/index.tsx"],"sourcesContent":["import type {\n AiToolInvocationPart,\n AiToolInvocationProps,\n JsonObject,\n MessageId,\n ToolResultData,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport { useClient } from \"@liveblocks/react\";\nimport { useSignal } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { FunctionComponent } from \"react\";\nimport { forwardRef, useCallback, useMemo } from \"react\";\n\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Markdown } from \"../Markdown\";\nimport { AiToolInvocationContext } from \"./contexts\";\nimport type {\n AiMessageContentComponents,\n AiMessageContentProps,\n} from \"./types\";\n\nconst AI_MESSAGE_CONTENT_NAME = \"AiMessageContent\";\n\nconst defaultMessageContentComponents: AiMessageContentComponents = {\n TextPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ReasoningPart: ({ part }) => {\n return <Markdown content={part.text} />;\n },\n ToolInvocationPart: ({ children }) => children,\n};\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\n\nfunction StableRenderFn(props: {\n renderFn: FunctionComponent<\n AiToolInvocationProps<JsonObject, ToolResultData>\n >;\n props: AiToolInvocationProps<JsonObject, ToolResultData>;\n}) {\n return props.renderFn(props.props);\n}\n\nfunction ToolInvocation({\n chatId,\n messageId,\n part,\n}: {\n chatId: string;\n messageId: MessageId;\n part: AiToolInvocationPart;\n}) {\n const client = useClient();\n const ai = client[kInternal].ai;\n const tool = useSignal(ai.signals.getToolΣ(part.name, chatId));\n\n const respond = useCallback(\n (result: ToolResultData) => {\n if (part.status === \"receiving\") {\n console.log(\n `Ignoring respond(): tool '${part.name}' (${part.invocationId}) is still receiving`\n );\n } else if (part.status === \"executed\") {\n console.log(\n `Ignoring respond(): tool '${part.name}' (${part.invocationId}) has already executed`\n );\n } else {\n ai.setToolResult(\n chatId,\n messageId,\n part.invocationId,\n result\n // TODO Pass in AiGenerationOptions here?\n );\n }\n },\n [ai, chatId, messageId, part.status, part.name, part.invocationId]\n );\n\n const props = useMemo(() => {\n const { type: _, ...rest } = part;\n return {\n ...rest,\n respond,\n types: undefined as never,\n [kInternal]: {\n execute: tool?.execute,\n },\n };\n }, [part, respond, tool?.execute]);\n\n if (tool?.render === undefined) return null;\n return (\n <ErrorBoundary\n fallback={\n <p style={{ color: \"red\" }}>\n Failed to render tool call result for ‘{part.name}’. See console\n for details.\n </p>\n }\n >\n <AiToolInvocationContext.Provider value={props}>\n <StableRenderFn\n renderFn={\n tool.render as FunctionComponent<\n AiToolInvocationProps<JsonObject, ToolResultData>\n >\n }\n props={props}\n />\n </AiToolInvocationContext.Provider>\n </ErrorBoundary>\n );\n}\n\n/**\n * --------------------------------------------------------------------------\n * @private The API for this component is not yet stable.\n * --------------------------------------------------------------------------\n *\n * Primitive to help display an user or assistant message’s content, which is\n * an array of parts.\n *\n * @example\n * <AiMessage.Content message={message} components={{ TextPart }} />\n */\nconst AiMessageContent = forwardRef<HTMLDivElement, AiMessageContentProps>(\n ({ message, components, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const { TextPart, ReasoningPart, ToolInvocationPart } = useMemo(\n () => ({ ...defaultMessageContentComponents, ...components }),\n [components]\n );\n\n const content = message.content ?? message.contentSoFar;\n const numParts = content.length;\n const isGenerating =\n message.role === \"assistant\" && message.status === \"generating\";\n return (\n <Component {...props} ref={forwardedRef}>\n {content.map((part, index) => {\n // A part is considered to be still \"streaming in\" if it's the last\n // part in the content array, and the message is in \"generating\"\n // state.\n const isStreaming = isGenerating && index === numParts - 1;\n const extra = { index, isStreaming };\n switch (part.type) {\n case \"text\":\n return <TextPart key={index} part={part} {...extra} />;\n case \"reasoning\":\n return <ReasoningPart key={index} part={part} {...extra} />;\n case \"tool-invocation\":\n // TODO: If the render() method doesn't exist, we should not render the ToolInvocationPart\n // or pass it no children so that it can decide to not render?\n return (\n <ToolInvocationPart key={index} part={part} {...extra}>\n <ToolInvocation\n key={index}\n part={part}\n chatId={message.chatId}\n messageId={message.id}\n />\n </ToolInvocationPart>\n );\n default:\n return null;\n }\n })}\n </Component>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n AiMessageContent.displayName = AI_MESSAGE_CONTENT_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as AiMessage.*\nexport { AiMessageContent as Content };\n"],"names":[],"mappings":";;;;;;;;;;AAsBA,MAAM,uBAA0B,GAAA,kBAAA,CAAA;AAEhC,MAAM,+BAA8D,GAAA;AAAA,EAClE,QAAU,EAAA,CAAC,EAAE,IAAA,EAAW,KAAA;AACtB,IAAA,uBAAQ,GAAA,CAAA,QAAA,EAAA;AAAA,MAAS,SAAS,IAAK,CAAA,IAAA;AAAA,KAAM,CAAA,CAAA;AAAA,GACvC;AAAA,EACA,aAAe,EAAA,CAAC,EAAE,IAAA,EAAW,KAAA;AAC3B,IAAA,uBAAQ,GAAA,CAAA,QAAA,EAAA;AAAA,MAAS,SAAS,IAAK,CAAA,IAAA;AAAA,KAAM,CAAA,CAAA;AAAA,GACvC;AAAA,EACA,kBAAoB,EAAA,CAAC,EAAE,QAAA,EAAe,KAAA,QAAA;AACxC,CAAA,CAAA;AAMA,SAAS,eAAe,KAKrB,EAAA;AACD,EAAO,OAAA,KAAA,CAAM,QAAS,CAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AACnC,CAAA;AAEA,SAAS,cAAe,CAAA;AAAA,EACtB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA;AACF,CAIG,EAAA;AACD,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAM,MAAA,EAAA,GAAK,OAAO,SAAW,CAAA,CAAA,EAAA,CAAA;AAC7B,EAAM,MAAA,IAAA,GAAO,UAAU,EAAG,CAAA,OAAA,CAAQ,cAAS,IAAK,CAAA,IAAA,EAAM,MAAM,CAAC,CAAA,CAAA;AAE7D,EAAA,MAAM,OAAU,GAAA,WAAA;AAAA,IACd,CAAC,MAA2B,KAAA;AAC1B,MAAI,IAAA,IAAA,CAAK,WAAW,WAAa,EAAA;AAC/B,QAAQ,OAAA,CAAA,GAAA;AAAA,UACN,CAAA,0BAAA,EAA6B,IAAK,CAAA,IAAA,CAAA,GAAA,EAAU,IAAK,CAAA,YAAA,CAAA,oBAAA,CAAA;AAAA,SACnD,CAAA;AAAA,OACF,MAAA,IAAW,IAAK,CAAA,MAAA,KAAW,UAAY,EAAA;AACrC,QAAQ,OAAA,CAAA,GAAA;AAAA,UACN,CAAA,0BAAA,EAA6B,IAAK,CAAA,IAAA,CAAA,GAAA,EAAU,IAAK,CAAA,YAAA,CAAA,sBAAA,CAAA;AAAA,SACnD,CAAA;AAAA,OACK,MAAA;AACL,QAAG,EAAA,CAAA,aAAA;AAAA,UACD,MAAA;AAAA,UACA,SAAA;AAAA,UACA,IAAK,CAAA,YAAA;AAAA,UACL,MAAA;AAAA,SAEF,CAAA;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,IAAI,MAAQ,EAAA,SAAA,EAAW,KAAK,MAAQ,EAAA,IAAA,CAAK,IAAM,EAAA,IAAA,CAAK,YAAY,CAAA;AAAA,GACnE,CAAA;AAEA,EAAM,MAAA,KAAA,GAAQ,QAAQ,MAAM;AAC1B,IAAA,MAAM,EAAE,IAAA,EAAM,CAAM,EAAA,GAAA,IAAA,EAAS,GAAA,IAAA,CAAA;AAC7B,IAAO,OAAA;AAAA,MACL,GAAG,IAAA;AAAA,MACH,OAAA;AAAA,MACA,KAAO,EAAA,KAAA,CAAA;AAAA,MACP,CAAC,SAAY,GAAA;AAAA,QACX,SAAS,IAAM,EAAA,OAAA;AAAA,OACjB;AAAA,KACF,CAAA;AAAA,KACC,CAAC,IAAA,EAAM,OAAS,EAAA,IAAA,EAAM,OAAO,CAAC,CAAA,CAAA;AAEjC,EAAA,IAAI,MAAM,MAAW,KAAA,KAAA,CAAA;AAAW,IAAO,OAAA,IAAA,CAAA;AACvC,EAAA,uBACG,GAAA,CAAA,aAAA,EAAA;AAAA,IACC,0BACG,IAAA,CAAA,GAAA,EAAA;AAAA,MAAE,KAAA,EAAO,EAAE,KAAA,EAAO,KAAM,EAAA;AAAA,MAAG,QAAA,EAAA;AAAA,QAAA,8CAAA;AAAA,QACc,IAAK,CAAA,IAAA;AAAA,QAAK,kCAAA;AAAA,OAAA;AAAA,KAEpD,CAAA;AAAA,IAGF,QAAA,kBAAA,GAAA,CAAC,wBAAwB,QAAxB,EAAA;AAAA,MAAiC,KAAO,EAAA,KAAA;AAAA,MACvC,QAAC,kBAAA,GAAA,CAAA,cAAA,EAAA;AAAA,QACC,UACE,IAAK,CAAA,MAAA;AAAA,QAIP,KAAA;AAAA,OACF,CAAA;AAAA,KACF,CAAA;AAAA,GACF,CAAA,CAAA;AAEJ,CAAA;AAaA,MAAM,gBAAmB,GAAA,UAAA;AAAA,EACvB,CAAC,EAAE,OAAA,EAAS,YAAY,OAAY,EAAA,GAAA,KAAA,IAAS,YAAiB,KAAA;AAC5D,IAAM,MAAA,SAAA,GAAY,UAAU,IAAO,GAAA,KAAA,CAAA;AACnC,IAAA,MAAM,EAAE,QAAA,EAAU,aAAe,EAAA,kBAAA,EAAuB,GAAA,OAAA;AAAA,MACtD,OAAO,EAAE,GAAG,+BAAA,EAAiC,GAAG,UAAW,EAAA,CAAA;AAAA,MAC3D,CAAC,UAAU,CAAA;AAAA,KACb,CAAA;AAEA,IAAM,MAAA,OAAA,GAAU,OAAQ,CAAA,OAAA,IAAW,OAAQ,CAAA,YAAA,CAAA;AAC3C,IAAA,MAAM,WAAW,OAAQ,CAAA,MAAA,CAAA;AACzB,IAAA,MAAM,YACJ,GAAA,OAAA,CAAQ,IAAS,KAAA,WAAA,IAAe,QAAQ,MAAW,KAAA,YAAA,CAAA;AACrD,IAAA,uBACG,GAAA,CAAA,SAAA,EAAA;AAAA,MAAW,GAAG,KAAA;AAAA,MAAO,GAAK,EAAA,YAAA;AAAA,MACxB,QAAQ,EAAA,OAAA,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,KAAU,KAAA;AAI5B,QAAM,MAAA,WAAA,GAAc,YAAgB,IAAA,KAAA,KAAU,QAAW,GAAA,CAAA,CAAA;AACzD,QAAM,MAAA,KAAA,GAAQ,EAAE,KAAA,EAAO,WAAY,EAAA,CAAA;AACnC,QAAA,QAAQ,KAAK,IAAM;AAAA,UACjB,KAAK,MAAA;AACH,YAAA,uBAAQ,GAAA,CAAA,QAAA,EAAA;AAAA,cAAqB,IAAA;AAAA,cAAa,GAAG,KAAA;AAAA,aAAA,EAAvB,KAA8B,CAAA,CAAA;AAAA,UACtD,KAAK,WAAA;AACH,YAAA,uBAAQ,GAAA,CAAA,aAAA,EAAA;AAAA,cAA0B,IAAA;AAAA,cAAa,GAAG,KAAA;AAAA,aAAA,EAAvB,KAA8B,CAAA,CAAA;AAAA,UAC3D,KAAK,iBAAA;AAGH,YAAA,uBACG,GAAA,CAAA,kBAAA,EAAA;AAAA,cAA+B,IAAA;AAAA,cAAa,GAAG,KAAA;AAAA,cAC9C,QAAC,kBAAA,GAAA,CAAA,cAAA,EAAA;AAAA,gBAEC,IAAA;AAAA,gBACA,QAAQ,OAAQ,CAAA,MAAA;AAAA,gBAChB,WAAW,OAAQ,CAAA,EAAA;AAAA,eAAA,EAHd,KAIP,CAAA;AAAA,aAAA,EANuB,KAOzB,CAAA,CAAA;AAAA,UAEJ;AACE,YAAO,OAAA,IAAA,CAAA;AAAA,SACX;AAAA,OACD,CAAA;AAAA,KACH,CAAA,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,IAAI,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AACzC,EAAA,gBAAA,CAAiB,WAAc,GAAA,uBAAA,CAAA;AACjC;;;;"}
|
|
@@ -19,9 +19,9 @@ const CollapsibleRoot = react.forwardRef(
|
|
|
19
19
|
...props
|
|
20
20
|
}, forwardedRef) => {
|
|
21
21
|
const [isOpen, onOpenChange] = useControllableState.useControllableState(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
defaultOpen ?? true,
|
|
23
|
+
controlledOpen,
|
|
24
|
+
controlledOnOpenChange
|
|
25
25
|
);
|
|
26
26
|
const Component = asChild ? reactSlot.Slot : "div";
|
|
27
27
|
const id = react.useId();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../src/primitives/Collapsible/index.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n} from \"react\";\n\nimport { useControllableState } from \"../../utils/use-controllable-state\";\nimport type { ContentProps, RootProps, TriggerProps } from \"./types\";\n\nconst COLLAPSIBLE_ROOT_NAME = \"CollapsibleRoot\";\nconst COLLAPSIBLE_TRIGGER_NAME = \"CollapsibleTrigger\";\nconst COLLAPSIBLE_CONTENT_NAME = \"CollapsibleContent\";\n\nconst CollapsibleContext = createContext<{\n open?: boolean;\n onOpenChange: (open: boolean) => void;\n disabled: boolean;\n contentId: string;\n} | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleRoot = forwardRef<HTMLDivElement, RootProps>(\n (\n {\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n defaultOpen,\n disabled = false,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const [isOpen, onOpenChange] = useControllableState(\n
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../src/primitives/Collapsible/index.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n} from \"react\";\n\nimport { useControllableState } from \"../../utils/use-controllable-state\";\nimport type { ContentProps, RootProps, TriggerProps } from \"./types\";\n\nconst COLLAPSIBLE_ROOT_NAME = \"CollapsibleRoot\";\nconst COLLAPSIBLE_TRIGGER_NAME = \"CollapsibleTrigger\";\nconst COLLAPSIBLE_CONTENT_NAME = \"CollapsibleContent\";\n\nconst CollapsibleContext = createContext<{\n open?: boolean;\n onOpenChange: (open: boolean) => void;\n disabled: boolean;\n contentId: string;\n} | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleRoot = forwardRef<HTMLDivElement, RootProps>(\n (\n {\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n defaultOpen,\n disabled = false,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const [isOpen, onOpenChange] = useControllableState(\n defaultOpen ?? true,\n controlledOpen,\n controlledOnOpenChange\n );\n const Component = asChild ? Slot : \"div\";\n const id = useId();\n\n return (\n <CollapsibleContext.Provider\n value={{ open: isOpen, onOpenChange, disabled, contentId: id }}\n >\n <Component\n {...props}\n ref={forwardedRef}\n data-state={isOpen ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n />\n </CollapsibleContext.Provider>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Trigger\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleTrigger = forwardRef<HTMLButtonElement, TriggerProps>(\n ({ onClick, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const context = useContext(CollapsibleContext);\n\n if (!context) {\n throw new Error(\"Collapsible.Root is missing from the React tree.\");\n }\n\n const { open, disabled, contentId, onOpenChange } = context;\n\n return (\n <Component\n {...props}\n ref={forwardedRef}\n type=\"button\"\n aria-controls={contentId}\n aria-expanded={open || false}\n data-state={open ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n disabled={disabled}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n if (disabled) return;\n onOpenChange(!open);\n }}\n />\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Content\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleContent = forwardRef<HTMLDivElement, ContentProps>(\n ({ asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const context = useContext(CollapsibleContext);\n const divRef = useRef<HTMLDivElement>(null);\n\n if (!context) {\n throw new Error(\"Collapsible.Root is missing from the React tree.\");\n }\n\n const { open, onOpenChange, disabled, contentId } = context;\n\n useEffect(() => {\n const element = divRef.current;\n if (element === null) return;\n\n const isHiddenUntilFoundSupported = \"onbeforematch\" in document.body;\n if (!isHiddenUntilFoundSupported) return;\n\n function handleBeforeMatch() {\n onOpenChange(true);\n }\n\n // https://developer.chrome.com/articles/hidden-until-found/\n element.addEventListener(\"beforematch\", handleBeforeMatch);\n return () => {\n element.removeEventListener(\"beforematch\", handleBeforeMatch);\n };\n }, [onOpenChange]);\n\n // Passing `string` to `hidden` in JSX is not currently supported: https://github.com/facebook/react/issues/24740\n useEffect(() => {\n const element = divRef.current;\n if (element === null) return;\n\n if (open) return;\n\n const isHiddenUntilFoundSupported = \"onbeforematch\" in document.body;\n if (!isHiddenUntilFoundSupported) return;\n\n element.setAttribute(\"hidden\", \"until-found\");\n return () => {\n element.removeAttribute(\"hidden\");\n };\n }, [open]);\n\n useImperativeHandle<\n HTMLDivElement | null,\n HTMLDivElement | null\n >(forwardedRef, () => {\n return divRef.current;\n }, []);\n\n return (\n <Component\n {...props}\n ref={divRef}\n data-state={open ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n id={contentId}\n hidden={!open}\n />\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n CollapsibleContent.displayName = COLLAPSIBLE_CONTENT_NAME;\n CollapsibleRoot.displayName = COLLAPSIBLE_ROOT_NAME;\n CollapsibleTrigger.displayName = COLLAPSIBLE_TRIGGER_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as Collapsible.*\nexport {\n CollapsibleContent as Content,\n CollapsibleRoot as Root,\n CollapsibleTrigger as Trigger,\n};\n"],"names":["createContext","forwardRef","useControllableState","Slot","useId","jsx","useContext","useRef","useEffect","useImperativeHandle"],"mappings":"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"}
|
|
@@ -17,9 +17,9 @@ const CollapsibleRoot = forwardRef(
|
|
|
17
17
|
...props
|
|
18
18
|
}, forwardedRef) => {
|
|
19
19
|
const [isOpen, onOpenChange] = useControllableState(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
defaultOpen ?? true,
|
|
21
|
+
controlledOpen,
|
|
22
|
+
controlledOnOpenChange
|
|
23
23
|
);
|
|
24
24
|
const Component = asChild ? Slot : "div";
|
|
25
25
|
const id = useId();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/primitives/Collapsible/index.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n} from \"react\";\n\nimport { useControllableState } from \"../../utils/use-controllable-state\";\nimport type { ContentProps, RootProps, TriggerProps } from \"./types\";\n\nconst COLLAPSIBLE_ROOT_NAME = \"CollapsibleRoot\";\nconst COLLAPSIBLE_TRIGGER_NAME = \"CollapsibleTrigger\";\nconst COLLAPSIBLE_CONTENT_NAME = \"CollapsibleContent\";\n\nconst CollapsibleContext = createContext<{\n open?: boolean;\n onOpenChange: (open: boolean) => void;\n disabled: boolean;\n contentId: string;\n} | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleRoot = forwardRef<HTMLDivElement, RootProps>(\n (\n {\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n defaultOpen,\n disabled = false,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const [isOpen, onOpenChange] = useControllableState(\n
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/primitives/Collapsible/index.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useId,\n useImperativeHandle,\n useRef,\n} from \"react\";\n\nimport { useControllableState } from \"../../utils/use-controllable-state\";\nimport type { ContentProps, RootProps, TriggerProps } from \"./types\";\n\nconst COLLAPSIBLE_ROOT_NAME = \"CollapsibleRoot\";\nconst COLLAPSIBLE_TRIGGER_NAME = \"CollapsibleTrigger\";\nconst COLLAPSIBLE_CONTENT_NAME = \"CollapsibleContent\";\n\nconst CollapsibleContext = createContext<{\n open?: boolean;\n onOpenChange: (open: boolean) => void;\n disabled: boolean;\n contentId: string;\n} | null>(null);\n\n/* -------------------------------------------------------------------------------------------------\n * Root\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleRoot = forwardRef<HTMLDivElement, RootProps>(\n (\n {\n open: controlledOpen,\n onOpenChange: controlledOnOpenChange,\n defaultOpen,\n disabled = false,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const [isOpen, onOpenChange] = useControllableState(\n defaultOpen ?? true,\n controlledOpen,\n controlledOnOpenChange\n );\n const Component = asChild ? Slot : \"div\";\n const id = useId();\n\n return (\n <CollapsibleContext.Provider\n value={{ open: isOpen, onOpenChange, disabled, contentId: id }}\n >\n <Component\n {...props}\n ref={forwardedRef}\n data-state={isOpen ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n />\n </CollapsibleContext.Provider>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Trigger\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleTrigger = forwardRef<HTMLButtonElement, TriggerProps>(\n ({ onClick, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const context = useContext(CollapsibleContext);\n\n if (!context) {\n throw new Error(\"Collapsible.Root is missing from the React tree.\");\n }\n\n const { open, disabled, contentId, onOpenChange } = context;\n\n return (\n <Component\n {...props}\n ref={forwardedRef}\n type=\"button\"\n aria-controls={contentId}\n aria-expanded={open || false}\n data-state={open ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n disabled={disabled}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n if (disabled) return;\n onOpenChange(!open);\n }}\n />\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Content\n * -----------------------------------------------------------------------------------------------*/\n\nconst CollapsibleContent = forwardRef<HTMLDivElement, ContentProps>(\n ({ asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const context = useContext(CollapsibleContext);\n const divRef = useRef<HTMLDivElement>(null);\n\n if (!context) {\n throw new Error(\"Collapsible.Root is missing from the React tree.\");\n }\n\n const { open, onOpenChange, disabled, contentId } = context;\n\n useEffect(() => {\n const element = divRef.current;\n if (element === null) return;\n\n const isHiddenUntilFoundSupported = \"onbeforematch\" in document.body;\n if (!isHiddenUntilFoundSupported) return;\n\n function handleBeforeMatch() {\n onOpenChange(true);\n }\n\n // https://developer.chrome.com/articles/hidden-until-found/\n element.addEventListener(\"beforematch\", handleBeforeMatch);\n return () => {\n element.removeEventListener(\"beforematch\", handleBeforeMatch);\n };\n }, [onOpenChange]);\n\n // Passing `string` to `hidden` in JSX is not currently supported: https://github.com/facebook/react/issues/24740\n useEffect(() => {\n const element = divRef.current;\n if (element === null) return;\n\n if (open) return;\n\n const isHiddenUntilFoundSupported = \"onbeforematch\" in document.body;\n if (!isHiddenUntilFoundSupported) return;\n\n element.setAttribute(\"hidden\", \"until-found\");\n return () => {\n element.removeAttribute(\"hidden\");\n };\n }, [open]);\n\n useImperativeHandle<\n HTMLDivElement | null,\n HTMLDivElement | null\n >(forwardedRef, () => {\n return divRef.current;\n }, []);\n\n return (\n <Component\n {...props}\n ref={divRef}\n data-state={open ? \"open\" : \"closed\"}\n data-disabled={disabled ? \"\" : undefined}\n id={contentId}\n hidden={!open}\n />\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n CollapsibleContent.displayName = COLLAPSIBLE_CONTENT_NAME;\n CollapsibleRoot.displayName = COLLAPSIBLE_ROOT_NAME;\n CollapsibleTrigger.displayName = COLLAPSIBLE_TRIGGER_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as Collapsible.*\nexport {\n CollapsibleContent as Content,\n CollapsibleRoot as Root,\n CollapsibleTrigger as Trigger,\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@liveblocks/core');
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var useRerender = require('./use-rerender.cjs');
|
|
5
6
|
|
|
6
|
-
function useControllableState(value, onChange
|
|
7
|
+
function useControllableState(defaultValue, value, onChange) {
|
|
7
8
|
const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
|
|
8
9
|
const isControlled = value !== void 0;
|
|
9
10
|
const wasControlled = react.useRef(isControlled);
|
|
10
11
|
react.useEffect(() => {
|
|
11
12
|
if (process.env.NODE_ENV !== "production" && wasControlled.current !== isControlled) {
|
|
12
13
|
core.console.warn(
|
|
13
|
-
`A component is changing from ${wasControlled ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}.`
|
|
14
|
+
`A component is changing from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}.`
|
|
14
15
|
);
|
|
15
16
|
}
|
|
16
17
|
wasControlled.current = isControlled;
|
|
@@ -29,6 +30,28 @@ function useControllableState(value, onChange, defaultValue) {
|
|
|
29
30
|
);
|
|
30
31
|
return [currentValue, setValue];
|
|
31
32
|
}
|
|
33
|
+
function useSemiControllableState(value, onChange) {
|
|
34
|
+
const [uncontrolledValue, setUncontrolledValue] = react.useState(value);
|
|
35
|
+
const lastChange = react.useRef("controlled");
|
|
36
|
+
const lastValue = react.useRef(value);
|
|
37
|
+
const [rerender] = useRerender.useRerender();
|
|
38
|
+
if (!Object.is(lastValue.current, value)) {
|
|
39
|
+
lastValue.current = value;
|
|
40
|
+
lastChange.current = "controlled";
|
|
41
|
+
}
|
|
42
|
+
const setValue = react.useCallback(
|
|
43
|
+
(value2) => {
|
|
44
|
+
lastChange.current = "uncontrolled";
|
|
45
|
+
setUncontrolledValue(value2);
|
|
46
|
+
rerender();
|
|
47
|
+
onChange?.(value2);
|
|
48
|
+
},
|
|
49
|
+
[onChange, rerender]
|
|
50
|
+
);
|
|
51
|
+
const currentValue = lastChange.current === "uncontrolled" ? uncontrolledValue : value;
|
|
52
|
+
return [currentValue, setValue];
|
|
53
|
+
}
|
|
32
54
|
|
|
33
55
|
exports.useControllableState = useControllableState;
|
|
56
|
+
exports.useSemiControllableState = useSemiControllableState;
|
|
34
57
|
//# sourceMappingURL=use-controllable-state.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-controllable-state.cjs","sources":["../../src/utils/use-controllable-state.ts"],"sourcesContent":["import { console } from \"@liveblocks/core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport function useControllableState<T>(\n value
|
|
1
|
+
{"version":3,"file":"use-controllable-state.cjs","sources":["../../src/utils/use-controllable-state.ts"],"sourcesContent":["import { console } from \"@liveblocks/core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useRerender } from \"./use-rerender\";\n\n/**\n * Hold a state in a \"controlled\" or \"uncontrolled\" way.\n */\nexport function useControllableState<T>(\n /**\n * The default uncontrolled value.\n */\n defaultValue: T,\n\n /**\n * The controlled value.\n *\n * If `undefined`, the returned value is uncontrolled.\n * If set, this controlled value is used and returned as is.\n */\n value: T | undefined,\n\n /**\n * The event handler called when the value changes.\n */\n onChange: ((value: T) => void) | undefined\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const isControlled = value !== undefined;\n const wasControlled = useRef(isControlled);\n\n useEffect(() => {\n if (\n process.env.NODE_ENV !== \"production\" &&\n wasControlled.current !== isControlled\n ) {\n console.warn(\n `A component is changing from ${\n wasControlled.current ? \"controlled\" : \"uncontrolled\"\n } to ${isControlled ? \"controlled\" : \"uncontrolled\"}.`\n );\n }\n\n wasControlled.current = isControlled;\n }, [isControlled]);\n\n const currentValue = isControlled ? value : uncontrolledValue;\n\n const setValue = useCallback(\n (value: T) => {\n if (isControlled) {\n return onChange?.(value);\n } else {\n setUncontrolledValue(value);\n\n return onChange?.(value);\n }\n },\n [isControlled, onChange]\n );\n\n return [currentValue, setValue] as const;\n}\n\n/**\n * @experimental\n *\n * Hold a value in a \"semi-controlled\" way: a controlled value that can be\n * overridden by uncontrolled changes in a \"most recent wins\" way.\n *\n * @example\n *\n * A `Collapsible` component uses `useSemiControllableState` to control\n * its \"open\" state, it accepts two optional props: `open` and `onOpenChange`.\n *\n * Internally, it passes them to `useSemiControllableState`:\n *\n * ```tsx\n * const [isOpen, setIsOpen] = useSemiControllableState(\n * open ?? true, // Defaults to `true` if `open` is not provided\n * onOpenChange\n * );\n *\n * // ... `isOpen` and `setIsOpen` are used in the component's implementation ...\n * ```\n *\n * And finally here's how it could be used in a \"semi-controlled\" way:\n *\n * ```tsx\n * const status: `\"loading\" | \"success\" | \"error\"`;\n *\n * <Collapsible open={status === \"success\"} />\n * ```\n *\n * Like with a traditional controlled value, the collapsible will start closed\n * and will automatically open when `status` becomes `\"success\"`.\n *\n * But unlike with a traditional controlled value, the collapsible can still\n * open/close when it's clicked on by the user, overriding `open={status === \"success\"}`.\n *\n * It's possible to use it as a traditional uncontrolled value:\n *\n * ```tsx\n * const defaultOpen = false;\n *\n * <Collapsible open={defaultOpen} />\n * ```\n *\n * Or to sync the uncontrolled value like with a traditional uncontrolled value:\n *\n * ```tsx\n * const [isOpen, setIsOpen] = useState(false);\n *\n * // `isOpen` is synced with the uncontrolled value when the user clicks\n * <Collapsible open={isOpen} onOpenChange={setIsOpen} />\n * ```\n *\n * But with the caveat that it will still be possible to change the\n * uncontrolled value:\n *\n * ```tsx\n * const open = false;\n *\n * // Clicking on the collapsible will still open/close it, unlike with a\n * // traditional controlled value.\n * <Collapsible open={open} />\n * ```\n */\nexport function useSemiControllableState<T>(\n /**\n * The controlled value.\n *\n * When this value changes, it becomes the current value.\n * But unlike a traditional controlled value, it can be overridden by\n * uncontrolled changes.\n */\n value: T,\n\n /**\n * The event handler called when the uncontrolled value changes.\n */\n onChange: ((value: T) => void) | undefined\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(value);\n const lastChange = useRef<\"uncontrolled\" | \"controlled\">(\"controlled\");\n const lastValue = useRef(value);\n const [rerender] = useRerender();\n\n // Listen to `value` changes during the render phase to avoid\n // having to always sync `uncontrolledValue` on every change.\n if (!Object.is(lastValue.current, value)) {\n lastValue.current = value;\n lastChange.current = \"controlled\";\n }\n\n const setValue = useCallback(\n (value: T) => {\n lastChange.current = \"uncontrolled\";\n setUncontrolledValue(value);\n\n // If the new `uncontrolledValue` is the same as last time it was the \"last change\",\n // `setUncontrolledValue` won't trigger a re-render, but the fact that it's becoming\n // uncontrolled again is a change that needs a re-render.\n rerender();\n\n onChange?.(value);\n },\n [onChange, rerender]\n );\n\n const currentValue =\n lastChange.current === \"uncontrolled\" ? uncontrolledValue : value;\n\n return [currentValue, setValue] as const;\n}\n"],"names":["useState","useRef","useEffect","console","useCallback","value","useRerender"],"mappings":";;;;;;AAQgB,SAAA,oBAAA,CAId,YAQA,EAAA,KAAA,EAKA,QACA,EAAA;AACA,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAIA,eAAS,YAAY,CAAA,CAAA;AACvE,EAAA,MAAM,eAAe,KAAU,KAAA,KAAA,CAAA,CAAA;AAC/B,EAAM,MAAA,aAAA,GAAgBC,aAAO,YAAY,CAAA,CAAA;AAEzC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IACE,QAAQ,GAAI,CAAA,QAAA,KAAa,YACzB,IAAA,aAAA,CAAc,YAAY,YAC1B,EAAA;AACA,MAAQC,YAAA,CAAA,IAAA;AAAA,QACN,gCACE,aAAc,CAAA,OAAA,GAAU,YAAe,GAAA,cAAA,CAAA,IAAA,EAClC,eAAe,YAAe,GAAA,cAAA,CAAA,CAAA,CAAA;AAAA,OACvC,CAAA;AAAA,KACF;AAEA,IAAA,aAAA,CAAc,OAAU,GAAA,YAAA,CAAA;AAAA,GAC1B,EAAG,CAAC,YAAY,CAAC,CAAA,CAAA;AAEjB,EAAM,MAAA,YAAA,GAAe,eAAe,KAAQ,GAAA,iBAAA,CAAA;AAE5C,EAAA,MAAM,QAAW,GAAAC,iBAAA;AAAA,IACf,CAACC,MAAa,KAAA;AACZ,MAAA,IAAI,YAAc,EAAA;AAChB,QAAA,OAAO,WAAWA,MAAK,CAAA,CAAA;AAAA,OAClB,MAAA;AACL,QAAA,oBAAA,CAAqBA,MAAK,CAAA,CAAA;AAE1B,QAAA,OAAO,WAAWA,MAAK,CAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,IACA,CAAC,cAAc,QAAQ,CAAA;AAAA,GACzB,CAAA;AAEA,EAAO,OAAA,CAAC,cAAc,QAAQ,CAAA,CAAA;AAChC,CAAA;AAkEgB,SAAA,wBAAA,CAQd,OAKA,QACA,EAAA;AACA,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAIL,eAAS,KAAK,CAAA,CAAA;AAChE,EAAM,MAAA,UAAA,GAAaC,aAAsC,YAAY,CAAA,CAAA;AACrE,EAAM,MAAA,SAAA,GAAYA,aAAO,KAAK,CAAA,CAAA;AAC9B,EAAM,MAAA,CAAC,QAAQ,CAAA,GAAIK,uBAAY,EAAA,CAAA;AAI/B,EAAA,IAAI,CAAC,MAAO,CAAA,EAAA,CAAG,SAAU,CAAA,OAAA,EAAS,KAAK,CAAG,EAAA;AACxC,IAAA,SAAA,CAAU,OAAU,GAAA,KAAA,CAAA;AACpB,IAAA,UAAA,CAAW,OAAU,GAAA,YAAA,CAAA;AAAA,GACvB;AAEA,EAAA,MAAM,QAAW,GAAAF,iBAAA;AAAA,IACf,CAACC,MAAa,KAAA;AACZ,MAAA,UAAA,CAAW,OAAU,GAAA,cAAA,CAAA;AACrB,MAAA,oBAAA,CAAqBA,MAAK,CAAA,CAAA;AAK1B,MAAS,QAAA,EAAA,CAAA;AAET,MAAA,QAAA,GAAWA,MAAK,CAAA,CAAA;AAAA,KAClB;AAAA,IACA,CAAC,UAAU,QAAQ,CAAA;AAAA,GACrB,CAAA;AAEA,EAAA,MAAM,YACJ,GAAA,UAAA,CAAW,OAAY,KAAA,cAAA,GAAiB,iBAAoB,GAAA,KAAA,CAAA;AAE9D,EAAO,OAAA,CAAC,cAAc,QAAQ,CAAA,CAAA;AAChC;;;;;"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { console } from '@liveblocks/core';
|
|
2
2
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
import { useRerender } from './use-rerender.js';
|
|
3
4
|
|
|
4
|
-
function useControllableState(value, onChange
|
|
5
|
+
function useControllableState(defaultValue, value, onChange) {
|
|
5
6
|
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
6
7
|
const isControlled = value !== void 0;
|
|
7
8
|
const wasControlled = useRef(isControlled);
|
|
8
9
|
useEffect(() => {
|
|
9
10
|
if (process.env.NODE_ENV !== "production" && wasControlled.current !== isControlled) {
|
|
10
11
|
console.warn(
|
|
11
|
-
`A component is changing from ${wasControlled ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}.`
|
|
12
|
+
`A component is changing from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}.`
|
|
12
13
|
);
|
|
13
14
|
}
|
|
14
15
|
wasControlled.current = isControlled;
|
|
@@ -27,6 +28,27 @@ function useControllableState(value, onChange, defaultValue) {
|
|
|
27
28
|
);
|
|
28
29
|
return [currentValue, setValue];
|
|
29
30
|
}
|
|
31
|
+
function useSemiControllableState(value, onChange) {
|
|
32
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(value);
|
|
33
|
+
const lastChange = useRef("controlled");
|
|
34
|
+
const lastValue = useRef(value);
|
|
35
|
+
const [rerender] = useRerender();
|
|
36
|
+
if (!Object.is(lastValue.current, value)) {
|
|
37
|
+
lastValue.current = value;
|
|
38
|
+
lastChange.current = "controlled";
|
|
39
|
+
}
|
|
40
|
+
const setValue = useCallback(
|
|
41
|
+
(value2) => {
|
|
42
|
+
lastChange.current = "uncontrolled";
|
|
43
|
+
setUncontrolledValue(value2);
|
|
44
|
+
rerender();
|
|
45
|
+
onChange?.(value2);
|
|
46
|
+
},
|
|
47
|
+
[onChange, rerender]
|
|
48
|
+
);
|
|
49
|
+
const currentValue = lastChange.current === "uncontrolled" ? uncontrolledValue : value;
|
|
50
|
+
return [currentValue, setValue];
|
|
51
|
+
}
|
|
30
52
|
|
|
31
|
-
export { useControllableState };
|
|
53
|
+
export { useControllableState, useSemiControllableState };
|
|
32
54
|
//# sourceMappingURL=use-controllable-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-controllable-state.js","sources":["../../src/utils/use-controllable-state.ts"],"sourcesContent":["import { console } from \"@liveblocks/core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport function useControllableState<T>(\n value
|
|
1
|
+
{"version":3,"file":"use-controllable-state.js","sources":["../../src/utils/use-controllable-state.ts"],"sourcesContent":["import { console } from \"@liveblocks/core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { useRerender } from \"./use-rerender\";\n\n/**\n * Hold a state in a \"controlled\" or \"uncontrolled\" way.\n */\nexport function useControllableState<T>(\n /**\n * The default uncontrolled value.\n */\n defaultValue: T,\n\n /**\n * The controlled value.\n *\n * If `undefined`, the returned value is uncontrolled.\n * If set, this controlled value is used and returned as is.\n */\n value: T | undefined,\n\n /**\n * The event handler called when the value changes.\n */\n onChange: ((value: T) => void) | undefined\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const isControlled = value !== undefined;\n const wasControlled = useRef(isControlled);\n\n useEffect(() => {\n if (\n process.env.NODE_ENV !== \"production\" &&\n wasControlled.current !== isControlled\n ) {\n console.warn(\n `A component is changing from ${\n wasControlled.current ? \"controlled\" : \"uncontrolled\"\n } to ${isControlled ? \"controlled\" : \"uncontrolled\"}.`\n );\n }\n\n wasControlled.current = isControlled;\n }, [isControlled]);\n\n const currentValue = isControlled ? value : uncontrolledValue;\n\n const setValue = useCallback(\n (value: T) => {\n if (isControlled) {\n return onChange?.(value);\n } else {\n setUncontrolledValue(value);\n\n return onChange?.(value);\n }\n },\n [isControlled, onChange]\n );\n\n return [currentValue, setValue] as const;\n}\n\n/**\n * @experimental\n *\n * Hold a value in a \"semi-controlled\" way: a controlled value that can be\n * overridden by uncontrolled changes in a \"most recent wins\" way.\n *\n * @example\n *\n * A `Collapsible` component uses `useSemiControllableState` to control\n * its \"open\" state, it accepts two optional props: `open` and `onOpenChange`.\n *\n * Internally, it passes them to `useSemiControllableState`:\n *\n * ```tsx\n * const [isOpen, setIsOpen] = useSemiControllableState(\n * open ?? true, // Defaults to `true` if `open` is not provided\n * onOpenChange\n * );\n *\n * // ... `isOpen` and `setIsOpen` are used in the component's implementation ...\n * ```\n *\n * And finally here's how it could be used in a \"semi-controlled\" way:\n *\n * ```tsx\n * const status: `\"loading\" | \"success\" | \"error\"`;\n *\n * <Collapsible open={status === \"success\"} />\n * ```\n *\n * Like with a traditional controlled value, the collapsible will start closed\n * and will automatically open when `status` becomes `\"success\"`.\n *\n * But unlike with a traditional controlled value, the collapsible can still\n * open/close when it's clicked on by the user, overriding `open={status === \"success\"}`.\n *\n * It's possible to use it as a traditional uncontrolled value:\n *\n * ```tsx\n * const defaultOpen = false;\n *\n * <Collapsible open={defaultOpen} />\n * ```\n *\n * Or to sync the uncontrolled value like with a traditional uncontrolled value:\n *\n * ```tsx\n * const [isOpen, setIsOpen] = useState(false);\n *\n * // `isOpen` is synced with the uncontrolled value when the user clicks\n * <Collapsible open={isOpen} onOpenChange={setIsOpen} />\n * ```\n *\n * But with the caveat that it will still be possible to change the\n * uncontrolled value:\n *\n * ```tsx\n * const open = false;\n *\n * // Clicking on the collapsible will still open/close it, unlike with a\n * // traditional controlled value.\n * <Collapsible open={open} />\n * ```\n */\nexport function useSemiControllableState<T>(\n /**\n * The controlled value.\n *\n * When this value changes, it becomes the current value.\n * But unlike a traditional controlled value, it can be overridden by\n * uncontrolled changes.\n */\n value: T,\n\n /**\n * The event handler called when the uncontrolled value changes.\n */\n onChange: ((value: T) => void) | undefined\n) {\n const [uncontrolledValue, setUncontrolledValue] = useState(value);\n const lastChange = useRef<\"uncontrolled\" | \"controlled\">(\"controlled\");\n const lastValue = useRef(value);\n const [rerender] = useRerender();\n\n // Listen to `value` changes during the render phase to avoid\n // having to always sync `uncontrolledValue` on every change.\n if (!Object.is(lastValue.current, value)) {\n lastValue.current = value;\n lastChange.current = \"controlled\";\n }\n\n const setValue = useCallback(\n (value: T) => {\n lastChange.current = \"uncontrolled\";\n setUncontrolledValue(value);\n\n // If the new `uncontrolledValue` is the same as last time it was the \"last change\",\n // `setUncontrolledValue` won't trigger a re-render, but the fact that it's becoming\n // uncontrolled again is a change that needs a re-render.\n rerender();\n\n onChange?.(value);\n },\n [onChange, rerender]\n );\n\n const currentValue =\n lastChange.current === \"uncontrolled\" ? uncontrolledValue : value;\n\n return [currentValue, setValue] as const;\n}\n"],"names":["value"],"mappings":";;;;AAQgB,SAAA,oBAAA,CAId,YAQA,EAAA,KAAA,EAKA,QACA,EAAA;AACA,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,YAAY,CAAA,CAAA;AACvE,EAAA,MAAM,eAAe,KAAU,KAAA,KAAA,CAAA,CAAA;AAC/B,EAAM,MAAA,aAAA,GAAgB,OAAO,YAAY,CAAA,CAAA;AAEzC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IACE,QAAQ,GAAI,CAAA,QAAA,KAAa,YACzB,IAAA,aAAA,CAAc,YAAY,YAC1B,EAAA;AACA,MAAQ,OAAA,CAAA,IAAA;AAAA,QACN,gCACE,aAAc,CAAA,OAAA,GAAU,YAAe,GAAA,cAAA,CAAA,IAAA,EAClC,eAAe,YAAe,GAAA,cAAA,CAAA,CAAA,CAAA;AAAA,OACvC,CAAA;AAAA,KACF;AAEA,IAAA,aAAA,CAAc,OAAU,GAAA,YAAA,CAAA;AAAA,GAC1B,EAAG,CAAC,YAAY,CAAC,CAAA,CAAA;AAEjB,EAAM,MAAA,YAAA,GAAe,eAAe,KAAQ,GAAA,iBAAA,CAAA;AAE5C,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAACA,MAAa,KAAA;AACZ,MAAA,IAAI,YAAc,EAAA;AAChB,QAAA,OAAO,WAAWA,MAAK,CAAA,CAAA;AAAA,OAClB,MAAA;AACL,QAAA,oBAAA,CAAqBA,MAAK,CAAA,CAAA;AAE1B,QAAA,OAAO,WAAWA,MAAK,CAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,IACA,CAAC,cAAc,QAAQ,CAAA;AAAA,GACzB,CAAA;AAEA,EAAO,OAAA,CAAC,cAAc,QAAQ,CAAA,CAAA;AAChC,CAAA;AAkEgB,SAAA,wBAAA,CAQd,OAKA,QACA,EAAA;AACA,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAChE,EAAM,MAAA,UAAA,GAAa,OAAsC,YAAY,CAAA,CAAA;AACrE,EAAM,MAAA,SAAA,GAAY,OAAO,KAAK,CAAA,CAAA;AAC9B,EAAM,MAAA,CAAC,QAAQ,CAAA,GAAI,WAAY,EAAA,CAAA;AAI/B,EAAA,IAAI,CAAC,MAAO,CAAA,EAAA,CAAG,SAAU,CAAA,OAAA,EAAS,KAAK,CAAG,EAAA;AACxC,IAAA,SAAA,CAAU,OAAU,GAAA,KAAA,CAAA;AACpB,IAAA,UAAA,CAAW,OAAU,GAAA,YAAA,CAAA;AAAA,GACvB;AAEA,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAACA,MAAa,KAAA;AACZ,MAAA,UAAA,CAAW,OAAU,GAAA,cAAA,CAAA;AACrB,MAAA,oBAAA,CAAqBA,MAAK,CAAA,CAAA;AAK1B,MAAS,QAAA,EAAA,CAAA;AAET,MAAA,QAAA,GAAWA,MAAK,CAAA,CAAA;AAAA,KAClB;AAAA,IACA,CAAC,UAAU,QAAQ,CAAA;AAAA,GACrB,CAAA;AAEA,EAAA,MAAM,YACJ,GAAA,UAAA,CAAW,OAAY,KAAA,cAAA,GAAiB,iBAAoB,GAAA,KAAA,CAAA;AAE9D,EAAO,OAAA,CAAC,cAAc,QAAQ,CAAA,CAAA;AAChC;;;;"}
|
|
@@ -74,7 +74,9 @@ function useIntersectionCallback(ref, callback, options) {
|
|
|
74
74
|
}, [ref, enabled, latestCallback, root, rootMargin]);
|
|
75
75
|
}
|
|
76
76
|
function useVisible(ref, options) {
|
|
77
|
-
const [isVisible, setVisible] = react.useState(
|
|
77
|
+
const [isVisible, setVisible] = react.useState(
|
|
78
|
+
options?.initialValue !== void 0 ? options.initialValue : false
|
|
79
|
+
);
|
|
78
80
|
useIntersectionCallback(
|
|
79
81
|
ref,
|
|
80
82
|
(isIntersecting) => setVisible(isIntersecting),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-visible.cjs","sources":["../../src/utils/use-visible.ts"],"sourcesContent":["import { type RefObject, useEffect, useState } from \"react\";\n\nimport { useLatest } from \"./use-latest\";\n\ninterface ObserveOptions {\n rootMargin?: string | number;\n root?: RefObject<Element>;\n}\n\ninterface Options extends ObserveOptions {\n enabled?: boolean;\n}\n\ntype IntersectionObserverSingleCallback = (\n entry: IntersectionObserverEntry\n) => void;\n\nlet optionlessIntersectionObserver: IntersectionObserver | undefined;\nconst optionlessIntersectionCallbacks = new WeakMap<\n Element,\n IntersectionObserverSingleCallback\n>();\n\nconst individualIntersectionObservers = new WeakMap<\n Element,\n IntersectionObserver\n>();\n\nfunction observe(\n element: Element,\n callback: IntersectionObserverSingleCallback,\n options?: ObserveOptions\n) {\n // Observers without options share a common IntersectionObserver instance, ones with options have their own\n if (!options) {\n if (!optionlessIntersectionObserver) {\n optionlessIntersectionObserver = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n const callback = optionlessIntersectionCallbacks.get(entry.target);\n\n callback?.(entry);\n }\n });\n }\n\n optionlessIntersectionCallbacks.set(element, callback);\n optionlessIntersectionObserver.observe(element);\n } else {\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n callback?.(entry);\n }\n },\n {\n root: options.root?.current,\n rootMargin:\n typeof options.rootMargin === \"number\"\n ? `${options.rootMargin}px`\n : options.rootMargin,\n }\n );\n\n individualIntersectionObservers.set(element, observer);\n observer.observe(element);\n }\n}\n\nfunction unobserve(element: Element, options?: ObserveOptions) {\n if (!options) {\n optionlessIntersectionCallbacks.delete(element);\n optionlessIntersectionObserver?.unobserve(element);\n } else {\n const observer = individualIntersectionObservers.get(element);\n\n observer?.unobserve(element);\n individualIntersectionObservers.delete(element);\n }\n}\n\n/**\n * Observe when an element enters or exits the viewport.\n *\n * If you only need to get a stateful visibility value, use the higher level hook `useVisible` instead.\n */\nexport function useIntersectionCallback(\n ref: RefObject<Element>,\n callback: (isIntersecting: boolean, entry: IntersectionObserverEntry) => void,\n options?: Options\n) {\n const enabled = options?.enabled ?? true;\n const latestCallback = useLatest(callback);\n const { root, rootMargin } = options ?? {};\n\n useEffect(() => {\n const element = ref.current;\n\n if (!element) {\n return;\n }\n\n const observeOptions: ObserveOptions = {\n root,\n rootMargin,\n };\n\n if (enabled) {\n observe(\n element,\n (entry) => {\n // The intersection observer entry might be useful in some cases but the main information\n // is whether the element is intersecting or not so we pass that as the first argument.\n latestCallback.current(entry.isIntersecting, entry);\n },\n observeOptions\n );\n } else {\n unobserve(element, observeOptions);\n }\n\n return () => {\n unobserve(element, observeOptions);\n };\n }, [ref, enabled, latestCallback, root, rootMargin]);\n}\n\n/**\n * Observe whether an element is currently visible or not.\n */\nexport function useVisible(ref: RefObject<Element
|
|
1
|
+
{"version":3,"file":"use-visible.cjs","sources":["../../src/utils/use-visible.ts"],"sourcesContent":["import { type RefObject, useEffect, useState } from \"react\";\n\nimport { useLatest } from \"./use-latest\";\n\ninterface ObserveOptions {\n rootMargin?: string | number;\n root?: RefObject<Element>;\n}\n\ninterface Options extends ObserveOptions {\n enabled?: boolean;\n}\n\ninterface VisibleOptions<T = boolean> extends Options {\n initialValue?: T;\n}\n\ntype IntersectionObserverSingleCallback = (\n entry: IntersectionObserverEntry\n) => void;\n\nlet optionlessIntersectionObserver: IntersectionObserver | undefined;\nconst optionlessIntersectionCallbacks = new WeakMap<\n Element,\n IntersectionObserverSingleCallback\n>();\n\nconst individualIntersectionObservers = new WeakMap<\n Element,\n IntersectionObserver\n>();\n\nfunction observe(\n element: Element,\n callback: IntersectionObserverSingleCallback,\n options?: ObserveOptions\n) {\n // Observers without options share a common IntersectionObserver instance, ones with options have their own\n if (!options) {\n if (!optionlessIntersectionObserver) {\n optionlessIntersectionObserver = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n const callback = optionlessIntersectionCallbacks.get(entry.target);\n\n callback?.(entry);\n }\n });\n }\n\n optionlessIntersectionCallbacks.set(element, callback);\n optionlessIntersectionObserver.observe(element);\n } else {\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n callback?.(entry);\n }\n },\n {\n root: options.root?.current,\n rootMargin:\n typeof options.rootMargin === \"number\"\n ? `${options.rootMargin}px`\n : options.rootMargin,\n }\n );\n\n individualIntersectionObservers.set(element, observer);\n observer.observe(element);\n }\n}\n\nfunction unobserve(element: Element, options?: ObserveOptions) {\n if (!options) {\n optionlessIntersectionCallbacks.delete(element);\n optionlessIntersectionObserver?.unobserve(element);\n } else {\n const observer = individualIntersectionObservers.get(element);\n\n observer?.unobserve(element);\n individualIntersectionObservers.delete(element);\n }\n}\n\n/**\n * Observe when an element enters or exits the viewport.\n *\n * If you only need to get a stateful visibility value, use the higher level hook `useVisible` instead.\n */\nexport function useIntersectionCallback(\n ref: RefObject<Element>,\n callback: (isIntersecting: boolean, entry: IntersectionObserverEntry) => void,\n options?: Options\n) {\n const enabled = options?.enabled ?? true;\n const latestCallback = useLatest(callback);\n const { root, rootMargin } = options ?? {};\n\n useEffect(() => {\n const element = ref.current;\n\n if (!element) {\n return;\n }\n\n const observeOptions: ObserveOptions = {\n root,\n rootMargin,\n };\n\n if (enabled) {\n observe(\n element,\n (entry) => {\n // The intersection observer entry might be useful in some cases but the main information\n // is whether the element is intersecting or not so we pass that as the first argument.\n latestCallback.current(entry.isIntersecting, entry);\n },\n observeOptions\n );\n } else {\n unobserve(element, observeOptions);\n }\n\n return () => {\n unobserve(element, observeOptions);\n };\n }, [ref, enabled, latestCallback, root, rootMargin]);\n}\n\n/**\n * Observe whether an element is currently visible or not.\n */\nexport function useVisible<T extends boolean | null = boolean>(\n ref: RefObject<Element>,\n options?: VisibleOptions<T>\n) {\n const [isVisible, setVisible] = useState(\n options?.initialValue !== undefined ? options.initialValue : false\n );\n\n useIntersectionCallback(\n ref,\n (isIntersecting) => setVisible(isIntersecting),\n options\n );\n\n return isVisible;\n}\n"],"names":["callback","useLatest","useEffect","useState"],"mappings":";;;;;AAqBA,IAAI,8BAAA,CAAA;AACJ,MAAM,+BAAA,uBAAsC,OAG1C,EAAA,CAAA;AAEF,MAAM,+BAAA,uBAAsC,OAG1C,EAAA,CAAA;AAEF,SAAS,OAAA,CACP,OACA,EAAA,QAAA,EACA,OACA,EAAA;AAEA,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAA,IAAI,CAAC,8BAAgC,EAAA;AACnC,MAAiC,8BAAA,GAAA,IAAI,oBAAqB,CAAA,CAAC,OAAY,KAAA;AACrE,QAAA,KAAA,MAAW,SAAS,OAAS,EAAA;AAC3B,UAAA,MAAMA,SAAW,GAAA,+BAAA,CAAgC,GAAI,CAAA,KAAA,CAAM,MAAM,CAAA,CAAA;AAEjE,UAAAA,YAAW,KAAK,CAAA,CAAA;AAAA,SAClB;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAEA,IAAgC,+BAAA,CAAA,GAAA,CAAI,SAAS,QAAQ,CAAA,CAAA;AACrD,IAAA,8BAAA,CAA+B,QAAQ,OAAO,CAAA,CAAA;AAAA,GACzC,MAAA;AACL,IAAA,MAAM,WAAW,IAAI,oBAAA;AAAA,MACnB,CAAC,OAAY,KAAA;AACX,QAAA,KAAA,MAAW,SAAS,OAAS,EAAA;AAC3B,UAAA,QAAA,GAAW,KAAK,CAAA,CAAA;AAAA,SAClB;AAAA,OACF;AAAA,MACA;AAAA,QACE,IAAA,EAAM,QAAQ,IAAM,EAAA,OAAA;AAAA,QACpB,UAAA,EACE,OAAO,OAAQ,CAAA,UAAA,KAAe,WAC1B,CAAG,EAAA,OAAA,CAAQ,iBACX,OAAQ,CAAA,UAAA;AAAA,OAChB;AAAA,KACF,CAAA;AAEA,IAAgC,+BAAA,CAAA,GAAA,CAAI,SAAS,QAAQ,CAAA,CAAA;AACrD,IAAA,QAAA,CAAS,QAAQ,OAAO,CAAA,CAAA;AAAA,GAC1B;AACF,CAAA;AAEA,SAAS,SAAA,CAAU,SAAkB,OAA0B,EAAA;AAC7D,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAA,+BAAA,CAAgC,OAAO,OAAO,CAAA,CAAA;AAC9C,IAAA,8BAAA,EAAgC,UAAU,OAAO,CAAA,CAAA;AAAA,GAC5C,MAAA;AACL,IAAM,MAAA,QAAA,GAAW,+BAAgC,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAE5D,IAAA,QAAA,EAAU,UAAU,OAAO,CAAA,CAAA;AAC3B,IAAA,+BAAA,CAAgC,OAAO,OAAO,CAAA,CAAA;AAAA,GAChD;AACF,CAAA;AAOgB,SAAA,uBAAA,CACd,GACA,EAAA,QAAA,EACA,OACA,EAAA;AACA,EAAM,MAAA,OAAA,GAAU,SAAS,OAAW,IAAA,IAAA,CAAA;AACpC,EAAM,MAAA,cAAA,GAAiBC,oBAAU,QAAQ,CAAA,CAAA;AACzC,EAAA,MAAM,EAAE,IAAA,EAAM,UAAW,EAAA,GAAI,WAAW,EAAC,CAAA;AAEzC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAU,GAAI,CAAA,OAAA,CAAA;AAEpB,IAAA,IAAI,CAAC,OAAS,EAAA;AACZ,MAAA,OAAA;AAAA,KACF;AAEA,IAAA,MAAM,cAAiC,GAAA;AAAA,MACrC,IAAA;AAAA,MACA,UAAA;AAAA,KACF,CAAA;AAEA,IAAA,IAAI,OAAS,EAAA;AACX,MAAA,OAAA;AAAA,QACE,OAAA;AAAA,QACA,CAAC,KAAU,KAAA;AAGT,UAAe,cAAA,CAAA,OAAA,CAAQ,KAAM,CAAA,cAAA,EAAgB,KAAK,CAAA,CAAA;AAAA,SACpD;AAAA,QACA,cAAA;AAAA,OACF,CAAA;AAAA,KACK,MAAA;AACL,MAAA,SAAA,CAAU,SAAS,cAAc,CAAA,CAAA;AAAA,KACnC;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,CAAU,SAAS,cAAc,CAAA,CAAA;AAAA,KACnC,CAAA;AAAA,KACC,CAAC,GAAA,EAAK,SAAS,cAAgB,EAAA,IAAA,EAAM,UAAU,CAAC,CAAA,CAAA;AACrD,CAAA;AAKgB,SAAA,UAAA,CACd,KACA,OACA,EAAA;AACA,EAAM,MAAA,CAAC,SAAW,EAAA,UAAU,CAAI,GAAAC,cAAA;AAAA,IAC9B,OAAS,EAAA,YAAA,KAAiB,KAAY,CAAA,GAAA,OAAA,CAAQ,YAAe,GAAA,KAAA;AAAA,GAC/D,CAAA;AAEA,EAAA,uBAAA;AAAA,IACE,GAAA;AAAA,IACA,CAAC,cAAmB,KAAA,UAAA,CAAW,cAAc,CAAA;AAAA,IAC7C,OAAA;AAAA,GACF,CAAA;AAEA,EAAO,OAAA,SAAA,CAAA;AACT;;;;;"}
|
|
@@ -72,7 +72,9 @@ function useIntersectionCallback(ref, callback, options) {
|
|
|
72
72
|
}, [ref, enabled, latestCallback, root, rootMargin]);
|
|
73
73
|
}
|
|
74
74
|
function useVisible(ref, options) {
|
|
75
|
-
const [isVisible, setVisible] = useState(
|
|
75
|
+
const [isVisible, setVisible] = useState(
|
|
76
|
+
options?.initialValue !== void 0 ? options.initialValue : false
|
|
77
|
+
);
|
|
76
78
|
useIntersectionCallback(
|
|
77
79
|
ref,
|
|
78
80
|
(isIntersecting) => setVisible(isIntersecting),
|