@cossistant/react 0.0.14 → 0.0.17
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/hooks/index.d.ts +2 -1
- package/hooks/index.js +2 -1
- package/hooks/use-home-page.js +1 -1
- package/hooks/use-home-page.js.map +1 -1
- package/hooks/use-scroll-mask.d.ts +24 -0
- package/hooks/use-scroll-mask.d.ts.map +1 -0
- package/hooks/use-scroll-mask.js +90 -0
- package/hooks/use-scroll-mask.js.map +1 -0
- package/hooks/use-send-message.js +1 -1
- package/hooks/use-send-message.js.map +1 -1
- package/index.d.ts +7 -2
- package/index.js +9 -5
- package/package.json +8 -4
- package/parse.d.ts.map +1 -1
- package/primitives/avatar/image.d.ts +1 -1
- package/primitives/bubble.d.ts +10 -2
- package/primitives/bubble.d.ts.map +1 -1
- package/primitives/bubble.js +11 -3
- package/primitives/bubble.js.map +1 -1
- package/primitives/conversation-timeline.d.ts.map +1 -1
- package/primitives/conversation-timeline.js +10 -20
- package/primitives/conversation-timeline.js.map +1 -1
- package/primitives/index.d.ts +5 -2
- package/primitives/index.js +11 -3
- package/primitives/index.parts.d.ts +4 -1
- package/primitives/index.parts.js +5 -2
- package/primitives/multimodal-input.d.ts +2 -2
- package/primitives/multimodal-input.d.ts.map +1 -1
- package/primitives/page-registry.d.ts +30 -0
- package/primitives/page-registry.d.ts.map +1 -0
- package/primitives/page-registry.js +45 -0
- package/primitives/page-registry.js.map +1 -0
- package/primitives/page.d.ts +21 -0
- package/primitives/page.d.ts.map +1 -0
- package/primitives/page.js +18 -0
- package/primitives/page.js.map +1 -0
- package/primitives/router.d.ts +35 -0
- package/primitives/router.d.ts.map +1 -0
- package/primitives/router.js +22 -0
- package/primitives/router.js.map +1 -0
- package/primitives/window.d.ts +8 -3
- package/primitives/window.d.ts.map +1 -1
- package/primitives/window.js +8 -3
- package/primitives/window.js.map +1 -1
- package/realtime/index.js +1 -1
- package/realtime/provider.js +1 -1
- package/realtime/support-provider.js +0 -4
- package/realtime/support-provider.js.map +1 -1
- package/schemas2.d.ts.map +1 -1
- package/support/components/avatar-stack.js +1 -1
- package/support/components/avatar-stack.js.map +1 -1
- package/support/components/bubble.js +1 -1
- package/support/components/bubble.js.map +1 -1
- package/support/components/button.js +3 -3
- package/support/components/button.js.map +1 -1
- package/support/components/container.js +1 -1
- package/support/components/container.js.map +1 -1
- package/support/components/conversation-timeline.js +1 -1
- package/support/components/conversation-timeline.js.map +1 -1
- package/support/components/multimodal-input.js +2 -2
- package/support/components/multimodal-input.js.map +1 -1
- package/support/components/support-content.d.ts +5 -7
- package/support/components/support-content.d.ts.map +1 -1
- package/support/components/support-content.js +9 -11
- package/support/components/support-content.js.map +1 -1
- package/support/components/theme-wrapper.d.ts +15 -0
- package/support/components/theme-wrapper.d.ts.map +1 -0
- package/support/components/theme-wrapper.js +18 -0
- package/support/components/theme-wrapper.js.map +1 -0
- package/support/components/timeline-identification-tool.js +2 -2
- package/support/components/timeline-identification-tool.js.map +1 -1
- package/support/components/watermark.js +2 -2
- package/support/components/watermark.js.map +1 -1
- package/support/index.d.ts +36 -6
- package/support/index.d.ts.map +1 -1
- package/support/index.js +43 -20
- package/support/index.js.map +1 -1
- package/support/pages/articles.d.ts +4 -1
- package/support/pages/articles.d.ts.map +1 -1
- package/support/pages/articles.js +1 -1
- package/support/pages/articles.js.map +1 -1
- package/support/pages/conversation-history.d.ts +5 -10
- package/support/pages/conversation-history.d.ts.map +1 -1
- package/support/pages/conversation-history.js +2 -9
- package/support/pages/conversation-history.js.map +1 -1
- package/support/pages/conversation.d.ts +17 -12
- package/support/pages/conversation.d.ts.map +1 -1
- package/support/pages/conversation.js +5 -2
- package/support/pages/conversation.js.map +1 -1
- package/support/pages/home.d.ts +5 -12
- package/support/pages/home.d.ts.map +1 -1
- package/support/pages/home.js +3 -12
- package/support/pages/home.js.map +1 -1
- package/support/router.d.ts +9 -4
- package/support/router.d.ts.map +1 -1
- package/support/router.js +34 -15
- package/support/router.js.map +1 -1
- package/support/store/support-store.d.ts +17 -14
- package/support/store/support-store.d.ts.map +1 -1
- package/support/store/support-store.js +13 -10
- package/support/store/support-store.js.map +1 -1
- package/support/{support-D0JydWRx.css → support-BQhCt9Za.css} +10 -9
- package/support/support-BQhCt9Za.css.map +1 -0
- package/support/types.d.ts +28 -0
- package/support/types.d.ts.map +1 -0
- package/support/types.js +1 -0
- package/support.css +1 -1
- package/tailwind.css +9 -8
- package/utils/conversation.d.ts.map +1 -1
- package/utils/conversation.js +3 -1
- package/utils/conversation.js.map +1 -1
- package/zod-extensions.d.ts.map +1 -1
- package/index4.d.ts +0 -18
- package/index4.d.ts.map +0 -1
- package/index5.d.ts +0 -999
- package/index5.d.ts.map +0 -1
- package/index6.d.ts +0 -6
- package/react.d.ts +0 -4
- package/support/components/text-effect.d.ts +0 -53
- package/support/components/text-effect.d.ts.map +0 -1
- package/support/components/text-effect.js +0 -225
- package/support/components/text-effect.js.map +0 -1
- package/support/support-D0JydWRx.css.map +0 -1
- package/types.d-BJcRxCew.d.ts +0 -39
- package/types.d-BJcRxCew.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-timeline.js","names":["React","renderProps: ConversationTimelineRenderProps"],"sources":["../../src/primitives/conversation-timeline.tsx"],"sourcesContent":["import type { TimelineItem as TimelineItemType } from \"@cossistant/types/api/timeline-item\";\nimport * as React from \"react\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\n/**\n * High-level state of the timeline handed to render-prop children so they can show\n * skeletons, empty states or pagination affordances.\n */\nexport type ConversationTimelineRenderProps = {\n\titemCount: number;\n\tisLoading?: boolean;\n\thasMore?: boolean;\n\tisEmpty: boolean;\n};\n\nexport type ConversationTimelineProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?:\n\t\t| React.ReactNode\n\t\t| ((props: ConversationTimelineRenderProps) => React.ReactNode);\n\tasChild?: boolean;\n\tclassName?: string;\n\titems?: TimelineItemType[];\n\tisLoading?: boolean;\n\thasMore?: boolean;\n\tautoScroll?: boolean;\n\tonScrollEnd?: () => void;\n\tonScrollStart?: () => void;\n};\n\nconst BOTTOM_THRESHOLD_PX = 12;\nconst TOP_THRESHOLD_PX = 2;\n\nfunction getLastItemKey(items: TimelineItemType[]): string | number | null {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst lastItem = items.at(-1);\n\n\tif (lastItem?.id) {\n\t\treturn lastItem.id;\n\t}\n\n\treturn lastItem?.createdAt ?? null;\n}\n\n/**\n * Scrollable conversation timeline that wires auto-scroll behaviour, live-region semantics and\n * pagination callbacks for displaying timeline items (messages, events, etc.).\n */\nexport const ConversationTimeline = (() => {\n\tconst Component = React.forwardRef<HTMLDivElement, ConversationTimelineProps>(\n\t\t(\n\t\t\t{\n\t\t\t\tchildren,\n\t\t\t\tclassName,\n\t\t\t\tasChild = false,\n\t\t\t\titems = [],\n\t\t\t\tisLoading = false,\n\t\t\t\thasMore = false,\n\t\t\t\tautoScroll = true,\n\t\t\t\tonScrollEnd,\n\t\t\t\tonScrollStart,\n\t\t\t\t...props\n\t\t\t},\n\t\t\tref\n\t\t) => {\n\t\t\tconst internalRef = React.useRef<HTMLDivElement>(null);\n\t\t\tconst setRefs = React.useCallback(\n\t\t\t\t(node: HTMLDivElement | null) => {\n\t\t\t\t\tinternalRef.current = node;\n\t\t\t\t\tif (typeof ref === \"function\") {\n\t\t\t\t\t\tref(node);\n\t\t\t\t\t} else if (ref) {\n\t\t\t\t\t\t(ref as React.MutableRefObject<HTMLDivElement | null>).current =\n\t\t\t\t\t\t\tnode;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t[ref]\n\t\t\t);\n\n\t\t\tconst isInitialRender = React.useRef(true);\n\t\t\tconst previousItemCount = React.useRef(items.length);\n\t\t\tconst previousLastItemKey = React.useRef<string | number | null>(\n\t\t\t\tgetLastItemKey(items)\n\t\t\t);\n\t\t\tconst isPinnedToBottom = React.useRef(true);\n\t\t\tconst isAtTop = React.useRef(true);\n\n\t\t\tconst renderProps: ConversationTimelineRenderProps = {\n\t\t\t\titemCount: items.length,\n\t\t\t\tisLoading,\n\t\t\t\thasMore,\n\t\t\t\tisEmpty: items.length === 0,\n\t\t\t};\n\n\t\t\tconst content =\n\t\t\t\ttypeof children === \"function\" ? children(renderProps) : children;\n\n\t\t\tconst lastItemKey = getLastItemKey(items);\n\n\t\t\t// Auto-scroll to bottom when new timeline items are added\n\t\t\tReact.useEffect(() => {\n\t\t\t\tconst element = internalRef.current;\n\n\t\t\t\tif (!(element && autoScroll)) {\n\t\t\t\t\tpreviousItemCount.current = items.length;\n\t\t\t\t\tpreviousLastItemKey.current = lastItemKey;\n\t\t\t\t\tisInitialRender.current = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst hasNewItems = items.length > previousItemCount.current;\n\t\t\t\tconst itemsRemoved = items.length < previousItemCount.current;\n\t\t\t\tconst appendedNewItem =\n\t\t\t\t\thasNewItems &&\n\t\t\t\t\tlastItemKey !== null &&\n\t\t\t\t\tlastItemKey !== previousLastItemKey.current;\n\t\t\t\tconst replacedLastItem =\n\t\t\t\t\t!hasNewItems &&\n\t\t\t\t\tlastItemKey !== null &&\n\t\t\t\t\tlastItemKey !== previousLastItemKey.current;\n\n\t\t\t\tconst shouldSnapToBottom =\n\t\t\t\t\tisInitialRender.current ||\n\t\t\t\t\t(itemsRemoved && isPinnedToBottom.current) ||\n\t\t\t\t\t(appendedNewItem && isPinnedToBottom.current) ||\n\t\t\t\t\t(replacedLastItem && isPinnedToBottom.current);\n\n\t\t\t\tif (shouldSnapToBottom) {\n\t\t\t\t\telement.scrollTop = element.scrollHeight;\n\t\t\t\t\tisPinnedToBottom.current = true;\n\t\t\t\t\tisAtTop.current = false;\n\t\t\t\t}\n\n\t\t\t\tpreviousItemCount.current = items.length;\n\t\t\t\tpreviousLastItemKey.current = lastItemKey;\n\t\t\t\tisInitialRender.current = false;\n\t\t\t}, [autoScroll, items.length, lastItemKey]);\n\n\t\t\t// Handle scroll events for infinite scrolling\n\t\t\tconst handleScroll = React.useCallback(\n\t\t\t\t(e: React.UIEvent<HTMLDivElement>) => {\n\t\t\t\t\tconst element = e.currentTarget;\n\t\t\t\t\tconst { scrollTop, scrollHeight, clientHeight } = element;\n\n\t\t\t\t\tconst distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n\t\t\t\t\tconst pinnedNow = distanceFromBottom <= BOTTOM_THRESHOLD_PX;\n\t\t\t\t\tif (pinnedNow && !isPinnedToBottom.current) {\n\t\t\t\t\t\tonScrollEnd?.();\n\t\t\t\t\t}\n\t\t\t\t\tisPinnedToBottom.current = pinnedNow;\n\n\t\t\t\t\tconst atTop = scrollTop <= TOP_THRESHOLD_PX;\n\t\t\t\t\tif (atTop && !isAtTop.current) {\n\t\t\t\t\t\tonScrollStart?.();\n\t\t\t\t\t}\n\t\t\t\t\tisAtTop.current = atTop;\n\t\t\t\t},\n\t\t\t\t[onScrollStart, onScrollEnd]\n\t\t\t);\n\n\t\t\t// Static fade effect on top and bottom\n\t\t\tconst fadeStyle = React.useMemo(() => {\n\t\t\t\tconst maskHeight = \"90px\";\n\t\t\t\tconst scrollbarWidth = \"8px\";\n\n\t\t\t\tconst maskImage = `linear-gradient(to bottom, transparent, black ${maskHeight}, black calc(100% - ${maskHeight}), transparent), linear-gradient(black, black)`;\n\t\t\t\tconst maskSize = `calc(100% - ${scrollbarWidth}) 100%, ${scrollbarWidth} 100%`;\n\t\t\t\tconst maskPosition = \"0 0, 100% 0\";\n\t\t\t\tconst maskRepeat = \"no-repeat, no-repeat\";\n\n\t\t\t\treturn {\n\t\t\t\t\tmaskImage,\n\t\t\t\t\tmaskSize,\n\t\t\t\t\tmaskPosition,\n\t\t\t\t\tmaskRepeat,\n\t\t\t\t\tWebkitMaskImage: maskImage,\n\t\t\t\t\tWebkitMaskSize: maskSize,\n\t\t\t\t\tWebkitMaskPosition: maskPosition,\n\t\t\t\t\tWebkitMaskRepeat: maskRepeat,\n\t\t\t\t};\n\t\t\t}, []);\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tclassName,\n\t\t\t\t\tasChild,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref: setRefs,\n\t\t\t\t\tstate: renderProps,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\trole: \"log\",\n\t\t\t\t\t\t\"aria-label\": \"Conversation timeline\",\n\t\t\t\t\t\t\"aria-live\": \"polite\",\n\t\t\t\t\t\t\"aria-relevant\": \"additions\",\n\t\t\t\t\t\tonScroll: handleScroll,\n\t\t\t\t\t\tstyle: fadeStyle,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"ConversationTimeline\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineContainerProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Wrapper around the scrollable timeline giving consumers an easy hook to add\n * padding, backgrounds or transitions without touching the core timeline logic.\n */\nexport const ConversationTimelineContainer = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineContainerProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineContainer\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineLoadingProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Accessible status region for loading more timeline items. Lets host apps render\n * skeletons or shimmer states without reimplementing ARIA wiring.\n */\nexport const ConversationTimelineLoading = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineLoadingProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\trole: \"status\",\n\t\t\t\t\t\"aria-label\": \"Loading timeline items\",\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineLoading\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineEmptyProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Placeholder state rendered when no timeline items are present. Uses a polite status\n * region so screen readers announce the empty state.\n */\nexport const ConversationTimelineEmpty = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineEmptyProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\trole: \"status\",\n\t\t\t\t\t\"aria-label\": \"No timeline items\",\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineEmpty\";\n\treturn Component;\n})();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conversation-timeline.js","names":["React","renderProps: ConversationTimelineRenderProps"],"sources":["../../src/primitives/conversation-timeline.tsx"],"sourcesContent":["import type { TimelineItem as TimelineItemType } from \"@cossistant/types/api/timeline-item\";\nimport * as React from \"react\";\nimport { useScrollMask } from \"../hooks/use-scroll-mask\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\n/**\n * High-level state of the timeline handed to render-prop children so they can show\n * skeletons, empty states or pagination affordances.\n */\nexport type ConversationTimelineRenderProps = {\n\titemCount: number;\n\tisLoading?: boolean;\n\thasMore?: boolean;\n\tisEmpty: boolean;\n};\n\nexport type ConversationTimelineProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?:\n\t\t| React.ReactNode\n\t\t| ((props: ConversationTimelineRenderProps) => React.ReactNode);\n\tasChild?: boolean;\n\tclassName?: string;\n\titems?: TimelineItemType[];\n\tisLoading?: boolean;\n\thasMore?: boolean;\n\tautoScroll?: boolean;\n\tonScrollEnd?: () => void;\n\tonScrollStart?: () => void;\n};\n\nconst BOTTOM_THRESHOLD_PX = 12;\nconst TOP_THRESHOLD_PX = 2;\n\nfunction getLastItemKey(items: TimelineItemType[]): string | number | null {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst lastItem = items.at(-1);\n\n\tif (lastItem?.id) {\n\t\treturn lastItem.id;\n\t}\n\n\treturn lastItem?.createdAt ?? null;\n}\n\n/**\n * Scrollable conversation timeline that wires auto-scroll behaviour, live-region semantics and\n * pagination callbacks for displaying timeline items (messages, events, etc.).\n */\nexport const ConversationTimeline = (() => {\n\tconst Component = React.forwardRef<HTMLDivElement, ConversationTimelineProps>(\n\t\t(\n\t\t\t{\n\t\t\t\tchildren,\n\t\t\t\tclassName,\n\t\t\t\tasChild = false,\n\t\t\t\titems = [],\n\t\t\t\tisLoading = false,\n\t\t\t\thasMore = false,\n\t\t\t\tautoScroll = true,\n\t\t\t\tonScrollEnd,\n\t\t\t\tonScrollStart,\n\t\t\t\t...props\n\t\t\t},\n\t\t\tref\n\t\t) => {\n\t\t\tconst internalRef = React.useRef<HTMLDivElement>(null);\n\t\t\tconst { ref: scrollMaskRef, style: scrollMaskStyle } = useScrollMask({\n\t\t\t\tmaskHeight: \"54px\",\n\t\t\t\tscrollbarWidth: \"8px\",\n\t\t\t\ttopThreshold: TOP_THRESHOLD_PX,\n\t\t\t\tbottomThreshold: BOTTOM_THRESHOLD_PX,\n\t\t\t});\n\n\t\t\tconst setRefs = React.useCallback(\n\t\t\t\t(node: HTMLDivElement | null) => {\n\t\t\t\t\tinternalRef.current = node;\n\t\t\t\t\t(\n\t\t\t\t\t\tscrollMaskRef as React.MutableRefObject<HTMLDivElement | null>\n\t\t\t\t\t).current = node;\n\t\t\t\t\tif (typeof ref === \"function\") {\n\t\t\t\t\t\tref(node);\n\t\t\t\t\t} else if (ref) {\n\t\t\t\t\t\t(ref as React.MutableRefObject<HTMLDivElement | null>).current =\n\t\t\t\t\t\t\tnode;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t[ref, scrollMaskRef]\n\t\t\t);\n\n\t\t\tconst isInitialRender = React.useRef(true);\n\t\t\tconst previousItemCount = React.useRef(items.length);\n\t\t\tconst previousLastItemKey = React.useRef<string | number | null>(\n\t\t\t\tgetLastItemKey(items)\n\t\t\t);\n\t\t\tconst isPinnedToBottom = React.useRef(true);\n\t\t\tconst isAtTop = React.useRef(true);\n\n\t\t\tconst renderProps: ConversationTimelineRenderProps = {\n\t\t\t\titemCount: items.length,\n\t\t\t\tisLoading,\n\t\t\t\thasMore,\n\t\t\t\tisEmpty: items.length === 0,\n\t\t\t};\n\n\t\t\tconst content =\n\t\t\t\ttypeof children === \"function\" ? children(renderProps) : children;\n\n\t\t\tconst lastItemKey = getLastItemKey(items);\n\n\t\t\t// Auto-scroll to bottom when new timeline items are added\n\t\t\tReact.useEffect(() => {\n\t\t\t\tconst element = internalRef.current;\n\n\t\t\t\tif (!(element && autoScroll)) {\n\t\t\t\t\tpreviousItemCount.current = items.length;\n\t\t\t\t\tpreviousLastItemKey.current = lastItemKey;\n\t\t\t\t\tisInitialRender.current = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst hasNewItems = items.length > previousItemCount.current;\n\t\t\t\tconst itemsRemoved = items.length < previousItemCount.current;\n\t\t\t\tconst appendedNewItem =\n\t\t\t\t\thasNewItems &&\n\t\t\t\t\tlastItemKey !== null &&\n\t\t\t\t\tlastItemKey !== previousLastItemKey.current;\n\t\t\t\tconst replacedLastItem =\n\t\t\t\t\t!hasNewItems &&\n\t\t\t\t\tlastItemKey !== null &&\n\t\t\t\t\tlastItemKey !== previousLastItemKey.current;\n\n\t\t\t\tconst shouldSnapToBottom =\n\t\t\t\t\tisInitialRender.current ||\n\t\t\t\t\t(itemsRemoved && isPinnedToBottom.current) ||\n\t\t\t\t\t(appendedNewItem && isPinnedToBottom.current) ||\n\t\t\t\t\t(replacedLastItem && isPinnedToBottom.current);\n\n\t\t\t\tif (shouldSnapToBottom) {\n\t\t\t\t\telement.scrollTop = element.scrollHeight;\n\t\t\t\t\tisPinnedToBottom.current = true;\n\t\t\t\t\tisAtTop.current = false;\n\t\t\t\t}\n\n\t\t\t\tpreviousItemCount.current = items.length;\n\t\t\t\tpreviousLastItemKey.current = lastItemKey;\n\t\t\t\tisInitialRender.current = false;\n\t\t\t}, [autoScroll, items.length, lastItemKey]);\n\n\t\t\t// Handle scroll events for infinite scrolling\n\t\t\tconst handleScroll = React.useCallback(\n\t\t\t\t(e: React.UIEvent<HTMLDivElement>) => {\n\t\t\t\t\tconst element = e.currentTarget;\n\t\t\t\t\tconst { scrollTop, scrollHeight, clientHeight } = element;\n\n\t\t\t\t\tconst distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n\t\t\t\t\tconst pinnedNow = distanceFromBottom <= BOTTOM_THRESHOLD_PX;\n\t\t\t\t\tif (pinnedNow && !isPinnedToBottom.current) {\n\t\t\t\t\t\tonScrollEnd?.();\n\t\t\t\t\t}\n\t\t\t\t\tisPinnedToBottom.current = pinnedNow;\n\n\t\t\t\t\tconst atTop = scrollTop <= TOP_THRESHOLD_PX;\n\t\t\t\t\tif (atTop && !isAtTop.current) {\n\t\t\t\t\t\tonScrollStart?.();\n\t\t\t\t\t}\n\t\t\t\t\tisAtTop.current = atTop;\n\t\t\t\t},\n\t\t\t\t[onScrollStart, onScrollEnd]\n\t\t\t);\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tclassName,\n\t\t\t\t\tasChild,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref: setRefs,\n\t\t\t\t\tstate: renderProps,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\trole: \"log\",\n\t\t\t\t\t\t\"aria-label\": \"Conversation timeline\",\n\t\t\t\t\t\t\"aria-live\": \"polite\",\n\t\t\t\t\t\t\"aria-relevant\": \"additions\",\n\t\t\t\t\t\tonScroll: handleScroll,\n\t\t\t\t\t\tstyle: scrollMaskStyle,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"ConversationTimeline\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineContainerProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Wrapper around the scrollable timeline giving consumers an easy hook to add\n * padding, backgrounds or transitions without touching the core timeline logic.\n */\nexport const ConversationTimelineContainer = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineContainerProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineContainer\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineLoadingProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Accessible status region for loading more timeline items. Lets host apps render\n * skeletons or shimmer states without reimplementing ARIA wiring.\n */\nexport const ConversationTimelineLoading = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineLoadingProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\trole: \"status\",\n\t\t\t\t\t\"aria-label\": \"Loading timeline items\",\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineLoading\";\n\treturn Component;\n})();\n\nexport type ConversationTimelineEmptyProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Placeholder state rendered when no timeline items are present. Uses a polite status\n * region so screen readers announce the empty state.\n */\nexport const ConversationTimelineEmpty = (() => {\n\tconst Component = React.forwardRef<\n\t\tHTMLDivElement,\n\t\tConversationTimelineEmptyProps\n\t>(({ children, className, asChild = false, ...props }, ref) =>\n\t\tuseRenderElement(\n\t\t\t\"div\",\n\t\t\t{\n\t\t\t\tclassName,\n\t\t\t\tasChild,\n\t\t\t},\n\t\t\t{\n\t\t\t\tref,\n\t\t\t\tprops: {\n\t\t\t\t\trole: \"status\",\n\t\t\t\t\t\"aria-label\": \"No timeline items\",\n\t\t\t\t\t...props,\n\t\t\t\t\tchildren,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t);\n\n\tComponent.displayName = \"ConversationTimelineEmpty\";\n\treturn Component;\n})();\n"],"mappings":"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"}
|
package/primitives/index.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ import { SupportBubble } from "./bubble.js";
|
|
|
7
7
|
import { Button } from "./button.js";
|
|
8
8
|
import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
|
|
9
9
|
import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
|
|
10
|
+
import { Page, PageProps } from "./page.js";
|
|
11
|
+
import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
|
|
12
|
+
import { Router, RouterProps } from "./router.js";
|
|
10
13
|
import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
|
|
11
14
|
import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
|
|
12
15
|
import { SupportWindow } from "./window.js";
|
|
@@ -14,8 +17,8 @@ import "./index.parts.js";
|
|
|
14
17
|
|
|
15
18
|
//#region src/primitives/index.d.ts
|
|
16
19
|
declare namespace index_d_exports {
|
|
17
|
-
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window };
|
|
20
|
+
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
|
|
18
21
|
}
|
|
19
22
|
//#endregion
|
|
20
|
-
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports };
|
|
23
|
+
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports, usePageRegistry, useRegisterPage };
|
|
21
24
|
//# sourceMappingURL=index.d.ts.map
|
package/primitives/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { __export } from "../_virtual/rolldown_runtime.js";
|
|
2
|
-
import { SupportConfig } from "../support-config.js";
|
|
3
2
|
import { Avatar } from "./avatar/avatar.js";
|
|
4
3
|
import { AvatarFallback } from "./avatar/fallback.js";
|
|
5
4
|
import { AvatarImage } from "./avatar/image.js";
|
|
6
5
|
import { TypingIndicator } from "../support/components/typing-indicator.js";
|
|
6
|
+
import { SupportConfig } from "../support-config.js";
|
|
7
7
|
import { SupportBubble } from "./bubble.js";
|
|
8
8
|
import { Button } from "./button.js";
|
|
9
9
|
import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
|
|
10
10
|
import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
|
|
11
|
+
import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
|
|
12
|
+
import { Page } from "./page.js";
|
|
13
|
+
import { Router } from "./router.js";
|
|
11
14
|
import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
|
|
12
15
|
import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
|
|
13
16
|
import { SupportWindow } from "./window.js";
|
|
@@ -27,6 +30,9 @@ var primitives_exports = /* @__PURE__ */ __export({
|
|
|
27
30
|
FileInput: () => FileInput,
|
|
28
31
|
Input: () => SupportInput,
|
|
29
32
|
MultimodalInput: () => MultimodalInput,
|
|
33
|
+
Page: () => Page,
|
|
34
|
+
PageRegistryProvider: () => PageRegistryProvider,
|
|
35
|
+
Router: () => Router,
|
|
30
36
|
TimelineItem: () => TimelineItem,
|
|
31
37
|
TimelineItemContent: () => TimelineItemContent,
|
|
32
38
|
TimelineItemGroup: () => TimelineItemGroup,
|
|
@@ -37,9 +43,11 @@ var primitives_exports = /* @__PURE__ */ __export({
|
|
|
37
43
|
TimelineItemGroupSeenIndicator: () => TimelineItemGroupSeenIndicator,
|
|
38
44
|
TimelineItemTimestamp: () => TimelineItemTimestamp,
|
|
39
45
|
TypingIndicator: () => TypingIndicator,
|
|
40
|
-
Window: () => SupportWindow
|
|
46
|
+
Window: () => SupportWindow,
|
|
47
|
+
usePageRegistry: () => usePageRegistry,
|
|
48
|
+
useRegisterPage: () => useRegisterPage
|
|
41
49
|
});
|
|
42
50
|
|
|
43
51
|
//#endregion
|
|
44
|
-
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports };
|
|
52
|
+
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageRegistryProvider, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports, usePageRegistry, useRegisterPage };
|
|
45
53
|
//# sourceMappingURL=index.js.map
|
|
@@ -8,7 +8,10 @@ import { SupportBubble } from "./bubble.js";
|
|
|
8
8
|
import { Button } from "./button.js";
|
|
9
9
|
import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
|
|
10
10
|
import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
|
|
11
|
+
import { Page, PageProps } from "./page.js";
|
|
12
|
+
import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
|
|
13
|
+
import { Router, RouterProps } from "./router.js";
|
|
11
14
|
import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
|
|
12
15
|
import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
|
|
13
16
|
import { SupportWindow } from "./window.js";
|
|
14
|
-
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window };
|
|
17
|
+
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, type PageProps, PageRegistryProvider, Router, type RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { SupportConfig } from "../support-config.js";
|
|
2
1
|
import { Avatar } from "./avatar/avatar.js";
|
|
3
2
|
import { AvatarFallback } from "./avatar/fallback.js";
|
|
4
3
|
import { AvatarImage } from "./avatar/image.js";
|
|
5
4
|
import { TypingIndicator } from "../support/components/typing-indicator.js";
|
|
5
|
+
import { SupportConfig } from "../support-config.js";
|
|
6
6
|
import { SupportBubble } from "./bubble.js";
|
|
7
7
|
import { Button } from "./button.js";
|
|
8
8
|
import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
|
|
9
9
|
import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
|
|
10
|
+
import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
|
|
11
|
+
import { Page } from "./page.js";
|
|
12
|
+
import { Router } from "./router.js";
|
|
10
13
|
import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
|
|
11
14
|
import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
|
|
12
15
|
import { SupportWindow } from "./window.js";
|
|
13
16
|
|
|
14
|
-
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window };
|
|
17
|
+
export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageRegistryProvider, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, usePageRegistry, useRegisterPage };
|
|
@@ -16,7 +16,7 @@ type MultimodalInputProps = Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElem
|
|
|
16
16
|
* clipboard uploads and auto-resizing while remaining composable via
|
|
17
17
|
* `asChild`.
|
|
18
18
|
*/
|
|
19
|
-
declare const MultimodalInput: React$1.ForwardRefExoticComponent<Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "
|
|
19
|
+
declare const MultimodalInput: React$1.ForwardRefExoticComponent<Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "onChange"> & {
|
|
20
20
|
value: string;
|
|
21
21
|
onChange: (value: string) => void;
|
|
22
22
|
onSubmit?: () => void;
|
|
@@ -38,7 +38,7 @@ declare const FileInput: React$1.ForwardRefExoticComponent<React$1.InputHTMLAttr
|
|
|
38
38
|
onFileSelect?: (files: File[]) => void;
|
|
39
39
|
asChild?: boolean;
|
|
40
40
|
} & React$1.RefAttributes<HTMLInputElement>>;
|
|
41
|
-
declare const SupportInput: React$1.ForwardRefExoticComponent<Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "
|
|
41
|
+
declare const SupportInput: React$1.ForwardRefExoticComponent<Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "onChange"> & {
|
|
42
42
|
value: string;
|
|
43
43
|
onChange: (value: string) => void;
|
|
44
44
|
onSubmit?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multimodal-input.d.ts","names":[],"sources":["../../src/primitives/multimodal-input.tsx"],"sourcesContent":[],"mappings":";;;KAGY,oBAAA,GAAuB,KAClC,OAAA,CAAM,uBAAuB;;EADlB,QAAA,EAAA,CAAA,KAAA,EAAA,MAAoB,EAAA,GAAA,IAAA;EACF,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAA7B,YAAM,CAAA,EAAA,CAAA,KAAA,EAMiB,IANjB,EAAA,EAAA,GAAA,IAAA;EAD4B,OAAA,CAAA,EAAA,OAAA;EAOX,SAAA,CAAA,EAAA,MAAA;EAGf,KAAA,CAAA,EAAA,KAAA,GAAA,IAAA;EAAK,QAAA,CAAA,EAAA,OAAA;AASd,CAAA;;;;;;cAAa,iBAAe,OAAA,CAAA,0BAAA,KAAA,OAAA,CAAA,uBAAA;;EAAA,QAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAA,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EA4GhB,YAAA,CAAA,EAAA,CAAA,KAAc,EAxHF,IAwHE,EAAA,EAAA,GAAA,IAAA;EAA6B,OAAA,CAAA,EAAA,OAAA;EAA1B,SAAM,CAAA,EAAA,MAAA;EACX,KAAA,CAAA,EAtHf,KAsHe,GAAA,IAAA;EAAI,QAAA,CAAA,EAAA,OAAA;AAQ5B,CAAA,wBAkCI,oBAAA,CAAA,CAAA;AAlCkB,KATV,cAAA,GAAiB,OAAA,CAAM,mBASb,CATiC,gBASjC,CAAA,GAAA;EAAA,YAAA,CAAA,EAAA,CAAA,KAAA,EARE,IAQF,EAAA,EAAA,GAAA,IAAA;EARE,OAAA,CAAA,EAAA,OAAA;;;;;AA6CxB;AAAyB,cArCZ,SAqCY,EArCH,OAAA,CAAA,yBAqCG,CArCH,OAAA,CAAA,mBAqCG,CArCH,gBAqCG,CAAA,GAAA;EAAA,YAAA,CAAA,EAAA,CAAA,KAAA,EA7CD,IA6CC,EAAA,EAAA,GAAA,IAAA;EAAA,OAAA,CAAA,EAAA,OAAA;CAtKD,wBAAA,iBAAA,CAAA,CAAA;AAGf,cAmKI,YAnKJ,EAmKgB,OAAA,CAAA,yBAnKhB,CAmKgB,IAnKhB,CAmKgB,OAAA,CAAA,sBAnKhB,CAmKgB,mBAnKhB,CAAA,EAAA,
|
|
1
|
+
{"version":3,"file":"multimodal-input.d.ts","names":[],"sources":["../../src/primitives/multimodal-input.tsx"],"sourcesContent":[],"mappings":";;;KAGY,oBAAA,GAAuB,KAClC,OAAA,CAAM,uBAAuB;;EADlB,QAAA,EAAA,CAAA,KAAA,EAAA,MAAoB,EAAA,GAAA,IAAA;EACF,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAA7B,YAAM,CAAA,EAAA,CAAA,KAAA,EAMiB,IANjB,EAAA,EAAA,GAAA,IAAA;EAD4B,OAAA,CAAA,EAAA,OAAA;EAOX,SAAA,CAAA,EAAA,MAAA;EAGf,KAAA,CAAA,EAAA,KAAA,GAAA,IAAA;EAAK,QAAA,CAAA,EAAA,OAAA;AASd,CAAA;;;;;;cAAa,iBAAe,OAAA,CAAA,0BAAA,KAAA,OAAA,CAAA,uBAAA;;EAAA,QAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAA,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EA4GhB,YAAA,CAAA,EAAA,CAAA,KAAc,EAxHF,IAwHE,EAAA,EAAA,GAAA,IAAA;EAA6B,OAAA,CAAA,EAAA,OAAA;EAA1B,SAAM,CAAA,EAAA,MAAA;EACX,KAAA,CAAA,EAtHf,KAsHe,GAAA,IAAA;EAAI,QAAA,CAAA,EAAA,OAAA;AAQ5B,CAAA,wBAkCI,oBAAA,CAAA,CAAA;AAlCkB,KATV,cAAA,GAAiB,OAAA,CAAM,mBASb,CATiC,gBASjC,CAAA,GAAA;EAAA,YAAA,CAAA,EAAA,CAAA,KAAA,EARE,IAQF,EAAA,EAAA,GAAA,IAAA;EARE,OAAA,CAAA,EAAA,OAAA;;;;;AA6CxB;AAAyB,cArCZ,SAqCY,EArCH,OAAA,CAAA,yBAqCG,CArCH,OAAA,CAAA,mBAqCG,CArCH,gBAqCG,CAAA,GAAA;EAAA,YAAA,CAAA,EAAA,CAAA,KAAA,EA7CD,IA6CC,EAAA,EAAA,GAAA,IAAA;EAAA,OAAA,CAAA,EAAA,OAAA;CAtKD,wBAAA,iBAAA,CAAA,CAAA;AAGf,cAmKI,YAnKJ,EAmKgB,OAAA,CAAA,yBAnKhB,CAmKgB,IAnKhB,CAmKgB,OAAA,CAAA,sBAnKhB,CAmKgB,mBAnKhB,CAAA,EAAA,OAAA,GAAA,UAAA,CAAA,GAAA;;;EAmKgB,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAAA,YAAA,CAAA,EAAA,CAAA,KAAA,EAtKD,IAsKC,EAAA,EAAA,GAAA,IAAA;;;UAnKhB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/primitives/page-registry.d.ts
|
|
4
|
+
type PageComponent<P = unknown> = React.ComponentType<{
|
|
5
|
+
params?: P;
|
|
6
|
+
}>;
|
|
7
|
+
type PageRegistry = Map<string, PageComponent>;
|
|
8
|
+
/**
|
|
9
|
+
* Context provider for declarative page registration.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <PageRegistryProvider>
|
|
13
|
+
* <Page name="HOME" component={HomePage} />
|
|
14
|
+
* <Router page={currentPage} />
|
|
15
|
+
* </PageRegistryProvider>
|
|
16
|
+
*/
|
|
17
|
+
declare const PageRegistryProvider: React.FC<{
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Access the page registry (used internally by Router and Page).
|
|
22
|
+
*/
|
|
23
|
+
declare const usePageRegistry: () => PageRegistry;
|
|
24
|
+
/**
|
|
25
|
+
* Register a page in the registry (used internally by Page component).
|
|
26
|
+
*/
|
|
27
|
+
declare const useRegisterPage: (name: string, component: PageComponent) => void;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { PageRegistryProvider, usePageRegistry, useRegisterPage };
|
|
30
|
+
//# sourceMappingURL=page-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-registry.d.ts","names":[],"sources":["../../src/primitives/page-registry.tsx"],"sourcesContent":[],"mappings":";;;KAEK,6BAA6B,KAAA,CAAM;WAAyB;AAFC,CAAA,CAAA;AAEb,KAEhD,YAAA,GAAe,GAAH,CAAA,MAAA,EAAe,aAAA,CAAA;AAahC;AAeA;AAKA;;;;;;;cApBa,sBAAsB,KAAA,CAAM;YAAe,KAAA,CAAM;;;;;cAejD,uBAAe;;;;cAKf,2CAA4C"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { createContext, useContext, useMemo } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/primitives/page-registry.tsx
|
|
5
|
+
const PageRegistryContext = createContext(/* @__PURE__ */ new Map());
|
|
6
|
+
/**
|
|
7
|
+
* Context provider for declarative page registration.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <PageRegistryProvider>
|
|
11
|
+
* <Page name="HOME" component={HomePage} />
|
|
12
|
+
* <Router page={currentPage} />
|
|
13
|
+
* </PageRegistryProvider>
|
|
14
|
+
*/
|
|
15
|
+
const PageRegistryProvider = ({ children }) => {
|
|
16
|
+
const registry = useMemo(() => /* @__PURE__ */ new Map(), []);
|
|
17
|
+
return /* @__PURE__ */ jsx(PageRegistryContext.Provider, {
|
|
18
|
+
value: registry,
|
|
19
|
+
children
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Access the page registry (used internally by Router and Page).
|
|
24
|
+
*/
|
|
25
|
+
const usePageRegistry = () => useContext(PageRegistryContext);
|
|
26
|
+
/**
|
|
27
|
+
* Register a page in the registry (used internally by Page component).
|
|
28
|
+
*/
|
|
29
|
+
const useRegisterPage = (name, component) => {
|
|
30
|
+
const registry = usePageRegistry();
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
registry.set(name, component);
|
|
33
|
+
return () => {
|
|
34
|
+
registry.delete(name);
|
|
35
|
+
};
|
|
36
|
+
}, [
|
|
37
|
+
name,
|
|
38
|
+
component,
|
|
39
|
+
registry
|
|
40
|
+
]);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { PageRegistryProvider, usePageRegistry, useRegisterPage };
|
|
45
|
+
//# sourceMappingURL=page-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-registry.js","names":["PageRegistryProvider: React.FC<{ children: React.ReactNode }>"],"sources":["../../src/primitives/page-registry.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo } from \"react\";\n\ntype PageComponent<P = unknown> = React.ComponentType<{ params?: P }>;\n\ntype PageRegistry = Map<string, PageComponent>;\n\nconst PageRegistryContext = createContext<PageRegistry>(new Map());\n\n/**\n * Context provider for declarative page registration.\n *\n * @example\n * <PageRegistryProvider>\n * <Page name=\"HOME\" component={HomePage} />\n * <Router page={currentPage} />\n * </PageRegistryProvider>\n */\nexport const PageRegistryProvider: React.FC<{ children: React.ReactNode }> = ({\n\tchildren,\n}) => {\n\tconst registry = useMemo(() => new Map<string, PageComponent>(), []);\n\n\treturn (\n\t\t<PageRegistryContext.Provider value={registry}>\n\t\t\t{children}\n\t\t</PageRegistryContext.Provider>\n\t);\n};\n\n/**\n * Access the page registry (used internally by Router and Page).\n */\nexport const usePageRegistry = () => useContext(PageRegistryContext);\n\n/**\n * Register a page in the registry (used internally by Page component).\n */\nexport const useRegisterPage = (name: string, component: PageComponent) => {\n\tconst registry = usePageRegistry();\n\n\tReact.useEffect(() => {\n\t\tregistry.set(name, component);\n\t\treturn () => {\n\t\t\tregistry.delete(name);\n\t\t};\n\t}, [name, component, registry]);\n};\n"],"mappings":";;;;AAMA,MAAM,sBAAsB,8BAA4B,IAAI,KAAK,CAAC;;;;;;;;;;AAWlE,MAAaA,wBAAiE,EAC7E,eACK;CACL,MAAM,WAAW,8BAAc,IAAI,KAA4B,EAAE,EAAE,CAAC;AAEpE,QACC,oBAAC,oBAAoB;EAAS,OAAO;EACnC;GAC6B;;;;;AAOjC,MAAa,wBAAwB,WAAW,oBAAoB;;;;AAKpE,MAAa,mBAAmB,MAAc,cAA6B;CAC1E,MAAM,WAAW,iBAAiB;AAElC,OAAM,gBAAgB;AACrB,WAAS,IAAI,MAAM,UAAU;AAC7B,eAAa;AACZ,YAAS,OAAO,KAAK;;IAEpB;EAAC;EAAM;EAAW;EAAS,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/primitives/page.d.ts
|
|
2
|
+
type PageProps<Params = unknown> = {
|
|
3
|
+
name: string;
|
|
4
|
+
component: React.ComponentType<{
|
|
5
|
+
params?: Params;
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Declaratively register a page component.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <Page name="HOME" component={HomePage} />
|
|
13
|
+
* <Page name="SETTINGS" component={SettingsPage} />
|
|
14
|
+
*/
|
|
15
|
+
declare function Page<Params = unknown>({
|
|
16
|
+
name,
|
|
17
|
+
component
|
|
18
|
+
}: PageProps<Params>): null;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { Page, PageProps };
|
|
21
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","names":[],"sources":["../../src/primitives/page.tsx"],"sourcesContent":[],"mappings":";KAEY;EAAA,IAAA,EAAA,MAAS;EAYL,SAAI,EAVR,KAAA,CAAM,aAUE,CAAA;IACnB,MAAA,CAAA,EAX0C,MAW1C;EACA,CAAA,CAAA;CACY;;;;;;;;iBAHG;;;GAGb,UAAU"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useRegisterPage } from "./page-registry.js";
|
|
2
|
+
|
|
3
|
+
//#region src/primitives/page.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Declaratively register a page component.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* <Page name="HOME" component={HomePage} />
|
|
9
|
+
* <Page name="SETTINGS" component={SettingsPage} />
|
|
10
|
+
*/
|
|
11
|
+
function Page({ name, component }) {
|
|
12
|
+
useRegisterPage(name, component);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { Page };
|
|
18
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","names":[],"sources":["../../src/primitives/page.tsx"],"sourcesContent":["import { useRegisterPage } from \"./page-registry\";\n\nexport type PageProps<Params = unknown> = {\n\tname: string;\n\tcomponent: React.ComponentType<{ params?: Params }>;\n};\n\n/**\n * Declaratively register a page component.\n *\n * @example\n * <Page name=\"HOME\" component={HomePage} />\n * <Page name=\"SETTINGS\" component={SettingsPage} />\n */\nexport function Page<Params = unknown>({\n\tname,\n\tcomponent,\n}: PageProps<Params>): null {\n\tuseRegisterPage(name, component as React.ComponentType<{ params?: unknown }>);\n\treturn null;\n}\n"],"mappings":";;;;;;;;;;AAcA,SAAgB,KAAuB,EACtC,MACA,aAC2B;AAC3B,iBAAgB,MAAM,UAAuD;AAC7E,QAAO"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/primitives/router.d.ts
|
|
4
|
+
type RouterProps = {
|
|
5
|
+
/**
|
|
6
|
+
* Current page name to render
|
|
7
|
+
*/
|
|
8
|
+
page: string;
|
|
9
|
+
/**
|
|
10
|
+
* Params to pass to the page component
|
|
11
|
+
*/
|
|
12
|
+
params?: unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Fallback component when page is not found
|
|
15
|
+
*/
|
|
16
|
+
fallback?: React.ComponentType<{
|
|
17
|
+
params?: unknown;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Children (Page components for registration)
|
|
21
|
+
*/
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Router that renders registered pages based on current page name.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* <Router page={currentPage} params={params} fallback={NotFoundPage}>
|
|
29
|
+
* <Page name="HOME" component={HomePage} />
|
|
30
|
+
* </Router>
|
|
31
|
+
*/
|
|
32
|
+
declare const Router: React.FC<RouterProps>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { Router, RouterProps };
|
|
35
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","names":[],"sources":["../../src/primitives/router.tsx"],"sourcesContent":[],"mappings":";;;KAGY,WAAA;;AAAZ;AA8BA;;;;;;;;;aAhBY,KAAA,CAAM;;;;;;aAKN,KAAA,CAAM;;;;;;;;;;cAWL,QAAQ,KAAA,CAAM,GAAG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { usePageRegistry } from "./page-registry.js";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/primitives/router.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Router that renders registered pages based on current page name.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <Router page={currentPage} params={params} fallback={NotFoundPage}>
|
|
10
|
+
* <Page name="HOME" component={HomePage} />
|
|
11
|
+
* </Router>
|
|
12
|
+
*/
|
|
13
|
+
const Router = ({ page, params, fallback: Fallback, children }) => {
|
|
14
|
+
const PageComponent = usePageRegistry().get(page);
|
|
15
|
+
if (PageComponent) return /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsx(PageComponent, { params })] });
|
|
16
|
+
if (Fallback) return /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsx(Fallback, { params })] });
|
|
17
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { Router };
|
|
22
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","names":["Router: React.FC<RouterProps>"],"sources":["../../src/primitives/router.tsx"],"sourcesContent":["import type React from \"react\";\nimport { usePageRegistry } from \"./page-registry\";\n\nexport type RouterProps = {\n\t/**\n\t * Current page name to render\n\t */\n\tpage: string;\n\n\t/**\n\t * Params to pass to the page component\n\t */\n\tparams?: unknown;\n\n\t/**\n\t * Fallback component when page is not found\n\t */\n\tfallback?: React.ComponentType<{ params?: unknown }>;\n\n\t/**\n\t * Children (Page components for registration)\n\t */\n\tchildren?: React.ReactNode;\n};\n\n/**\n * Router that renders registered pages based on current page name.\n *\n * @example\n * <Router page={currentPage} params={params} fallback={NotFoundPage}>\n * <Page name=\"HOME\" component={HomePage} />\n * </Router>\n */\nexport const Router: React.FC<RouterProps> = ({\n\tpage,\n\tparams,\n\tfallback: Fallback,\n\tchildren,\n}) => {\n\tconst registry = usePageRegistry();\n\n\t// Render children first (they register pages via useEffect)\n\t// Page components return null, so this is effectively a no-op render\n\n\t// Get the page component from registry\n\tconst PageComponent = registry.get(page);\n\n\tif (PageComponent) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{children}\n\t\t\t\t<PageComponent params={params} />\n\t\t\t</>\n\t\t);\n\t}\n\n\t// Fall back if provided\n\tif (Fallback) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{children}\n\t\t\t\t<Fallback params={params} />\n\t\t\t</>\n\t\t);\n\t}\n\n\treturn <>{children}</>;\n};\n"],"mappings":";;;;;;;;;;;;AAiCA,MAAaA,UAAiC,EAC7C,MACA,QACA,UAAU,UACV,eACK;CAOL,MAAM,gBANW,iBAAiB,CAMH,IAAI,KAAK;AAExC,KAAI,cACH,QACC,4CACE,UACD,oBAAC,iBAAsB,SAAU,IAC/B;AAKL,KAAI,SACH,QACC,4CACE,UACD,oBAAC,YAAiB,SAAU,IAC1B;AAIL,QAAO,gCAAG,WAAY"}
|
package/primitives/window.d.ts
CHANGED
|
@@ -14,9 +14,14 @@ type WindowProps = Omit<React$1.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
|
14
14
|
id?: string;
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Dialog container with open/close state and escape key handling.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <Window isOpen={isOpen} onOpenChange={setOpen}>
|
|
21
|
+
* {({ isOpen, close }) => (
|
|
22
|
+
* <div>Content here</div>
|
|
23
|
+
* )}
|
|
24
|
+
* </Window>
|
|
20
25
|
*/
|
|
21
26
|
declare const SupportWindow: React$1.ForwardRefExoticComponent<Omit<React$1.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
22
27
|
isOpen?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window.d.ts","names":[],"sources":["../../src/primitives/window.tsx"],"sourcesContent":[],"mappings":";;;KAIY,iBAAA;;EAAA,KAAA,EAAA,GAAA,GAAA,IAAA;AAKZ,CAAA;AACsB,KADV,WAAA,GAAc,IACJ,CAArB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,EAAA,UAAA,CAAA,GAAA;EAArB,MAAM,CAAA,EAAA,OAAA;EADmB,YAAA,CAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAAA,IAAA;EAMd,QAAM,CAAA,EAAN,OAAA,CAAM,SAAA,GAAA,CAAA,CAAA,KAAA,EAAqB,iBAArB,EAAA,GAA2C,OAAA,CAAM,SAAjD,CAAA;EAAqB,OAAA,CAAA,EAAA,OAAA;EAAsB,aAAM,CAAA,EAAA,OAAA;EAAS,EAAA,CAAA,EAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"window.d.ts","names":[],"sources":["../../src/primitives/window.tsx"],"sourcesContent":[],"mappings":";;;KAIY,iBAAA;;EAAA,KAAA,EAAA,GAAA,GAAA,IAAA;AAKZ,CAAA;AACsB,KADV,WAAA,GAAc,IACJ,CAArB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,EAAA,UAAA,CAAA,GAAA;EAArB,MAAM,CAAA,EAAA,OAAA;EADmB,YAAA,CAAA,EAAA,CAAA,IAAA,EAAA,OAAA,EAAA,GAAA,IAAA;EAMd,QAAM,CAAA,EAAN,OAAA,CAAM,SAAA,GAAA,CAAA,CAAA,KAAA,EAAqB,iBAArB,EAAA,GAA2C,OAAA,CAAM,SAAjD,CAAA;EAAqB,OAAA,CAAA,EAAA,OAAA;EAAsB,aAAM,CAAA,EAAA,OAAA;EAAS,EAAA,CAAA,EAAA,MAAA;AAgB5E,CAAA;;;;;;;;;;;cAAa,eAAa,OAAA,CAAA,0BAAA,KAAA,OAAA,CAAA,eAAA;;;aAhBd,OAAA,CAAM,qBAAqB,sBAAsB,OAAA,CAAM"}
|
package/primitives/window.js
CHANGED
|
@@ -4,9 +4,14 @@ import * as React$1 from "react";
|
|
|
4
4
|
|
|
5
5
|
//#region src/primitives/window.tsx
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Dialog container with open/close state and escape key handling.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <Window isOpen={isOpen} onOpenChange={setOpen}>
|
|
11
|
+
* {({ isOpen, close }) => (
|
|
12
|
+
* <div>Content here</div>
|
|
13
|
+
* )}
|
|
14
|
+
* </Window>
|
|
10
15
|
*/
|
|
11
16
|
const SupportWindow = (() => {
|
|
12
17
|
const Component = React$1.forwardRef(({ isOpen: isOpenProp, onOpenChange, children, className, asChild = false, closeOnEscape = true, id = "cossistant-window",...props }, ref) => {
|
package/primitives/window.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window.js","names":["React","renderProps: WindowRenderProps"],"sources":["../../src/primitives/window.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSupportConfig } from \"../support/store/support-store\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\nexport type WindowRenderProps = {\n\tisOpen: boolean;\n\tclose: () => void;\n};\n\nexport type WindowProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tisOpen?: boolean;\n\tonOpenChange?: (open: boolean) => void;\n\tchildren?: React.ReactNode | ((props: WindowRenderProps) => React.ReactNode);\n\tasChild?: boolean;\n\tcloseOnEscape?: boolean;\n\tid?: string;\n};\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"window.js","names":["React","renderProps: WindowRenderProps"],"sources":["../../src/primitives/window.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSupportConfig } from \"../support/store/support-store\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\nexport type WindowRenderProps = {\n\tisOpen: boolean;\n\tclose: () => void;\n};\n\nexport type WindowProps = Omit<\n\tReact.HTMLAttributes<HTMLDivElement>,\n\t\"children\"\n> & {\n\tisOpen?: boolean;\n\tonOpenChange?: (open: boolean) => void;\n\tchildren?: React.ReactNode | ((props: WindowRenderProps) => React.ReactNode);\n\tasChild?: boolean;\n\tcloseOnEscape?: boolean;\n\tid?: string;\n};\n\n/**\n * Dialog container with open/close state and escape key handling.\n *\n * @example\n * <Window isOpen={isOpen} onOpenChange={setOpen}>\n * {({ isOpen, close }) => (\n * <div>Content here</div>\n * )}\n * </Window>\n */\nexport const SupportWindow = (() => {\n\tconst Component = React.forwardRef<HTMLDivElement, WindowProps>(\n\t\t(\n\t\t\t{\n\t\t\t\tisOpen: isOpenProp,\n\t\t\t\tonOpenChange,\n\t\t\t\tchildren,\n\t\t\t\tclassName,\n\t\t\t\tasChild = false,\n\t\t\t\tcloseOnEscape = true,\n\t\t\t\tid = \"cossistant-window\",\n\t\t\t\t...props\n\t\t\t},\n\t\t\tref\n\t\t) => {\n\t\t\tconst { isOpen, close } = useSupportConfig();\n\n\t\t\tconst open = isOpenProp ?? isOpen ?? false;\n\n\t\t\tconst closeFn = React.useCallback(() => {\n\t\t\t\tif (onOpenChange) {\n\t\t\t\t\tonOpenChange(false);\n\t\t\t\t} else if (close) {\n\t\t\t\t\tclose();\n\t\t\t\t}\n\t\t\t}, [onOpenChange, close]);\n\n\t\t\t// Close on Escape\n\t\t\tReact.useEffect(() => {\n\t\t\t\tif (!(open && closeOnEscape)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst onKey = (e: KeyboardEvent) => {\n\t\t\t\t\tif (e.key === \"Escape\") {\n\t\t\t\t\t\tclose();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\twindow.addEventListener(\"keydown\", onKey);\n\t\t\t\treturn () => window.removeEventListener(\"keydown\", onKey);\n\t\t\t}, [open, close, closeOnEscape]);\n\n\t\t\tconst renderProps: WindowRenderProps = { isOpen: open, close: closeFn };\n\n\t\t\tconst content =\n\t\t\t\ttypeof children === \"function\" ? children(renderProps) : children;\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tclassName,\n\t\t\t\t\tasChild,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref,\n\t\t\t\t\tstate: renderProps,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\trole: \"dialog\",\n\t\t\t\t\t\t\"aria-modal\": \"true\",\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t\tenabled: open,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"SupportWindow\";\n\treturn Component;\n})();\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,MAAa,uBAAuB;CACnC,MAAM,YAAYA,QAAM,YAEtB,EACC,QAAQ,YACR,cACA,UACA,WACA,UAAU,OACV,gBAAgB,MAChB,KAAK,oBACL,GAAG,SAEJ,QACI;EACJ,MAAM,EAAE,QAAQ,UAAU,kBAAkB;EAE5C,MAAM,OAAO,cAAc,UAAU;EAErC,MAAM,UAAUA,QAAM,kBAAkB;AACvC,OAAI,aACH,cAAa,MAAM;YACT,MACV,QAAO;KAEN,CAAC,cAAc,MAAM,CAAC;AAGzB,UAAM,gBAAgB;AACrB,OAAI,EAAE,QAAQ,eACb;GAED,MAAM,SAAS,MAAqB;AACnC,QAAI,EAAE,QAAQ,SACb,QAAO;;AAGT,UAAO,iBAAiB,WAAW,MAAM;AACzC,gBAAa,OAAO,oBAAoB,WAAW,MAAM;KACvD;GAAC;GAAM;GAAO;GAAc,CAAC;EAEhC,MAAMC,cAAiC;GAAE,QAAQ;GAAM,OAAO;GAAS;EAEvE,MAAM,UACL,OAAO,aAAa,aAAa,SAAS,YAAY,GAAG;AAE1D,SAAO,iBACN,OACA;GACC;GACA;GACA,EACD;GACC;GACA,OAAO;GACP,OAAO;IACN,MAAM;IACN,cAAc;IACd;IACA,GAAG;IACH,UAAU;IACV;GACD,SAAS;GACT,CACD;GAEF;AAED,WAAU,cAAc;AACxB,QAAO;IACJ"}
|
package/realtime/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./seen-store.js";
|
|
2
|
-
import { RealtimeProvider, useRealtimeConnection } from "./provider.js";
|
|
3
2
|
import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./typing-store.js";
|
|
3
|
+
import { RealtimeProvider, useRealtimeConnection } from "./provider.js";
|
|
4
4
|
import { useRealtime } from "./use-realtime.js";
|
|
5
5
|
import { SupportRealtimeProvider } from "./support-provider.js";
|
|
6
6
|
|
package/realtime/provider.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
import { isValidEventType, validateRealtimeEvent } from "@cossistant/types/realtime-events";
|
|
6
7
|
import useWebSocket, { ReadyState } from "react-use-websocket";
|
|
7
|
-
import { jsx } from "react/jsx-runtime";
|
|
8
8
|
|
|
9
9
|
//#region src/realtime/provider.tsx
|
|
10
10
|
const DEFAULT_HEARTBEAT_INTERVAL_MS = 15e3;
|
|
@@ -36,10 +36,6 @@ function SupportRealtimeProvider({ children }) {
|
|
|
36
36
|
conversationTyping: (_data, { event, context }) => {
|
|
37
37
|
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
38
38
|
applyConversationTypingEvent(event, { ignoreVisitorId: context.visitorId });
|
|
39
|
-
},
|
|
40
|
-
conversationEventCreated: (_data, { event, context }) => {
|
|
41
|
-
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
42
|
-
context.client.handleRealtimeEvent(event);
|
|
43
39
|
}
|
|
44
40
|
}), []),
|
|
45
41
|
websiteId: realtimeContext.websiteId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support-provider.js","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { applyConversationSeenEvent } from \"./seen-store\";\nimport {\n\tapplyConversationTypingEvent,\n\tclearTypingFromTimelineItem,\n} from \"./typing-store\";\nimport { useRealtime } from \"./use-realtime\";\n\ntype SupportRealtimeContext = {\n\twebsiteId: string | null;\n\tvisitorId: string | null;\n\tclient: CossistantClient;\n};\n\ntype SupportRealtimeProviderProps = {\n\tchildren: React.ReactNode;\n};\n\n/**\n * Bridges websocket events into the core client stores so support hooks stay\n * in sync without forcing refetches.\n */\nexport function SupportRealtimeProvider({\n\tchildren,\n}: SupportRealtimeProviderProps): React.ReactElement {\n\tconst { website, client, visitor } = useSupport();\n\n\tconst realtimeContext = useMemo<SupportRealtimeContext>(\n\t\t() => ({\n\t\t\twebsiteId: website?.id ?? null,\n\t\t\tvisitorId: visitor?.id ?? null,\n\t\t\tclient,\n\t\t}),\n\t\t[website?.id, visitor?.id, client]\n\t);\n\n\tconst events = useMemo(\n\t\t() => ({\n\t\t\ttimelineItemCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"timelineItemCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Clear typing state when a timeline item is created\n\t\t\t\tclearTypingFromTimelineItem(event);\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t\tconversationSeen: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationSeen\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update the seen store so the UI reflects who has seen messages\n\t\t\t\tapplyConversationSeenEvent(event);\n\t\t\t},\n\t\t\tconversationTyping: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationTyping\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update typing store, but ignore events from the current visitor (their own typing)\n\t\t\t\t// Note: We use context.visitorId which is fresh from the context object\n\t\t\t\tapplyConversationTypingEvent(event, {\n\t\t\t\t\tignoreVisitorId: context.visitorId,\n\t\t\t\t});\n\t\t\t},\n\t\t
|
|
1
|
+
{"version":3,"file":"support-provider.js","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { applyConversationSeenEvent } from \"./seen-store\";\nimport {\n\tapplyConversationTypingEvent,\n\tclearTypingFromTimelineItem,\n} from \"./typing-store\";\nimport { useRealtime } from \"./use-realtime\";\n\ntype SupportRealtimeContext = {\n\twebsiteId: string | null;\n\tvisitorId: string | null;\n\tclient: CossistantClient;\n};\n\ntype SupportRealtimeProviderProps = {\n\tchildren: React.ReactNode;\n};\n\n/**\n * Bridges websocket events into the core client stores so support hooks stay\n * in sync without forcing refetches.\n */\nexport function SupportRealtimeProvider({\n\tchildren,\n}: SupportRealtimeProviderProps): React.ReactElement {\n\tconst { website, client, visitor } = useSupport();\n\n\tconst realtimeContext = useMemo<SupportRealtimeContext>(\n\t\t() => ({\n\t\t\twebsiteId: website?.id ?? null,\n\t\t\tvisitorId: visitor?.id ?? null,\n\t\t\tclient,\n\t\t}),\n\t\t[website?.id, visitor?.id, client]\n\t);\n\n\tconst events = useMemo(\n\t\t() => ({\n\t\t\ttimelineItemCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"timelineItemCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Clear typing state when a timeline item is created\n\t\t\t\tclearTypingFromTimelineItem(event);\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t\tconversationSeen: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationSeen\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update the seen store so the UI reflects who has seen messages\n\t\t\t\tapplyConversationSeenEvent(event);\n\t\t\t},\n\t\t\tconversationTyping: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationTyping\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update typing store, but ignore events from the current visitor (their own typing)\n\t\t\t\t// Note: We use context.visitorId which is fresh from the context object\n\t\t\t\tapplyConversationTypingEvent(event, {\n\t\t\t\t\tignoreVisitorId: context.visitorId,\n\t\t\t\t});\n\t\t\t},\n\t\t}),\n\t\t// Empty dependencies is fine here since we use the context parameter\n\t\t// which always has fresh data from the memoized realtimeContext\n\t\t[]\n\t);\n\n\tuseRealtime<SupportRealtimeContext>({\n\t\tcontext: realtimeContext,\n\t\tevents,\n\t\twebsiteId: realtimeContext.websiteId,\n\t\tvisitorId: realtimeContext.visitorId,\n\t});\n\n\treturn <>{children}</>;\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,wBAAwB,EACvC,YACoD;CACpD,MAAM,EAAE,SAAS,QAAQ,YAAY,YAAY;CAEjD,MAAM,kBAAkB,eAChB;EACN,WAAW,SAAS,MAAM;EAC1B,WAAW,SAAS,MAAM;EAC1B;EACA,GACD;EAAC,SAAS;EAAI,SAAS;EAAI;EAAO,CAClC;AA2ED,aAAoC;EACnC,SAAS;EACT,QA3Ec,eACP;GACN,sBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAID,gCAA4B,MAAM;AAElC,YAAQ,OAAO,oBAAoB,MAAM;;GAE1C,mBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAID,+BAA2B,MAAM;;GAElC,qBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAKD,iCAA6B,OAAO,EACnC,iBAAiB,QAAQ,WACzB,CAAC;;GAEH,GAGD,EAAE,CACF;EAKA,WAAW,gBAAgB;EAC3B,WAAW,gBAAgB;EAC3B,CAAC;AAEF,QAAO,gCAAG,WAAY"}
|