@sero-ai/ui 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.turbo/turbo-build.log +636 -628
  2. package/.turbo/turbo-test.log +12 -11
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/CHANGELOG.md +20 -2
  5. package/dist/components/ai-elements/conversation-virtual.cjs +115 -0
  6. package/dist/components/ai-elements/conversation-virtual.d.cts +30 -0
  7. package/dist/components/ai-elements/conversation-virtual.d.ts +30 -0
  8. package/dist/components/ai-elements/conversation-virtual.js +115 -0
  9. package/dist/components/model-selection/available-model-picker.cjs +21 -77
  10. package/dist/components/model-selection/available-model-picker.js +22 -78
  11. package/dist/components/model-selection/model-picker-body.cjs +106 -0
  12. package/dist/components/model-selection/model-picker-body.d.cts +41 -0
  13. package/dist/components/model-selection/model-picker-body.d.ts +41 -0
  14. package/dist/components/model-selection/model-picker-body.js +106 -0
  15. package/dist/components/model-selection/thinking-level-picker.cjs +7 -3
  16. package/dist/components/model-selection/thinking-level-picker.js +7 -3
  17. package/dist/components/model-selection/thinking-picker.cjs +1 -1
  18. package/dist/components/model-selection/thinking-picker.js +1 -1
  19. package/dist/components/ui/calendar.cjs +1 -1
  20. package/dist/components/ui/calendar.js +1 -1
  21. package/dist/components/ui/combobox.cjs +1 -1
  22. package/dist/components/ui/combobox.js +1 -1
  23. package/dist/components/ui/form.d.cts +2 -2
  24. package/dist/components/ui/form.d.ts +2 -2
  25. package/dist/components/ui/input-group.cjs +1 -1
  26. package/dist/components/ui/input-group.js +1 -1
  27. package/dist/components/ui/input-otp.cjs +1 -1
  28. package/dist/components/ui/input-otp.js +1 -1
  29. package/dist/components/ui/input.cjs +3 -3
  30. package/dist/components/ui/input.js +3 -3
  31. package/dist/components/ui/native-select.cjs +2 -2
  32. package/dist/components/ui/native-select.js +2 -2
  33. package/dist/components/ui/select.cjs +1 -1
  34. package/dist/components/ui/select.js +1 -1
  35. package/dist/components/ui/slider.cjs +6 -0
  36. package/dist/components/ui/slider.d.cts +1 -1
  37. package/dist/components/ui/slider.d.ts +1 -1
  38. package/dist/components/ui/slider.js +6 -0
  39. package/dist/components/ui/spinner.d.cts +2 -1
  40. package/dist/components/ui/spinner.d.ts +2 -1
  41. package/dist/components/ui/textarea.cjs +1 -1
  42. package/dist/components/ui/textarea.js +1 -1
  43. package/dist/index.cjs +0 -55
  44. package/dist/index.d.cts +2 -66
  45. package/dist/index.d.ts +2 -66
  46. package/dist/index.js +0 -55
  47. package/dist/reference.cjs +56 -83
  48. package/dist/reference.js +56 -83
  49. package/dist/styles/ai-elements.css +2 -0
  50. package/dist/styles/context-editor.css +2 -0
  51. package/dist/styles/globals.css +32 -0
  52. package/dist/styles/model-selection.css +2 -0
  53. package/dist/styles/plugin.css +4 -1
  54. package/dist/theme/apply-theme.cjs +65 -12
  55. package/dist/theme/apply-theme.js +55 -2
  56. package/dist/theme/index.d.cts +1 -1
  57. package/dist/theme/index.d.ts +1 -1
  58. package/dist/theme/types.cjs +15 -2
  59. package/dist/theme/types.d.cts +21 -1
  60. package/dist/theme/types.d.ts +21 -1
  61. package/dist/theme/types.js +14 -1
  62. package/package.json +44 -30
  63. package/scripts/smoke-dist.mjs +106 -4
  64. package/src/components/ai-elements/conversation-virtual.test.tsx +126 -0
  65. package/src/components/ai-elements/conversation-virtual.tsx +162 -0
  66. package/src/components/model-selection/available-model-picker.tsx +26 -98
  67. package/src/components/model-selection/model-picker-body.test.tsx +152 -0
  68. package/src/components/model-selection/model-picker-body.tsx +188 -0
  69. package/src/components/model-selection/thinking-level-picker.tsx +9 -3
  70. package/src/components/model-selection/thinking-picker.test.tsx +41 -0
  71. package/src/components/model-selection/thinking-picker.tsx +1 -1
  72. package/src/components/ui/calendar.test.tsx +43 -0
  73. package/src/components/ui/calendar.tsx +1 -1
  74. package/src/components/ui/combobox.tsx +1 -1
  75. package/src/components/ui/input-group.tsx +1 -1
  76. package/src/components/ui/input-otp.tsx +1 -1
  77. package/src/components/ui/input.tsx +3 -3
  78. package/src/components/ui/native-select.tsx +2 -2
  79. package/src/components/ui/select.tsx +1 -1
  80. package/src/components/ui/slider.tsx +6 -0
  81. package/src/components/ui/spinner.tsx +1 -1
  82. package/src/components/ui/textarea.tsx +1 -1
  83. package/src/index.ts +4 -63
  84. package/src/styles/ai-elements.css +2 -0
  85. package/src/styles/context-editor.css +2 -0
  86. package/src/styles/globals.css +32 -0
  87. package/src/styles/model-selection.css +2 -0
  88. package/src/styles/plugin.css +4 -1
  89. package/src/theme/apply-theme.test.ts +126 -0
  90. package/src/theme/apply-theme.ts +66 -3
  91. package/src/theme/types.ts +33 -0
@@ -1,18 +1,19 @@
1
1
 
2
- > @sero-ai/ui@0.4.1 test /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
2
+ > @sero-ai/ui@0.5.0 test /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
3
3
  > vitest run
4
4
 
5
5
 
6
- RUN v4.1.7 /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
6
+ RUN v4.1.10 /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
7
7
 
8
- ✓ src/plugin-style-scope.test.tsx (1 test) 57ms
9
- ✓ src/components/dashboard/__tests__/catalog.test.ts (5 tests) 4ms
10
- ✓ src/components/dashboard/__tests__/state.test.tsx (14 tests) 30ms
11
- ✓ src/components/dashboard/__tests__/glass.test.tsx (4 tests) 14ms
12
- ✓ src/components/dashboard/__tests__/variants.test.tsx (13 tests) 64ms
8
+ ✓ src/plugin-style-scope.test.tsx (1 test) 19ms
9
+ ✓ src/components/dashboard/__tests__/variants.test.tsx (13 tests) 36ms
10
+ ✓ src/components/dashboard/__tests__/glass.test.tsx (4 tests) 11ms
11
+ ✓ src/components/dashboard/__tests__/state.test.tsx (14 tests) 64ms
12
+ ✓ src/components/dashboard/__tests__/catalog.test.ts (5 tests) 7ms
13
+ ✓ src/components/model-selection/thinking-picker.test.tsx (2 tests) 32ms
13
14
 
14
- Test Files 5 passed (5)
15
- Tests 37 passed (37)
16
- Start at 15:46:29
17
- Duration 4.51s (transform 1.63s, setup 0ms, import 7.49s, tests 169ms, environment 7.99s)
15
+ Test Files 6 passed (6)
16
+ Tests 39 passed (39)
17
+ Start at 22:43:26
18
+ Duration 1.83s (transform 862ms, setup 0ms, import 3.20s, tests 169ms, environment 5.28s)
18
19
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @sero-ai/ui@0.4.1 typecheck /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
2
+ > @sero-ai/ui@0.5.0 typecheck /Users/danielcarter/Documents/Dev/projects/sero/sero/packages/ui
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @sero-ai/ui changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Breaking
6
+
7
+ - AI elements and model controls are no longer exported from the package root.
8
+ Migrate them to `@sero-ai/ui/ai-elements/*` and
9
+ `@sero-ai/ui/model-selection/*`. Plugins using those component families must
10
+ also import the matching specialized stylesheet after `styles/plugin.css`.
11
+
12
+ ### Fixed
13
+
14
+ - Root imports now expose primitives, dashboard components, hooks and theme
15
+ utilities without traversing specialized dependency graphs, so a plugin
16
+ importing `Button` and `cn` no longer emits Mermaid, Shiki or graph-rendering
17
+ assets or loads their transitive types. Specialized plugin styles opt in through
18
+ `styles/ai-elements.css`, `styles/model-selection.css`, and
19
+ `styles/context-editor.css`.
20
+
3
21
  ## 0.4.1
4
22
 
5
23
  ### Fixed
@@ -54,5 +72,5 @@
54
72
  worked examples, importable to preview or copy-paste. (Replaces the removed
55
73
  `sero-showcase-plugin`.)
56
74
 
57
- See `docs/features/dashboard-ui/dashboard-widgets-plan.md` and
58
- `glass-restyle-spec.md` for the design and authoring guidance.
75
+ See `apps/docs-site/docs/guide/dashboard-widgets.md` and
76
+ `apps/docs-site/docs/reference/dashboard-components.md` for authoring guidance.
@@ -0,0 +1,115 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+ var _jsxruntime = require('react/jsx-runtime');
3
+ var _react = require('react');
4
+ var _reactvirtual = require('@tanstack/react-virtual');
5
+ var _usesticktobottom = require('use-stick-to-bottom');
6
+ var _utils = require('../../lib/utils');
7
+ function ConversationVirtualList({
8
+ items,
9
+ getItemKey,
10
+ renderItem,
11
+ onReachStart,
12
+ startThreshold = 240,
13
+ estimateSize = 96,
14
+ initialScrollToEnd = false,
15
+ overscan = 6,
16
+ rowClassName,
17
+ className
18
+ }) {
19
+ const { scrollRef, state: scrollState } = _usesticktobottom.useStickToBottomContext.call(void 0, );
20
+ const [initialPositioned, setInitialPositioned] = _react.useState.call(void 0, !initialScrollToEnd);
21
+ const [scrollElement, setScrollElement] = _react.useState.call(void 0, null);
22
+ _react.useEffect.call(void 0, () => {
23
+ setScrollElement(scrollRef.current);
24
+ }, [scrollRef]);
25
+ const virtualizer = _reactvirtual.useVirtualizer.call(void 0, {
26
+ count: items.length,
27
+ getScrollElement: () => scrollElement,
28
+ estimateSize: () => estimateSize,
29
+ overscan,
30
+ getItemKey: (index) => getItemKey(items[index], index)
31
+ });
32
+ _react.useEffect.call(void 0, () => {
33
+ if (initialPositioned) return;
34
+ const timeout = setTimeout(() => setInitialPositioned(true), 250);
35
+ return () => clearTimeout(timeout);
36
+ }, [initialPositioned]);
37
+ _react.useEffect.call(void 0, () => {
38
+ if (initialPositioned || !scrollElement || items.length === 0) return;
39
+ let frame;
40
+ let previousHeight = -1;
41
+ let stableFrames = 0;
42
+ const position = () => {
43
+ const height = scrollElement.scrollHeight;
44
+ const target = Math.max(0, scrollState.calculatedTargetScrollTop);
45
+ const lastRow = virtualizer.getVirtualItems().at(-1);
46
+ const settled = _optionalChain([lastRow, 'optionalAccess', _ => _.index]) === items.length - 1 && Math.abs(scrollElement.scrollTop - target) <= 1 && height === previousHeight;
47
+ stableFrames = settled ? stableFrames + 1 : 0;
48
+ previousHeight = height;
49
+ scrollState.scrollTop = target;
50
+ if (stableFrames >= 2) {
51
+ setInitialPositioned(true);
52
+ return;
53
+ }
54
+ frame = requestAnimationFrame(position);
55
+ };
56
+ frame = requestAnimationFrame(position);
57
+ return () => cancelAnimationFrame(frame);
58
+ }, [initialPositioned, items.length, scrollElement, scrollState, virtualizer]);
59
+ const firstKeyRef = _react.useRef.call(void 0, null);
60
+ const totalSizeRef = _react.useRef.call(void 0, 0);
61
+ const firstKey = items.length > 0 ? getItemKey(items[0], 0) : null;
62
+ _react.useLayoutEffect.call(void 0, () => {
63
+ const previousFirstKey = firstKeyRef.current;
64
+ const previousTotal = totalSizeRef.current;
65
+ firstKeyRef.current = firstKey;
66
+ totalSizeRef.current = virtualizer.getTotalSize();
67
+ if (previousFirstKey === null || previousFirstKey === firstKey) return;
68
+ const previousFirstIndex = items.findIndex((item, index) => getItemKey(item, index) === previousFirstKey);
69
+ if (previousFirstIndex <= 0) return;
70
+ const scrollElement2 = scrollRef.current;
71
+ if (!scrollElement2) return;
72
+ scrollElement2.scrollTop += totalSizeRef.current - previousTotal;
73
+ });
74
+ const onReachStartRef = _react.useRef.call(void 0, onReachStart);
75
+ _react.useLayoutEffect.call(void 0, () => {
76
+ onReachStartRef.current = onReachStart;
77
+ }, [onReachStart]);
78
+ _react.useEffect.call(void 0, () => {
79
+ const scrollElement2 = scrollRef.current;
80
+ if (!scrollElement2) return;
81
+ const handleScroll = () => {
82
+ if (scrollElement2.scrollTop <= startThreshold) _optionalChain([onReachStartRef, 'access', _2 => _2.current, 'optionalCall', _3 => _3()]);
83
+ };
84
+ scrollElement2.addEventListener("scroll", handleScroll, { passive: true });
85
+ return () => scrollElement2.removeEventListener("scroll", handleScroll);
86
+ }, [scrollRef, startThreshold]);
87
+ const measureRow = _react.useCallback.call(void 0,
88
+ (node) => virtualizer.measureElement(node),
89
+ [virtualizer]
90
+ );
91
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
92
+ "div",
93
+ {
94
+ className: _utils.cn.call(void 0, "relative w-full", className),
95
+ style: { height: virtualizer.getTotalSize(), visibility: initialPositioned ? void 0 : "hidden" },
96
+ children: virtualizer.getVirtualItems().map((virtualRow) => {
97
+ const content = renderItem(items[virtualRow.index], virtualRow.index);
98
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
99
+ "div",
100
+ {
101
+ "data-index": virtualRow.index,
102
+ ref: measureRow,
103
+ className: "absolute top-0 left-0 w-full",
104
+ style: { transform: `translateY(${virtualRow.start}px)` },
105
+ children: content === null ? null : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: rowClassName, children: content })
106
+ },
107
+ virtualRow.key
108
+ );
109
+ })
110
+ }
111
+ );
112
+ }
113
+
114
+
115
+ exports.ConversationVirtualList = ConversationVirtualList;
@@ -0,0 +1,30 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ConversationVirtualListProps<T> {
5
+ items: T[];
6
+ getItemKey: (item: T, index: number) => string;
7
+ /** Return null for an item that renders nothing; it then takes no space. */
8
+ renderItem: (item: T, index: number) => ReactNode;
9
+ /** Called on a scroll within `startThreshold` of the top, including programmatic scrolls. */
10
+ onReachStart?: () => void;
11
+ startThreshold?: number;
12
+ estimateSize?: number;
13
+ /** Reveal the initial transcript only after its last row is positioned. */
14
+ initialScrollToEnd?: boolean;
15
+ overscan?: number;
16
+ /** Class for the wrapper around each rendered item, for example a bottom gap. */
17
+ rowClassName?: string;
18
+ className?: string;
19
+ }
20
+ /**
21
+ * Windowed rows inside a `Conversation`. Only rows near the viewport are in
22
+ * the DOM, so node count stays bounded for any thread length. The scroll
23
+ * element and stick-to-bottom behavior stay with `StickToBottom`.
24
+ *
25
+ * Items prepended to `items` (older history) keep the viewport anchored:
26
+ * the scroll offset moves by the height the new rows added above it.
27
+ */
28
+ declare function ConversationVirtualList<T>({ items, getItemKey, renderItem, onReachStart, startThreshold, estimateSize, initialScrollToEnd, overscan, rowClassName, className, }: ConversationVirtualListProps<T>): react_jsx_runtime.JSX.Element;
29
+
30
+ export { ConversationVirtualList, type ConversationVirtualListProps };
@@ -0,0 +1,30 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ConversationVirtualListProps<T> {
5
+ items: T[];
6
+ getItemKey: (item: T, index: number) => string;
7
+ /** Return null for an item that renders nothing; it then takes no space. */
8
+ renderItem: (item: T, index: number) => ReactNode;
9
+ /** Called on a scroll within `startThreshold` of the top, including programmatic scrolls. */
10
+ onReachStart?: () => void;
11
+ startThreshold?: number;
12
+ estimateSize?: number;
13
+ /** Reveal the initial transcript only after its last row is positioned. */
14
+ initialScrollToEnd?: boolean;
15
+ overscan?: number;
16
+ /** Class for the wrapper around each rendered item, for example a bottom gap. */
17
+ rowClassName?: string;
18
+ className?: string;
19
+ }
20
+ /**
21
+ * Windowed rows inside a `Conversation`. Only rows near the viewport are in
22
+ * the DOM, so node count stays bounded for any thread length. The scroll
23
+ * element and stick-to-bottom behavior stay with `StickToBottom`.
24
+ *
25
+ * Items prepended to `items` (older history) keep the viewport anchored:
26
+ * the scroll offset moves by the height the new rows added above it.
27
+ */
28
+ declare function ConversationVirtualList<T>({ items, getItemKey, renderItem, onReachStart, startThreshold, estimateSize, initialScrollToEnd, overscan, rowClassName, className, }: ConversationVirtualListProps<T>): react_jsx_runtime.JSX.Element;
29
+
30
+ export { ConversationVirtualList, type ConversationVirtualListProps };
@@ -0,0 +1,115 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
4
+ import { useVirtualizer } from "@tanstack/react-virtual";
5
+ import { useStickToBottomContext } from "use-stick-to-bottom";
6
+ import { cn } from "../../lib/utils";
7
+ function ConversationVirtualList({
8
+ items,
9
+ getItemKey,
10
+ renderItem,
11
+ onReachStart,
12
+ startThreshold = 240,
13
+ estimateSize = 96,
14
+ initialScrollToEnd = false,
15
+ overscan = 6,
16
+ rowClassName,
17
+ className
18
+ }) {
19
+ const { scrollRef, state: scrollState } = useStickToBottomContext();
20
+ const [initialPositioned, setInitialPositioned] = useState(!initialScrollToEnd);
21
+ const [scrollElement, setScrollElement] = useState(null);
22
+ useEffect(() => {
23
+ setScrollElement(scrollRef.current);
24
+ }, [scrollRef]);
25
+ const virtualizer = useVirtualizer({
26
+ count: items.length,
27
+ getScrollElement: () => scrollElement,
28
+ estimateSize: () => estimateSize,
29
+ overscan,
30
+ getItemKey: (index) => getItemKey(items[index], index)
31
+ });
32
+ useEffect(() => {
33
+ if (initialPositioned) return;
34
+ const timeout = setTimeout(() => setInitialPositioned(true), 250);
35
+ return () => clearTimeout(timeout);
36
+ }, [initialPositioned]);
37
+ useEffect(() => {
38
+ if (initialPositioned || !scrollElement || items.length === 0) return;
39
+ let frame;
40
+ let previousHeight = -1;
41
+ let stableFrames = 0;
42
+ const position = () => {
43
+ const height = scrollElement.scrollHeight;
44
+ const target = Math.max(0, scrollState.calculatedTargetScrollTop);
45
+ const lastRow = virtualizer.getVirtualItems().at(-1);
46
+ const settled = lastRow?.index === items.length - 1 && Math.abs(scrollElement.scrollTop - target) <= 1 && height === previousHeight;
47
+ stableFrames = settled ? stableFrames + 1 : 0;
48
+ previousHeight = height;
49
+ scrollState.scrollTop = target;
50
+ if (stableFrames >= 2) {
51
+ setInitialPositioned(true);
52
+ return;
53
+ }
54
+ frame = requestAnimationFrame(position);
55
+ };
56
+ frame = requestAnimationFrame(position);
57
+ return () => cancelAnimationFrame(frame);
58
+ }, [initialPositioned, items.length, scrollElement, scrollState, virtualizer]);
59
+ const firstKeyRef = useRef(null);
60
+ const totalSizeRef = useRef(0);
61
+ const firstKey = items.length > 0 ? getItemKey(items[0], 0) : null;
62
+ useLayoutEffect(() => {
63
+ const previousFirstKey = firstKeyRef.current;
64
+ const previousTotal = totalSizeRef.current;
65
+ firstKeyRef.current = firstKey;
66
+ totalSizeRef.current = virtualizer.getTotalSize();
67
+ if (previousFirstKey === null || previousFirstKey === firstKey) return;
68
+ const previousFirstIndex = items.findIndex((item, index) => getItemKey(item, index) === previousFirstKey);
69
+ if (previousFirstIndex <= 0) return;
70
+ const scrollElement2 = scrollRef.current;
71
+ if (!scrollElement2) return;
72
+ scrollElement2.scrollTop += totalSizeRef.current - previousTotal;
73
+ });
74
+ const onReachStartRef = useRef(onReachStart);
75
+ useLayoutEffect(() => {
76
+ onReachStartRef.current = onReachStart;
77
+ }, [onReachStart]);
78
+ useEffect(() => {
79
+ const scrollElement2 = scrollRef.current;
80
+ if (!scrollElement2) return;
81
+ const handleScroll = () => {
82
+ if (scrollElement2.scrollTop <= startThreshold) onReachStartRef.current?.();
83
+ };
84
+ scrollElement2.addEventListener("scroll", handleScroll, { passive: true });
85
+ return () => scrollElement2.removeEventListener("scroll", handleScroll);
86
+ }, [scrollRef, startThreshold]);
87
+ const measureRow = useCallback(
88
+ (node) => virtualizer.measureElement(node),
89
+ [virtualizer]
90
+ );
91
+ return /* @__PURE__ */ jsx(
92
+ "div",
93
+ {
94
+ className: cn("relative w-full", className),
95
+ style: { height: virtualizer.getTotalSize(), visibility: initialPositioned ? void 0 : "hidden" },
96
+ children: virtualizer.getVirtualItems().map((virtualRow) => {
97
+ const content = renderItem(items[virtualRow.index], virtualRow.index);
98
+ return /* @__PURE__ */ jsx(
99
+ "div",
100
+ {
101
+ "data-index": virtualRow.index,
102
+ ref: measureRow,
103
+ className: "absolute top-0 left-0 w-full",
104
+ style: { transform: `translateY(${virtualRow.start}px)` },
105
+ children: content === null ? null : /* @__PURE__ */ jsx("div", { className: rowClassName, children: content })
106
+ },
107
+ virtualRow.key
108
+ );
109
+ })
110
+ }
111
+ );
112
+ }
113
+ export {
114
+ ConversationVirtualList
115
+ };
@@ -1,15 +1,13 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _jsxruntime = require('react/jsx-runtime');
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _jsxruntime = require('react/jsx-runtime');
2
2
  var _react = require('react');
3
3
  var _lucidereact = require('lucide-react');
4
4
 
5
5
 
6
6
 
7
7
 
8
-
9
-
10
8
  var _common = require('@sero-ai/common');
11
9
  var _popover = require('../ui/popover');
12
- var _searchinput = require('../ui/search-input');
10
+ var _modelpickerbody = require('./model-picker-body');
13
11
  var _utils = require('../../lib/utils');
14
12
  function AvailableModelPicker({
15
13
  groups,
@@ -24,8 +22,6 @@ function AvailableModelPicker({
24
22
  className
25
23
  }) {
26
24
  const [open, setOpen] = _react.useState.call(void 0, false);
27
- const [query, setQuery] = _react.useState.call(void 0, "");
28
- const inputRef = _react.useRef.call(void 0, null);
29
25
  const selected = _react.useMemo.call(void 0, () => {
30
26
  const parsed = _common.parseModelKey.call(void 0, value);
31
27
  if (!parsed) {
@@ -39,32 +35,16 @@ function AvailableModelPicker({
39
35
  fallbackLabel: model ? null : value
40
36
  };
41
37
  }, [groups, value]);
42
- const filteredGroups = _react.useMemo.call(void 0,
43
- () => _common.filterModelGroups.call(void 0, groups, query),
44
- [groups, query]
45
- );
46
- const totalResults = _react.useMemo.call(void 0,
47
- () => filteredGroups.reduce((count, group) => count + group.models.length, 0),
48
- [filteredGroups]
49
- );
50
- const handleOpenChange = _react.useCallback.call(void 0, (nextOpen) => {
51
- setOpen(nextOpen);
52
- if (!nextOpen) return;
53
- setQuery("");
54
- requestAnimationFrame(() => _optionalChain([inputRef, 'access', _ => _.current, 'optionalAccess', _2 => _2.focus, 'call', _3 => _3()]));
55
- }, []);
56
- const handleSelect = _react.useCallback.call(void 0, (provider, modelId) => {
57
- onChange(_common.modelKey.call(void 0, provider, modelId));
38
+ const handleSelect = _react.useCallback.call(void 0, (nextValue) => {
39
+ onChange(nextValue);
58
40
  setOpen(false);
59
- setQuery("");
60
41
  }, [onChange]);
61
42
  const handleClear = _react.useCallback.call(void 0, (event) => {
62
43
  event.stopPropagation();
63
44
  onChange("");
64
45
  setOpen(false);
65
- setQuery("");
66
46
  }, [onChange]);
67
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _popover.Popover, { open, onOpenChange: handleOpenChange, children: [
47
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _popover.Popover, { open, onOpenChange: setOpen, children: [
68
48
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _popover.PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
69
49
  "div",
70
50
  {
@@ -79,11 +59,11 @@ function AvailableModelPicker({
79
59
  children: [
80
60
  selected.group && selected.model ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
81
61
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
82
- "img",
62
+ _modelpickerbody.ProviderLogo,
83
63
  {
84
- src: selected.group.logo,
85
- alt: selected.group.displayName,
86
- className: "size-4 shrink-0 rounded-sm dark:invert"
64
+ logo: selected.group.logo,
65
+ displayName: selected.group.displayName,
66
+ className: "size-4"
87
67
  }
88
68
  ),
89
69
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1", children: [
@@ -108,7 +88,7 @@ function AvailableModelPicker({
108
88
  ]
109
89
  }
110
90
  ) }),
111
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
91
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
112
92
  _popover.PopoverContent,
113
93
  {
114
94
  side: "bottom",
@@ -116,53 +96,17 @@ function AvailableModelPicker({
116
96
  sideOffset: 4,
117
97
  className: "w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-xl border-border/60 bg-background p-0 shadow-xl",
118
98
  onWheel: (event) => event.stopPropagation(),
119
- children: [
120
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
121
- _searchinput.SearchInput,
122
- {
123
- ref: inputRef,
124
- value: query,
125
- onChange: (event) => setQuery(event.target.value),
126
- placeholder: searchPlaceholder,
127
- containerClassName: "border-b border-border/40"
128
- }
129
- ),
130
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "max-h-[280px] overflow-y-auto py-1", children: groups.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: noModelsLabel }) : totalResults === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: emptyLabel }) : filteredGroups.map((group, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
131
- index > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mx-3 border-t border-border/30" }) : null,
132
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 px-3 pb-1 pt-2", children: [
133
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
134
- "img",
135
- {
136
- src: group.logo,
137
- alt: group.displayName,
138
- className: "size-3.5 shrink-0 rounded-sm dark:invert"
139
- }
140
- ),
141
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-semibold uppercase tracking-wider text-muted-foreground", children: group.displayName })
142
- ] }),
143
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "px-1", children: group.models.map((model) => {
144
- const nextValue = _common.modelKey.call(void 0, model.provider, model.modelId);
145
- const isSelected = nextValue === value;
146
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
147
- "button",
148
- {
149
- type: "button",
150
- onClick: () => handleSelect(model.provider, model.modelId),
151
- className: _utils.cn.call(void 0,
152
- "flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-left text-sm transition-colors",
153
- isSelected ? "bg-secondary text-foreground" : "text-muted-foreground hover:bg-secondary/60 hover:text-foreground"
154
- ),
155
- children: [
156
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex size-4 shrink-0 items-center justify-center", children: isSelected ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "size-1.5 rounded-full bg-border" }) }),
157
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "min-w-0 flex-1 truncate font-medium", children: model.name }),
158
- model.reasoning ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Sparkles, { className: "size-3 shrink-0 text-amber-500/60" }) : null
159
- ]
160
- },
161
- nextValue
162
- );
163
- }) })
164
- ] }, group.provider)) })
165
- ]
99
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
100
+ _modelpickerbody.ModelPickerBody,
101
+ {
102
+ groups,
103
+ value,
104
+ onChange: handleSelect,
105
+ searchPlaceholder,
106
+ emptyLabel,
107
+ noModelsLabel
108
+ }
109
+ )
166
110
  }
167
111
  )
168
112
  ] });