ajo-ui 0.1.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/LICENSE +15 -0
- package/README.md +126 -0
- package/dist/accordion.js +130 -0
- package/dist/avatar.js +54 -0
- package/dist/calendar.js +2 -0
- package/dist/carousel.js +239 -0
- package/dist/chart.js +790 -0
- package/dist/checkbox-group.js +70 -0
- package/dist/checkbox.js +77 -0
- package/dist/chunks/bar-CVafh6C1.js +99 -0
- package/dist/chunks/calendar-q8jZ8Cxr.js +1923 -0
- package/dist/chunks/collection-DtRB63U4.js +111 -0
- package/dist/chunks/data-table-DpkWv4y4.js +1039 -0
- package/dist/chunks/menu-B45IyHHC.js +704 -0
- package/dist/chunks/native-BJdhd9XJ.js +20 -0
- package/dist/chunks/popup-C8Bb3l_g.js +459 -0
- package/dist/chunks/popup-surface-BDCgtVU0.js +18 -0
- package/dist/chunks/position-D6_i_SRn.js +434 -0
- package/dist/chunks/virtual-list-B7hjGkjk.js +413 -0
- package/dist/collapsible.js +106 -0
- package/dist/command.js +263 -0
- package/dist/context-menu.js +112 -0
- package/dist/data-table.js +5 -0
- package/dist/dialog.js +207 -0
- package/dist/direction.js +22 -0
- package/dist/drawer.js +139 -0
- package/dist/field.js +26 -0
- package/dist/index.js +38 -0
- package/dist/input-date.js +994 -0
- package/dist/input-group.js +52 -0
- package/dist/input-otp.js +179 -0
- package/dist/menu.js +2 -0
- package/dist/menubar.js +236 -0
- package/dist/message-scroller.js +446 -0
- package/dist/navigation-menu.js +330 -0
- package/dist/popover.js +307 -0
- package/dist/progress.js +39 -0
- package/dist/radio-group.js +107 -0
- package/dist/resizable.js +172 -0
- package/dist/select.js +961 -0
- package/dist/sidebar.js +343 -0
- package/dist/slider.js +259 -0
- package/dist/switch.js +53 -0
- package/dist/tabs.js +182 -0
- package/dist/toast.js +492 -0
- package/dist/toggle-group.js +111 -0
- package/dist/toggle.js +52 -0
- package/dist/toolbar.js +127 -0
- package/dist/tooltip.js +196 -0
- package/dist/utils.js +104 -0
- package/dist/virtual-list.js +2 -0
- package/package.json +250 -0
- package/src/accordion.tsx +261 -0
- package/src/availability.ts +261 -0
- package/src/avatar.tsx +99 -0
- package/src/bar.ts +156 -0
- package/src/calendar.tsx +1441 -0
- package/src/carousel.tsx +424 -0
- package/src/chart.tsx +1194 -0
- package/src/checkbox-group.tsx +132 -0
- package/src/checkbox.tsx +130 -0
- package/src/collapsible.tsx +188 -0
- package/src/collection.ts +154 -0
- package/src/command.tsx +511 -0
- package/src/context-menu.tsx +233 -0
- package/src/data-table-contract.ts +143 -0
- package/src/data-table-model.ts +760 -0
- package/src/data-table.tsx +475 -0
- package/src/dialog.tsx +393 -0
- package/src/direction.tsx +45 -0
- package/src/drawer.tsx +251 -0
- package/src/field.tsx +61 -0
- package/src/index.ts +37 -0
- package/src/input-date.tsx +1539 -0
- package/src/input-group.tsx +142 -0
- package/src/input-otp.tsx +324 -0
- package/src/menu-cluster.ts +124 -0
- package/src/menu.tsx +1095 -0
- package/src/menubar.tsx +459 -0
- package/src/message-scroller.tsx +732 -0
- package/src/native.ts +26 -0
- package/src/navigation-menu.tsx +578 -0
- package/src/popover.tsx +519 -0
- package/src/popup-surface.tsx +31 -0
- package/src/popup.ts +569 -0
- package/src/position.ts +523 -0
- package/src/progress.tsx +70 -0
- package/src/radio-group.tsx +186 -0
- package/src/resizable.tsx +310 -0
- package/src/segments.ts +922 -0
- package/src/select.tsx +1501 -0
- package/src/sidebar.tsx +683 -0
- package/src/slider.tsx +424 -0
- package/src/switch.tsx +104 -0
- package/src/tabs.tsx +314 -0
- package/src/toast.tsx +923 -0
- package/src/toggle-group.tsx +249 -0
- package/src/toggle.tsx +91 -0
- package/src/toolbar.tsx +212 -0
- package/src/tooltip.tsx +359 -0
- package/src/utils.ts +204 -0
- package/src/virtual-list.tsx +205 -0
- package/src/virtual.ts +385 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { browser, callHandler, callRef, frame, overflow, resize, scrolling, timer } from "ajo-cloves";
|
|
2
|
+
import { context } from "ajo/context";
|
|
3
|
+
import { Fragment, jsx } from "ajo/jsx-runtime";
|
|
4
|
+
//#region packages/ajo-ui/src/message-scroller.tsx
|
|
5
|
+
/** Read the public controller inherited from the nearest MessageScrollerProvider. */
|
|
6
|
+
var MessageScrollerContext = context(null);
|
|
7
|
+
var MessageScrollerPartsContext = context(null);
|
|
8
|
+
var edge = 2;
|
|
9
|
+
var messageScroller = () => {
|
|
10
|
+
const api = MessageScrollerContext();
|
|
11
|
+
if (!api) throw new Error("MessageScroller controls must be used within a <MessageScrollerProvider />");
|
|
12
|
+
return api;
|
|
13
|
+
};
|
|
14
|
+
var messageScrollerParts = () => {
|
|
15
|
+
const parts = MessageScrollerPartsContext();
|
|
16
|
+
if (!parts) throw new Error("MessageScroller parts must be used within a <MessageScrollerProvider />");
|
|
17
|
+
return parts;
|
|
18
|
+
};
|
|
19
|
+
var getItems = (content) => content ? Array.from(content.querySelectorAll("[data-slot=\"message-scroller-item\"]")) : [];
|
|
20
|
+
var rectTop = (viewport, element) => element.getBoundingClientRect().top - viewport.getBoundingClientRect().top;
|
|
21
|
+
var stamp = (element, name, value) => {
|
|
22
|
+
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
23
|
+
};
|
|
24
|
+
/** Unstyled provider for imperative scroll behavior and visibility state. */
|
|
25
|
+
var MessageScrollerProvider = function* ({ autoScroll = true, defaultScrollPosition = "end", preserveScrollOnPrepend = true, scrollPreviousItemPeek = 0 }) {
|
|
26
|
+
let root = null;
|
|
27
|
+
let viewport = null;
|
|
28
|
+
let content = null;
|
|
29
|
+
let mutation;
|
|
30
|
+
let initialized = false;
|
|
31
|
+
let didInitialScroll = false;
|
|
32
|
+
let following = defaultScrollPosition !== "start";
|
|
33
|
+
let currentAutoScroll = autoScroll;
|
|
34
|
+
let currentDefaultPosition = defaultScrollPosition;
|
|
35
|
+
let currentPreserve = preserveScrollOnPrepend;
|
|
36
|
+
let currentPeek = scrollPreviousItemPeek;
|
|
37
|
+
let currentSetApi;
|
|
38
|
+
let pending = null;
|
|
39
|
+
let preserveAnchor = null;
|
|
40
|
+
let settles = 0;
|
|
41
|
+
const items = /* @__PURE__ */ new Map();
|
|
42
|
+
const buttons = {
|
|
43
|
+
end: null,
|
|
44
|
+
start: null
|
|
45
|
+
};
|
|
46
|
+
const scrollable = {
|
|
47
|
+
end: false,
|
|
48
|
+
start: false
|
|
49
|
+
};
|
|
50
|
+
const visibility = { visibleMessageIds: [] };
|
|
51
|
+
const autoscroll = timer(this);
|
|
52
|
+
const setAutoscrolling = (active) => {
|
|
53
|
+
if (!viewport || !root) return;
|
|
54
|
+
root.toggleAttribute("data-autoscrolling", active);
|
|
55
|
+
viewport.toggleAttribute("data-autoscrolling", active);
|
|
56
|
+
if (!active) {
|
|
57
|
+
autoscroll.stop();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
autoscroll.start(1200, () => {
|
|
61
|
+
root?.toggleAttribute("data-autoscrolling", false);
|
|
62
|
+
viewport?.toggleAttribute("data-autoscrolling", false);
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const atStart = () => !viewport || viewport.scrollTop <= edge;
|
|
66
|
+
const atEnd = () => !viewport || viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <= edge;
|
|
67
|
+
const buttonActive = (direction) => direction === "start" ? scrollable.start : scrollable.end;
|
|
68
|
+
const updateButton = (direction) => {
|
|
69
|
+
const button = buttons[direction];
|
|
70
|
+
if (!button) return;
|
|
71
|
+
const active = buttonActive(direction);
|
|
72
|
+
const tabIndex = active ? 0 : -1;
|
|
73
|
+
stamp(button, "data-active", String(active));
|
|
74
|
+
if (button.tabIndex !== tabIndex) button.tabIndex = tabIndex;
|
|
75
|
+
if (button.hasAttribute("inert") === active) button.toggleAttribute("inert", !active);
|
|
76
|
+
};
|
|
77
|
+
const readEdges = () => {
|
|
78
|
+
const canStart = !atStart();
|
|
79
|
+
return {
|
|
80
|
+
canEnd: !atEnd(),
|
|
81
|
+
canStart
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
const commitEdges = ({ canEnd, canStart }) => {
|
|
85
|
+
scrollable.start = canStart;
|
|
86
|
+
scrollable.end = canEnd;
|
|
87
|
+
updateButton("start");
|
|
88
|
+
updateButton("end");
|
|
89
|
+
};
|
|
90
|
+
const updateData = () => commitEdges(readEdges());
|
|
91
|
+
const findItem = (messageId) => {
|
|
92
|
+
const registered = items.get(messageId);
|
|
93
|
+
if (registered) return registered;
|
|
94
|
+
return getItems(content).find((item) => item.dataset.messageId === messageId);
|
|
95
|
+
};
|
|
96
|
+
const readItems = () => {
|
|
97
|
+
if (!viewport || !content) return {
|
|
98
|
+
currentAnchorId: void 0,
|
|
99
|
+
preserveAnchor: null,
|
|
100
|
+
visibleMessageIds: []
|
|
101
|
+
};
|
|
102
|
+
const viewportRect = viewport.getBoundingClientRect();
|
|
103
|
+
const visible = [];
|
|
104
|
+
let anchor;
|
|
105
|
+
let preserved = null;
|
|
106
|
+
for (const item of getItems(content)) {
|
|
107
|
+
const rect = item.getBoundingClientRect();
|
|
108
|
+
const id = item.dataset.messageId;
|
|
109
|
+
const intersects = rect.bottom > viewportRect.top && rect.top < viewportRect.bottom;
|
|
110
|
+
if (intersects && id) visible.push(id);
|
|
111
|
+
if (currentPreserve && !preserveAnchor && !preserved && intersects && id) preserved = {
|
|
112
|
+
id,
|
|
113
|
+
top: rect.top - viewportRect.top
|
|
114
|
+
};
|
|
115
|
+
if (id && item.dataset.scrollAnchor === "true" && rect.top <= viewportRect.top + viewport.clientHeight * .65) anchor = id;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
currentAnchorId: anchor,
|
|
119
|
+
preserveAnchor: preserved,
|
|
120
|
+
visibleMessageIds: visible
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
const commitItems = (reading) => {
|
|
124
|
+
visibility.currentAnchorId = reading.currentAnchorId;
|
|
125
|
+
visibility.visibleMessageIds = reading.visibleMessageIds;
|
|
126
|
+
if (!currentPreserve) preserveAnchor = null;
|
|
127
|
+
else preserveAnchor ??= reading.preserveAnchor;
|
|
128
|
+
};
|
|
129
|
+
const sync = () => {
|
|
130
|
+
const edges = readEdges();
|
|
131
|
+
commitItems(readItems());
|
|
132
|
+
commitEdges(edges);
|
|
133
|
+
};
|
|
134
|
+
const schedule = frame(sync);
|
|
135
|
+
const handleViewportScroll = (element) => {
|
|
136
|
+
if (!element.hasAttribute("data-autoscrolling")) following = atEnd();
|
|
137
|
+
preserveAnchor = null;
|
|
138
|
+
sync();
|
|
139
|
+
};
|
|
140
|
+
const handleViewportEnd = (element) => {
|
|
141
|
+
if (following && !atEnd() && settles < 10) {
|
|
142
|
+
settles += 1;
|
|
143
|
+
setAutoscrolling(true);
|
|
144
|
+
element.scrollTo({
|
|
145
|
+
behavior: "auto",
|
|
146
|
+
top: element.scrollHeight
|
|
147
|
+
});
|
|
148
|
+
} else setAutoscrolling(false);
|
|
149
|
+
schedule();
|
|
150
|
+
};
|
|
151
|
+
const viewportScroll = scrolling(this, {
|
|
152
|
+
target: () => viewport,
|
|
153
|
+
onScroll: handleViewportScroll,
|
|
154
|
+
onEnd: handleViewportEnd
|
|
155
|
+
});
|
|
156
|
+
const viewportSize = resize(this, {
|
|
157
|
+
target: () => viewport,
|
|
158
|
+
onResize: sync
|
|
159
|
+
});
|
|
160
|
+
const edges = overflow(this, { target: () => viewport });
|
|
161
|
+
const scrollTopFor = (element, options = {}) => {
|
|
162
|
+
if (!viewport) return 0;
|
|
163
|
+
const peek = options.peek ?? currentPeek;
|
|
164
|
+
const top = rectTop(viewport, element) + viewport.scrollTop;
|
|
165
|
+
if (options.position === "center") return top - (viewport.clientHeight - element.offsetHeight) / 2;
|
|
166
|
+
if (options.position === "end") return top - viewport.clientHeight + element.offsetHeight + peek;
|
|
167
|
+
return top - peek;
|
|
168
|
+
};
|
|
169
|
+
const scrollToTop = (top, behavior = "smooth") => {
|
|
170
|
+
if (!viewport) return false;
|
|
171
|
+
preserveAnchor = null;
|
|
172
|
+
settles = 0;
|
|
173
|
+
setAutoscrolling(true);
|
|
174
|
+
viewport.scrollTo({
|
|
175
|
+
behavior,
|
|
176
|
+
top: Math.max(0, top)
|
|
177
|
+
});
|
|
178
|
+
schedule();
|
|
179
|
+
return true;
|
|
180
|
+
};
|
|
181
|
+
const scrollToStart = (options = {}) => {
|
|
182
|
+
following = false;
|
|
183
|
+
return scrollToTop(0, options.behavior);
|
|
184
|
+
};
|
|
185
|
+
const scrollToEnd = (options = {}) => {
|
|
186
|
+
if (!viewport) return false;
|
|
187
|
+
following = true;
|
|
188
|
+
return scrollToTop(viewport.scrollHeight, options.behavior);
|
|
189
|
+
};
|
|
190
|
+
const scrollToMessage = (messageId, options = {}) => {
|
|
191
|
+
const item = findItem(messageId);
|
|
192
|
+
if (!item) {
|
|
193
|
+
if (!initialized) {
|
|
194
|
+
pending = {
|
|
195
|
+
id: messageId,
|
|
196
|
+
options
|
|
197
|
+
};
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
following = false;
|
|
203
|
+
return scrollToTop(scrollTopFor(item, options), options.behavior);
|
|
204
|
+
};
|
|
205
|
+
const flushPending = () => {
|
|
206
|
+
if (!pending) return;
|
|
207
|
+
const target = pending;
|
|
208
|
+
pending = null;
|
|
209
|
+
if (!scrollToMessage(target.id, {
|
|
210
|
+
behavior: "auto",
|
|
211
|
+
...target.options
|
|
212
|
+
})) pending = target;
|
|
213
|
+
};
|
|
214
|
+
const restoreAnchor = () => {
|
|
215
|
+
if (!viewport || !preserveAnchor || following || !currentPreserve) return;
|
|
216
|
+
const item = findItem(preserveAnchor.id);
|
|
217
|
+
if (!item) {
|
|
218
|
+
preserveAnchor = null;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const nextTop = rectTop(viewport, item);
|
|
222
|
+
viewport.scrollTop += nextTop - preserveAnchor.top;
|
|
223
|
+
};
|
|
224
|
+
const handleContentChange = () => {
|
|
225
|
+
queueMicrotask(() => {
|
|
226
|
+
restoreAnchor();
|
|
227
|
+
if (currentAutoScroll && following) scrollToEnd({ behavior: "auto" });
|
|
228
|
+
flushPending();
|
|
229
|
+
edges.sync();
|
|
230
|
+
schedule();
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
const contentSize = resize(this, {
|
|
234
|
+
target: () => content,
|
|
235
|
+
onResize: handleContentChange
|
|
236
|
+
});
|
|
237
|
+
const applyInitialScroll = () => {
|
|
238
|
+
if (didInitialScroll || !viewport) return;
|
|
239
|
+
didInitialScroll = true;
|
|
240
|
+
initialized = true;
|
|
241
|
+
if (pending) flushPending();
|
|
242
|
+
else if (currentDefaultPosition === "start") scrollToStart({ behavior: "auto" });
|
|
243
|
+
else if (currentDefaultPosition === "last-anchor") {
|
|
244
|
+
const anchor = getItems(content).filter((item) => item.dataset.scrollAnchor === "true" && item.dataset.messageId).at(-1);
|
|
245
|
+
if (anchor?.dataset.messageId) scrollToMessage(anchor.dataset.messageId, {
|
|
246
|
+
behavior: "auto",
|
|
247
|
+
peek: currentPeek
|
|
248
|
+
});
|
|
249
|
+
else scrollToEnd({ behavior: "auto" });
|
|
250
|
+
} else scrollToEnd({ behavior: "auto" });
|
|
251
|
+
sync();
|
|
252
|
+
};
|
|
253
|
+
const scheduleInitial = frame(applyInitialScroll);
|
|
254
|
+
const scheduleInitialScroll = () => {
|
|
255
|
+
if (!browser() || didInitialScroll) return;
|
|
256
|
+
scheduleInitial();
|
|
257
|
+
};
|
|
258
|
+
const setRoot = (element) => {
|
|
259
|
+
root = element;
|
|
260
|
+
updateData();
|
|
261
|
+
};
|
|
262
|
+
const setViewport = (element) => {
|
|
263
|
+
if (viewport === element) return;
|
|
264
|
+
viewport = element;
|
|
265
|
+
viewportScroll.sync();
|
|
266
|
+
viewportSize.sync();
|
|
267
|
+
edges.sync();
|
|
268
|
+
if (!element) {
|
|
269
|
+
updateData();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
updateData();
|
|
273
|
+
scheduleInitialScroll();
|
|
274
|
+
};
|
|
275
|
+
const setContent = (element) => {
|
|
276
|
+
if (content === element) return;
|
|
277
|
+
mutation?.disconnect();
|
|
278
|
+
content = element;
|
|
279
|
+
contentSize.sync();
|
|
280
|
+
edges.sync();
|
|
281
|
+
if (!element) {
|
|
282
|
+
updateData();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (typeof MutationObserver !== "undefined") {
|
|
286
|
+
mutation = new MutationObserver(handleContentChange);
|
|
287
|
+
mutation.observe(element, {
|
|
288
|
+
childList: true,
|
|
289
|
+
subtree: true
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
updateData();
|
|
293
|
+
scheduleInitialScroll();
|
|
294
|
+
};
|
|
295
|
+
const setItem = (messageId, element) => {
|
|
296
|
+
if (element) {
|
|
297
|
+
for (const [registeredId, registered] of items) if (registered === element && registeredId !== messageId) items.delete(registeredId);
|
|
298
|
+
if (messageId) {
|
|
299
|
+
items.set(messageId, element);
|
|
300
|
+
flushPending();
|
|
301
|
+
}
|
|
302
|
+
} else if (messageId) items.delete(messageId);
|
|
303
|
+
schedule();
|
|
304
|
+
};
|
|
305
|
+
const setButton = (direction, element) => {
|
|
306
|
+
if (element) {
|
|
307
|
+
for (const registeredDirection of ["start", "end"]) if (registeredDirection !== direction && buttons[registeredDirection] === element) buttons[registeredDirection] = null;
|
|
308
|
+
}
|
|
309
|
+
buttons[direction] = element;
|
|
310
|
+
updateButton("start");
|
|
311
|
+
updateButton("end");
|
|
312
|
+
};
|
|
313
|
+
const publicApi = {
|
|
314
|
+
scrollToEnd,
|
|
315
|
+
scrollToMessage,
|
|
316
|
+
scrollToStart,
|
|
317
|
+
scrollable,
|
|
318
|
+
visibility
|
|
319
|
+
};
|
|
320
|
+
const parts = {
|
|
321
|
+
setButton,
|
|
322
|
+
setContent,
|
|
323
|
+
setItem,
|
|
324
|
+
setRoot,
|
|
325
|
+
setViewport
|
|
326
|
+
};
|
|
327
|
+
this.signal.addEventListener("abort", () => {
|
|
328
|
+
schedule.cancel();
|
|
329
|
+
scheduleInitial.cancel();
|
|
330
|
+
mutation?.disconnect();
|
|
331
|
+
});
|
|
332
|
+
for (const { autoScroll = true, children, defaultScrollPosition = "end", preserveScrollOnPrepend = true, scrollPreviousItemPeek = 0, setApi } of this) {
|
|
333
|
+
const wasPreserving = currentPreserve;
|
|
334
|
+
currentAutoScroll = autoScroll;
|
|
335
|
+
currentDefaultPosition = defaultScrollPosition;
|
|
336
|
+
currentPreserve = preserveScrollOnPrepend;
|
|
337
|
+
if (!currentPreserve) preserveAnchor = null;
|
|
338
|
+
else if (!wasPreserving && !following) preserveAnchor = readItems().preserveAnchor;
|
|
339
|
+
currentPeek = scrollPreviousItemPeek;
|
|
340
|
+
if (setApi && setApi !== currentSetApi) {
|
|
341
|
+
currentSetApi = setApi;
|
|
342
|
+
setApi(publicApi);
|
|
343
|
+
}
|
|
344
|
+
viewportScroll.sync();
|
|
345
|
+
viewportSize.sync();
|
|
346
|
+
edges.sync();
|
|
347
|
+
contentSize.sync();
|
|
348
|
+
MessageScrollerContext(publicApi);
|
|
349
|
+
MessageScrollerPartsContext(parts);
|
|
350
|
+
queueMicrotask(scheduleInitialScroll);
|
|
351
|
+
yield /* @__PURE__ */ jsx(Fragment, { children });
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
MessageScrollerProvider.attrs = { "data-slot": "message-scroller-provider" };
|
|
355
|
+
/** Unstyled root container for a scroll-managed message transcript. */
|
|
356
|
+
var MessageScroller = ({ children, ref, ...attrs }) => {
|
|
357
|
+
const parts = messageScrollerParts();
|
|
358
|
+
return /* @__PURE__ */ jsx("div", {
|
|
359
|
+
...attrs,
|
|
360
|
+
"data-slot": "message-scroller",
|
|
361
|
+
ref: (element) => {
|
|
362
|
+
parts.setRoot(element);
|
|
363
|
+
callRef(ref, element);
|
|
364
|
+
},
|
|
365
|
+
children
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
/** Unstyled keyboard-focusable transcript viewport. */
|
|
369
|
+
var MessageScrollerViewport = ({ children, role = "region", tabIndex = 0, "aria-label": label = "Messages", ref, ...attrs }) => {
|
|
370
|
+
const parts = messageScrollerParts();
|
|
371
|
+
return /* @__PURE__ */ jsx("div", {
|
|
372
|
+
...attrs,
|
|
373
|
+
"aria-label": label,
|
|
374
|
+
"data-slot": "message-scroller-viewport",
|
|
375
|
+
ref: (element) => {
|
|
376
|
+
parts.setViewport(element);
|
|
377
|
+
callRef(ref, element);
|
|
378
|
+
},
|
|
379
|
+
role,
|
|
380
|
+
tabIndex,
|
|
381
|
+
children
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
/** Unstyled live-region content list for rendered messages. */
|
|
385
|
+
var MessageScrollerContent = ({ children, role = "log", "aria-live": live = "polite", "aria-relevant": relevant = "additions", ref, ...attrs }) => {
|
|
386
|
+
const parts = messageScrollerParts();
|
|
387
|
+
return /* @__PURE__ */ jsx("div", {
|
|
388
|
+
...attrs,
|
|
389
|
+
"aria-live": live,
|
|
390
|
+
"aria-relevant": relevant,
|
|
391
|
+
"data-slot": "message-scroller-content",
|
|
392
|
+
ref: (element) => {
|
|
393
|
+
parts.setContent(element);
|
|
394
|
+
callRef(ref, element);
|
|
395
|
+
},
|
|
396
|
+
role,
|
|
397
|
+
children
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
/** Unstyled scroll-trackable transcript item. */
|
|
401
|
+
var MessageScrollerItem = ({ children, messageId, ref, scrollAnchor = false, ...attrs }) => {
|
|
402
|
+
const parts = messageScrollerParts();
|
|
403
|
+
return /* @__PURE__ */ jsx("div", {
|
|
404
|
+
...attrs,
|
|
405
|
+
"data-message-id": messageId,
|
|
406
|
+
"data-scroll-anchor": String(scrollAnchor),
|
|
407
|
+
"data-slot": "message-scroller-item",
|
|
408
|
+
ref: (element) => {
|
|
409
|
+
parts.setItem(messageId, element);
|
|
410
|
+
callRef(ref, element);
|
|
411
|
+
},
|
|
412
|
+
children
|
|
413
|
+
});
|
|
414
|
+
};
|
|
415
|
+
/** Unstyled floating button that jumps to the start or end of the transcript. */
|
|
416
|
+
var MessageScrollerButton = ({ "aria-label": label, children, direction = "end", disabled, ref, type = "button", "set:onclick": onClick, ...attrs }) => {
|
|
417
|
+
const scroller = messageScroller();
|
|
418
|
+
const parts = messageScrollerParts();
|
|
419
|
+
const buttonActive = (next) => next === "start" ? scroller.scrollable.start : scroller.scrollable.end;
|
|
420
|
+
const active = buttonActive(direction);
|
|
421
|
+
const title = label ?? (direction === "end" ? "Scroll to end" : "Scroll to start");
|
|
422
|
+
const click = (event) => {
|
|
423
|
+
callHandler(onClick, event);
|
|
424
|
+
if (event.defaultPrevented || disabled || !buttonActive(direction)) return;
|
|
425
|
+
if (direction === "start") scroller.scrollToStart();
|
|
426
|
+
else scroller.scrollToEnd();
|
|
427
|
+
};
|
|
428
|
+
return /* @__PURE__ */ jsx("button", {
|
|
429
|
+
...attrs,
|
|
430
|
+
"aria-label": title,
|
|
431
|
+
"data-active": active ? "true" : "false",
|
|
432
|
+
"data-direction": direction,
|
|
433
|
+
"data-slot": "message-scroller-button",
|
|
434
|
+
disabled,
|
|
435
|
+
ref: (element) => {
|
|
436
|
+
parts.setButton(direction, element);
|
|
437
|
+
callRef(ref, element);
|
|
438
|
+
},
|
|
439
|
+
"set:onclick": click,
|
|
440
|
+
tabIndex: active ? attrs.tabIndex : -1,
|
|
441
|
+
type,
|
|
442
|
+
children
|
|
443
|
+
});
|
|
444
|
+
};
|
|
445
|
+
//#endregion
|
|
446
|
+
export { MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerContext, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport };
|