@epicbagel/saas-kit 1.12.0 → 1.14.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.
- package/README.md +41 -0
- package/THIRD_PARTY_NOTICES.md +20 -0
- package/dist/chunk-34AS3OCC.cjs +256 -0
- package/dist/chunk-KI7SWNIN.js +53 -0
- package/dist/{chunk-5VMKDVB6.cjs → chunk-PD5UQEKY.cjs} +21 -2
- package/dist/chunk-SJB4DPGQ.cjs +51 -0
- package/dist/chunk-SRIGG5I5.js +51 -0
- package/dist/{chunk-2V7AVB2U.js → chunk-UBTLWSKK.js} +19 -0
- package/dist/chunk-VKYRB37O.cjs +53 -0
- package/dist/chunk-VT2WDFSU.js +256 -0
- package/dist/primitives/chat.cjs +15 -13
- package/dist/primitives/chat.js +6 -4
- package/dist/primitives/message-scroller.cjs +6 -2
- package/dist/primitives/message-scroller.d.cts +5 -1
- package/dist/primitives/message-scroller.d.ts +5 -1
- package/dist/primitives/message-scroller.js +5 -1
- package/dist/primitives/notes.cjs +259 -0
- package/dist/primitives/notes.d.cts +123 -0
- package/dist/primitives/notes.d.ts +123 -0
- package/dist/primitives/notes.js +259 -0
- package/dist/primitives/panel-section.cjs +4 -48
- package/dist/primitives/panel-section.js +3 -47
- package/dist/primitives/scroll-navigator.cjs +10 -0
- package/dist/primitives/scroll-navigator.d.cts +40 -0
- package/dist/primitives/scroll-navigator.d.ts +40 -0
- package/dist/primitives/scroll-navigator.js +10 -0
- package/dist/primitives/section-header.cjs +4 -45
- package/dist/primitives/section-header.js +4 -45
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -439,3 +439,44 @@ export function Appearance() {
|
|
|
439
439
|
|
|
440
440
|
MIT. Some components and styles are adapted from shadcn/ui, and the file
|
|
441
441
|
drop handling from AI SDK Elements (Apache-2.0); see `THIRD_PARTY_NOTICES.md`.
|
|
442
|
+
|
|
443
|
+
## Scroll navigation
|
|
444
|
+
|
|
445
|
+
`primitives/scroll-navigator` exports `ScrollNavigator`: pass an `items` array
|
|
446
|
+
with stable `id`, accessible `label`, optional `imageSrc`/`fallback`, and
|
|
447
|
+
`content`. It renders the list and a clickable avatar index while the list is
|
|
448
|
+
visible. The item at the top of the scroll viewport is highlighted; the index
|
|
449
|
+
scrolls independently for long lists. With insufficient left gutter, it uses
|
|
450
|
+
a compact horizontal row above the content. Single-item lists have no index.
|
|
451
|
+
|
|
452
|
+
It detects the nearest scrolling ancestor, supports an explicit `scrollRoot`
|
|
453
|
+
and `topOffset` for sticky headers, and offers `onNavigate` for custom scroll
|
|
454
|
+
controllers. Keyboard users Tab into the index, use arrows or Home/End, then
|
|
455
|
+
Enter to jump. Reduced-motion preferences are respected. No data or selected
|
|
456
|
+
record state changes when scrolling or navigating.
|
|
457
|
+
|
|
458
|
+
Inside a `MessageScrollerProvider`, use `MessageScrollerNavigator` from
|
|
459
|
+
`primitives/message-scroller` with the same props. It uses the thread's scroll
|
|
460
|
+
controller so incoming messages do not undo a jump into a long list.
|
|
461
|
+
|
|
462
|
+
## Notes
|
|
463
|
+
|
|
464
|
+
`primitives/notes` provides a reusable `Notes` area and `NoteComposer` for any
|
|
465
|
+
record. Pass display data with stable IDs; the list owns rendering and count,
|
|
466
|
+
preserves order, and accepts author/date nodes and optional context, pinned,
|
|
467
|
+
voice/assistant and deletion metadata. Hosts resolve identity, authorize saves
|
|
468
|
+
and confirm deletions.
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
<Notes
|
|
472
|
+
notes={[{ id: "note-1", author: "You", date: "Today", text: "Follow up next week." }]}
|
|
473
|
+
composer={<NoteComposer onSubmit={saveNote} onVoice={openRecorder} />}
|
|
474
|
+
/>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Omit `onVoice` for a text-only composer. A rejected save retains the draft; all
|
|
478
|
+
conflicting actions are disabled during a save. `value` / `onValueChange` and
|
|
479
|
+
`editing` / `onEditingChange` support host-owned drafts, including failed voice
|
|
480
|
+
transcripts. A controlled host clears or replaces `value` after saving. Set
|
|
481
|
+
`maxLength` to the application's limit. `NoteList` and `NoteCard` are available
|
|
482
|
+
for existing compositions.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -52,6 +52,26 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
52
52
|
SOFTWARE.
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
## Attributed notes
|
|
56
|
+
|
|
57
|
+
`primitives/notes` adapts the attributed note cards and voice/text composer
|
|
58
|
+
from the public `@recruiteros/recruit-ui` package, version 0.16.0. The adaptation
|
|
59
|
+
adds a generic notes-array API, controlled drafts, accessible labels and
|
|
60
|
+
serialized asynchronous saves. It contains no application data or persistence.
|
|
61
|
+
|
|
62
|
+
These adapted portions are licensed under the Apache License, Version 2.0,
|
|
63
|
+
reproduced below. The upstream notice is retained here:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Recruit UI
|
|
67
|
+
Copyright 2026 RecruiterOS
|
|
68
|
+
|
|
69
|
+
RecruiterOS-authored portions are licensed under the Apache License,
|
|
70
|
+
Version 2.0. The UI primitives come from the separately installed
|
|
71
|
+
@epicbagel/saas-kit package (MIT). Third-party runtime dependencies retain
|
|
72
|
+
their own licenses and copyright notices. See THIRD_PARTY_NOTICES.md.
|
|
73
|
+
```
|
|
74
|
+
|
|
55
75
|
## AI SDK Elements
|
|
56
76
|
|
|
57
77
|
Source: https://github.com/vercel/ai-elements (`packages/elements/src/prompt-input.tsx`,
|
|
@@ -0,0 +1,256 @@
|
|
|
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; }"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var _chunkWABCLRBRcjs = require('./chunk-WABCLRBR.cjs');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
|
|
10
|
+
|
|
11
|
+
// src/primitives/scroll-navigator.tsx
|
|
12
|
+
var _react = require('react');
|
|
13
|
+
var _reactdom = require('react-dom');
|
|
14
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
15
|
+
var GAP = 12;
|
|
16
|
+
var RAIL_WIDTH = 56;
|
|
17
|
+
var ROW_HEIGHT = 64;
|
|
18
|
+
var initialPlacement = { mode: "row", top: 0, left: 0, width: 0, maxHeight: 0, active: 0, visible: false };
|
|
19
|
+
function findScrollRoot(element) {
|
|
20
|
+
for (let parent = element.parentElement; parent; parent = parent.parentElement) {
|
|
21
|
+
if (/(auto|scroll|overlay)/.test(getComputedStyle(parent).overflowY) && parent.scrollHeight > parent.clientHeight) return parent;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function viewportBounds(root) {
|
|
26
|
+
const viewport = window.visualViewport;
|
|
27
|
+
const top = _nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _ => _.offsetTop]), () => ( 0));
|
|
28
|
+
const left = _nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _2 => _2.offsetLeft]), () => ( 0));
|
|
29
|
+
const bounds = { top, left, right: left + (_nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _3 => _3.width]), () => ( innerWidth))), bottom: top + (_nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _4 => _4.height]), () => ( innerHeight))) };
|
|
30
|
+
for (let parent = root; parent; parent = parent.parentElement) {
|
|
31
|
+
const style = getComputedStyle(parent);
|
|
32
|
+
if (parent !== root && !/(auto|scroll|hidden|clip)/.test(`${style.overflowX} ${style.overflowY}`)) continue;
|
|
33
|
+
const rect = parent.getBoundingClientRect();
|
|
34
|
+
bounds.top = Math.max(bounds.top, rect.top + parent.clientTop);
|
|
35
|
+
bounds.left = Math.max(bounds.left, rect.left + parent.clientLeft);
|
|
36
|
+
bounds.right = Math.min(bounds.right, rect.left + parent.clientLeft + parent.clientWidth);
|
|
37
|
+
bounds.bottom = Math.min(bounds.bottom, rect.top + parent.clientTop + parent.clientHeight);
|
|
38
|
+
}
|
|
39
|
+
return bounds;
|
|
40
|
+
}
|
|
41
|
+
var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
|
|
42
|
+
items,
|
|
43
|
+
label = "Browse items",
|
|
44
|
+
topOffset = 0,
|
|
45
|
+
scrollRoot,
|
|
46
|
+
onNavigate,
|
|
47
|
+
className,
|
|
48
|
+
...props
|
|
49
|
+
}, forwardedRef) {
|
|
50
|
+
const rootRef = _react.useRef.call(void 0, null);
|
|
51
|
+
const targets = _react.useRef.call(void 0, /* @__PURE__ */ new Map());
|
|
52
|
+
const controls = _react.useRef.call(void 0, /* @__PURE__ */ new Map());
|
|
53
|
+
const indexRef = _react.useRef.call(void 0, null);
|
|
54
|
+
const scroller = _react.useRef.call(void 0, null);
|
|
55
|
+
const [placement, setPlacement] = _react.useState.call(void 0, initialPlacement);
|
|
56
|
+
const [focusId, setFocusId] = _react.useState.call(void 0, null);
|
|
57
|
+
const id = _react.useId.call(void 0, );
|
|
58
|
+
const keys = JSON.stringify(items.map((item) => item.id));
|
|
59
|
+
const navigable = items.length > 1;
|
|
60
|
+
_react.useLayoutEffect.call(void 0, () => {
|
|
61
|
+
const element = rootRef.current;
|
|
62
|
+
if (!element || !navigable) return;
|
|
63
|
+
let frame = 0;
|
|
64
|
+
let intersects = true;
|
|
65
|
+
const measure = () => {
|
|
66
|
+
frame = 0;
|
|
67
|
+
if (!intersects) {
|
|
68
|
+
setPlacement((previous) => previous.visible ? { ...previous, visible: false } : previous);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const scrollElement = scrollRoot === void 0 ? findScrollRoot(element) : scrollRoot;
|
|
72
|
+
scroller.current = scrollElement;
|
|
73
|
+
const view = viewportBounds(scrollElement);
|
|
74
|
+
const box = element.getBoundingClientRect();
|
|
75
|
+
const mode = box.left - view.left >= RAIL_WIDTH + GAP ? "rail" : "row";
|
|
76
|
+
const top = Math.max(view.top + topOffset + GAP, box.top);
|
|
77
|
+
const bottom = Math.min(view.bottom, box.bottom) - GAP;
|
|
78
|
+
const visible = box.width > 0 && box.right > view.left && box.left < view.right && bottom - top >= ROW_HEIGHT;
|
|
79
|
+
const readingEdge = view.top + topOffset + GAP + (mode === "row" ? ROW_HEIGHT : 0);
|
|
80
|
+
const active = visible ? Math.max(0, items.findIndex((item) => (_nullishCoalesce(_optionalChain([targets, 'access', _5 => _5.current, 'access', _6 => _6.get, 'call', _7 => _7(item.id), 'optionalAccess', _8 => _8.getBoundingClientRect, 'call', _9 => _9(), 'access', _10 => _10.bottom]), () => ( 0))) > readingEdge + 1)) : 0;
|
|
81
|
+
const next = {
|
|
82
|
+
mode,
|
|
83
|
+
top,
|
|
84
|
+
left: mode === "rail" ? box.left - RAIL_WIDTH - GAP : Math.max(box.left, view.left),
|
|
85
|
+
width: mode === "rail" ? RAIL_WIDTH : Math.max(0, Math.min(box.right, view.right) - Math.max(box.left, view.left)),
|
|
86
|
+
maxHeight: Math.max(0, bottom - top),
|
|
87
|
+
active,
|
|
88
|
+
visible
|
|
89
|
+
};
|
|
90
|
+
setPlacement((previous) => Object.keys(next).every((key) => previous[key] === next[key]) ? previous : next);
|
|
91
|
+
};
|
|
92
|
+
const schedule = () => {
|
|
93
|
+
if (!frame) frame = requestAnimationFrame(measure);
|
|
94
|
+
};
|
|
95
|
+
const visibility = typeof IntersectionObserver === "undefined" ? null : new IntersectionObserver((entries) => {
|
|
96
|
+
intersects = _nullishCoalesce(_optionalChain([entries, 'access', _11 => _11[entries.length - 1], 'optionalAccess', _12 => _12.isIntersecting]), () => ( intersects));
|
|
97
|
+
schedule();
|
|
98
|
+
});
|
|
99
|
+
_optionalChain([visibility, 'optionalAccess', _13 => _13.observe, 'call', _14 => _14(element)]);
|
|
100
|
+
const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(schedule);
|
|
101
|
+
for (let parent = element; parent; parent = parent.parentElement) {
|
|
102
|
+
_optionalChain([resize, 'optionalAccess', _15 => _15.observe, 'call', _16 => _16(parent)]);
|
|
103
|
+
}
|
|
104
|
+
targets.current.forEach((target) => _optionalChain([resize, 'optionalAccess', _17 => _17.observe, 'call', _18 => _18(target)]));
|
|
105
|
+
document.addEventListener("scroll", schedule, { passive: true, capture: true });
|
|
106
|
+
window.addEventListener("resize", schedule);
|
|
107
|
+
_optionalChain([window, 'access', _19 => _19.visualViewport, 'optionalAccess', _20 => _20.addEventListener, 'call', _21 => _21("resize", schedule)]);
|
|
108
|
+
_optionalChain([window, 'access', _22 => _22.visualViewport, 'optionalAccess', _23 => _23.addEventListener, 'call', _24 => _24("scroll", schedule)]);
|
|
109
|
+
measure();
|
|
110
|
+
return () => {
|
|
111
|
+
cancelAnimationFrame(frame);
|
|
112
|
+
_optionalChain([resize, 'optionalAccess', _25 => _25.disconnect, 'call', _26 => _26()]);
|
|
113
|
+
_optionalChain([visibility, 'optionalAccess', _27 => _27.disconnect, 'call', _28 => _28()]);
|
|
114
|
+
document.removeEventListener("scroll", schedule, true);
|
|
115
|
+
window.removeEventListener("resize", schedule);
|
|
116
|
+
_optionalChain([window, 'access', _29 => _29.visualViewport, 'optionalAccess', _30 => _30.removeEventListener, 'call', _31 => _31("resize", schedule)]);
|
|
117
|
+
_optionalChain([window, 'access', _32 => _32.visualViewport, 'optionalAccess', _33 => _33.removeEventListener, 'call', _34 => _34("scroll", schedule)]);
|
|
118
|
+
};
|
|
119
|
+
}, [keys, navigable, topOffset, scrollRoot]);
|
|
120
|
+
_react.useEffect.call(void 0, () => {
|
|
121
|
+
const index = indexRef.current;
|
|
122
|
+
const button = controls.current.get(_nullishCoalesce(_nullishCoalesce(focusId, () => ( _optionalChain([items, 'access', _35 => _35[placement.active], 'optionalAccess', _36 => _36.id]))), () => ( "")));
|
|
123
|
+
if (!index || !button || !placement.visible) return;
|
|
124
|
+
const horizontal = placement.mode === "row";
|
|
125
|
+
const start = horizontal ? button.offsetLeft : button.offsetTop;
|
|
126
|
+
const end = start + (horizontal ? button.offsetWidth : button.offsetHeight);
|
|
127
|
+
const position = horizontal ? index.scrollLeft : index.scrollTop;
|
|
128
|
+
const size = horizontal ? index.clientWidth : index.clientHeight;
|
|
129
|
+
const next = start < position ? start : end > position + size ? end - size : position;
|
|
130
|
+
if (horizontal) index.scrollLeft = next;
|
|
131
|
+
else index.scrollTop = next;
|
|
132
|
+
}, [placement.active, placement.mode, placement.visible, focusId, keys]);
|
|
133
|
+
function navigate(item) {
|
|
134
|
+
const target = targets.current.get(item.id);
|
|
135
|
+
if (!target) return;
|
|
136
|
+
const options = {
|
|
137
|
+
offset: topOffset + GAP + (placement.mode === "row" ? ROW_HEIGHT : 0),
|
|
138
|
+
behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "instant" : "smooth"
|
|
139
|
+
};
|
|
140
|
+
if (_optionalChain([onNavigate, 'optionalCall', _37 => _37(item.id, target, options)]) === true) return;
|
|
141
|
+
const scrollElement = scroller.current;
|
|
142
|
+
const view = viewportBounds(scrollElement);
|
|
143
|
+
const top = (_nullishCoalesce(_optionalChain([scrollElement, 'optionalAccess', _38 => _38.scrollTop]), () => ( window.scrollY))) + target.getBoundingClientRect().top - view.top - options.offset;
|
|
144
|
+
if (scrollElement) scrollElement.scrollTo({ top, behavior: options.behavior });
|
|
145
|
+
else window.scrollTo({ top, behavior: options.behavior });
|
|
146
|
+
}
|
|
147
|
+
const activeId = _optionalChain([items, 'access', _39 => _39[placement.active], 'optionalAccess', _40 => _40.id]);
|
|
148
|
+
const tabId = focusId && items.some((item) => item.id === focusId) ? focusId : activeId;
|
|
149
|
+
const row = placement.mode === "row";
|
|
150
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
...props,
|
|
154
|
+
"data-slot": "scroll-navigator",
|
|
155
|
+
"data-orientation": row ? "horizontal" : "vertical",
|
|
156
|
+
ref: (element) => {
|
|
157
|
+
rootRef.current = element;
|
|
158
|
+
if (typeof forwardedRef === "function") forwardedRef(element);
|
|
159
|
+
else if (forwardedRef) forwardedRef.current = element;
|
|
160
|
+
},
|
|
161
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "relative min-w-0", navigable && row && "pt-16", className),
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-w-0 flex-col gap-4", children: items.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
164
|
+
"div",
|
|
165
|
+
{
|
|
166
|
+
id: `${id}-${index}`,
|
|
167
|
+
"data-slot": "scroll-navigator-item",
|
|
168
|
+
"data-item-id": item.id,
|
|
169
|
+
ref: (element) => {
|
|
170
|
+
if (element) targets.current.set(item.id, element);
|
|
171
|
+
else targets.current.delete(item.id);
|
|
172
|
+
},
|
|
173
|
+
className: "min-w-0",
|
|
174
|
+
children: item.content
|
|
175
|
+
},
|
|
176
|
+
item.id
|
|
177
|
+
)) }),
|
|
178
|
+
navigable && placement.visible && _reactdom.createPortal.call(void 0,
|
|
179
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
180
|
+
"nav",
|
|
181
|
+
{
|
|
182
|
+
"aria-label": label,
|
|
183
|
+
"data-slot": "scroll-navigator-controls",
|
|
184
|
+
"data-orientation": row ? "horizontal" : "vertical",
|
|
185
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "fixed z-20 flex rounded-full border border-border/60 bg-background/95 p-1 shadow-sm backdrop-blur-sm", row ? "items-center gap-1" : "flex-col items-center gap-1"),
|
|
186
|
+
style: { top: placement.top, left: placement.left, width: placement.width, maxHeight: placement.maxHeight },
|
|
187
|
+
onBlur: (event) => {
|
|
188
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setFocusId(null);
|
|
189
|
+
},
|
|
190
|
+
children: [
|
|
191
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
ref: indexRef,
|
|
195
|
+
"data-slot": "scroll-navigator-index",
|
|
196
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "relative flex min-h-0 min-w-0 gap-1 overscroll-contain p-0.5 scrollbar-none", row ? "flex-1 overflow-x-auto" : "flex-col overflow-y-auto"),
|
|
197
|
+
onKeyDown: (event) => {
|
|
198
|
+
const current = items.findIndex((item) => controls.current.get(item.id) === document.activeElement);
|
|
199
|
+
let next = current;
|
|
200
|
+
if (event.key === "Home") next = 0;
|
|
201
|
+
else if (event.key === "End") next = items.length - 1;
|
|
202
|
+
else if (event.key === (row ? "ArrowRight" : "ArrowDown")) next = Math.min(items.length - 1, current + 1);
|
|
203
|
+
else if (event.key === (row ? "ArrowLeft" : "ArrowUp")) next = Math.max(0, current - 1);
|
|
204
|
+
else return;
|
|
205
|
+
event.preventDefault();
|
|
206
|
+
const button = controls.current.get(items[next].id);
|
|
207
|
+
_optionalChain([button, 'optionalAccess', _41 => _41.focus, 'call', _42 => _42({ preventScroll: true })]);
|
|
208
|
+
const index = indexRef.current;
|
|
209
|
+
if (index && button) {
|
|
210
|
+
if (row) index.scrollLeft = button.offsetLeft - (index.clientWidth - button.offsetWidth) / 2;
|
|
211
|
+
else index.scrollTop = button.offsetTop - (index.clientHeight - button.offsetHeight) / 2;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
children: items.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
215
|
+
"button",
|
|
216
|
+
{
|
|
217
|
+
type: "button",
|
|
218
|
+
ref: (element) => {
|
|
219
|
+
if (element) controls.current.set(item.id, element);
|
|
220
|
+
else controls.current.delete(item.id);
|
|
221
|
+
},
|
|
222
|
+
"aria-label": `${item.label}, ${index + 1} / ${items.length}`,
|
|
223
|
+
title: item.label,
|
|
224
|
+
"aria-controls": `${id}-${index}`,
|
|
225
|
+
"aria-current": item.id === activeId ? "location" : void 0,
|
|
226
|
+
tabIndex: item.id === tabId ? 0 : -1,
|
|
227
|
+
onFocus: () => setFocusId(item.id),
|
|
228
|
+
onClick: () => navigate(item),
|
|
229
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex size-11 shrink-0 items-center justify-center rounded-full border-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", item.id === activeId ? "border-primary bg-primary/10" : "border-transparent opacity-60 hover:bg-muted hover:opacity-100 focus-visible:opacity-100"),
|
|
230
|
+
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkWABCLRBRcjs.Avatar, { size: "xs", "aria-hidden": "true", children: [
|
|
231
|
+
item.imageSrc ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkWABCLRBRcjs.AvatarImage, { src: item.imageSrc, alt: "" }) : null,
|
|
232
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkWABCLRBRcjs.AvatarFallback, { textSize: "micro", children: _nullishCoalesce(item.fallback, () => ( item.label.trim().split(/\s+/).map((word) => word[0]).slice(0, 2).join(""))) })
|
|
233
|
+
] })
|
|
234
|
+
},
|
|
235
|
+
item.id
|
|
236
|
+
))
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "aria-hidden": "true", className: _chunkKWLSBTB2cjs.cn.call(void 0, "shrink-0 text-center text-[10px] tabular-nums text-muted-foreground", row ? "px-2" : "pb-1"), children: [
|
|
240
|
+
placement.active + 1,
|
|
241
|
+
" / ",
|
|
242
|
+
items.length
|
|
243
|
+
] })
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
document.body
|
|
248
|
+
)
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
exports.ScrollNavigator = ScrollNavigator;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-G6SRSWXB.js";
|
|
5
|
+
|
|
6
|
+
// src/primitives/panel-section.tsx
|
|
7
|
+
import { forwardRef } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
var borders = {
|
|
10
|
+
none: "",
|
|
11
|
+
top: "border-t",
|
|
12
|
+
bottom: "border-b"
|
|
13
|
+
};
|
|
14
|
+
var paddings = {
|
|
15
|
+
none: "",
|
|
16
|
+
compact: "px-[22px] py-[18px]",
|
|
17
|
+
default: "px-[26px] py-[26px]"
|
|
18
|
+
};
|
|
19
|
+
var PanelSection = forwardRef(
|
|
20
|
+
function PanelSection2({ as, border = "none", padding = "default", paddingX = "none", paddingTop = "none", paddingBottom = "none", paddingY = "none", surface = "default", layout = "block", gap = "none", shrink = true, className, ...props }, ref) {
|
|
21
|
+
const Component = as ?? "section";
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
Component,
|
|
24
|
+
{
|
|
25
|
+
ref,
|
|
26
|
+
className: cn(
|
|
27
|
+
borders[border],
|
|
28
|
+
paddings[padding],
|
|
29
|
+
paddingX === "md" && "px-[22px]",
|
|
30
|
+
paddingX === "lg" && "px-[26px]",
|
|
31
|
+
paddingTop === "sm" && "pt-2",
|
|
32
|
+
paddingTop === "md" && "pt-3",
|
|
33
|
+
paddingTop === "lg" && "pt-5",
|
|
34
|
+
paddingBottom === "xs" && "pb-1",
|
|
35
|
+
paddingBottom === "sm" && "pb-2",
|
|
36
|
+
paddingBottom === "md" && "pb-3",
|
|
37
|
+
paddingBottom === "lg" && "pb-4",
|
|
38
|
+
paddingY === "xl" && "py-12",
|
|
39
|
+
surface === "muted" && "bg-muted/40",
|
|
40
|
+
layout === "row" && "flex",
|
|
41
|
+
gap === "sm" && "gap-2",
|
|
42
|
+
!shrink && "shrink-0",
|
|
43
|
+
className
|
|
44
|
+
),
|
|
45
|
+
...props
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
PanelSection
|
|
53
|
+
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client";
|
|
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; }"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunk34AS3OCCcjs = require('./chunk-34AS3OCC.cjs');
|
|
2
5
|
|
|
3
6
|
|
|
4
7
|
var _chunkJDEXZGIYcjs = require('./chunk-JDEXZGIY.cjs');
|
|
@@ -18,6 +21,21 @@ var _jsxruntime = require('react/jsx-runtime');
|
|
|
18
21
|
function MessageScrollerProvider(props) {
|
|
19
22
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _messagescroller.MessageScroller.Provider, { ...props });
|
|
20
23
|
}
|
|
24
|
+
function MessageScrollerNavigator(props) {
|
|
25
|
+
const { scrollToMessage } = _messagescroller.useMessageScroller.call(void 0, );
|
|
26
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk34AS3OCCcjs.ScrollNavigator, { ...props, onNavigate: (id, target, options) => {
|
|
27
|
+
if (_optionalChain([props, 'access', _ => _.onNavigate, 'optionalCall', _2 => _2(id, target, options)]) === true) return true;
|
|
28
|
+
const message = target.closest("[data-message-id]");
|
|
29
|
+
const messageId = _optionalChain([message, 'optionalAccess', _3 => _3.dataset, 'access', _4 => _4.messageId]);
|
|
30
|
+
if (!messageId || !_optionalChain([message, 'optionalAccess', _5 => _5.parentElement])) return false;
|
|
31
|
+
const padding = Number.parseFloat(getComputedStyle(message.parentElement).paddingTop) || 0;
|
|
32
|
+
return scrollToMessage(messageId, {
|
|
33
|
+
align: "start",
|
|
34
|
+
behavior: options.behavior,
|
|
35
|
+
scrollMargin: message.getBoundingClientRect().top - target.getBoundingClientRect().top + options.offset - padding
|
|
36
|
+
});
|
|
37
|
+
} });
|
|
38
|
+
}
|
|
21
39
|
function MessageScroller({
|
|
22
40
|
className,
|
|
23
41
|
...props
|
|
@@ -129,4 +147,5 @@ function MessageScrollerButton({
|
|
|
129
147
|
|
|
130
148
|
|
|
131
149
|
|
|
132
|
-
|
|
150
|
+
|
|
151
|
+
exports.useMessageScroller = _messagescroller.useMessageScroller; exports.useMessageScrollerScrollable = _messagescroller.useMessageScrollerScrollable; exports.useMessageScrollerVisibility = _messagescroller.useMessageScrollerVisibility; exports.MessageScrollerProvider = MessageScrollerProvider; exports.MessageScrollerNavigator = MessageScrollerNavigator; exports.MessageScroller = MessageScroller; exports.MessageScrollerViewport = MessageScrollerViewport; exports.MessageScrollerContent = MessageScrollerContent; exports.MessageScrollerItem = MessageScrollerItem; exports.MessageScrollerButton = MessageScrollerButton;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkVGTINL5Qcjs = require('./chunk-VGTINL5Q.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
|
|
8
|
+
|
|
9
|
+
// src/primitives/section-header.tsx
|
|
10
|
+
var _react = require('react');
|
|
11
|
+
var _classvarianceauthority = require('class-variance-authority');
|
|
12
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
13
|
+
var sectionHeaderVariants = _classvarianceauthority.cva.call(void 0, "flex items-center gap-1", {
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
muted: "text-xs font-semibold text-muted-foreground uppercase tracking-wide",
|
|
17
|
+
plain: "text-sm font-medium text-foreground"
|
|
18
|
+
},
|
|
19
|
+
spacing: {
|
|
20
|
+
tight: "mb-2",
|
|
21
|
+
loose: "mb-3",
|
|
22
|
+
none: ""
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "muted",
|
|
27
|
+
spacing: "tight"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
var SectionHeader = _react.forwardRef.call(void 0,
|
|
31
|
+
function SectionHeader2({ icon, label, count, action, variant, spacing, className, ...rest }, ref) {
|
|
32
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
33
|
+
"h3",
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, sectionHeaderVariants({ variant, spacing }), className),
|
|
37
|
+
...rest,
|
|
38
|
+
children: [
|
|
39
|
+
icon,
|
|
40
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: label }),
|
|
41
|
+
typeof count === "number" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVGTINL5Qcjs.CountBadge, { value: count, variant: "secondary" }),
|
|
42
|
+
action && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "ml-auto", children: action })
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
exports.SectionHeader = SectionHeader;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
CountBadge
|
|
4
|
+
} from "./chunk-H7TETFLB.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-G6SRSWXB.js";
|
|
8
|
+
|
|
9
|
+
// src/primitives/section-header.tsx
|
|
10
|
+
import { forwardRef } from "react";
|
|
11
|
+
import { cva } from "class-variance-authority";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var sectionHeaderVariants = cva("flex items-center gap-1", {
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
muted: "text-xs font-semibold text-muted-foreground uppercase tracking-wide",
|
|
17
|
+
plain: "text-sm font-medium text-foreground"
|
|
18
|
+
},
|
|
19
|
+
spacing: {
|
|
20
|
+
tight: "mb-2",
|
|
21
|
+
loose: "mb-3",
|
|
22
|
+
none: ""
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "muted",
|
|
27
|
+
spacing: "tight"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
var SectionHeader = forwardRef(
|
|
31
|
+
function SectionHeader2({ icon, label, count, action, variant, spacing, className, ...rest }, ref) {
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"h3",
|
|
34
|
+
{
|
|
35
|
+
ref,
|
|
36
|
+
className: cn(sectionHeaderVariants({ variant, spacing }), className),
|
|
37
|
+
...rest,
|
|
38
|
+
children: [
|
|
39
|
+
icon,
|
|
40
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
41
|
+
typeof count === "number" && /* @__PURE__ */ jsx(CountBadge, { value: count, variant: "secondary" }),
|
|
42
|
+
action && /* @__PURE__ */ jsx("span", { className: "ml-auto", children: action })
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
SectionHeader
|
|
51
|
+
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import {
|
|
3
|
+
ScrollNavigator
|
|
4
|
+
} from "./chunk-VT2WDFSU.js";
|
|
2
5
|
import {
|
|
3
6
|
Button
|
|
4
7
|
} from "./chunk-W326GKML.js";
|
|
@@ -18,6 +21,21 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
18
21
|
function MessageScrollerProvider(props) {
|
|
19
22
|
return /* @__PURE__ */ jsx(MessageScrollerPrimitive.Provider, { ...props });
|
|
20
23
|
}
|
|
24
|
+
function MessageScrollerNavigator(props) {
|
|
25
|
+
const { scrollToMessage } = useMessageScroller();
|
|
26
|
+
return /* @__PURE__ */ jsx(ScrollNavigator, { ...props, onNavigate: (id, target, options) => {
|
|
27
|
+
if (props.onNavigate?.(id, target, options) === true) return true;
|
|
28
|
+
const message = target.closest("[data-message-id]");
|
|
29
|
+
const messageId = message?.dataset.messageId;
|
|
30
|
+
if (!messageId || !message?.parentElement) return false;
|
|
31
|
+
const padding = Number.parseFloat(getComputedStyle(message.parentElement).paddingTop) || 0;
|
|
32
|
+
return scrollToMessage(messageId, {
|
|
33
|
+
align: "start",
|
|
34
|
+
behavior: options.behavior,
|
|
35
|
+
scrollMargin: message.getBoundingClientRect().top - target.getBoundingClientRect().top + options.offset - padding
|
|
36
|
+
});
|
|
37
|
+
} });
|
|
38
|
+
}
|
|
21
39
|
function MessageScroller({
|
|
22
40
|
className,
|
|
23
41
|
...props
|
|
@@ -124,6 +142,7 @@ export {
|
|
|
124
142
|
useMessageScrollerScrollable,
|
|
125
143
|
useMessageScrollerVisibility,
|
|
126
144
|
MessageScrollerProvider,
|
|
145
|
+
MessageScrollerNavigator,
|
|
127
146
|
MessageScroller,
|
|
128
147
|
MessageScrollerViewport,
|
|
129
148
|
MessageScrollerContent,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
|
|
5
|
+
|
|
6
|
+
// src/primitives/panel-section.tsx
|
|
7
|
+
var _react = require('react');
|
|
8
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
9
|
+
var borders = {
|
|
10
|
+
none: "",
|
|
11
|
+
top: "border-t",
|
|
12
|
+
bottom: "border-b"
|
|
13
|
+
};
|
|
14
|
+
var paddings = {
|
|
15
|
+
none: "",
|
|
16
|
+
compact: "px-[22px] py-[18px]",
|
|
17
|
+
default: "px-[26px] py-[26px]"
|
|
18
|
+
};
|
|
19
|
+
var PanelSection = _react.forwardRef.call(void 0,
|
|
20
|
+
function PanelSection2({ as, border = "none", padding = "default", paddingX = "none", paddingTop = "none", paddingBottom = "none", paddingY = "none", surface = "default", layout = "block", gap = "none", shrink = true, className, ...props }, ref) {
|
|
21
|
+
const Component = _nullishCoalesce(as, () => ( "section"));
|
|
22
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
23
|
+
Component,
|
|
24
|
+
{
|
|
25
|
+
ref,
|
|
26
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
27
|
+
borders[border],
|
|
28
|
+
paddings[padding],
|
|
29
|
+
paddingX === "md" && "px-[22px]",
|
|
30
|
+
paddingX === "lg" && "px-[26px]",
|
|
31
|
+
paddingTop === "sm" && "pt-2",
|
|
32
|
+
paddingTop === "md" && "pt-3",
|
|
33
|
+
paddingTop === "lg" && "pt-5",
|
|
34
|
+
paddingBottom === "xs" && "pb-1",
|
|
35
|
+
paddingBottom === "sm" && "pb-2",
|
|
36
|
+
paddingBottom === "md" && "pb-3",
|
|
37
|
+
paddingBottom === "lg" && "pb-4",
|
|
38
|
+
paddingY === "xl" && "py-12",
|
|
39
|
+
surface === "muted" && "bg-muted/40",
|
|
40
|
+
layout === "row" && "flex",
|
|
41
|
+
gap === "sm" && "gap-2",
|
|
42
|
+
!shrink && "shrink-0",
|
|
43
|
+
className
|
|
44
|
+
),
|
|
45
|
+
...props
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
exports.PanelSection = PanelSection;
|