@refraction-ui/react 0.9.2 → 0.10.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/dist/form.cjs +1 -0
- package/dist/form.js +1 -0
- package/dist/index.cjs +1807 -473
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2084 -766
- package/dist/index.js.map +1 -1
- package/dist/internal/conversation/index.d.cts +235 -0
- package/dist/internal/conversation/index.d.ts +235 -0
- package/dist/internal/cookie-consent/index.d.cts +77 -0
- package/dist/internal/cookie-consent/index.d.ts +77 -0
- package/dist/internal/react-conversation/index.d.cts +97 -0
- package/dist/internal/react-conversation/index.d.ts +97 -0
- package/dist/internal/react-cookie-consent/index.d.cts +46 -0
- package/dist/internal/react-cookie-consent/index.d.ts +46 -0
- package/dist/theme.cjs +1 -0
- package/dist/theme.js +1 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { cn, devWarn, cva, createKeyboardHandler, Keys, createMachine, generateId } from './chunk-VZLV27H2.js';
|
|
2
3
|
export { createFaroSink } from './chunk-XWP763SH.js';
|
|
3
4
|
import * as React11 from 'react';
|
|
@@ -2679,239 +2680,1861 @@ var CommandSeparator = React11.forwardRef(
|
|
|
2679
2680
|
);
|
|
2680
2681
|
CommandSeparator.displayName = "CommandSeparator";
|
|
2681
2682
|
|
|
2682
|
-
// ../
|
|
2683
|
-
function
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
const
|
|
2691
|
-
if (
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
const
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
}
|
|
2716
|
-
var
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
(
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
onSelect: api.eventHandlers.onSelectStart,
|
|
2746
|
-
...props,
|
|
2747
|
-
children: [
|
|
2748
|
-
children,
|
|
2749
|
-
api.watermarkConfig && /* @__PURE__ */ jsx(
|
|
2750
|
-
"div",
|
|
2751
|
-
{
|
|
2752
|
-
className: watermarkVariants(),
|
|
2753
|
-
"aria-hidden": "true",
|
|
2754
|
-
style: {
|
|
2755
|
-
opacity: api.watermarkConfig.opacity,
|
|
2756
|
-
transform: `rotate(${api.watermarkConfig.angle}deg)`,
|
|
2757
|
-
backgroundImage: `repeating-linear-gradient(
|
|
2758
|
-
${api.watermarkConfig.angle}deg,
|
|
2759
|
-
transparent,
|
|
2760
|
-
transparent 80px,
|
|
2761
|
-
currentColor 80px,
|
|
2762
|
-
currentColor 80px
|
|
2763
|
-
)`
|
|
2764
|
-
},
|
|
2765
|
-
children: /* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", children: [
|
|
2766
|
-
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
|
|
2767
|
-
"pattern",
|
|
2768
|
-
{
|
|
2769
|
-
id: "rfr-watermark",
|
|
2770
|
-
x: "0",
|
|
2771
|
-
y: "0",
|
|
2772
|
-
width: "200",
|
|
2773
|
-
height: "200",
|
|
2774
|
-
patternUnits: "userSpaceOnUse",
|
|
2775
|
-
patternTransform: `rotate(${api.watermarkConfig.angle})`,
|
|
2776
|
-
children: /* @__PURE__ */ jsx(
|
|
2777
|
-
"text",
|
|
2778
|
-
{
|
|
2779
|
-
x: "0",
|
|
2780
|
-
y: "100",
|
|
2781
|
-
fill: "currentColor",
|
|
2782
|
-
fontSize: "16",
|
|
2783
|
-
fontFamily: "sans-serif",
|
|
2784
|
-
children: api.watermarkConfig.text
|
|
2785
|
-
}
|
|
2786
|
-
)
|
|
2787
|
-
}
|
|
2788
|
-
) }),
|
|
2789
|
-
/* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: "url(#rfr-watermark)" })
|
|
2790
|
-
] })
|
|
2791
|
-
}
|
|
2792
|
-
)
|
|
2793
|
-
]
|
|
2794
|
-
}
|
|
2795
|
-
);
|
|
2796
|
-
}
|
|
2797
|
-
);
|
|
2798
|
-
ContentProtection.displayName = "ContentProtection";
|
|
2799
|
-
|
|
2800
|
-
// ../data-table/dist/index.js
|
|
2801
|
-
function createDataTable(props) {
|
|
2802
|
-
const {
|
|
2803
|
-
columns,
|
|
2804
|
-
data,
|
|
2805
|
-
sortBy: initialSortBy,
|
|
2806
|
-
sortDir: initialSortDir = "asc",
|
|
2807
|
-
onSort,
|
|
2808
|
-
filters: initialFilters
|
|
2809
|
-
} = props;
|
|
2810
|
-
let sortBy = initialSortBy ?? null;
|
|
2811
|
-
let sortDir = initialSortDir;
|
|
2812
|
-
let filters = { ...initialFilters ?? {} };
|
|
2813
|
-
function getFilteredData() {
|
|
2814
|
-
let result = [...data];
|
|
2815
|
-
for (const [columnId, filterValue] of Object.entries(filters)) {
|
|
2816
|
-
if (!filterValue) continue;
|
|
2817
|
-
const col = columns.find((c) => c.id === columnId);
|
|
2818
|
-
if (!col) continue;
|
|
2819
|
-
const lowerFilter = filterValue.toLowerCase();
|
|
2820
|
-
result = result.filter((row) => {
|
|
2821
|
-
const cellValue = col.accessor(row);
|
|
2822
|
-
return String(cellValue ?? "").toLowerCase().includes(lowerFilter);
|
|
2823
|
-
});
|
|
2824
|
-
}
|
|
2825
|
-
return result;
|
|
2683
|
+
// ../conversation/dist/index.js
|
|
2684
|
+
function byTime(a, b) {
|
|
2685
|
+
return a.timestamp.getTime() - b.timestamp.getTime();
|
|
2686
|
+
}
|
|
2687
|
+
function findMessage(messages, id) {
|
|
2688
|
+
return messages.find((m) => m.id === id);
|
|
2689
|
+
}
|
|
2690
|
+
function rootIdOf(messages, id) {
|
|
2691
|
+
const m = findMessage(messages, id);
|
|
2692
|
+
if (!m) return id;
|
|
2693
|
+
return m.parentId ?? m.id;
|
|
2694
|
+
}
|
|
2695
|
+
function selectRoots(messages) {
|
|
2696
|
+
return messages.filter((m) => !m.parentId).sort(byTime);
|
|
2697
|
+
}
|
|
2698
|
+
function selectReplies(messages, rootId) {
|
|
2699
|
+
return messages.filter((m) => m.parentId === rootId).sort(byTime);
|
|
2700
|
+
}
|
|
2701
|
+
function selectThreadMessages(messages, rootId) {
|
|
2702
|
+
const root = findMessage(messages, rootId);
|
|
2703
|
+
const replies = selectReplies(messages, rootId);
|
|
2704
|
+
return root ? [root, ...replies] : replies;
|
|
2705
|
+
}
|
|
2706
|
+
function getReplyCount(messages, rootId) {
|
|
2707
|
+
return messages.reduce((n, m) => m.parentId === rootId ? n + 1 : n, 0);
|
|
2708
|
+
}
|
|
2709
|
+
function selectMainTimeline(messages, mode) {
|
|
2710
|
+
if (mode === "panel") return selectRoots(messages);
|
|
2711
|
+
return [...messages].sort(byTime);
|
|
2712
|
+
}
|
|
2713
|
+
function selectTimelineFromState(state) {
|
|
2714
|
+
return selectMainTimeline(state.messages, state.threadingMode);
|
|
2715
|
+
}
|
|
2716
|
+
var DEFAULT_ASSISTANT = { id: "assistant", name: "Assistant" };
|
|
2717
|
+
var DEFAULT_USER = { id: "user", name: "You" };
|
|
2718
|
+
var DEFAULT_TITLE = "New conversation";
|
|
2719
|
+
function defaultGenerateTitle(firstMessage) {
|
|
2720
|
+
const firstLine = firstMessage.split("\n", 1)[0].trim();
|
|
2721
|
+
if (firstLine.length <= 48) return firstLine || DEFAULT_TITLE;
|
|
2722
|
+
return `${firstLine.slice(0, 47).trimEnd()}\u2026`;
|
|
2723
|
+
}
|
|
2724
|
+
function createConversation(config = {}) {
|
|
2725
|
+
const assistant = config.assistant ?? DEFAULT_ASSISTANT;
|
|
2726
|
+
const currentUser = config.currentUser ?? DEFAULT_USER;
|
|
2727
|
+
const generateTitle = config.generateTitle ?? defaultGenerateTitle;
|
|
2728
|
+
let transport = config.transport;
|
|
2729
|
+
let threadingMode = config.threadingMode ?? "inline";
|
|
2730
|
+
const conversations = /* @__PURE__ */ new Map();
|
|
2731
|
+
const messagesByConv = /* @__PURE__ */ new Map();
|
|
2732
|
+
let activeConversationId = config.activeConversationId ?? null;
|
|
2733
|
+
let openThreadRootId = null;
|
|
2734
|
+
let status = "idle";
|
|
2735
|
+
let error = null;
|
|
2736
|
+
let abortController = null;
|
|
2737
|
+
for (const c of config.conversations ?? []) {
|
|
2738
|
+
conversations.set(c.id, c);
|
|
2739
|
+
messagesByConv.set(c.id, []);
|
|
2740
|
+
}
|
|
2741
|
+
for (const [conversationId, msgs] of Object.entries(config.messages ?? {})) {
|
|
2742
|
+
messagesByConv.set(conversationId, [...msgs]);
|
|
2743
|
+
}
|
|
2744
|
+
if (activeConversationId === null && config.conversations?.length) {
|
|
2745
|
+
activeConversationId = config.conversations[0].id;
|
|
2826
2746
|
}
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
});
|
|
2747
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2748
|
+
let snapshot = buildSnapshot();
|
|
2749
|
+
function buildSnapshot() {
|
|
2750
|
+
return {
|
|
2751
|
+
conversations: orderedConversations(),
|
|
2752
|
+
activeConversationId,
|
|
2753
|
+
messages: activeConversationId ? messagesByConv.get(activeConversationId) ?? [] : [],
|
|
2754
|
+
openThreadRootId,
|
|
2755
|
+
threadingMode,
|
|
2756
|
+
status,
|
|
2757
|
+
error
|
|
2758
|
+
};
|
|
2840
2759
|
}
|
|
2841
|
-
function
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
if (sortBy === columnId) {
|
|
2845
|
-
sortDir = sortDir === "asc" ? "desc" : "asc";
|
|
2846
|
-
} else {
|
|
2847
|
-
sortBy = columnId;
|
|
2848
|
-
sortDir = "asc";
|
|
2849
|
-
}
|
|
2850
|
-
onSort?.(sortBy, sortDir);
|
|
2760
|
+
function emit() {
|
|
2761
|
+
snapshot = buildSnapshot();
|
|
2762
|
+
for (const l of listeners) l();
|
|
2851
2763
|
}
|
|
2852
|
-
function
|
|
2853
|
-
|
|
2764
|
+
function orderedConversations() {
|
|
2765
|
+
return [...conversations.values()].sort(
|
|
2766
|
+
(a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
|
|
2767
|
+
);
|
|
2854
2768
|
}
|
|
2855
|
-
function
|
|
2856
|
-
const
|
|
2857
|
-
|
|
2769
|
+
function touch(conversationId) {
|
|
2770
|
+
const c = conversations.get(conversationId);
|
|
2771
|
+
if (c) conversations.set(conversationId, { ...c, updatedAt: /* @__PURE__ */ new Date() });
|
|
2772
|
+
}
|
|
2773
|
+
function ensureActiveConversation(opts) {
|
|
2774
|
+
if (opts?.conversationId) {
|
|
2775
|
+
if (!conversations.has(opts.conversationId)) createConversationInternal({}, opts.conversationId);
|
|
2776
|
+
return opts.conversationId;
|
|
2777
|
+
}
|
|
2778
|
+
if (activeConversationId && conversations.has(activeConversationId)) return activeConversationId;
|
|
2779
|
+
return createConversationInternal({}).id;
|
|
2780
|
+
}
|
|
2781
|
+
function createConversationInternal(opts, id) {
|
|
2782
|
+
const now = /* @__PURE__ */ new Date();
|
|
2783
|
+
const conversation = {
|
|
2784
|
+
id: id ?? generateId("rfr-conv"),
|
|
2785
|
+
title: opts.title ?? DEFAULT_TITLE,
|
|
2786
|
+
createdAt: now,
|
|
2787
|
+
updatedAt: now,
|
|
2788
|
+
metadata: opts.metadata
|
|
2858
2789
|
};
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2790
|
+
conversations.set(conversation.id, conversation);
|
|
2791
|
+
messagesByConv.set(conversation.id, []);
|
|
2792
|
+
activeConversationId = conversation.id;
|
|
2793
|
+
return conversation;
|
|
2794
|
+
}
|
|
2795
|
+
async function streamReply(conversationId, assistantMsg, userMsg, history) {
|
|
2796
|
+
abortController = new AbortController();
|
|
2797
|
+
status = "streaming";
|
|
2798
|
+
emit();
|
|
2799
|
+
try {
|
|
2800
|
+
const stream = transport.send({
|
|
2801
|
+
conversationId,
|
|
2802
|
+
message: userMsg,
|
|
2803
|
+
history,
|
|
2804
|
+
parentId: assistantMsg.parentId,
|
|
2805
|
+
signal: abortController.signal
|
|
2806
|
+
});
|
|
2807
|
+
for await (const chunk of stream) {
|
|
2808
|
+
if (chunk.content !== void 0) assistantMsg.content = chunk.content;
|
|
2809
|
+
if (chunk.delta) assistantMsg.content += chunk.delta;
|
|
2810
|
+
if (chunk.metadata) {
|
|
2811
|
+
assistantMsg.metadata = { ...assistantMsg.metadata, ...chunk.metadata };
|
|
2812
|
+
}
|
|
2813
|
+
emit();
|
|
2814
|
+
if (abortController.signal.aborted) break;
|
|
2815
|
+
}
|
|
2816
|
+
assistantMsg.status = "sent";
|
|
2817
|
+
status = "idle";
|
|
2818
|
+
error = null;
|
|
2819
|
+
} catch (err) {
|
|
2820
|
+
if (abortController.signal.aborted) {
|
|
2821
|
+
assistantMsg.status = "sent";
|
|
2822
|
+
status = "idle";
|
|
2862
2823
|
} else {
|
|
2863
|
-
|
|
2824
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2825
|
+
assistantMsg.status = "error";
|
|
2826
|
+
assistantMsg.error = message;
|
|
2827
|
+
status = "error";
|
|
2828
|
+
error = message;
|
|
2864
2829
|
}
|
|
2830
|
+
} finally {
|
|
2831
|
+
abortController = null;
|
|
2832
|
+
touch(conversationId);
|
|
2833
|
+
emit();
|
|
2865
2834
|
}
|
|
2866
|
-
return props2;
|
|
2867
|
-
}
|
|
2868
|
-
function getCellProps(col, _row) {
|
|
2869
|
-
return {
|
|
2870
|
-
role: "cell",
|
|
2871
|
-
"data-column": col.id
|
|
2872
|
-
};
|
|
2873
2835
|
}
|
|
2874
|
-
function
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
"data-row-index": index
|
|
2878
|
-
};
|
|
2836
|
+
function historyFor(list, parentId) {
|
|
2837
|
+
const scope = parentId ? selectThreadMessages(list, parentId) : selectRoots(list);
|
|
2838
|
+
return scope.filter((m) => m.status !== "error");
|
|
2879
2839
|
}
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
return
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2840
|
+
const api = {
|
|
2841
|
+
getState() {
|
|
2842
|
+
return snapshot;
|
|
2843
|
+
},
|
|
2844
|
+
subscribe(listener) {
|
|
2845
|
+
listeners.add(listener);
|
|
2846
|
+
return () => listeners.delete(listener);
|
|
2847
|
+
},
|
|
2848
|
+
newConversation(opts) {
|
|
2849
|
+
const conversation = createConversationInternal(opts ?? {});
|
|
2850
|
+
openThreadRootId = null;
|
|
2851
|
+
emit();
|
|
2852
|
+
return conversation;
|
|
2853
|
+
},
|
|
2854
|
+
selectConversation(conversationId) {
|
|
2855
|
+
if (!conversations.has(conversationId) || activeConversationId === conversationId) return;
|
|
2856
|
+
activeConversationId = conversationId;
|
|
2857
|
+
openThreadRootId = null;
|
|
2858
|
+
emit();
|
|
2859
|
+
},
|
|
2860
|
+
deleteConversation(conversationId) {
|
|
2861
|
+
if (!conversations.has(conversationId)) return;
|
|
2862
|
+
conversations.delete(conversationId);
|
|
2863
|
+
messagesByConv.delete(conversationId);
|
|
2864
|
+
if (activeConversationId === conversationId) {
|
|
2865
|
+
activeConversationId = orderedConversations()[0]?.id ?? null;
|
|
2866
|
+
openThreadRootId = null;
|
|
2867
|
+
}
|
|
2868
|
+
emit();
|
|
2869
|
+
},
|
|
2870
|
+
renameConversation(conversationId, title) {
|
|
2871
|
+
const c = conversations.get(conversationId);
|
|
2872
|
+
if (!c) return;
|
|
2873
|
+
conversations.set(conversationId, { ...c, title });
|
|
2874
|
+
emit();
|
|
2875
|
+
},
|
|
2876
|
+
appendMessage(message) {
|
|
2877
|
+
const list = messagesByConv.get(message.conversationId);
|
|
2878
|
+
if (!list) return;
|
|
2879
|
+
list.push(message);
|
|
2880
|
+
touch(message.conversationId);
|
|
2881
|
+
emit();
|
|
2882
|
+
},
|
|
2883
|
+
editMessage(messageId, content) {
|
|
2884
|
+
if (!activeConversationId) return;
|
|
2885
|
+
const list = messagesByConv.get(activeConversationId);
|
|
2886
|
+
const msg = list.find((m) => m.id === messageId);
|
|
2887
|
+
if (!msg) return;
|
|
2888
|
+
msg.content = content;
|
|
2889
|
+
msg.edited = true;
|
|
2890
|
+
emit();
|
|
2891
|
+
},
|
|
2892
|
+
deleteMessage(messageId) {
|
|
2893
|
+
if (!activeConversationId) return;
|
|
2894
|
+
const list = messagesByConv.get(activeConversationId);
|
|
2895
|
+
const msg = list.find((m) => m.id === messageId);
|
|
2896
|
+
if (!msg) return;
|
|
2897
|
+
const removeIds = /* @__PURE__ */ new Set([messageId]);
|
|
2898
|
+
if (!msg.parentId) {
|
|
2899
|
+
for (const r of list) if (r.parentId === messageId) removeIds.add(r.id);
|
|
2900
|
+
}
|
|
2901
|
+
const next = list.filter((m) => !removeIds.has(m.id));
|
|
2902
|
+
messagesByConv.set(activeConversationId, next);
|
|
2903
|
+
if (openThreadRootId && removeIds.has(openThreadRootId)) openThreadRootId = null;
|
|
2904
|
+
emit();
|
|
2905
|
+
},
|
|
2906
|
+
react(messageId, emoji) {
|
|
2907
|
+
if (!activeConversationId) return;
|
|
2908
|
+
const list = messagesByConv.get(activeConversationId);
|
|
2909
|
+
const msg = list.find((m) => m.id === messageId);
|
|
2910
|
+
if (!msg) return;
|
|
2911
|
+
const reactions = [...msg.reactions ?? []];
|
|
2912
|
+
const idx = reactions.findIndex((r) => r.emoji === emoji);
|
|
2913
|
+
if (idx === -1) {
|
|
2914
|
+
reactions.push({ emoji, count: 1, userReacted: true });
|
|
2915
|
+
} else {
|
|
2916
|
+
const r = reactions[idx];
|
|
2917
|
+
if (r.userReacted) {
|
|
2918
|
+
const count = r.count - 1;
|
|
2919
|
+
if (count <= 0) reactions.splice(idx, 1);
|
|
2920
|
+
else reactions[idx] = { ...r, count, userReacted: false };
|
|
2921
|
+
} else {
|
|
2922
|
+
reactions[idx] = { ...r, count: r.count + 1, userReacted: true };
|
|
2894
2923
|
}
|
|
2924
|
+
}
|
|
2925
|
+
msg.reactions = reactions;
|
|
2926
|
+
emit();
|
|
2927
|
+
},
|
|
2928
|
+
async sendMessage(content, opts) {
|
|
2929
|
+
const trimmed = content.trim();
|
|
2930
|
+
if (!trimmed && !opts?.attachments?.length) return;
|
|
2931
|
+
const conversationId = ensureActiveConversation(opts);
|
|
2932
|
+
const list = messagesByConv.get(conversationId);
|
|
2933
|
+
const parentId = opts?.replyTo ? rootIdOf(list, opts.replyTo) : void 0;
|
|
2934
|
+
const isFirstRoot = !parentId && selectRoots(list).length === 0;
|
|
2935
|
+
const userMsg = {
|
|
2936
|
+
id: generateId("rfr-msg"),
|
|
2937
|
+
conversationId,
|
|
2938
|
+
role: "user",
|
|
2939
|
+
author: currentUser,
|
|
2940
|
+
content: trimmed,
|
|
2941
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2942
|
+
status: "sent",
|
|
2943
|
+
parentId,
|
|
2944
|
+
attachments: opts?.attachments,
|
|
2945
|
+
metadata: opts?.metadata
|
|
2946
|
+
};
|
|
2947
|
+
list.push(userMsg);
|
|
2948
|
+
const conversation = conversations.get(conversationId);
|
|
2949
|
+
if (isFirstRoot && conversation.title === DEFAULT_TITLE) {
|
|
2950
|
+
conversations.set(conversationId, { ...conversation, title: generateTitle(trimmed) });
|
|
2951
|
+
}
|
|
2952
|
+
touch(conversationId);
|
|
2953
|
+
if (!transport) {
|
|
2954
|
+
status = "idle";
|
|
2955
|
+
emit();
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
const history = historyFor(list, parentId).filter((m) => m.id !== userMsg.id);
|
|
2959
|
+
const assistantMsg = {
|
|
2960
|
+
id: generateId("rfr-msg"),
|
|
2961
|
+
conversationId,
|
|
2962
|
+
role: "assistant",
|
|
2963
|
+
author: assistant,
|
|
2964
|
+
content: "",
|
|
2965
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2966
|
+
status: "streaming",
|
|
2967
|
+
parentId
|
|
2895
2968
|
};
|
|
2969
|
+
list.push(assistantMsg);
|
|
2970
|
+
await streamReply(conversationId, assistantMsg, userMsg, history);
|
|
2896
2971
|
},
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2972
|
+
async retryLast() {
|
|
2973
|
+
if (!activeConversationId || !transport) return;
|
|
2974
|
+
const list = messagesByConv.get(activeConversationId);
|
|
2975
|
+
const last = list[list.length - 1];
|
|
2976
|
+
const parentId = last?.parentId;
|
|
2977
|
+
if (last && last.role === "assistant" && last.status === "error") list.pop();
|
|
2978
|
+
const scope = parentId ? selectThreadMessages(list, parentId) : selectRoots(list);
|
|
2979
|
+
const lastUser = [...scope].reverse().find((m) => m.role === "user");
|
|
2980
|
+
if (!lastUser) return;
|
|
2981
|
+
const history = historyFor(list, parentId);
|
|
2982
|
+
const assistantMsg = {
|
|
2983
|
+
id: generateId("rfr-msg"),
|
|
2984
|
+
conversationId: activeConversationId,
|
|
2985
|
+
role: "assistant",
|
|
2986
|
+
author: assistant,
|
|
2987
|
+
content: "",
|
|
2988
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2989
|
+
status: "streaming",
|
|
2990
|
+
parentId
|
|
2991
|
+
};
|
|
2992
|
+
list.push(assistantMsg);
|
|
2993
|
+
await streamReply(activeConversationId, assistantMsg, lastUser, history);
|
|
2994
|
+
},
|
|
2995
|
+
stop() {
|
|
2996
|
+
abortController?.abort();
|
|
2997
|
+
},
|
|
2998
|
+
openThread(rootId) {
|
|
2999
|
+
openThreadRootId = rootId;
|
|
3000
|
+
emit();
|
|
3001
|
+
},
|
|
3002
|
+
closeThread() {
|
|
3003
|
+
if (openThreadRootId === null) return;
|
|
3004
|
+
openThreadRootId = null;
|
|
3005
|
+
emit();
|
|
3006
|
+
},
|
|
3007
|
+
setThreadingMode(mode) {
|
|
3008
|
+
if (threadingMode === mode) return;
|
|
3009
|
+
threadingMode = mode;
|
|
3010
|
+
emit();
|
|
3011
|
+
},
|
|
3012
|
+
setTransport(next) {
|
|
3013
|
+
transport = next;
|
|
3014
|
+
}
|
|
2902
3015
|
};
|
|
3016
|
+
return api;
|
|
2903
3017
|
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3018
|
+
|
|
3019
|
+
// ../markdown-renderer/dist/index.js
|
|
3020
|
+
function escapeHtml(text) {
|
|
3021
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3022
|
+
}
|
|
3023
|
+
function parseInline(text, linkResolver) {
|
|
3024
|
+
let result = escapeHtml(text);
|
|
3025
|
+
result = result.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
3026
|
+
result = result.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
3027
|
+
result = result.replace(/__([^_]+)__/g, "<strong>$1</strong>");
|
|
3028
|
+
result = result.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
3029
|
+
result = result.replace(/_([^_]+)_/g, "<em>$1</em>");
|
|
3030
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text2, url) => {
|
|
3031
|
+
if (/^\s*javascript\s*:/i.test(url)) {
|
|
3032
|
+
return text2;
|
|
3033
|
+
}
|
|
3034
|
+
const resolvedUrl = linkResolver ? linkResolver(url) : url;
|
|
3035
|
+
return `<a href="${resolvedUrl}">${text2}</a>`;
|
|
3036
|
+
});
|
|
3037
|
+
return result;
|
|
3038
|
+
}
|
|
3039
|
+
function parseMarkdown(content, linkResolver) {
|
|
3040
|
+
const lines = content.split("\n");
|
|
3041
|
+
const outputLines = [];
|
|
3042
|
+
let inCodeBlock = false;
|
|
3043
|
+
let codeBlockContent = [];
|
|
3044
|
+
let codeBlockLang = "";
|
|
3045
|
+
let inList = null;
|
|
3046
|
+
let inBlockquote = false;
|
|
3047
|
+
function closeList() {
|
|
3048
|
+
if (inList) {
|
|
3049
|
+
outputLines.push(inList === "ul" ? "</ul>" : "</ol>");
|
|
3050
|
+
inList = null;
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
function closeBlockquote() {
|
|
3054
|
+
if (inBlockquote) {
|
|
3055
|
+
outputLines.push("</blockquote>");
|
|
3056
|
+
inBlockquote = false;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3060
|
+
const line = lines[i];
|
|
3061
|
+
if (line.trimStart().startsWith("```")) {
|
|
3062
|
+
if (inCodeBlock) {
|
|
3063
|
+
outputLines.push(`<pre><code${codeBlockLang ? ` class="language-${escapeHtml(codeBlockLang)}"` : ""}>${escapeHtml(codeBlockContent.join("\n"))}</code></pre>`);
|
|
3064
|
+
codeBlockContent = [];
|
|
3065
|
+
codeBlockLang = "";
|
|
3066
|
+
inCodeBlock = false;
|
|
3067
|
+
} else {
|
|
3068
|
+
closeList();
|
|
3069
|
+
closeBlockquote();
|
|
3070
|
+
inCodeBlock = true;
|
|
3071
|
+
codeBlockLang = line.trimStart().slice(3).trim();
|
|
3072
|
+
}
|
|
3073
|
+
continue;
|
|
3074
|
+
}
|
|
3075
|
+
if (inCodeBlock) {
|
|
3076
|
+
codeBlockContent.push(line);
|
|
3077
|
+
continue;
|
|
3078
|
+
}
|
|
3079
|
+
if (/^(\s*[-*_]\s*){3,}$/.test(line)) {
|
|
3080
|
+
closeList();
|
|
3081
|
+
closeBlockquote();
|
|
3082
|
+
outputLines.push("<hr />");
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
3086
|
+
if (headingMatch) {
|
|
3087
|
+
closeList();
|
|
3088
|
+
closeBlockquote();
|
|
3089
|
+
const level = headingMatch[1].length;
|
|
3090
|
+
const text = parseInline(headingMatch[2], linkResolver);
|
|
3091
|
+
outputLines.push(`<h${level}>${text}</h${level}>`);
|
|
3092
|
+
continue;
|
|
3093
|
+
}
|
|
3094
|
+
const blockquoteMatch = line.match(/^>\s?(.*)$/);
|
|
3095
|
+
if (blockquoteMatch) {
|
|
3096
|
+
closeList();
|
|
3097
|
+
if (!inBlockquote) {
|
|
3098
|
+
inBlockquote = true;
|
|
3099
|
+
outputLines.push("<blockquote>");
|
|
3100
|
+
}
|
|
3101
|
+
const text = blockquoteMatch[1].trim();
|
|
3102
|
+
if (text) {
|
|
3103
|
+
outputLines.push(`<p>${parseInline(text, linkResolver)}</p>`);
|
|
3104
|
+
}
|
|
3105
|
+
continue;
|
|
3106
|
+
} else if (inBlockquote) {
|
|
3107
|
+
closeBlockquote();
|
|
3108
|
+
}
|
|
3109
|
+
const ulMatch = line.match(/^[\s]*[-*+]\s+(.+)$/);
|
|
3110
|
+
if (ulMatch) {
|
|
3111
|
+
closeBlockquote();
|
|
3112
|
+
if (inList !== "ul") {
|
|
3113
|
+
closeList();
|
|
3114
|
+
inList = "ul";
|
|
3115
|
+
outputLines.push("<ul>");
|
|
3116
|
+
}
|
|
3117
|
+
outputLines.push(`<li>${parseInline(ulMatch[1], linkResolver)}</li>`);
|
|
3118
|
+
continue;
|
|
3119
|
+
}
|
|
3120
|
+
const olMatch = line.match(/^[\s]*\d+\.\s+(.+)$/);
|
|
3121
|
+
if (olMatch) {
|
|
3122
|
+
closeBlockquote();
|
|
3123
|
+
if (inList !== "ol") {
|
|
3124
|
+
closeList();
|
|
3125
|
+
inList = "ol";
|
|
3126
|
+
outputLines.push("<ol>");
|
|
3127
|
+
}
|
|
3128
|
+
outputLines.push(`<li>${parseInline(olMatch[1], linkResolver)}</li>`);
|
|
3129
|
+
continue;
|
|
3130
|
+
}
|
|
3131
|
+
if (inList) {
|
|
3132
|
+
closeList();
|
|
3133
|
+
}
|
|
3134
|
+
if (line.trim() === "") {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
outputLines.push(`<p>${parseInline(line, linkResolver)}</p>`);
|
|
3138
|
+
}
|
|
3139
|
+
if (inCodeBlock) {
|
|
3140
|
+
outputLines.push(`<pre><code${codeBlockLang ? ` class="language-${escapeHtml(codeBlockLang)}"` : ""}>${escapeHtml(codeBlockContent.join("\n"))}</code></pre>`);
|
|
3141
|
+
}
|
|
3142
|
+
closeList();
|
|
3143
|
+
closeBlockquote();
|
|
3144
|
+
return outputLines.join("\n");
|
|
3145
|
+
}
|
|
3146
|
+
function extractComponents(content, components) {
|
|
3147
|
+
if (!components) return [];
|
|
3148
|
+
const extracted = [];
|
|
3149
|
+
for (const [name, def] of Object.entries(components)) {
|
|
3150
|
+
const matches = Array.from(content.matchAll(def.pattern));
|
|
3151
|
+
matches.forEach(() => {
|
|
3152
|
+
extracted.push({
|
|
3153
|
+
name,
|
|
3154
|
+
props: { ...def.props }
|
|
3155
|
+
});
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
return extracted;
|
|
3159
|
+
}
|
|
3160
|
+
function createMarkdownRenderer(props) {
|
|
3161
|
+
const { content, components, linkResolver } = props;
|
|
3162
|
+
const html = parseMarkdown(content, linkResolver);
|
|
3163
|
+
const extractedComponents = extractComponents(content, components);
|
|
3164
|
+
const ariaProps = {
|
|
3165
|
+
role: "document",
|
|
3166
|
+
"aria-label": "Rendered markdown content"
|
|
3167
|
+
};
|
|
3168
|
+
return {
|
|
3169
|
+
html,
|
|
3170
|
+
components: extractedComponents,
|
|
3171
|
+
ariaProps
|
|
3172
|
+
};
|
|
3173
|
+
}
|
|
3174
|
+
var markdownRendererTokens = {
|
|
3175
|
+
name: "markdown-renderer",
|
|
3176
|
+
tokens: {
|
|
3177
|
+
bg: { variable: "--rfr-markdown-bg", fallback: "hsl(var(--background))" },
|
|
3178
|
+
fg: { variable: "--rfr-markdown-fg", fallback: "hsl(var(--foreground))" },
|
|
3179
|
+
codeBg: { variable: "--rfr-markdown-code-bg", fallback: "hsl(var(--muted))" },
|
|
3180
|
+
linkColor: { variable: "--rfr-markdown-link", fallback: "hsl(var(--primary))" },
|
|
3181
|
+
borderColor: { variable: "--rfr-markdown-border", fallback: "hsl(var(--border))" }
|
|
3182
|
+
}
|
|
3183
|
+
};
|
|
3184
|
+
var proseVariants = cva({
|
|
3185
|
+
base: "prose max-w-none text-foreground leading-relaxed",
|
|
3186
|
+
variants: {
|
|
3187
|
+
size: {
|
|
3188
|
+
sm: "prose-sm text-sm",
|
|
3189
|
+
default: "prose-base text-base",
|
|
3190
|
+
lg: "prose-lg text-lg"
|
|
3191
|
+
},
|
|
3192
|
+
theme: {
|
|
3193
|
+
light: "bg-white text-gray-900",
|
|
3194
|
+
dark: "bg-gray-900 text-gray-100"
|
|
3195
|
+
}
|
|
3196
|
+
},
|
|
3197
|
+
defaultVariants: {
|
|
3198
|
+
size: "default"
|
|
3199
|
+
}
|
|
3200
|
+
});
|
|
3201
|
+
function sanitizeHtml(html) {
|
|
3202
|
+
let sanitized = html;
|
|
3203
|
+
sanitized = sanitized.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
|
|
3204
|
+
sanitized = sanitized.replace(/<\/?script[^>]*>/gi, "");
|
|
3205
|
+
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, "");
|
|
3206
|
+
sanitized = sanitized.replace(/(href|src)\s*=\s*["']?\s*javascript\s*:[^"'>]*/gi, '$1=""');
|
|
3207
|
+
return sanitized;
|
|
3208
|
+
}
|
|
3209
|
+
var MarkdownRenderer = React11.forwardRef(
|
|
3210
|
+
({ content, components, linkResolver, className, size }, ref) => {
|
|
3211
|
+
const coreProps = { content, components, linkResolver };
|
|
3212
|
+
const api = createMarkdownRenderer(coreProps);
|
|
3213
|
+
const classes = cn(proseVariants({ size }), className);
|
|
3214
|
+
const sanitizedHtml = sanitizeHtml(api.html);
|
|
3215
|
+
return /* @__PURE__ */ jsx(
|
|
3216
|
+
"div",
|
|
3217
|
+
{
|
|
3218
|
+
ref,
|
|
3219
|
+
className: classes,
|
|
3220
|
+
...api.ariaProps,
|
|
3221
|
+
dangerouslySetInnerHTML: { __html: sanitizedHtml }
|
|
3222
|
+
}
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
);
|
|
3226
|
+
MarkdownRenderer.displayName = "MarkdownRenderer";
|
|
3227
|
+
|
|
3228
|
+
// ../thread-view/dist/index.js
|
|
3229
|
+
function formatTimestamp(date) {
|
|
3230
|
+
const hours = date.getHours();
|
|
3231
|
+
const minutes = date.getMinutes();
|
|
3232
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
3233
|
+
const displayHours = hours % 12 || 12;
|
|
3234
|
+
const displayMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
|
3235
|
+
return `${displayHours}:${displayMinutes} ${ampm}`;
|
|
3236
|
+
}
|
|
3237
|
+
function formatRelativeTime(date, now) {
|
|
3238
|
+
const reference = now ?? /* @__PURE__ */ new Date();
|
|
3239
|
+
const diffMs = reference.getTime() - date.getTime();
|
|
3240
|
+
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
3241
|
+
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
3242
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
3243
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
3244
|
+
if (diffSeconds < 60) return "just now";
|
|
3245
|
+
if (diffMinutes < 60) return `${diffMinutes} minute${diffMinutes === 1 ? "" : "s"} ago`;
|
|
3246
|
+
if (diffHours < 24) return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
|
|
3247
|
+
if (diffDays < 7) return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
3248
|
+
return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
3249
|
+
}
|
|
3250
|
+
function createThreadView(props) {
|
|
3251
|
+
const { messages, onReply, onReact, currentUserId } = props;
|
|
3252
|
+
let replyingTo = null;
|
|
3253
|
+
const threadId = generateId("rfr-thread");
|
|
3254
|
+
const labelId = generateId("rfr-thread-label");
|
|
3255
|
+
function startReply(messageId) {
|
|
3256
|
+
replyingTo = messageId;
|
|
3257
|
+
}
|
|
3258
|
+
function cancelReply() {
|
|
3259
|
+
replyingTo = null;
|
|
3260
|
+
}
|
|
3261
|
+
function reply(messageId, content) {
|
|
3262
|
+
onReply?.(messageId, content);
|
|
3263
|
+
replyingTo = null;
|
|
3264
|
+
}
|
|
3265
|
+
function react(messageId, emoji) {
|
|
3266
|
+
onReact?.(messageId, emoji);
|
|
3267
|
+
}
|
|
3268
|
+
const ariaProps = {
|
|
3269
|
+
role: "log",
|
|
3270
|
+
"aria-label": "Message thread",
|
|
3271
|
+
"aria-live": "polite",
|
|
3272
|
+
id: threadId
|
|
3273
|
+
};
|
|
3274
|
+
function getMessageAriaProps(message) {
|
|
3275
|
+
const isOwn = currentUserId && message.author.id === currentUserId;
|
|
3276
|
+
return {
|
|
3277
|
+
role: "article",
|
|
3278
|
+
"aria-label": `Message from ${message.author.name}${isOwn ? " (you)" : ""} at ${formatTimestamp(message.timestamp)}`
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
function getReplyButtonAriaProps(_messageId) {
|
|
3282
|
+
return {
|
|
3283
|
+
role: "button",
|
|
3284
|
+
"aria-label": `Reply to message`
|
|
3285
|
+
};
|
|
3286
|
+
}
|
|
3287
|
+
return {
|
|
3288
|
+
state: {
|
|
3289
|
+
messages,
|
|
3290
|
+
get replyingTo() {
|
|
3291
|
+
return replyingTo;
|
|
3292
|
+
}
|
|
3293
|
+
},
|
|
3294
|
+
startReply,
|
|
3295
|
+
cancelReply,
|
|
3296
|
+
reply,
|
|
3297
|
+
react,
|
|
3298
|
+
formatTimestamp,
|
|
3299
|
+
formatRelativeTime,
|
|
3300
|
+
ariaProps,
|
|
3301
|
+
getMessageAriaProps,
|
|
3302
|
+
getReplyButtonAriaProps,
|
|
3303
|
+
ids: {
|
|
3304
|
+
thread: threadId,
|
|
3305
|
+
label: labelId
|
|
3306
|
+
}
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
var threadContainerStyles = "flex flex-col gap-1";
|
|
3310
|
+
var threadMessageStyles = "flex gap-3 px-4 py-2 hover:bg-accent/50 rounded-md transition-colors group";
|
|
3311
|
+
var threadAvatarStyles = "h-9 w-9 rounded-full bg-muted flex items-center justify-center text-sm font-medium overflow-hidden flex-shrink-0";
|
|
3312
|
+
var threadContentStyles = "flex-1 min-w-0";
|
|
3313
|
+
var threadAuthorStyles = "font-semibold text-sm";
|
|
3314
|
+
var threadTimestampStyles = "text-xs text-muted-foreground ml-2";
|
|
3315
|
+
var threadBodyStyles = "text-sm mt-0.5 whitespace-pre-wrap break-words";
|
|
3316
|
+
var threadReactionsStyles = "flex flex-wrap gap-1 mt-1";
|
|
3317
|
+
var threadReplyIndicatorStyles = "flex items-center gap-1 mt-1 text-xs text-primary cursor-pointer hover:underline";
|
|
3318
|
+
var threadActionsStyles = "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity";
|
|
3319
|
+
var threadAttachmentStyles = "flex items-center gap-2 mt-1 p-2 rounded border text-xs bg-muted/50";
|
|
3320
|
+
var threadEditedStyles = "text-xs text-muted-foreground ml-1";
|
|
3321
|
+
|
|
3322
|
+
// ../react-conversation/dist/index.js
|
|
3323
|
+
function useConversation(config) {
|
|
3324
|
+
const apiRef = React11.useRef(null);
|
|
3325
|
+
if (apiRef.current === null) {
|
|
3326
|
+
apiRef.current = createConversation(config);
|
|
3327
|
+
}
|
|
3328
|
+
const api = apiRef.current;
|
|
3329
|
+
const state = React11.useSyncExternalStore(api.subscribe, api.getState, api.getState);
|
|
3330
|
+
const transport = config?.transport;
|
|
3331
|
+
React11.useEffect(() => {
|
|
3332
|
+
if (transport) api.setTransport(transport);
|
|
3333
|
+
}, [api, transport]);
|
|
3334
|
+
return {
|
|
3335
|
+
state,
|
|
3336
|
+
api,
|
|
3337
|
+
sendMessage: api.sendMessage,
|
|
3338
|
+
newConversation: api.newConversation,
|
|
3339
|
+
selectConversation: api.selectConversation,
|
|
3340
|
+
deleteConversation: api.deleteConversation,
|
|
3341
|
+
renameConversation: api.renameConversation,
|
|
3342
|
+
editMessage: api.editMessage,
|
|
3343
|
+
deleteMessage: api.deleteMessage,
|
|
3344
|
+
react: api.react,
|
|
3345
|
+
retryLast: api.retryLast,
|
|
3346
|
+
stop: api.stop,
|
|
3347
|
+
openThread: api.openThread,
|
|
3348
|
+
closeThread: api.closeThread,
|
|
3349
|
+
setThreadingMode: api.setThreadingMode
|
|
3350
|
+
};
|
|
3351
|
+
}
|
|
3352
|
+
var h = React11.createElement;
|
|
3353
|
+
var EMOJI = {
|
|
3354
|
+
smile: "\u{1F604}",
|
|
3355
|
+
grin: "\u{1F601}",
|
|
3356
|
+
joy: "\u{1F602}",
|
|
3357
|
+
rofl: "\u{1F923}",
|
|
3358
|
+
wink: "\u{1F609}",
|
|
3359
|
+
heart_eyes: "\u{1F60D}",
|
|
3360
|
+
thinking: "\u{1F914}",
|
|
3361
|
+
neutral: "\u{1F610}",
|
|
3362
|
+
sob: "\u{1F62D}",
|
|
3363
|
+
scream: "\u{1F631}",
|
|
3364
|
+
tada: "\u{1F389}",
|
|
3365
|
+
fire: "\u{1F525}",
|
|
3366
|
+
heart: "\u2764\uFE0F",
|
|
3367
|
+
thumbsup: "\u{1F44D}",
|
|
3368
|
+
thumbsdown: "\u{1F44E}",
|
|
3369
|
+
clap: "\u{1F44F}",
|
|
3370
|
+
pray: "\u{1F64F}",
|
|
3371
|
+
eyes: "\u{1F440}",
|
|
3372
|
+
rocket: "\u{1F680}",
|
|
3373
|
+
sparkles: "\u2728",
|
|
3374
|
+
star: "\u2B50",
|
|
3375
|
+
check: "\u2705",
|
|
3376
|
+
x: "\u274C",
|
|
3377
|
+
warning: "\u26A0\uFE0F",
|
|
3378
|
+
bulb: "\u{1F4A1}",
|
|
3379
|
+
bug: "\u{1F41B}",
|
|
3380
|
+
wave: "\u{1F44B}",
|
|
3381
|
+
ok_hand: "\u{1F44C}",
|
|
3382
|
+
muscle: "\u{1F4AA}",
|
|
3383
|
+
"100": "\u{1F4AF}",
|
|
3384
|
+
poop: "\u{1F4A9}",
|
|
3385
|
+
ghost: "\u{1F47B}",
|
|
3386
|
+
robot: "\u{1F916}",
|
|
3387
|
+
cat: "\u{1F431}",
|
|
3388
|
+
dog: "\u{1F436}",
|
|
3389
|
+
coffee: "\u2615",
|
|
3390
|
+
pizza: "\u{1F355}",
|
|
3391
|
+
beer: "\u{1F37A}",
|
|
3392
|
+
sun: "\u2600\uFE0F",
|
|
3393
|
+
moon: "\u{1F319}",
|
|
3394
|
+
zap: "\u26A1"
|
|
3395
|
+
};
|
|
3396
|
+
function detectTrigger(text, caret) {
|
|
3397
|
+
const before = text.slice(0, caret);
|
|
3398
|
+
const m = before.match(/(?:^|\s)([/@:])([\w+-]*)$/);
|
|
3399
|
+
if (!m) return null;
|
|
3400
|
+
const type = m[1];
|
|
3401
|
+
const query = m[2] ?? "";
|
|
3402
|
+
return { type, query, start: caret - query.length - 1, end: caret };
|
|
3403
|
+
}
|
|
3404
|
+
function Composer({
|
|
3405
|
+
placeholder = "Type a message\u2026 (/ commands, @ mentions, : emoji)",
|
|
3406
|
+
busy = false,
|
|
3407
|
+
slashCommands = [],
|
|
3408
|
+
mentions,
|
|
3409
|
+
toolbar = true,
|
|
3410
|
+
emoji = true,
|
|
3411
|
+
attachments = true,
|
|
3412
|
+
onSubmit,
|
|
3413
|
+
onStop,
|
|
3414
|
+
onSlashCommand,
|
|
3415
|
+
autoFocus
|
|
3416
|
+
}) {
|
|
3417
|
+
const [value, setValue] = React11.useState("");
|
|
3418
|
+
const [pending, setPending] = React11.useState([]);
|
|
3419
|
+
const [trigger, setTrigger] = React11.useState(null);
|
|
3420
|
+
const [active, setActive] = React11.useState(0);
|
|
3421
|
+
const [mentionItems, setMentionItems] = React11.useState([]);
|
|
3422
|
+
const ref = React11.useRef(null);
|
|
3423
|
+
const fileRef = React11.useRef(null);
|
|
3424
|
+
React11.useEffect(() => {
|
|
3425
|
+
if (trigger?.type !== "@" || !mentions) {
|
|
3426
|
+
setMentionItems([]);
|
|
3427
|
+
return;
|
|
3428
|
+
}
|
|
3429
|
+
if (Array.isArray(mentions)) {
|
|
3430
|
+
const q = trigger.query.toLowerCase();
|
|
3431
|
+
setMentionItems(mentions.filter((m) => m.label.toLowerCase().includes(q)).slice(0, 8));
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
let cancelled = false;
|
|
3435
|
+
Promise.resolve(mentions(trigger.query)).then((res) => {
|
|
3436
|
+
if (!cancelled) setMentionItems(res.slice(0, 8));
|
|
3437
|
+
});
|
|
3438
|
+
return () => {
|
|
3439
|
+
cancelled = true;
|
|
3440
|
+
};
|
|
3441
|
+
}, [trigger, mentions]);
|
|
3442
|
+
const items = React11.useMemo(() => {
|
|
3443
|
+
if (!trigger) return [];
|
|
3444
|
+
const q = trigger.query.toLowerCase();
|
|
3445
|
+
if (trigger.type === "/") {
|
|
3446
|
+
return slashCommands.filter((c) => c.label.toLowerCase().includes(q) || c.id.toLowerCase().includes(q)).slice(0, 8).map((c) => ({ key: c.id, primary: c.label, secondary: c.description, icon: c.icon, apply: c.insertText ?? "", runCmd: c }));
|
|
3447
|
+
}
|
|
3448
|
+
if (trigger.type === "@") {
|
|
3449
|
+
return mentionItems.map((m) => ({ key: m.id, primary: m.label, icon: m.avatarUrl ? "" : "@", apply: `@${m.label} ` }));
|
|
3450
|
+
}
|
|
3451
|
+
if (trigger.type === ":" && emoji) {
|
|
3452
|
+
return Object.entries(EMOJI).filter(([name]) => name.includes(q)).slice(0, 8).map(([name, char]) => ({ key: name, primary: `${char} :${name}:`, apply: char }));
|
|
3453
|
+
}
|
|
3454
|
+
return [];
|
|
3455
|
+
}, [trigger, slashCommands, mentionItems, emoji]);
|
|
3456
|
+
const menuOpen = trigger !== null && items.length > 0;
|
|
3457
|
+
React11.useEffect(() => setActive(0), [trigger?.type, trigger?.query]);
|
|
3458
|
+
function syncFromTextarea(el) {
|
|
3459
|
+
setValue(el.value);
|
|
3460
|
+
setTrigger(detectTrigger(el.value, el.selectionStart ?? el.value.length));
|
|
3461
|
+
}
|
|
3462
|
+
function selectItem(i) {
|
|
3463
|
+
const item = items[i];
|
|
3464
|
+
if (!item || !trigger) return;
|
|
3465
|
+
if (trigger.type === "/" && !item.apply && item.runCmd) {
|
|
3466
|
+
const next2 = value.slice(0, trigger.start) + value.slice(trigger.end);
|
|
3467
|
+
setValue(next2);
|
|
3468
|
+
setTrigger(null);
|
|
3469
|
+
onSlashCommand?.(item.runCmd);
|
|
3470
|
+
queueCaret(trigger.start);
|
|
3471
|
+
return;
|
|
3472
|
+
}
|
|
3473
|
+
const next = value.slice(0, trigger.start) + item.apply + value.slice(trigger.end);
|
|
3474
|
+
setValue(next);
|
|
3475
|
+
setTrigger(null);
|
|
3476
|
+
queueCaret(trigger.start + item.apply.length);
|
|
3477
|
+
}
|
|
3478
|
+
function queueCaret(pos) {
|
|
3479
|
+
requestAnimationFrame(() => {
|
|
3480
|
+
const el = ref.current;
|
|
3481
|
+
if (!el) return;
|
|
3482
|
+
el.focus();
|
|
3483
|
+
el.setSelectionRange(pos, pos);
|
|
3484
|
+
});
|
|
3485
|
+
}
|
|
3486
|
+
function format(kind) {
|
|
3487
|
+
const el = ref.current;
|
|
3488
|
+
if (!el) return;
|
|
3489
|
+
const start = el.selectionStart ?? 0;
|
|
3490
|
+
const end = el.selectionEnd ?? 0;
|
|
3491
|
+
const sel = value.slice(start, end);
|
|
3492
|
+
let replacement = sel;
|
|
3493
|
+
let caretOffset = 0;
|
|
3494
|
+
if (kind === "bold") replacement = `**${sel || "bold"}**`;
|
|
3495
|
+
else if (kind === "italic") replacement = `*${sel || "italic"}*`;
|
|
3496
|
+
else if (kind === "code") replacement = sel.includes("\n") ? `
|
|
3497
|
+
\`\`\`
|
|
3498
|
+
${sel}
|
|
3499
|
+
\`\`\`
|
|
3500
|
+
` : `\`${sel || "code"}\``;
|
|
3501
|
+
else if (kind === "link") {
|
|
3502
|
+
replacement = `[${sel || "text"}](url)`;
|
|
3503
|
+
caretOffset = replacement.length - 4;
|
|
3504
|
+
} else if (kind === "quote" || kind === "ul" || kind === "ol") {
|
|
3505
|
+
const prefix = kind === "quote" ? "> " : kind === "ul" ? "- " : "1. ";
|
|
3506
|
+
const block = (sel || "item").split("\n").map((l) => prefix + l).join("\n");
|
|
3507
|
+
replacement = (start > 0 && value[start - 1] !== "\n" ? "\n" : "") + block;
|
|
3508
|
+
}
|
|
3509
|
+
const next = value.slice(0, start) + replacement + value.slice(end);
|
|
3510
|
+
setValue(next);
|
|
3511
|
+
const caret = caretOffset ? start + caretOffset : start + replacement.length;
|
|
3512
|
+
queueCaret(caret);
|
|
3513
|
+
}
|
|
3514
|
+
function submit() {
|
|
3515
|
+
const text = value.trim();
|
|
3516
|
+
if (!text && pending.length === 0 || busy) return;
|
|
3517
|
+
onSubmit(text, pending.length ? pending : void 0);
|
|
3518
|
+
setValue("");
|
|
3519
|
+
setPending([]);
|
|
3520
|
+
setTrigger(null);
|
|
3521
|
+
}
|
|
3522
|
+
function onFiles(files) {
|
|
3523
|
+
if (!files) return;
|
|
3524
|
+
setPending((p) => [
|
|
3525
|
+
...p,
|
|
3526
|
+
...Array.from(files).map((f) => ({
|
|
3527
|
+
id: `${f.name}-${f.size}-${f.lastModified}`,
|
|
3528
|
+
name: f.name,
|
|
3529
|
+
url: URL.createObjectURL(f),
|
|
3530
|
+
type: f.type || "application/octet-stream",
|
|
3531
|
+
size: f.size
|
|
3532
|
+
}))
|
|
3533
|
+
]);
|
|
3534
|
+
}
|
|
3535
|
+
function onKeyDown(e) {
|
|
3536
|
+
if (menuOpen) {
|
|
3537
|
+
if (e.key === "ArrowDown") return e.preventDefault(), setActive((a) => (a + 1) % items.length);
|
|
3538
|
+
if (e.key === "ArrowUp") return e.preventDefault(), setActive((a) => (a - 1 + items.length) % items.length);
|
|
3539
|
+
if (e.key === "Enter" || e.key === "Tab") return e.preventDefault(), selectItem(active);
|
|
3540
|
+
if (e.key === "Escape") return e.preventDefault(), setTrigger(null);
|
|
3541
|
+
}
|
|
3542
|
+
const mod = e.metaKey || e.ctrlKey;
|
|
3543
|
+
if (mod && e.key.toLowerCase() === "b") return e.preventDefault(), format("bold");
|
|
3544
|
+
if (mod && e.key.toLowerCase() === "i") return e.preventDefault(), format("italic");
|
|
3545
|
+
if (mod && e.key.toLowerCase() === "e") return e.preventDefault(), format("code");
|
|
3546
|
+
if (mod && e.key.toLowerCase() === "k") return e.preventDefault(), format("link");
|
|
3547
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
3548
|
+
e.preventDefault();
|
|
3549
|
+
submit();
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
const toolbarBtn = (label, title, kind) => h(
|
|
3553
|
+
"button",
|
|
3554
|
+
{
|
|
3555
|
+
key: kind,
|
|
3556
|
+
type: "button",
|
|
3557
|
+
title,
|
|
3558
|
+
className: "rounded px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
3559
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3560
|
+
// keep textarea selection
|
|
3561
|
+
onClick: () => format(kind)
|
|
3562
|
+
},
|
|
3563
|
+
label
|
|
3564
|
+
);
|
|
3565
|
+
return h(
|
|
3566
|
+
"div",
|
|
3567
|
+
{ className: "border-t border-border" },
|
|
3568
|
+
// attachment chips
|
|
3569
|
+
pending.length > 0 ? h(
|
|
3570
|
+
"div",
|
|
3571
|
+
{ className: "flex flex-wrap gap-2 px-3 pt-2" },
|
|
3572
|
+
...pending.map(
|
|
3573
|
+
(a) => h(
|
|
3574
|
+
"span",
|
|
3575
|
+
{ key: a.id, className: "inline-flex items-center gap-1 rounded bg-muted px-2 py-0.5 text-xs" },
|
|
3576
|
+
a.name,
|
|
3577
|
+
h(
|
|
3578
|
+
"button",
|
|
3579
|
+
{
|
|
3580
|
+
type: "button",
|
|
3581
|
+
className: "text-muted-foreground hover:text-destructive",
|
|
3582
|
+
onClick: () => setPending((p) => p.filter((x) => x.id !== a.id))
|
|
3583
|
+
},
|
|
3584
|
+
"\u2715"
|
|
3585
|
+
)
|
|
3586
|
+
)
|
|
3587
|
+
)
|
|
3588
|
+
) : null,
|
|
3589
|
+
// toolbar
|
|
3590
|
+
toolbar ? h(
|
|
3591
|
+
"div",
|
|
3592
|
+
{ className: "flex items-center gap-0.5 px-2 pt-2" },
|
|
3593
|
+
toolbarBtn("B", "Bold (\u2318B)", "bold"),
|
|
3594
|
+
toolbarBtn("\u{1D456}", "Italic (\u2318I)", "italic"),
|
|
3595
|
+
toolbarBtn("</>", "Code (\u2318E)", "code"),
|
|
3596
|
+
toolbarBtn("\u{1F517}", "Link (\u2318K)", "link"),
|
|
3597
|
+
toolbarBtn("\u275D", "Quote", "quote"),
|
|
3598
|
+
toolbarBtn("\u2022", "Bulleted list", "ul"),
|
|
3599
|
+
toolbarBtn("1.", "Numbered list", "ol")
|
|
3600
|
+
) : null,
|
|
3601
|
+
// input row (relative for the popup menu)
|
|
3602
|
+
h(
|
|
3603
|
+
"div",
|
|
3604
|
+
{ className: "relative flex items-end gap-2 p-3" },
|
|
3605
|
+
menuOpen ? h(
|
|
3606
|
+
"div",
|
|
3607
|
+
{
|
|
3608
|
+
className: "absolute bottom-full left-3 z-20 mb-1 w-72 overflow-hidden rounded-lg border border-border bg-popover shadow-lg",
|
|
3609
|
+
role: "listbox"
|
|
3610
|
+
},
|
|
3611
|
+
h(
|
|
3612
|
+
"div",
|
|
3613
|
+
{ className: "border-b border-border px-2 py-1 text-[10px] uppercase tracking-wide text-muted-foreground" },
|
|
3614
|
+
trigger?.type === "/" ? "Commands" : trigger?.type === "@" ? "Mentions" : "Emoji"
|
|
3615
|
+
),
|
|
3616
|
+
...items.map(
|
|
3617
|
+
(it, i) => h(
|
|
3618
|
+
"button",
|
|
3619
|
+
{
|
|
3620
|
+
key: it.key,
|
|
3621
|
+
type: "button",
|
|
3622
|
+
role: "option",
|
|
3623
|
+
"aria-selected": i === active,
|
|
3624
|
+
className: cn(
|
|
3625
|
+
"flex w-full items-center gap-2 px-2 py-1.5 text-left text-sm",
|
|
3626
|
+
i === active ? "bg-accent" : "hover:bg-accent/50"
|
|
3627
|
+
),
|
|
3628
|
+
onMouseEnter: () => setActive(i),
|
|
3629
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3630
|
+
onClick: () => selectItem(i)
|
|
3631
|
+
},
|
|
3632
|
+
it.icon ? h("span", { className: "w-4 text-center text-muted-foreground" }, it.icon) : null,
|
|
3633
|
+
h("span", { className: "flex-1 truncate" }, it.primary),
|
|
3634
|
+
it.secondary ? h("span", { className: "truncate text-xs text-muted-foreground" }, it.secondary) : null
|
|
3635
|
+
)
|
|
3636
|
+
)
|
|
3637
|
+
) : null,
|
|
3638
|
+
attachments ? h(
|
|
3639
|
+
React11.Fragment,
|
|
3640
|
+
null,
|
|
3641
|
+
h("input", {
|
|
3642
|
+
ref: fileRef,
|
|
3643
|
+
type: "file",
|
|
3644
|
+
accept: "image/*",
|
|
3645
|
+
multiple: true,
|
|
3646
|
+
className: "hidden",
|
|
3647
|
+
onChange: (e) => {
|
|
3648
|
+
onFiles(e.target.files);
|
|
3649
|
+
e.target.value = "";
|
|
3650
|
+
}
|
|
3651
|
+
}),
|
|
3652
|
+
h(
|
|
3653
|
+
"button",
|
|
3654
|
+
{
|
|
3655
|
+
type: "button",
|
|
3656
|
+
className: "rounded-md border border-border px-2 py-2 text-sm hover:bg-accent",
|
|
3657
|
+
"aria-label": "Attach image or GIF",
|
|
3658
|
+
onClick: () => fileRef.current?.click()
|
|
3659
|
+
},
|
|
3660
|
+
"\u{1F4CE}"
|
|
3661
|
+
)
|
|
3662
|
+
) : null,
|
|
3663
|
+
h("textarea", {
|
|
3664
|
+
ref,
|
|
3665
|
+
className: "max-h-40 flex-1 resize-none rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
|
|
3666
|
+
rows: 1,
|
|
3667
|
+
value,
|
|
3668
|
+
placeholder,
|
|
3669
|
+
autoFocus,
|
|
3670
|
+
"aria-label": "Message",
|
|
3671
|
+
onChange: (e) => syncFromTextarea(e.target),
|
|
3672
|
+
onClick: (e) => syncFromTextarea(e.currentTarget),
|
|
3673
|
+
onKeyUp: (e) => syncFromTextarea(e.currentTarget),
|
|
3674
|
+
onKeyDown,
|
|
3675
|
+
onBlur: () => setTimeout(() => setTrigger(null), 120)
|
|
3676
|
+
}),
|
|
3677
|
+
busy ? h(
|
|
3678
|
+
"button",
|
|
3679
|
+
{
|
|
3680
|
+
type: "button",
|
|
3681
|
+
className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground",
|
|
3682
|
+
onClick: () => onStop?.()
|
|
3683
|
+
},
|
|
3684
|
+
"Stop"
|
|
3685
|
+
) : h(
|
|
3686
|
+
"button",
|
|
3687
|
+
{
|
|
3688
|
+
type: "button",
|
|
3689
|
+
className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50",
|
|
3690
|
+
disabled: !value.trim() && pending.length === 0,
|
|
3691
|
+
onClick: submit
|
|
3692
|
+
},
|
|
3693
|
+
"Send"
|
|
3694
|
+
)
|
|
3695
|
+
)
|
|
3696
|
+
);
|
|
3697
|
+
}
|
|
3698
|
+
var h2 = React11.createElement;
|
|
3699
|
+
var QUICK_EMOJIS = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F389}", "\u{1F440}", "\u{1F64F}"];
|
|
3700
|
+
var chatMd = cn(
|
|
3701
|
+
"max-w-none text-sm",
|
|
3702
|
+
"[&_p]:my-1 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0",
|
|
3703
|
+
"[&_pre]:my-2 [&_pre]:rounded-md [&_pre]:text-xs [&_pre]:leading-relaxed",
|
|
3704
|
+
"[&_ul]:my-1 [&_ol]:my-1 [&_li]:my-0.5",
|
|
3705
|
+
"[&_h1]:text-base [&_h1]:font-semibold [&_h1]:mt-2 [&_h1]:mb-1",
|
|
3706
|
+
"[&_h2]:text-sm [&_h2]:font-semibold [&_h2]:mt-2 [&_h2]:mb-1",
|
|
3707
|
+
"[&_h3]:text-sm [&_h3]:font-semibold",
|
|
3708
|
+
"[&_blockquote]:my-1 [&_blockquote]:border-l-2 [&_blockquote]:pl-2 [&_blockquote]:not-italic [&_blockquote]:text-muted-foreground",
|
|
3709
|
+
"[&_img]:my-1 [&_img]:max-h-60 [&_img]:rounded-md",
|
|
3710
|
+
"[&_code]:text-[0.85em]"
|
|
3711
|
+
);
|
|
3712
|
+
function Avatar({ name, avatarUrl, size = 8 }) {
|
|
3713
|
+
return h2(
|
|
3714
|
+
"div",
|
|
3715
|
+
{
|
|
3716
|
+
className: cn(
|
|
3717
|
+
"flex-shrink-0 overflow-hidden rounded-full bg-muted flex items-center justify-center text-xs font-medium",
|
|
3718
|
+
size === 8 ? "h-8 w-8" : "h-7 w-7"
|
|
3719
|
+
)
|
|
3720
|
+
},
|
|
3721
|
+
avatarUrl ? h2("img", { src: avatarUrl, alt: name, className: "h-full w-full object-cover" }) : (name.charAt(0) || "?").toUpperCase()
|
|
3722
|
+
);
|
|
3723
|
+
}
|
|
3724
|
+
function TypingDots() {
|
|
3725
|
+
return h2(
|
|
3726
|
+
"div",
|
|
3727
|
+
{ className: "flex items-center gap-1 py-1.5", "aria-label": "Assistant is typing" },
|
|
3728
|
+
...[0, 150, 300].map(
|
|
3729
|
+
(delay) => h2("span", {
|
|
3730
|
+
key: delay,
|
|
3731
|
+
className: "h-1.5 w-1.5 rounded-full bg-muted-foreground/60 animate-bounce",
|
|
3732
|
+
style: { animationDelay: `${delay}ms` }
|
|
3733
|
+
})
|
|
3734
|
+
)
|
|
3735
|
+
);
|
|
3736
|
+
}
|
|
3737
|
+
function Attachments({ attachments }) {
|
|
3738
|
+
return h2(
|
|
3739
|
+
"div",
|
|
3740
|
+
{ className: "mt-2 flex flex-wrap gap-2" },
|
|
3741
|
+
...attachments.map(
|
|
3742
|
+
(a) => a.type.startsWith("image/") ? h2("img", { key: a.id, src: a.url, alt: a.name, className: "max-h-60 rounded-md border border-border object-contain" }) : h2(
|
|
3743
|
+
"a",
|
|
3744
|
+
{
|
|
3745
|
+
key: a.id,
|
|
3746
|
+
href: a.url,
|
|
3747
|
+
target: "_blank",
|
|
3748
|
+
rel: "noreferrer",
|
|
3749
|
+
className: "inline-flex items-center gap-2 rounded-md border border-border bg-background/60 px-2 py-1 text-xs"
|
|
3750
|
+
},
|
|
3751
|
+
"\u{1F4CE} ",
|
|
3752
|
+
a.name
|
|
3753
|
+
)
|
|
3754
|
+
)
|
|
3755
|
+
);
|
|
3756
|
+
}
|
|
3757
|
+
function MessageBody({ message }) {
|
|
3758
|
+
if (message.status === "streaming" && message.content === "") return h2(TypingDots);
|
|
3759
|
+
return h2(
|
|
3760
|
+
React11.Fragment,
|
|
3761
|
+
null,
|
|
3762
|
+
message.content ? h2(MarkdownRenderer, { content: message.content, size: "sm", className: chatMd }) : null,
|
|
3763
|
+
message.attachments && message.attachments.length > 0 ? h2(Attachments, { attachments: message.attachments }) : null,
|
|
3764
|
+
message.status === "error" ? h2("div", { className: "mt-1 text-xs text-destructive", role: "alert" }, message.error ?? "Failed to send.") : null
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3767
|
+
function Reactions({ message, onReact, align }) {
|
|
3768
|
+
if (!message.reactions || message.reactions.length === 0) return null;
|
|
3769
|
+
return h2(
|
|
3770
|
+
"div",
|
|
3771
|
+
{ className: cn("mt-1 flex flex-wrap gap-1", align === "end" && "justify-end") },
|
|
3772
|
+
...message.reactions.map(
|
|
3773
|
+
(r) => h2(
|
|
3774
|
+
"button",
|
|
3775
|
+
{
|
|
3776
|
+
key: r.emoji,
|
|
3777
|
+
type: "button",
|
|
3778
|
+
onClick: () => onReact(r.emoji),
|
|
3779
|
+
className: cn(
|
|
3780
|
+
"inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-xs",
|
|
3781
|
+
r.userReacted ? "border-primary bg-primary/10" : "border-border bg-background"
|
|
3782
|
+
)
|
|
3783
|
+
},
|
|
3784
|
+
`${r.emoji} ${r.count}`
|
|
3785
|
+
)
|
|
3786
|
+
)
|
|
3787
|
+
);
|
|
3788
|
+
}
|
|
3789
|
+
function QuotedParent({ parent, onClick }) {
|
|
3790
|
+
const snippet = parent.content.length > 80 ? `${parent.content.slice(0, 80)}\u2026` : parent.content;
|
|
3791
|
+
return h2(
|
|
3792
|
+
"button",
|
|
3793
|
+
{
|
|
3794
|
+
type: "button",
|
|
3795
|
+
onClick,
|
|
3796
|
+
className: "mb-1 flex max-w-full items-start gap-2 rounded-md border-l-2 border-primary/50 bg-muted/50 px-2 py-1 text-left text-xs text-muted-foreground hover:bg-muted"
|
|
3797
|
+
},
|
|
3798
|
+
h2("span", { className: "font-medium" }, parent.author.name),
|
|
3799
|
+
h2("span", { className: "truncate" }, snippet)
|
|
3800
|
+
);
|
|
3801
|
+
}
|
|
3802
|
+
function HoverActions({
|
|
3803
|
+
message,
|
|
3804
|
+
conversation,
|
|
3805
|
+
isOwn,
|
|
3806
|
+
onEdit,
|
|
3807
|
+
onToggleEmojis,
|
|
3808
|
+
align
|
|
3809
|
+
}) {
|
|
3810
|
+
const { state, openThread, deleteMessage } = conversation;
|
|
3811
|
+
return h2(
|
|
3812
|
+
"div",
|
|
3813
|
+
{
|
|
3814
|
+
className: cn(
|
|
3815
|
+
"mt-1 flex items-center gap-3 text-xs text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
|
|
3816
|
+
align === "end" && "justify-end"
|
|
3817
|
+
)
|
|
3818
|
+
},
|
|
3819
|
+
h2("button", { type: "button", className: "hover:text-foreground", onClick: () => openThread(rootIdOf(state.messages, message.id)) }, "Reply"),
|
|
3820
|
+
h2("button", { type: "button", className: "hover:text-foreground", onClick: onToggleEmojis }, "React"),
|
|
3821
|
+
isOwn ? h2("button", { type: "button", className: "hover:text-foreground", onClick: onEdit }, "Edit") : null,
|
|
3822
|
+
isOwn ? h2("button", { type: "button", className: "hover:text-destructive", onClick: () => deleteMessage(message.id) }, "Delete") : null
|
|
3823
|
+
);
|
|
3824
|
+
}
|
|
3825
|
+
function EmojiRow({ onPick, align }) {
|
|
3826
|
+
return h2(
|
|
3827
|
+
"div",
|
|
3828
|
+
{ className: cn("mt-1 flex gap-1", align === "end" && "justify-end") },
|
|
3829
|
+
...QUICK_EMOJIS.map(
|
|
3830
|
+
(emoji) => h2("button", { key: emoji, type: "button", className: "rounded px-1 text-base hover:bg-accent", onClick: () => onPick(emoji) }, emoji)
|
|
3831
|
+
)
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3834
|
+
function EditField({ message, conversation, onDone }) {
|
|
3835
|
+
const [draft, setDraft] = React11.useState(message.content);
|
|
3836
|
+
function save() {
|
|
3837
|
+
const t = draft.trim();
|
|
3838
|
+
if (t && t !== message.content) conversation.editMessage(message.id, t);
|
|
3839
|
+
onDone();
|
|
3840
|
+
}
|
|
3841
|
+
return h2(
|
|
3842
|
+
"div",
|
|
3843
|
+
{ className: "mt-1" },
|
|
3844
|
+
h2("textarea", {
|
|
3845
|
+
className: "w-full resize-none rounded-md border border-border bg-background px-2 py-1 text-sm",
|
|
3846
|
+
value: draft,
|
|
3847
|
+
autoFocus: true,
|
|
3848
|
+
onChange: (e) => setDraft(e.target.value),
|
|
3849
|
+
onKeyDown: (e) => {
|
|
3850
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
3851
|
+
e.preventDefault();
|
|
3852
|
+
save();
|
|
3853
|
+
}
|
|
3854
|
+
if (e.key === "Escape") onDone();
|
|
3855
|
+
}
|
|
3856
|
+
}),
|
|
3857
|
+
h2(
|
|
3858
|
+
"div",
|
|
3859
|
+
{ className: "mt-1 flex gap-2 text-xs" },
|
|
3860
|
+
h2("button", { type: "button", className: "text-primary", onClick: save }, "Save"),
|
|
3861
|
+
h2("button", { type: "button", className: "text-muted-foreground", onClick: onDone }, "Cancel")
|
|
3862
|
+
)
|
|
3863
|
+
);
|
|
3864
|
+
}
|
|
3865
|
+
function MessageRow({
|
|
3866
|
+
message,
|
|
3867
|
+
conversation,
|
|
3868
|
+
currentUserId,
|
|
3869
|
+
showThreadAffordance,
|
|
3870
|
+
quotedParent
|
|
3871
|
+
}) {
|
|
3872
|
+
const { state, react, openThread } = conversation;
|
|
3873
|
+
const [showEmojis, setShowEmojis] = React11.useState(false);
|
|
3874
|
+
const [editing, setEditing] = React11.useState(false);
|
|
3875
|
+
const isUser = currentUserId ? message.author.id === currentUserId : message.role === "user";
|
|
3876
|
+
const replyCount = getReplyCount(state.messages, message.id);
|
|
3877
|
+
const align = isUser ? "end" : "start";
|
|
3878
|
+
const inner = h2(
|
|
3879
|
+
React11.Fragment,
|
|
3880
|
+
null,
|
|
3881
|
+
quotedParent ? h2(QuotedParent, { parent: quotedParent, onClick: () => openThread(quotedParent.id) }) : null,
|
|
3882
|
+
editing ? h2(EditField, { message, conversation, onDone: () => setEditing(false) }) : isUser ? h2("div", { className: "inline-block rounded-2xl rounded-br-sm bg-primary/10 px-3 py-2 text-left" }, h2(MessageBody, { message })) : h2(MessageBody, { message }),
|
|
3883
|
+
h2(Reactions, { message, onReact: (e) => react(message.id, e), align }),
|
|
3884
|
+
showThreadAffordance && replyCount > 0 ? h2(
|
|
3885
|
+
"button",
|
|
3886
|
+
{ type: "button", className: cn("mt-1 text-xs font-medium text-primary hover:underline", align === "end" && "self-end"), onClick: () => openThread(message.id) },
|
|
3887
|
+
`\u{1F4AC} ${replyCount} ${replyCount === 1 ? "reply" : "replies"}`
|
|
3888
|
+
) : null,
|
|
3889
|
+
h2(HoverActions, { message, conversation, isOwn: isUser, onEdit: () => setEditing(true), onToggleEmojis: () => setShowEmojis((v) => !v), align }),
|
|
3890
|
+
showEmojis ? h2(EmojiRow, {
|
|
3891
|
+
onPick: (e) => {
|
|
3892
|
+
react(message.id, e);
|
|
3893
|
+
setShowEmojis(false);
|
|
3894
|
+
},
|
|
3895
|
+
align
|
|
3896
|
+
}) : null
|
|
3897
|
+
);
|
|
3898
|
+
if (!isUser) {
|
|
3899
|
+
return h2(
|
|
3900
|
+
"div",
|
|
3901
|
+
{ className: "group flex gap-3 rounded-md px-3 py-2 hover:bg-accent/30", role: "article", "aria-label": `Message from ${message.author.name}`, "data-message-id": message.id },
|
|
3902
|
+
h2(Avatar, { name: message.author.name, avatarUrl: message.author.avatarUrl }),
|
|
3903
|
+
h2(
|
|
3904
|
+
"div",
|
|
3905
|
+
{ className: "min-w-0 flex-1" },
|
|
3906
|
+
h2(
|
|
3907
|
+
"div",
|
|
3908
|
+
{ className: "flex items-baseline gap-2" },
|
|
3909
|
+
h2("span", { className: "text-sm font-semibold" }, message.author.name),
|
|
3910
|
+
h2("span", { className: "text-xs text-muted-foreground", title: message.timestamp.toLocaleString() }, formatTimestamp(message.timestamp)),
|
|
3911
|
+
message.edited ? h2("span", { className: "text-xs text-muted-foreground" }, "(edited)") : null
|
|
3912
|
+
),
|
|
3913
|
+
inner
|
|
3914
|
+
)
|
|
3915
|
+
);
|
|
3916
|
+
}
|
|
3917
|
+
return h2(
|
|
3918
|
+
"div",
|
|
3919
|
+
{ className: "group flex flex-col items-end px-3 py-1.5", role: "article", "aria-label": `Message from ${message.author.name}`, "data-message-id": message.id },
|
|
3920
|
+
h2(
|
|
3921
|
+
"div",
|
|
3922
|
+
{ className: "flex items-baseline gap-2" },
|
|
3923
|
+
message.edited ? h2("span", { className: "text-xs text-muted-foreground" }, "(edited)") : null,
|
|
3924
|
+
h2("span", { className: "text-xs text-muted-foreground", title: message.timestamp.toLocaleString() }, formatTimestamp(message.timestamp)),
|
|
3925
|
+
h2("span", { className: "text-sm font-semibold" }, message.author.name)
|
|
3926
|
+
),
|
|
3927
|
+
h2("div", { className: "mt-0.5 flex max-w-[80%] flex-col items-end" }, inner)
|
|
3928
|
+
);
|
|
3929
|
+
}
|
|
3930
|
+
function ConversationSidebar({ conversation }) {
|
|
3931
|
+
const { state, newConversation, selectConversation, deleteConversation } = conversation;
|
|
3932
|
+
return h2(
|
|
3933
|
+
"aside",
|
|
3934
|
+
{ className: "flex w-56 flex-col gap-1 overflow-y-auto border-r border-border bg-muted/20 p-2", "aria-label": "Conversations" },
|
|
3935
|
+
h2(
|
|
3936
|
+
"button",
|
|
3937
|
+
{ type: "button", className: "mb-1 w-full rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90", onClick: () => newConversation() },
|
|
3938
|
+
"+ New chat"
|
|
3939
|
+
),
|
|
3940
|
+
...state.conversations.map(
|
|
3941
|
+
(conv) => h2(
|
|
3942
|
+
"div",
|
|
3943
|
+
{
|
|
3944
|
+
key: conv.id,
|
|
3945
|
+
role: "button",
|
|
3946
|
+
"aria-current": conv.id === state.activeConversationId,
|
|
3947
|
+
onClick: () => selectConversation(conv.id),
|
|
3948
|
+
className: cn(
|
|
3949
|
+
"group flex items-center justify-between gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-accent/60",
|
|
3950
|
+
conv.id === state.activeConversationId && "bg-accent font-medium"
|
|
3951
|
+
)
|
|
3952
|
+
},
|
|
3953
|
+
h2(
|
|
3954
|
+
"div",
|
|
3955
|
+
{ className: "min-w-0" },
|
|
3956
|
+
h2("div", { className: "truncate" }, conv.title),
|
|
3957
|
+
h2("div", { className: "truncate text-xs text-muted-foreground" }, formatRelativeTime(conv.updatedAt))
|
|
3958
|
+
),
|
|
3959
|
+
h2(
|
|
3960
|
+
"button",
|
|
3961
|
+
{
|
|
3962
|
+
type: "button",
|
|
3963
|
+
className: "text-xs text-muted-foreground opacity-0 hover:text-destructive group-hover:opacity-100",
|
|
3964
|
+
"aria-label": `Delete ${conv.title}`,
|
|
3965
|
+
onClick: (e) => {
|
|
3966
|
+
e.stopPropagation();
|
|
3967
|
+
deleteConversation(conv.id);
|
|
3968
|
+
}
|
|
3969
|
+
},
|
|
3970
|
+
"\u2715"
|
|
3971
|
+
)
|
|
3972
|
+
)
|
|
3973
|
+
)
|
|
3974
|
+
);
|
|
3975
|
+
}
|
|
3976
|
+
function ThreadPanel({ conversation, currentUserId, composer }) {
|
|
3977
|
+
const { state } = conversation;
|
|
3978
|
+
const rootId = state.openThreadRootId;
|
|
3979
|
+
if (!rootId) return null;
|
|
3980
|
+
const messages = selectThreadMessages(state.messages, rootId);
|
|
3981
|
+
return h2(
|
|
3982
|
+
"aside",
|
|
3983
|
+
{ className: "flex w-80 flex-col border-l border-border", "aria-label": "Thread" },
|
|
3984
|
+
h2(
|
|
3985
|
+
"div",
|
|
3986
|
+
{ className: "flex items-center justify-between border-b border-border px-3 py-2" },
|
|
3987
|
+
h2("span", { className: "text-sm font-semibold" }, "Thread"),
|
|
3988
|
+
h2("button", { type: "button", className: "text-muted-foreground hover:text-foreground", "aria-label": "Close thread", onClick: () => conversation.closeThread() }, "\u2715")
|
|
3989
|
+
),
|
|
3990
|
+
h2(
|
|
3991
|
+
"div",
|
|
3992
|
+
{ className: "flex-1 overflow-y-auto p-1" },
|
|
3993
|
+
...messages.map((m) => h2(MessageRow, { key: m.id, message: m, conversation, currentUserId, showThreadAffordance: false }))
|
|
3994
|
+
),
|
|
3995
|
+
composer
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
function ModeToggle({ conversation }) {
|
|
3999
|
+
const { state, setThreadingMode } = conversation;
|
|
4000
|
+
const opt = (mode, label) => h2(
|
|
4001
|
+
"button",
|
|
4002
|
+
{
|
|
4003
|
+
type: "button",
|
|
4004
|
+
onClick: () => setThreadingMode(mode),
|
|
4005
|
+
className: cn("rounded px-2 py-0.5 text-xs", state.threadingMode === mode ? "bg-background shadow-sm" : "text-muted-foreground")
|
|
4006
|
+
},
|
|
4007
|
+
label
|
|
4008
|
+
);
|
|
4009
|
+
return h2(
|
|
4010
|
+
"div",
|
|
4011
|
+
{ className: "inline-flex rounded-md bg-muted p-0.5", role: "group", "aria-label": "Threading mode" },
|
|
4012
|
+
opt("inline", "Inline"),
|
|
4013
|
+
opt("panel", "Threads")
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
4016
|
+
function Chat({
|
|
4017
|
+
conversation,
|
|
4018
|
+
showConversationList = true,
|
|
4019
|
+
showModeToggle = true,
|
|
4020
|
+
placeholder,
|
|
4021
|
+
currentUserId,
|
|
4022
|
+
emptyState,
|
|
4023
|
+
className,
|
|
4024
|
+
slashCommands,
|
|
4025
|
+
mentions,
|
|
4026
|
+
onSlashCommand,
|
|
4027
|
+
composerToolbar = true
|
|
4028
|
+
}) {
|
|
4029
|
+
const { state, sendMessage } = conversation;
|
|
4030
|
+
const timeline = selectMainTimeline(state.messages, state.threadingMode);
|
|
4031
|
+
const activeConv = state.conversations.find((c) => c.id === state.activeConversationId);
|
|
4032
|
+
const busy = state.status === "sending" || state.status === "streaming";
|
|
4033
|
+
const mainComposer = h2(Composer, {
|
|
4034
|
+
placeholder,
|
|
4035
|
+
busy,
|
|
4036
|
+
slashCommands,
|
|
4037
|
+
mentions,
|
|
4038
|
+
onSlashCommand,
|
|
4039
|
+
toolbar: composerToolbar,
|
|
4040
|
+
onSubmit: (content, atts) => void sendMessage(content, { attachments: atts }),
|
|
4041
|
+
onStop: () => conversation.stop()
|
|
4042
|
+
});
|
|
4043
|
+
const threadComposer = state.openThreadRootId ? h2(Composer, {
|
|
4044
|
+
placeholder: "Reply\u2026",
|
|
4045
|
+
busy,
|
|
4046
|
+
slashCommands,
|
|
4047
|
+
mentions,
|
|
4048
|
+
onSlashCommand,
|
|
4049
|
+
toolbar: composerToolbar,
|
|
4050
|
+
onSubmit: (content, atts) => void sendMessage(content, { replyTo: state.openThreadRootId, attachments: atts }),
|
|
4051
|
+
onStop: () => conversation.stop()
|
|
4052
|
+
}) : null;
|
|
4053
|
+
const body = timeline.length === 0 ? h2("div", { className: "flex flex-1 items-center justify-center p-6 text-sm text-muted-foreground" }, emptyState ?? "No messages yet. Say hello \u{1F44B}") : h2(
|
|
4054
|
+
"div",
|
|
4055
|
+
{ className: "flex-1 space-y-0.5 overflow-y-auto p-2" },
|
|
4056
|
+
...timeline.map(
|
|
4057
|
+
(m) => h2(MessageRow, {
|
|
4058
|
+
key: m.id,
|
|
4059
|
+
message: m,
|
|
4060
|
+
conversation,
|
|
4061
|
+
currentUserId,
|
|
4062
|
+
showThreadAffordance: state.threadingMode === "panel",
|
|
4063
|
+
quotedParent: state.threadingMode === "inline" && m.parentId ? findMessage(state.messages, m.parentId) : void 0
|
|
4064
|
+
})
|
|
4065
|
+
)
|
|
4066
|
+
);
|
|
4067
|
+
return h2(
|
|
4068
|
+
"div",
|
|
4069
|
+
{ className: cn("flex h-full min-h-0 overflow-hidden rounded-xl border border-border bg-background", className) },
|
|
4070
|
+
showConversationList ? h2(ConversationSidebar, { conversation }) : null,
|
|
4071
|
+
h2(
|
|
4072
|
+
"div",
|
|
4073
|
+
{ className: "flex min-w-0 flex-1 flex-col" },
|
|
4074
|
+
h2(
|
|
4075
|
+
"div",
|
|
4076
|
+
{ className: "flex items-center justify-between border-b border-border px-3 py-2" },
|
|
4077
|
+
h2("span", { className: "truncate text-sm font-semibold" }, activeConv?.title ?? "Chat"),
|
|
4078
|
+
showModeToggle ? h2(ModeToggle, { conversation }) : null
|
|
4079
|
+
),
|
|
4080
|
+
body,
|
|
4081
|
+
mainComposer
|
|
4082
|
+
),
|
|
4083
|
+
h2(ThreadPanel, { conversation, currentUserId, composer: threadComposer })
|
|
4084
|
+
);
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4087
|
+
// ../content-protection/dist/index.js
|
|
4088
|
+
function createContentProtection(props = {}) {
|
|
4089
|
+
const {
|
|
4090
|
+
enabled = true,
|
|
4091
|
+
disableCopy = true,
|
|
4092
|
+
disableContextMenu = true,
|
|
4093
|
+
watermarkText
|
|
4094
|
+
} = props;
|
|
4095
|
+
const eventHandlers = {};
|
|
4096
|
+
if (enabled) {
|
|
4097
|
+
if (disableCopy) {
|
|
4098
|
+
const prevent = (e) => e.preventDefault();
|
|
4099
|
+
eventHandlers.onCopy = prevent;
|
|
4100
|
+
eventHandlers.onCut = prevent;
|
|
4101
|
+
eventHandlers.onSelectStart = prevent;
|
|
4102
|
+
}
|
|
4103
|
+
if (disableContextMenu) {
|
|
4104
|
+
eventHandlers.onContextMenu = (e) => e.preventDefault();
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
const watermarkConfig = watermarkText ? { text: watermarkText, opacity: 0.08, angle: -45 } : null;
|
|
4108
|
+
const dataAttributes = {};
|
|
4109
|
+
if (enabled) {
|
|
4110
|
+
dataAttributes["data-protected"] = "true";
|
|
4111
|
+
}
|
|
4112
|
+
return {
|
|
4113
|
+
eventHandlers,
|
|
4114
|
+
watermarkConfig,
|
|
4115
|
+
dataAttributes
|
|
4116
|
+
};
|
|
4117
|
+
}
|
|
4118
|
+
var contentProtectionVariants = cva({
|
|
4119
|
+
base: "relative select-none"
|
|
4120
|
+
});
|
|
4121
|
+
var watermarkVariants = cva({
|
|
4122
|
+
base: "pointer-events-none absolute inset-0 z-50 overflow-hidden"
|
|
4123
|
+
});
|
|
4124
|
+
var ContentProtection = React11.forwardRef(
|
|
4125
|
+
({
|
|
4126
|
+
enabled,
|
|
4127
|
+
disableCopy,
|
|
4128
|
+
disableContextMenu,
|
|
4129
|
+
watermarkText,
|
|
4130
|
+
className,
|
|
4131
|
+
children,
|
|
4132
|
+
...props
|
|
4133
|
+
}, ref) => {
|
|
4134
|
+
const api = createContentProtection({
|
|
4135
|
+
enabled,
|
|
4136
|
+
disableCopy,
|
|
4137
|
+
disableContextMenu,
|
|
4138
|
+
watermarkText
|
|
4139
|
+
});
|
|
4140
|
+
const classes = cn(contentProtectionVariants(), className);
|
|
4141
|
+
return /* @__PURE__ */ jsxs(
|
|
4142
|
+
"div",
|
|
4143
|
+
{
|
|
4144
|
+
ref,
|
|
4145
|
+
className: classes,
|
|
4146
|
+
...api.dataAttributes,
|
|
4147
|
+
onCopy: api.eventHandlers.onCopy,
|
|
4148
|
+
onCut: api.eventHandlers.onCut,
|
|
4149
|
+
onContextMenu: api.eventHandlers.onContextMenu,
|
|
4150
|
+
onSelect: api.eventHandlers.onSelectStart,
|
|
4151
|
+
...props,
|
|
4152
|
+
children: [
|
|
4153
|
+
children,
|
|
4154
|
+
api.watermarkConfig && /* @__PURE__ */ jsx(
|
|
4155
|
+
"div",
|
|
4156
|
+
{
|
|
4157
|
+
className: watermarkVariants(),
|
|
4158
|
+
"aria-hidden": "true",
|
|
4159
|
+
style: {
|
|
4160
|
+
opacity: api.watermarkConfig.opacity,
|
|
4161
|
+
transform: `rotate(${api.watermarkConfig.angle}deg)`,
|
|
4162
|
+
backgroundImage: `repeating-linear-gradient(
|
|
4163
|
+
${api.watermarkConfig.angle}deg,
|
|
4164
|
+
transparent,
|
|
4165
|
+
transparent 80px,
|
|
4166
|
+
currentColor 80px,
|
|
4167
|
+
currentColor 80px
|
|
4168
|
+
)`
|
|
4169
|
+
},
|
|
4170
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", children: [
|
|
4171
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
|
|
4172
|
+
"pattern",
|
|
4173
|
+
{
|
|
4174
|
+
id: "rfr-watermark",
|
|
4175
|
+
x: "0",
|
|
4176
|
+
y: "0",
|
|
4177
|
+
width: "200",
|
|
4178
|
+
height: "200",
|
|
4179
|
+
patternUnits: "userSpaceOnUse",
|
|
4180
|
+
patternTransform: `rotate(${api.watermarkConfig.angle})`,
|
|
4181
|
+
children: /* @__PURE__ */ jsx(
|
|
4182
|
+
"text",
|
|
4183
|
+
{
|
|
4184
|
+
x: "0",
|
|
4185
|
+
y: "100",
|
|
4186
|
+
fill: "currentColor",
|
|
4187
|
+
fontSize: "16",
|
|
4188
|
+
fontFamily: "sans-serif",
|
|
4189
|
+
children: api.watermarkConfig.text
|
|
4190
|
+
}
|
|
4191
|
+
)
|
|
4192
|
+
}
|
|
4193
|
+
) }),
|
|
4194
|
+
/* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: "url(#rfr-watermark)" })
|
|
4195
|
+
] })
|
|
4196
|
+
}
|
|
4197
|
+
)
|
|
4198
|
+
]
|
|
4199
|
+
}
|
|
4200
|
+
);
|
|
4201
|
+
}
|
|
4202
|
+
);
|
|
4203
|
+
ContentProtection.displayName = "ContentProtection";
|
|
4204
|
+
|
|
4205
|
+
// ../cookie-consent/dist/index.js
|
|
4206
|
+
var DEFAULT_KEY = "rfr-cookie-consent";
|
|
4207
|
+
var DEFAULT_CATEGORIES = [
|
|
4208
|
+
{ id: "necessary", label: "Strictly necessary", description: "Required for the site to function. Always on.", required: true },
|
|
4209
|
+
{ id: "preferences", label: "Preferences", description: "Remembers your settings and choices." },
|
|
4210
|
+
{ id: "analytics", label: "Analytics", description: "Helps us understand how the site is used." },
|
|
4211
|
+
{ id: "marketing", label: "Marketing", description: "Used to personalize ads and measure campaigns." }
|
|
4212
|
+
];
|
|
4213
|
+
function baseline(categories) {
|
|
4214
|
+
const p = {};
|
|
4215
|
+
for (const c of categories) p[c.id] = !!c.required;
|
|
4216
|
+
return p;
|
|
4217
|
+
}
|
|
4218
|
+
function createCookieConsent(config = {}) {
|
|
4219
|
+
const categories = config.categories ?? DEFAULT_CATEGORIES;
|
|
4220
|
+
const storage = config.storage;
|
|
4221
|
+
const key = config.storageKey ?? DEFAULT_KEY;
|
|
4222
|
+
const version = config.version;
|
|
4223
|
+
let preferences = baseline(categories);
|
|
4224
|
+
let consented = false;
|
|
4225
|
+
const raw = storage?.get(key) ?? null;
|
|
4226
|
+
if (raw) {
|
|
4227
|
+
try {
|
|
4228
|
+
const parsed = JSON.parse(raw);
|
|
4229
|
+
if ((parsed.version ?? void 0) === version) {
|
|
4230
|
+
preferences = { ...baseline(categories), ...parsed.preferences };
|
|
4231
|
+
for (const c of categories) if (c.required) preferences[c.id] = true;
|
|
4232
|
+
consented = true;
|
|
4233
|
+
}
|
|
4234
|
+
} catch {
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
let open = !consented;
|
|
4238
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4239
|
+
let snapshot = build();
|
|
4240
|
+
function build() {
|
|
4241
|
+
return { consented, preferences: { ...preferences }, open, categories };
|
|
4242
|
+
}
|
|
4243
|
+
function emit() {
|
|
4244
|
+
snapshot = build();
|
|
4245
|
+
for (const l of listeners) l();
|
|
4246
|
+
}
|
|
4247
|
+
function persist() {
|
|
4248
|
+
storage?.set(key, JSON.stringify({ version, preferences }));
|
|
4249
|
+
config.onChange?.({ ...preferences });
|
|
4250
|
+
}
|
|
4251
|
+
function save(next) {
|
|
4252
|
+
const merged = { ...baseline(categories), ...next };
|
|
4253
|
+
for (const c of categories) if (c.required) merged[c.id] = true;
|
|
4254
|
+
preferences = merged;
|
|
4255
|
+
consented = true;
|
|
4256
|
+
open = false;
|
|
4257
|
+
persist();
|
|
4258
|
+
emit();
|
|
4259
|
+
}
|
|
4260
|
+
return {
|
|
4261
|
+
getState() {
|
|
4262
|
+
return snapshot;
|
|
4263
|
+
},
|
|
4264
|
+
subscribe(listener) {
|
|
4265
|
+
listeners.add(listener);
|
|
4266
|
+
return () => listeners.delete(listener);
|
|
4267
|
+
},
|
|
4268
|
+
acceptAll() {
|
|
4269
|
+
const all = {};
|
|
4270
|
+
for (const c of categories) all[c.id] = true;
|
|
4271
|
+
save(all);
|
|
4272
|
+
},
|
|
4273
|
+
rejectAll() {
|
|
4274
|
+
save(baseline(categories));
|
|
4275
|
+
},
|
|
4276
|
+
savePreferences(prefs) {
|
|
4277
|
+
save(prefs);
|
|
4278
|
+
},
|
|
4279
|
+
setPreference(id, value) {
|
|
4280
|
+
const cat = categories.find((c) => c.id === id);
|
|
4281
|
+
if (!cat || cat.required) return;
|
|
4282
|
+
preferences = { ...preferences, [id]: value };
|
|
4283
|
+
emit();
|
|
4284
|
+
},
|
|
4285
|
+
reset() {
|
|
4286
|
+
storage?.remove(key);
|
|
4287
|
+
preferences = baseline(categories);
|
|
4288
|
+
consented = false;
|
|
4289
|
+
open = true;
|
|
4290
|
+
emit();
|
|
4291
|
+
},
|
|
4292
|
+
openSettings() {
|
|
4293
|
+
if (open) return;
|
|
4294
|
+
open = true;
|
|
4295
|
+
emit();
|
|
4296
|
+
},
|
|
4297
|
+
close() {
|
|
4298
|
+
if (!open) return;
|
|
4299
|
+
open = false;
|
|
4300
|
+
emit();
|
|
4301
|
+
}
|
|
4302
|
+
};
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
// ../react-cookie-consent/dist/index.js
|
|
4306
|
+
var localStorageAdapter = {
|
|
4307
|
+
get(k) {
|
|
4308
|
+
try {
|
|
4309
|
+
return typeof localStorage !== "undefined" ? localStorage.getItem(k) : null;
|
|
4310
|
+
} catch {
|
|
4311
|
+
return null;
|
|
4312
|
+
}
|
|
4313
|
+
},
|
|
4314
|
+
set(k, v) {
|
|
4315
|
+
try {
|
|
4316
|
+
localStorage?.setItem(k, v);
|
|
4317
|
+
} catch {
|
|
4318
|
+
}
|
|
4319
|
+
},
|
|
4320
|
+
remove(k) {
|
|
4321
|
+
try {
|
|
4322
|
+
localStorage?.removeItem(k);
|
|
4323
|
+
} catch {
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
4326
|
+
};
|
|
4327
|
+
function useCookieConsent(config) {
|
|
4328
|
+
const apiRef = React11.useRef(null);
|
|
4329
|
+
if (apiRef.current === null) {
|
|
4330
|
+
apiRef.current = createCookieConsent({ storage: localStorageAdapter, ...config });
|
|
4331
|
+
}
|
|
4332
|
+
const api = apiRef.current;
|
|
4333
|
+
const state = React11.useSyncExternalStore(api.subscribe, api.getState, api.getState);
|
|
4334
|
+
return {
|
|
4335
|
+
state,
|
|
4336
|
+
api,
|
|
4337
|
+
acceptAll: api.acceptAll,
|
|
4338
|
+
rejectAll: api.rejectAll,
|
|
4339
|
+
savePreferences: api.savePreferences,
|
|
4340
|
+
setPreference: api.setPreference,
|
|
4341
|
+
reset: api.reset,
|
|
4342
|
+
openSettings: api.openSettings,
|
|
4343
|
+
close: api.close
|
|
4344
|
+
};
|
|
4345
|
+
}
|
|
4346
|
+
var h3 = React11.createElement;
|
|
4347
|
+
var btnPrimary = "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90";
|
|
4348
|
+
var btnGhost = "rounded-md border border-border px-3 py-1.5 text-sm hover:bg-accent";
|
|
4349
|
+
var btnLink = "text-sm text-muted-foreground underline hover:text-foreground";
|
|
4350
|
+
function CookieConsent({
|
|
4351
|
+
consent,
|
|
4352
|
+
position = "bottom",
|
|
4353
|
+
title = "We use cookies",
|
|
4354
|
+
description = "We use cookies to run the site, remember your preferences, and measure traffic. Choose which categories to allow.",
|
|
4355
|
+
policyUrl,
|
|
4356
|
+
policyLabel = "Cookie policy",
|
|
4357
|
+
className
|
|
4358
|
+
}) {
|
|
4359
|
+
const { state, acceptAll, rejectAll, savePreferences, setPreference } = consent;
|
|
4360
|
+
const [settings, setSettings] = React11.useState(false);
|
|
4361
|
+
if (!state.open) return null;
|
|
4362
|
+
const wrapper = cn(
|
|
4363
|
+
"fixed inset-x-0 z-50 p-4",
|
|
4364
|
+
position === "bottom" ? "bottom-0" : "top-0",
|
|
4365
|
+
className
|
|
4366
|
+
);
|
|
4367
|
+
const panel = "mx-auto max-w-3xl rounded-xl border border-border bg-background p-4 shadow-lg";
|
|
4368
|
+
const header = h3(
|
|
4369
|
+
"div",
|
|
4370
|
+
null,
|
|
4371
|
+
h3("h2", { className: "text-base font-semibold" }, title),
|
|
4372
|
+
h3("p", { className: "mt-1 text-sm text-muted-foreground" }, description),
|
|
4373
|
+
policyUrl ? h3("a", { href: policyUrl, target: "_blank", rel: "noreferrer", className: cn(btnLink, "mt-1 inline-block") }, policyLabel) : null
|
|
4374
|
+
);
|
|
4375
|
+
const promptActions = h3(
|
|
4376
|
+
"div",
|
|
4377
|
+
{ className: "mt-3 flex flex-wrap items-center gap-2" },
|
|
4378
|
+
h3("button", { type: "button", className: btnPrimary, onClick: () => acceptAll() }, "Accept all"),
|
|
4379
|
+
h3("button", { type: "button", className: btnGhost, onClick: () => rejectAll() }, "Reject all"),
|
|
4380
|
+
h3("button", { type: "button", className: cn(btnGhost, "ml-auto"), onClick: () => setSettings(true) }, "Manage preferences")
|
|
4381
|
+
);
|
|
4382
|
+
const settingsView = h3(
|
|
4383
|
+
"div",
|
|
4384
|
+
{ className: "mt-3 space-y-2" },
|
|
4385
|
+
...state.categories.map(
|
|
4386
|
+
(cat) => h3(
|
|
4387
|
+
"label",
|
|
4388
|
+
{
|
|
4389
|
+
key: cat.id,
|
|
4390
|
+
className: "flex items-start justify-between gap-3 rounded-md border border-border p-3"
|
|
4391
|
+
},
|
|
4392
|
+
h3(
|
|
4393
|
+
"span",
|
|
4394
|
+
{ className: "min-w-0" },
|
|
4395
|
+
h3("span", { className: "block text-sm font-medium" }, cat.label, cat.required ? " (required)" : ""),
|
|
4396
|
+
cat.description ? h3("span", { className: "block text-xs text-muted-foreground" }, cat.description) : null
|
|
4397
|
+
),
|
|
4398
|
+
h3("input", {
|
|
4399
|
+
type: "checkbox",
|
|
4400
|
+
className: "mt-0.5 h-4 w-4 accent-[hsl(var(--primary))]",
|
|
4401
|
+
checked: !!state.preferences[cat.id],
|
|
4402
|
+
disabled: cat.required,
|
|
4403
|
+
"aria-label": cat.label,
|
|
4404
|
+
onChange: (e) => setPreference(cat.id, e.target.checked)
|
|
4405
|
+
})
|
|
4406
|
+
)
|
|
4407
|
+
),
|
|
4408
|
+
h3(
|
|
4409
|
+
"div",
|
|
4410
|
+
{ className: "flex flex-wrap items-center gap-2 pt-1" },
|
|
4411
|
+
h3("button", { type: "button", className: btnPrimary, onClick: () => savePreferences(state.preferences) }, "Save preferences"),
|
|
4412
|
+
h3("button", { type: "button", className: btnGhost, onClick: () => acceptAll() }, "Accept all"),
|
|
4413
|
+
h3("button", { type: "button", className: cn(btnLink, "ml-auto"), onClick: () => setSettings(false) }, "Back")
|
|
4414
|
+
)
|
|
4415
|
+
);
|
|
4416
|
+
return h3(
|
|
4417
|
+
"div",
|
|
4418
|
+
{ className: wrapper, role: "dialog", "aria-label": "Cookie consent", "aria-modal": false },
|
|
4419
|
+
h3("div", { className: panel }, header, settings ? settingsView : promptActions)
|
|
4420
|
+
);
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
// ../data-table/dist/index.js
|
|
4424
|
+
function createDataTable(props) {
|
|
4425
|
+
const {
|
|
4426
|
+
columns,
|
|
4427
|
+
data,
|
|
4428
|
+
sortBy: initialSortBy,
|
|
4429
|
+
sortDir: initialSortDir = "asc",
|
|
4430
|
+
onSort,
|
|
4431
|
+
filters: initialFilters
|
|
4432
|
+
} = props;
|
|
4433
|
+
let sortBy = initialSortBy ?? null;
|
|
4434
|
+
let sortDir = initialSortDir;
|
|
4435
|
+
let filters = { ...initialFilters ?? {} };
|
|
4436
|
+
function getFilteredData() {
|
|
4437
|
+
let result = [...data];
|
|
4438
|
+
for (const [columnId, filterValue] of Object.entries(filters)) {
|
|
4439
|
+
if (!filterValue) continue;
|
|
4440
|
+
const col = columns.find((c) => c.id === columnId);
|
|
4441
|
+
if (!col) continue;
|
|
4442
|
+
const lowerFilter = filterValue.toLowerCase();
|
|
4443
|
+
result = result.filter((row) => {
|
|
4444
|
+
const cellValue = col.accessor(row);
|
|
4445
|
+
return String(cellValue ?? "").toLowerCase().includes(lowerFilter);
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
return result;
|
|
4449
|
+
}
|
|
4450
|
+
function getSortedData() {
|
|
4451
|
+
const filtered = getFilteredData();
|
|
4452
|
+
if (!sortBy) return filtered;
|
|
4453
|
+
const col = columns.find((c) => c.id === sortBy);
|
|
4454
|
+
if (!col) return filtered;
|
|
4455
|
+
return [...filtered].sort((a, b) => {
|
|
4456
|
+
const aVal = col.accessor(a);
|
|
4457
|
+
const bVal = col.accessor(b);
|
|
4458
|
+
const aStr = String(aVal ?? "");
|
|
4459
|
+
const bStr = String(bVal ?? "");
|
|
4460
|
+
const cmp = aStr.localeCompare(bStr, void 0, { numeric: true });
|
|
4461
|
+
return sortDir === "asc" ? cmp : -cmp;
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
function sort(columnId) {
|
|
4465
|
+
const col = columns.find((c) => c.id === columnId);
|
|
4466
|
+
if (!col?.sortable) return;
|
|
4467
|
+
if (sortBy === columnId) {
|
|
4468
|
+
sortDir = sortDir === "asc" ? "desc" : "asc";
|
|
4469
|
+
} else {
|
|
4470
|
+
sortBy = columnId;
|
|
4471
|
+
sortDir = "asc";
|
|
4472
|
+
}
|
|
4473
|
+
onSort?.(sortBy, sortDir);
|
|
4474
|
+
}
|
|
4475
|
+
function setFilter(columnId, value) {
|
|
4476
|
+
filters = { ...filters, [columnId]: value };
|
|
4477
|
+
}
|
|
4478
|
+
function getHeaderProps(col) {
|
|
4479
|
+
const props2 = {
|
|
4480
|
+
role: "columnheader"
|
|
4481
|
+
};
|
|
4482
|
+
if (col.sortable) {
|
|
4483
|
+
if (sortBy === col.id) {
|
|
4484
|
+
props2["aria-sort"] = sortDir === "asc" ? "ascending" : "descending";
|
|
4485
|
+
} else {
|
|
4486
|
+
props2["aria-sort"] = "none";
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
return props2;
|
|
4490
|
+
}
|
|
4491
|
+
function getCellProps(col, _row) {
|
|
4492
|
+
return {
|
|
4493
|
+
role: "cell",
|
|
4494
|
+
"data-column": col.id
|
|
4495
|
+
};
|
|
4496
|
+
}
|
|
4497
|
+
function getRowProps(_row, index) {
|
|
4498
|
+
return {
|
|
4499
|
+
role: "row",
|
|
4500
|
+
"data-row-index": index
|
|
4501
|
+
};
|
|
4502
|
+
}
|
|
4503
|
+
return {
|
|
4504
|
+
get state() {
|
|
4505
|
+
return {
|
|
4506
|
+
get sortedData() {
|
|
4507
|
+
return getSortedData();
|
|
4508
|
+
},
|
|
4509
|
+
get sortBy() {
|
|
4510
|
+
return sortBy;
|
|
4511
|
+
},
|
|
4512
|
+
get sortDir() {
|
|
4513
|
+
return sortDir;
|
|
4514
|
+
},
|
|
4515
|
+
get filters() {
|
|
4516
|
+
return { ...filters };
|
|
4517
|
+
}
|
|
4518
|
+
};
|
|
4519
|
+
},
|
|
4520
|
+
sort,
|
|
4521
|
+
setFilter,
|
|
4522
|
+
getHeaderProps,
|
|
4523
|
+
getCellProps,
|
|
4524
|
+
getRowProps
|
|
4525
|
+
};
|
|
4526
|
+
}
|
|
4527
|
+
var tableVariants = cva({
|
|
4528
|
+
base: "w-full caption-bottom text-sm border-collapse",
|
|
4529
|
+
variants: {
|
|
4530
|
+
size: {
|
|
4531
|
+
sm: "text-xs",
|
|
4532
|
+
md: "text-sm",
|
|
4533
|
+
lg: "text-base"
|
|
4534
|
+
}
|
|
4535
|
+
},
|
|
4536
|
+
defaultVariants: {
|
|
4537
|
+
size: "md"
|
|
2915
4538
|
}
|
|
2916
4539
|
});
|
|
2917
4540
|
var headerVariants = cva({
|
|
@@ -4321,460 +5944,251 @@ Input.displayName = "Input";
|
|
|
4321
5944
|
function createInputGroup(props = {}) {
|
|
4322
5945
|
const { orientation = "horizontal" } = props;
|
|
4323
5946
|
const id = props.id ?? generateId("rfr-input-group");
|
|
4324
|
-
const ariaProps = {
|
|
4325
|
-
role: "group"
|
|
4326
|
-
};
|
|
4327
|
-
if (props["aria-label"]) {
|
|
4328
|
-
ariaProps["aria-label"] = props["aria-label"];
|
|
4329
|
-
}
|
|
4330
|
-
if (props["aria-labelledby"]) {
|
|
4331
|
-
ariaProps["aria-labelledby"] = props["aria-labelledby"];
|
|
4332
|
-
}
|
|
4333
|
-
const dataAttributes = {
|
|
4334
|
-
"data-orientation": orientation,
|
|
4335
|
-
id
|
|
4336
|
-
};
|
|
4337
|
-
return {
|
|
4338
|
-
ariaProps,
|
|
4339
|
-
dataAttributes
|
|
4340
|
-
};
|
|
4341
|
-
}
|
|
4342
|
-
var inputGroupTokens = {
|
|
4343
|
-
name: "input-group",
|
|
4344
|
-
tokens: {
|
|
4345
|
-
bg: { variable: "--rfr-input-group-bg", fallback: "hsl(var(--background))" },
|
|
4346
|
-
border: { variable: "--rfr-input-group-border", fallback: "hsl(var(--border))" },
|
|
4347
|
-
radius: { variable: "--rfr-input-group-radius", fallback: "var(--radius)" }
|
|
4348
|
-
}
|
|
4349
|
-
};
|
|
4350
|
-
var inputGroupVariants = cva({
|
|
4351
|
-
base: "flex items-stretch [&>*:not(:first-child):not(:last-child)]:rounded-none",
|
|
4352
|
-
variants: {
|
|
4353
|
-
orientation: {
|
|
4354
|
-
horizontal: "flex-row [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none",
|
|
4355
|
-
vertical: "flex-col [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-t-none"
|
|
4356
|
-
}
|
|
4357
|
-
},
|
|
4358
|
-
defaultVariants: {
|
|
4359
|
-
orientation: "horizontal"
|
|
4360
|
-
}
|
|
4361
|
-
});
|
|
4362
|
-
var inputGroupAddonVariants = cva({
|
|
4363
|
-
base: "flex items-center justify-center border bg-muted px-3 text-sm text-muted-foreground",
|
|
4364
|
-
variants: {
|
|
4365
|
-
orientation: {
|
|
4366
|
-
horizontal: "border-y border-x first:border-r-0 last:border-l-0",
|
|
4367
|
-
vertical: "border-x border-y first:border-b-0 last:border-t-0"
|
|
4368
|
-
}
|
|
4369
|
-
},
|
|
4370
|
-
defaultVariants: {
|
|
4371
|
-
orientation: "horizontal"
|
|
4372
|
-
}
|
|
4373
|
-
});
|
|
4374
|
-
var inputGroupButtonVariants = cva({
|
|
4375
|
-
base: "relative inline-flex items-center justify-center whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
4376
|
-
variants: {
|
|
4377
|
-
orientation: {
|
|
4378
|
-
horizontal: "",
|
|
4379
|
-
vertical: ""
|
|
4380
|
-
}
|
|
4381
|
-
},
|
|
4382
|
-
defaultVariants: {
|
|
4383
|
-
orientation: "horizontal"
|
|
4384
|
-
}
|
|
4385
|
-
});
|
|
4386
|
-
var InputGroup = React11.forwardRef(
|
|
4387
|
-
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
4388
|
-
const api = createInputGroup({
|
|
4389
|
-
orientation,
|
|
4390
|
-
id: props.id,
|
|
4391
|
-
"aria-label": props["aria-label"],
|
|
4392
|
-
"aria-labelledby": props["aria-labelledby"]
|
|
4393
|
-
});
|
|
4394
|
-
return /* @__PURE__ */ jsx(
|
|
4395
|
-
"div",
|
|
4396
|
-
{
|
|
4397
|
-
ref,
|
|
4398
|
-
className: cn(inputGroupVariants({ orientation }), className),
|
|
4399
|
-
...api.ariaProps,
|
|
4400
|
-
...api.dataAttributes,
|
|
4401
|
-
...props,
|
|
4402
|
-
children
|
|
4403
|
-
}
|
|
4404
|
-
);
|
|
4405
|
-
}
|
|
4406
|
-
);
|
|
4407
|
-
InputGroup.displayName = "InputGroup";
|
|
4408
|
-
var InputGroupAddon = React11.forwardRef(
|
|
4409
|
-
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
4410
|
-
return /* @__PURE__ */ jsx(
|
|
4411
|
-
"div",
|
|
4412
|
-
{
|
|
4413
|
-
ref,
|
|
4414
|
-
className: cn(inputGroupAddonVariants({ orientation }), className),
|
|
4415
|
-
...props,
|
|
4416
|
-
children
|
|
4417
|
-
}
|
|
4418
|
-
);
|
|
4419
|
-
}
|
|
4420
|
-
);
|
|
4421
|
-
InputGroupAddon.displayName = "InputGroupAddon";
|
|
4422
|
-
var InputGroupText = React11.forwardRef(
|
|
4423
|
-
({ className, children, ...props }, ref) => {
|
|
4424
|
-
return /* @__PURE__ */ jsx(
|
|
4425
|
-
"span",
|
|
4426
|
-
{
|
|
4427
|
-
ref,
|
|
4428
|
-
className: cn("flex items-center px-3 text-sm text-muted-foreground", className),
|
|
4429
|
-
...props,
|
|
4430
|
-
children
|
|
4431
|
-
}
|
|
4432
|
-
);
|
|
4433
|
-
}
|
|
4434
|
-
);
|
|
4435
|
-
InputGroupText.displayName = "InputGroupText";
|
|
4436
|
-
var InputGroupButton = React11.forwardRef(
|
|
4437
|
-
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
4438
|
-
return /* @__PURE__ */ jsx(
|
|
4439
|
-
"button",
|
|
4440
|
-
{
|
|
4441
|
-
ref,
|
|
4442
|
-
type: props.type ?? "button",
|
|
4443
|
-
className: cn(inputGroupButtonVariants({ orientation }), className),
|
|
4444
|
-
...props,
|
|
4445
|
-
children
|
|
4446
|
-
}
|
|
4447
|
-
);
|
|
4448
|
-
}
|
|
4449
|
-
);
|
|
4450
|
-
InputGroupButton.displayName = "InputGroupButton";
|
|
4451
|
-
|
|
4452
|
-
// ../install-prompt/dist/index.js
|
|
4453
|
-
function createInstallPrompt(props = {}, storage) {
|
|
4454
|
-
const { storageKey = "rfr-install-dismissed" } = props;
|
|
4455
|
-
const dismissed = storage?.get(storageKey) === "true";
|
|
4456
|
-
const state = {
|
|
4457
|
-
canShow: false,
|
|
4458
|
-
isDismissed: dismissed
|
|
4459
|
-
};
|
|
4460
|
-
return {
|
|
4461
|
-
state,
|
|
4462
|
-
show() {
|
|
4463
|
-
if (!state.isDismissed) {
|
|
4464
|
-
state.canShow = true;
|
|
4465
|
-
}
|
|
4466
|
-
},
|
|
4467
|
-
dismiss() {
|
|
4468
|
-
state.canShow = false;
|
|
4469
|
-
state.isDismissed = true;
|
|
4470
|
-
storage?.set(storageKey, "true");
|
|
4471
|
-
},
|
|
4472
|
-
install(promptEvent) {
|
|
4473
|
-
promptEvent?.prompt();
|
|
4474
|
-
state.canShow = false;
|
|
4475
|
-
},
|
|
4476
|
-
ariaProps: {
|
|
4477
|
-
role: "banner",
|
|
4478
|
-
"aria-label": "Install application"
|
|
4479
|
-
}
|
|
4480
|
-
};
|
|
4481
|
-
}
|
|
4482
|
-
var installPromptVariants = cva({
|
|
4483
|
-
base: "fixed bottom-0 left-0 right-0 z-50 flex items-center justify-between gap-4 border-t bg-background px-4 py-3 shadow-lg"
|
|
4484
|
-
});
|
|
4485
|
-
function createLocalStorage() {
|
|
4486
|
-
return {
|
|
4487
|
-
get(key) {
|
|
4488
|
-
try {
|
|
4489
|
-
return localStorage.getItem(key);
|
|
4490
|
-
} catch {
|
|
4491
|
-
return null;
|
|
4492
|
-
}
|
|
4493
|
-
},
|
|
4494
|
-
set(key, value) {
|
|
4495
|
-
try {
|
|
4496
|
-
localStorage.setItem(key, value);
|
|
4497
|
-
} catch {
|
|
4498
|
-
}
|
|
4499
|
-
}
|
|
4500
|
-
};
|
|
4501
|
-
}
|
|
4502
|
-
var InstallPrompt = React11.forwardRef(
|
|
4503
|
-
({
|
|
4504
|
-
delay = 3e3,
|
|
4505
|
-
storageKey,
|
|
4506
|
-
installLabel = "Install",
|
|
4507
|
-
dismissLabel = "Dismiss",
|
|
4508
|
-
message = "Install this app for a better experience",
|
|
4509
|
-
className,
|
|
4510
|
-
...props
|
|
4511
|
-
}, ref) => {
|
|
4512
|
-
const storageRef = React11.useRef(void 0);
|
|
4513
|
-
if (typeof window !== "undefined" && !storageRef.current) {
|
|
4514
|
-
storageRef.current = createLocalStorage();
|
|
4515
|
-
}
|
|
4516
|
-
const api = createInstallPrompt({ storageKey }, storageRef.current);
|
|
4517
|
-
const [visible, setVisible] = React11.useState(false);
|
|
4518
|
-
const promptEventRef = React11.useRef(null);
|
|
4519
|
-
React11.useEffect(() => {
|
|
4520
|
-
if (api.state.isDismissed) return;
|
|
4521
|
-
const handleBeforeInstall = (e) => {
|
|
4522
|
-
e.preventDefault();
|
|
4523
|
-
promptEventRef.current = e;
|
|
4524
|
-
};
|
|
4525
|
-
window.addEventListener("beforeinstallprompt", handleBeforeInstall);
|
|
4526
|
-
const timer = setTimeout(() => {
|
|
4527
|
-
if (promptEventRef.current && !api.state.isDismissed) {
|
|
4528
|
-
api.show();
|
|
4529
|
-
setVisible(true);
|
|
4530
|
-
}
|
|
4531
|
-
}, delay);
|
|
4532
|
-
return () => {
|
|
4533
|
-
window.removeEventListener("beforeinstallprompt", handleBeforeInstall);
|
|
4534
|
-
clearTimeout(timer);
|
|
4535
|
-
};
|
|
4536
|
-
}, [delay, api]);
|
|
4537
|
-
if (!visible) return null;
|
|
4538
|
-
const classes = cn(installPromptVariants(), className);
|
|
4539
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: classes, ...api.ariaProps, ...props, children: [
|
|
4540
|
-
/* @__PURE__ */ jsx("span", { children: message }),
|
|
4541
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4542
|
-
/* @__PURE__ */ jsx(
|
|
4543
|
-
"button",
|
|
4544
|
-
{
|
|
4545
|
-
type: "button",
|
|
4546
|
-
onClick: () => {
|
|
4547
|
-
api.install(promptEventRef.current ?? void 0);
|
|
4548
|
-
setVisible(false);
|
|
4549
|
-
},
|
|
4550
|
-
children: installLabel
|
|
4551
|
-
}
|
|
4552
|
-
),
|
|
4553
|
-
/* @__PURE__ */ jsx(
|
|
4554
|
-
"button",
|
|
4555
|
-
{
|
|
4556
|
-
type: "button",
|
|
4557
|
-
onClick: () => {
|
|
4558
|
-
api.dismiss();
|
|
4559
|
-
setVisible(false);
|
|
4560
|
-
},
|
|
4561
|
-
children: dismissLabel
|
|
4562
|
-
}
|
|
4563
|
-
)
|
|
4564
|
-
] })
|
|
4565
|
-
] });
|
|
5947
|
+
const ariaProps = {
|
|
5948
|
+
role: "group"
|
|
5949
|
+
};
|
|
5950
|
+
if (props["aria-label"]) {
|
|
5951
|
+
ariaProps["aria-label"] = props["aria-label"];
|
|
4566
5952
|
}
|
|
4567
|
-
)
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
}
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
result = result.replace(/__([^_]+)__/g, "<strong>$1</strong>");
|
|
4579
|
-
result = result.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
4580
|
-
result = result.replace(/_([^_]+)_/g, "<em>$1</em>");
|
|
4581
|
-
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text2, url) => {
|
|
4582
|
-
if (/^\s*javascript\s*:/i.test(url)) {
|
|
4583
|
-
return text2;
|
|
4584
|
-
}
|
|
4585
|
-
const resolvedUrl = linkResolver ? linkResolver(url) : url;
|
|
4586
|
-
return `<a href="${resolvedUrl}">${text2}</a>`;
|
|
4587
|
-
});
|
|
4588
|
-
return result;
|
|
5953
|
+
if (props["aria-labelledby"]) {
|
|
5954
|
+
ariaProps["aria-labelledby"] = props["aria-labelledby"];
|
|
5955
|
+
}
|
|
5956
|
+
const dataAttributes = {
|
|
5957
|
+
"data-orientation": orientation,
|
|
5958
|
+
id
|
|
5959
|
+
};
|
|
5960
|
+
return {
|
|
5961
|
+
ariaProps,
|
|
5962
|
+
dataAttributes
|
|
5963
|
+
};
|
|
4589
5964
|
}
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
let inList = null;
|
|
4597
|
-
let inBlockquote = false;
|
|
4598
|
-
function closeList() {
|
|
4599
|
-
if (inList) {
|
|
4600
|
-
outputLines.push(inList === "ul" ? "</ul>" : "</ol>");
|
|
4601
|
-
inList = null;
|
|
4602
|
-
}
|
|
5965
|
+
var inputGroupTokens = {
|
|
5966
|
+
name: "input-group",
|
|
5967
|
+
tokens: {
|
|
5968
|
+
bg: { variable: "--rfr-input-group-bg", fallback: "hsl(var(--background))" },
|
|
5969
|
+
border: { variable: "--rfr-input-group-border", fallback: "hsl(var(--border))" },
|
|
5970
|
+
radius: { variable: "--rfr-input-group-radius", fallback: "var(--radius)" }
|
|
4603
5971
|
}
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
5972
|
+
};
|
|
5973
|
+
var inputGroupVariants = cva({
|
|
5974
|
+
base: "flex items-stretch [&>*:not(:first-child):not(:last-child)]:rounded-none",
|
|
5975
|
+
variants: {
|
|
5976
|
+
orientation: {
|
|
5977
|
+
horizontal: "flex-row [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none",
|
|
5978
|
+
vertical: "flex-col [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-t-none"
|
|
4608
5979
|
}
|
|
5980
|
+
},
|
|
5981
|
+
defaultVariants: {
|
|
5982
|
+
orientation: "horizontal"
|
|
4609
5983
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
inCodeBlock = false;
|
|
4618
|
-
} else {
|
|
4619
|
-
closeList();
|
|
4620
|
-
closeBlockquote();
|
|
4621
|
-
inCodeBlock = true;
|
|
4622
|
-
codeBlockLang = line.trimStart().slice(3).trim();
|
|
4623
|
-
}
|
|
4624
|
-
continue;
|
|
4625
|
-
}
|
|
4626
|
-
if (inCodeBlock) {
|
|
4627
|
-
codeBlockContent.push(line);
|
|
4628
|
-
continue;
|
|
4629
|
-
}
|
|
4630
|
-
if (/^(\s*[-*_]\s*){3,}$/.test(line)) {
|
|
4631
|
-
closeList();
|
|
4632
|
-
closeBlockquote();
|
|
4633
|
-
outputLines.push("<hr />");
|
|
4634
|
-
continue;
|
|
4635
|
-
}
|
|
4636
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
4637
|
-
if (headingMatch) {
|
|
4638
|
-
closeList();
|
|
4639
|
-
closeBlockquote();
|
|
4640
|
-
const level = headingMatch[1].length;
|
|
4641
|
-
const text = parseInline(headingMatch[2], linkResolver);
|
|
4642
|
-
outputLines.push(`<h${level}>${text}</h${level}>`);
|
|
4643
|
-
continue;
|
|
5984
|
+
});
|
|
5985
|
+
var inputGroupAddonVariants = cva({
|
|
5986
|
+
base: "flex items-center justify-center border bg-muted px-3 text-sm text-muted-foreground",
|
|
5987
|
+
variants: {
|
|
5988
|
+
orientation: {
|
|
5989
|
+
horizontal: "border-y border-x first:border-r-0 last:border-l-0",
|
|
5990
|
+
vertical: "border-x border-y first:border-b-0 last:border-t-0"
|
|
4644
5991
|
}
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
continue;
|
|
4657
|
-
} else if (inBlockquote) {
|
|
4658
|
-
closeBlockquote();
|
|
5992
|
+
},
|
|
5993
|
+
defaultVariants: {
|
|
5994
|
+
orientation: "horizontal"
|
|
5995
|
+
}
|
|
5996
|
+
});
|
|
5997
|
+
var inputGroupButtonVariants = cva({
|
|
5998
|
+
base: "relative inline-flex items-center justify-center whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
5999
|
+
variants: {
|
|
6000
|
+
orientation: {
|
|
6001
|
+
horizontal: "",
|
|
6002
|
+
vertical: ""
|
|
4659
6003
|
}
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
6004
|
+
},
|
|
6005
|
+
defaultVariants: {
|
|
6006
|
+
orientation: "horizontal"
|
|
6007
|
+
}
|
|
6008
|
+
});
|
|
6009
|
+
var InputGroup = React11.forwardRef(
|
|
6010
|
+
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
6011
|
+
const api = createInputGroup({
|
|
6012
|
+
orientation,
|
|
6013
|
+
id: props.id,
|
|
6014
|
+
"aria-label": props["aria-label"],
|
|
6015
|
+
"aria-labelledby": props["aria-labelledby"]
|
|
6016
|
+
});
|
|
6017
|
+
return /* @__PURE__ */ jsx(
|
|
6018
|
+
"div",
|
|
6019
|
+
{
|
|
6020
|
+
ref,
|
|
6021
|
+
className: cn(inputGroupVariants({ orientation }), className),
|
|
6022
|
+
...api.ariaProps,
|
|
6023
|
+
...api.dataAttributes,
|
|
6024
|
+
...props,
|
|
6025
|
+
children
|
|
4667
6026
|
}
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
6027
|
+
);
|
|
6028
|
+
}
|
|
6029
|
+
);
|
|
6030
|
+
InputGroup.displayName = "InputGroup";
|
|
6031
|
+
var InputGroupAddon = React11.forwardRef(
|
|
6032
|
+
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
6033
|
+
return /* @__PURE__ */ jsx(
|
|
6034
|
+
"div",
|
|
6035
|
+
{
|
|
6036
|
+
ref,
|
|
6037
|
+
className: cn(inputGroupAddonVariants({ orientation }), className),
|
|
6038
|
+
...props,
|
|
6039
|
+
children
|
|
4678
6040
|
}
|
|
4679
|
-
|
|
4680
|
-
continue;
|
|
4681
|
-
}
|
|
4682
|
-
if (inList) {
|
|
4683
|
-
closeList();
|
|
4684
|
-
}
|
|
4685
|
-
if (line.trim() === "") {
|
|
4686
|
-
continue;
|
|
4687
|
-
}
|
|
4688
|
-
outputLines.push(`<p>${parseInline(line, linkResolver)}</p>`);
|
|
6041
|
+
);
|
|
4689
6042
|
}
|
|
4690
|
-
|
|
4691
|
-
|
|
6043
|
+
);
|
|
6044
|
+
InputGroupAddon.displayName = "InputGroupAddon";
|
|
6045
|
+
var InputGroupText = React11.forwardRef(
|
|
6046
|
+
({ className, children, ...props }, ref) => {
|
|
6047
|
+
return /* @__PURE__ */ jsx(
|
|
6048
|
+
"span",
|
|
6049
|
+
{
|
|
6050
|
+
ref,
|
|
6051
|
+
className: cn("flex items-center px-3 text-sm text-muted-foreground", className),
|
|
6052
|
+
...props,
|
|
6053
|
+
children
|
|
6054
|
+
}
|
|
6055
|
+
);
|
|
4692
6056
|
}
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
}
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
});
|
|
6057
|
+
);
|
|
6058
|
+
InputGroupText.displayName = "InputGroupText";
|
|
6059
|
+
var InputGroupButton = React11.forwardRef(
|
|
6060
|
+
({ orientation = "horizontal", className, children, ...props }, ref) => {
|
|
6061
|
+
return /* @__PURE__ */ jsx(
|
|
6062
|
+
"button",
|
|
6063
|
+
{
|
|
6064
|
+
ref,
|
|
6065
|
+
type: props.type ?? "button",
|
|
6066
|
+
className: cn(inputGroupButtonVariants({ orientation }), className),
|
|
6067
|
+
...props,
|
|
6068
|
+
children
|
|
6069
|
+
}
|
|
6070
|
+
);
|
|
4708
6071
|
}
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
const
|
|
4715
|
-
const
|
|
4716
|
-
|
|
4717
|
-
|
|
6072
|
+
);
|
|
6073
|
+
InputGroupButton.displayName = "InputGroupButton";
|
|
6074
|
+
|
|
6075
|
+
// ../install-prompt/dist/index.js
|
|
6076
|
+
function createInstallPrompt(props = {}, storage) {
|
|
6077
|
+
const { storageKey = "rfr-install-dismissed" } = props;
|
|
6078
|
+
const dismissed = storage?.get(storageKey) === "true";
|
|
6079
|
+
const state = {
|
|
6080
|
+
canShow: false,
|
|
6081
|
+
isDismissed: dismissed
|
|
4718
6082
|
};
|
|
4719
6083
|
return {
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
6084
|
+
state,
|
|
6085
|
+
show() {
|
|
6086
|
+
if (!state.isDismissed) {
|
|
6087
|
+
state.canShow = true;
|
|
6088
|
+
}
|
|
6089
|
+
},
|
|
6090
|
+
dismiss() {
|
|
6091
|
+
state.canShow = false;
|
|
6092
|
+
state.isDismissed = true;
|
|
6093
|
+
storage?.set(storageKey, "true");
|
|
6094
|
+
},
|
|
6095
|
+
install(promptEvent) {
|
|
6096
|
+
promptEvent?.prompt();
|
|
6097
|
+
state.canShow = false;
|
|
6098
|
+
},
|
|
6099
|
+
ariaProps: {
|
|
6100
|
+
role: "banner",
|
|
6101
|
+
"aria-label": "Install application"
|
|
6102
|
+
}
|
|
4723
6103
|
};
|
|
4724
6104
|
}
|
|
4725
|
-
var
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
base: "prose max-w-none text-foreground leading-relaxed",
|
|
4737
|
-
variants: {
|
|
4738
|
-
size: {
|
|
4739
|
-
sm: "prose-sm text-sm",
|
|
4740
|
-
default: "prose-base text-base",
|
|
4741
|
-
lg: "prose-lg text-lg"
|
|
6105
|
+
var installPromptVariants = cva({
|
|
6106
|
+
base: "fixed bottom-0 left-0 right-0 z-50 flex items-center justify-between gap-4 border-t bg-background px-4 py-3 shadow-lg"
|
|
6107
|
+
});
|
|
6108
|
+
function createLocalStorage() {
|
|
6109
|
+
return {
|
|
6110
|
+
get(key) {
|
|
6111
|
+
try {
|
|
6112
|
+
return localStorage.getItem(key);
|
|
6113
|
+
} catch {
|
|
6114
|
+
return null;
|
|
6115
|
+
}
|
|
4742
6116
|
},
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
6117
|
+
set(key, value) {
|
|
6118
|
+
try {
|
|
6119
|
+
localStorage.setItem(key, value);
|
|
6120
|
+
} catch {
|
|
6121
|
+
}
|
|
4746
6122
|
}
|
|
4747
|
-
}
|
|
4748
|
-
defaultVariants: {
|
|
4749
|
-
size: "default"
|
|
4750
|
-
}
|
|
4751
|
-
});
|
|
4752
|
-
function sanitizeHtml(html) {
|
|
4753
|
-
let sanitized = html;
|
|
4754
|
-
sanitized = sanitized.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
|
|
4755
|
-
sanitized = sanitized.replace(/<\/?script[^>]*>/gi, "");
|
|
4756
|
-
sanitized = sanitized.replace(/\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, "");
|
|
4757
|
-
sanitized = sanitized.replace(/(href|src)\s*=\s*["']?\s*javascript\s*:[^"'>]*/gi, '$1=""');
|
|
4758
|
-
return sanitized;
|
|
6123
|
+
};
|
|
4759
6124
|
}
|
|
4760
|
-
var
|
|
4761
|
-
({
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
);
|
|
6125
|
+
var InstallPrompt = React11.forwardRef(
|
|
6126
|
+
({
|
|
6127
|
+
delay = 3e3,
|
|
6128
|
+
storageKey,
|
|
6129
|
+
installLabel = "Install",
|
|
6130
|
+
dismissLabel = "Dismiss",
|
|
6131
|
+
message = "Install this app for a better experience",
|
|
6132
|
+
className,
|
|
6133
|
+
...props
|
|
6134
|
+
}, ref) => {
|
|
6135
|
+
const storageRef = React11.useRef(void 0);
|
|
6136
|
+
if (typeof window !== "undefined" && !storageRef.current) {
|
|
6137
|
+
storageRef.current = createLocalStorage();
|
|
6138
|
+
}
|
|
6139
|
+
const api = createInstallPrompt({ storageKey }, storageRef.current);
|
|
6140
|
+
const [visible, setVisible] = React11.useState(false);
|
|
6141
|
+
const promptEventRef = React11.useRef(null);
|
|
6142
|
+
React11.useEffect(() => {
|
|
6143
|
+
if (api.state.isDismissed) return;
|
|
6144
|
+
const handleBeforeInstall = (e) => {
|
|
6145
|
+
e.preventDefault();
|
|
6146
|
+
promptEventRef.current = e;
|
|
6147
|
+
};
|
|
6148
|
+
window.addEventListener("beforeinstallprompt", handleBeforeInstall);
|
|
6149
|
+
const timer = setTimeout(() => {
|
|
6150
|
+
if (promptEventRef.current && !api.state.isDismissed) {
|
|
6151
|
+
api.show();
|
|
6152
|
+
setVisible(true);
|
|
6153
|
+
}
|
|
6154
|
+
}, delay);
|
|
6155
|
+
return () => {
|
|
6156
|
+
window.removeEventListener("beforeinstallprompt", handleBeforeInstall);
|
|
6157
|
+
clearTimeout(timer);
|
|
6158
|
+
};
|
|
6159
|
+
}, [delay, api]);
|
|
6160
|
+
if (!visible) return null;
|
|
6161
|
+
const classes = cn(installPromptVariants(), className);
|
|
6162
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: classes, ...api.ariaProps, ...props, children: [
|
|
6163
|
+
/* @__PURE__ */ jsx("span", { children: message }),
|
|
6164
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
6165
|
+
/* @__PURE__ */ jsx(
|
|
6166
|
+
"button",
|
|
6167
|
+
{
|
|
6168
|
+
type: "button",
|
|
6169
|
+
onClick: () => {
|
|
6170
|
+
api.install(promptEventRef.current ?? void 0);
|
|
6171
|
+
setVisible(false);
|
|
6172
|
+
},
|
|
6173
|
+
children: installLabel
|
|
6174
|
+
}
|
|
6175
|
+
),
|
|
6176
|
+
/* @__PURE__ */ jsx(
|
|
6177
|
+
"button",
|
|
6178
|
+
{
|
|
6179
|
+
type: "button",
|
|
6180
|
+
onClick: () => {
|
|
6181
|
+
api.dismiss();
|
|
6182
|
+
setVisible(false);
|
|
6183
|
+
},
|
|
6184
|
+
children: dismissLabel
|
|
6185
|
+
}
|
|
6186
|
+
)
|
|
6187
|
+
] })
|
|
6188
|
+
] });
|
|
4775
6189
|
}
|
|
4776
6190
|
);
|
|
4777
|
-
|
|
6191
|
+
InstallPrompt.displayName = "InstallPrompt";
|
|
4778
6192
|
|
|
4779
6193
|
// ../mobile-nav/dist/index.js
|
|
4780
6194
|
function createMobileNav(props = {}) {
|
|
@@ -9592,7 +11006,7 @@ var AvatarContext = React11.createContext({
|
|
|
9592
11006
|
setImageError: () => {
|
|
9593
11007
|
}
|
|
9594
11008
|
});
|
|
9595
|
-
var
|
|
11009
|
+
var Avatar2 = React11.forwardRef(
|
|
9596
11010
|
({ size = "md", className, children, ...props }, ref) => {
|
|
9597
11011
|
const [imageLoaded, setImageLoaded] = React11.useState(false);
|
|
9598
11012
|
const [imageError, setImageError] = React11.useState(false);
|
|
@@ -9610,7 +11024,7 @@ var Avatar = React11.forwardRef(
|
|
|
9610
11024
|
) });
|
|
9611
11025
|
}
|
|
9612
11026
|
);
|
|
9613
|
-
|
|
11027
|
+
Avatar2.displayName = "Avatar";
|
|
9614
11028
|
var AvatarImage = React11.forwardRef(
|
|
9615
11029
|
({ className, src, alt = "", onLoad, onError, ...props }, ref) => {
|
|
9616
11030
|
const { setImageLoaded, setImageError } = React11.useContext(AvatarContext);
|
|
@@ -10203,10 +11617,10 @@ function createDatePicker(props = {}) {
|
|
|
10203
11617
|
closePicker();
|
|
10204
11618
|
}
|
|
10205
11619
|
}
|
|
10206
|
-
function setHours(
|
|
10207
|
-
if (
|
|
11620
|
+
function setHours(h4) {
|
|
11621
|
+
if (h4 < 0 || h4 > 23) return;
|
|
10208
11622
|
const newDate = value ? new Date(value) : /* @__PURE__ */ new Date();
|
|
10209
|
-
newDate.setHours(
|
|
11623
|
+
newDate.setHours(h4);
|
|
10210
11624
|
onChange?.(newDate);
|
|
10211
11625
|
}
|
|
10212
11626
|
function setMinutes(m) {
|
|
@@ -10398,10 +11812,10 @@ function DatePicker({
|
|
|
10398
11812
|
}
|
|
10399
11813
|
};
|
|
10400
11814
|
const handleHoursChange = (e) => {
|
|
10401
|
-
const
|
|
10402
|
-
if (isNaN(
|
|
11815
|
+
const h4 = parseInt(e.target.value, 10);
|
|
11816
|
+
if (isNaN(h4) || h4 < 0 || h4 > 23) return;
|
|
10403
11817
|
const newDate = value ? new Date(value) : /* @__PURE__ */ new Date();
|
|
10404
|
-
newDate.setHours(
|
|
11818
|
+
newDate.setHours(h4);
|
|
10405
11819
|
onChange?.(newDate);
|
|
10406
11820
|
};
|
|
10407
11821
|
const handleMinutesChange = (e) => {
|
|
@@ -12575,102 +13989,6 @@ var Switch = React11.forwardRef(
|
|
|
12575
13989
|
}
|
|
12576
13990
|
);
|
|
12577
13991
|
Switch.displayName = "Switch";
|
|
12578
|
-
|
|
12579
|
-
// ../thread-view/dist/index.js
|
|
12580
|
-
function formatTimestamp(date) {
|
|
12581
|
-
const hours = date.getHours();
|
|
12582
|
-
const minutes = date.getMinutes();
|
|
12583
|
-
const ampm = hours >= 12 ? "PM" : "AM";
|
|
12584
|
-
const displayHours = hours % 12 || 12;
|
|
12585
|
-
const displayMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
|
12586
|
-
return `${displayHours}:${displayMinutes} ${ampm}`;
|
|
12587
|
-
}
|
|
12588
|
-
function formatRelativeTime(date, now) {
|
|
12589
|
-
const reference = now ?? /* @__PURE__ */ new Date();
|
|
12590
|
-
const diffMs = reference.getTime() - date.getTime();
|
|
12591
|
-
const diffSeconds = Math.floor(diffMs / 1e3);
|
|
12592
|
-
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
12593
|
-
const diffHours = Math.floor(diffMinutes / 60);
|
|
12594
|
-
const diffDays = Math.floor(diffHours / 24);
|
|
12595
|
-
if (diffSeconds < 60) return "just now";
|
|
12596
|
-
if (diffMinutes < 60) return `${diffMinutes} minute${diffMinutes === 1 ? "" : "s"} ago`;
|
|
12597
|
-
if (diffHours < 24) return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
|
|
12598
|
-
if (diffDays < 7) return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
12599
|
-
return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
12600
|
-
}
|
|
12601
|
-
function createThreadView(props) {
|
|
12602
|
-
const { messages, onReply, onReact, currentUserId } = props;
|
|
12603
|
-
let replyingTo = null;
|
|
12604
|
-
const threadId = generateId("rfr-thread");
|
|
12605
|
-
const labelId = generateId("rfr-thread-label");
|
|
12606
|
-
function startReply(messageId) {
|
|
12607
|
-
replyingTo = messageId;
|
|
12608
|
-
}
|
|
12609
|
-
function cancelReply() {
|
|
12610
|
-
replyingTo = null;
|
|
12611
|
-
}
|
|
12612
|
-
function reply(messageId, content) {
|
|
12613
|
-
onReply?.(messageId, content);
|
|
12614
|
-
replyingTo = null;
|
|
12615
|
-
}
|
|
12616
|
-
function react(messageId, emoji) {
|
|
12617
|
-
onReact?.(messageId, emoji);
|
|
12618
|
-
}
|
|
12619
|
-
const ariaProps = {
|
|
12620
|
-
role: "log",
|
|
12621
|
-
"aria-label": "Message thread",
|
|
12622
|
-
"aria-live": "polite",
|
|
12623
|
-
id: threadId
|
|
12624
|
-
};
|
|
12625
|
-
function getMessageAriaProps(message) {
|
|
12626
|
-
const isOwn = currentUserId && message.author.id === currentUserId;
|
|
12627
|
-
return {
|
|
12628
|
-
role: "article",
|
|
12629
|
-
"aria-label": `Message from ${message.author.name}${isOwn ? " (you)" : ""} at ${formatTimestamp(message.timestamp)}`
|
|
12630
|
-
};
|
|
12631
|
-
}
|
|
12632
|
-
function getReplyButtonAriaProps(_messageId) {
|
|
12633
|
-
return {
|
|
12634
|
-
role: "button",
|
|
12635
|
-
"aria-label": `Reply to message`
|
|
12636
|
-
};
|
|
12637
|
-
}
|
|
12638
|
-
return {
|
|
12639
|
-
state: {
|
|
12640
|
-
messages,
|
|
12641
|
-
get replyingTo() {
|
|
12642
|
-
return replyingTo;
|
|
12643
|
-
}
|
|
12644
|
-
},
|
|
12645
|
-
startReply,
|
|
12646
|
-
cancelReply,
|
|
12647
|
-
reply,
|
|
12648
|
-
react,
|
|
12649
|
-
formatTimestamp,
|
|
12650
|
-
formatRelativeTime,
|
|
12651
|
-
ariaProps,
|
|
12652
|
-
getMessageAriaProps,
|
|
12653
|
-
getReplyButtonAriaProps,
|
|
12654
|
-
ids: {
|
|
12655
|
-
thread: threadId,
|
|
12656
|
-
label: labelId
|
|
12657
|
-
}
|
|
12658
|
-
};
|
|
12659
|
-
}
|
|
12660
|
-
var threadContainerStyles = "flex flex-col gap-1";
|
|
12661
|
-
var threadMessageStyles = "flex gap-3 px-4 py-2 hover:bg-accent/50 rounded-md transition-colors group";
|
|
12662
|
-
var threadAvatarStyles = "h-9 w-9 rounded-full bg-muted flex items-center justify-center text-sm font-medium overflow-hidden flex-shrink-0";
|
|
12663
|
-
var threadContentStyles = "flex-1 min-w-0";
|
|
12664
|
-
var threadAuthorStyles = "font-semibold text-sm";
|
|
12665
|
-
var threadTimestampStyles = "text-xs text-muted-foreground ml-2";
|
|
12666
|
-
var threadBodyStyles = "text-sm mt-0.5 whitespace-pre-wrap break-words";
|
|
12667
|
-
var threadReactionsStyles = "flex flex-wrap gap-1 mt-1";
|
|
12668
|
-
var threadReplyIndicatorStyles = "flex items-center gap-1 mt-1 text-xs text-primary cursor-pointer hover:underline";
|
|
12669
|
-
var threadActionsStyles = "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity";
|
|
12670
|
-
var threadAttachmentStyles = "flex items-center gap-2 mt-1 p-2 rounded border text-xs bg-muted/50";
|
|
12671
|
-
var threadEditedStyles = "text-xs text-muted-foreground ml-1";
|
|
12672
|
-
|
|
12673
|
-
// ../react-thread-view/dist/index.js
|
|
12674
13992
|
function MessageComponent({
|
|
12675
13993
|
message,
|
|
12676
13994
|
api
|
|
@@ -12782,11 +14100,11 @@ ThreadView.displayName = "ThreadView";
|
|
|
12782
14100
|
// ../table-of-contents/dist/index.js
|
|
12783
14101
|
function parseHeadings(container, selectors = "h2, h3, h4") {
|
|
12784
14102
|
const headings = Array.from(container.querySelectorAll(selectors));
|
|
12785
|
-
return headings.map((
|
|
12786
|
-
id:
|
|
12787
|
-
text:
|
|
12788
|
-
level: parseInt(
|
|
12789
|
-
})).filter((
|
|
14103
|
+
return headings.map((h4) => ({
|
|
14104
|
+
id: h4.id || h4.textContent?.toLowerCase().replace(/\s+/g, "-") || "",
|
|
14105
|
+
text: h4.textContent || "",
|
|
14106
|
+
level: parseInt(h4.tagName.charAt(1), 10)
|
|
14107
|
+
})).filter((h4) => h4.id !== "");
|
|
12790
14108
|
}
|
|
12791
14109
|
function observeHeadings(headingIds, callback, options) {
|
|
12792
14110
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -12813,7 +14131,7 @@ var TableOfContents = React11.forwardRef(
|
|
|
12813
14131
|
const parsedHeadings = parseHeadings(container, selectors);
|
|
12814
14132
|
setHeadings(parsedHeadings);
|
|
12815
14133
|
if (parsedHeadings.length === 0) return;
|
|
12816
|
-
const disconnect = observeHeadings(parsedHeadings.map((
|
|
14134
|
+
const disconnect = observeHeadings(parsedHeadings.map((h4) => h4.id), (id) => {
|
|
12817
14135
|
setActiveId(id);
|
|
12818
14136
|
onActiveIdChange?.(id);
|
|
12819
14137
|
});
|
|
@@ -13943,7 +15261,7 @@ function resolveStorage(override) {
|
|
|
13943
15261
|
return createMemoryStorage();
|
|
13944
15262
|
}
|
|
13945
15263
|
var DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
13946
|
-
var
|
|
15264
|
+
var DEFAULT_KEY2 = "rfx:analytics:session";
|
|
13947
15265
|
var CAMPAIGN_PARAMS = [
|
|
13948
15266
|
"utm_source",
|
|
13949
15267
|
"utm_medium",
|
|
@@ -13974,7 +15292,7 @@ function campaignFingerprint(search) {
|
|
|
13974
15292
|
}
|
|
13975
15293
|
function createSession(config, now = () => Date.now()) {
|
|
13976
15294
|
const storage = resolveStorage(config?.storage);
|
|
13977
|
-
const key = config?.storageKey ??
|
|
15295
|
+
const key = config?.storageKey ?? DEFAULT_KEY2;
|
|
13978
15296
|
const timeoutMs = config?.timeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
|
|
13979
15297
|
const resetOnCampaign = config?.resetOnCampaign ?? true;
|
|
13980
15298
|
function read() {
|
|
@@ -14043,10 +15361,10 @@ function createSession(config, now = () => Date.now()) {
|
|
|
14043
15361
|
}
|
|
14044
15362
|
};
|
|
14045
15363
|
}
|
|
14046
|
-
var
|
|
15364
|
+
var DEFAULT_KEY22 = "rfx:analytics:anon";
|
|
14047
15365
|
function createIdentity(config) {
|
|
14048
15366
|
const storage = resolveStorage(config?.storage);
|
|
14049
|
-
const key = config?.storageKey ??
|
|
15367
|
+
const key = config?.storageKey ?? DEFAULT_KEY22;
|
|
14050
15368
|
let userId;
|
|
14051
15369
|
function loadOrMintAnon() {
|
|
14052
15370
|
const existing = storage.get(key);
|
|
@@ -15515,6 +16833,6 @@ function useTrackEvent(options) {
|
|
|
15515
16833
|
);
|
|
15516
16834
|
}
|
|
15517
16835
|
|
|
15518
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AltHintState, AnalyticsProvider, AnimatedText, AppShell, AuthGuard, AuthProvider, Avatar, AvatarFallback, AvatarGroup, AvatarImage, Badge, BadgeDisplay, BottomNav, Breadcrumbs, Button, CATEGORY_LABELS, Calendar, CalendarHeader, Callout, CalloutContent, CalloutDescription, CalloutIcon, CalloutTitle, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselTrigger, Checkbox, CodeBlock, CodeBlockContent, CodeBlockHeader, CodeEditor, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, ContentProtection, DEFAULT_VOICE_PILL_POSITION, DEFAULT_VOICE_PILL_SPEAKER, DEFAULT_WAVEFORM_BAR_COUNT, DEFAULT_WAVEFORM_COLOR, DEFAULT_WAVEFORM_HEIGHT, DEFAULT_WAVEFORM_INTENSITY, DEFAULT_WAVEFORM_SMOOTHING, DataTable, DatePicker, DeviceFrame, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EMOJI_CATEGORIES, EMOJI_DATA, EmojiPicker, FeedbackButton, FeedbackDialog, FileTree, FileUpload, Footer, IconSystem, InlineEditor, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InstallPrompt, KeyboardShortcut, LanguageSelector, LinkCard, MarkdownRenderer, MobileNav, MobileNavContent, MobileNavLink, MobileNavTrigger, Navbar, OtpInput, STATUS_COLORS as PRESENCE_STATUS_COLORS, STATUS_LABELS as PRESENCE_STATUS_LABELS, Pagination, Payment, Popover, PopoverClose, PopoverContent, PopoverTrigger, PresenceIndicator, ProgressBar, RadioGroup, RadioItem, ReactionBar, ResizableDivider, ResizableLayout, ResizablePane, SANE_DEFAULTS, STATUS_INDICATOR_COLORS as STATUS_COLORS, STATUS_INDICATOR_LABELS as STATUS_LABELS, SearchBar, SearchResultItem, SearchResults, Select, SelectContent, SelectItem, SelectTrigger, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetTitle, SheetTrigger, ShortcutBadge, ShortcutContext, ShortcutHint, ShortcutProvider, ShortcutRegistry, Sidebar, Skeleton, SkeletonText, SkipToContent, SlideViewer, StatsGrid, StatusIndicator, Step, StepContent, StepDescription, StepIndicator, StepTitle, Steps, Switch, TableOfContents, Tabs, TabsContent, TabsList, TabsTrigger, TelemetryErrorBoundary, TelemetryProvider, Textarea, ThreadView, Toast, ToastProvider, Toaster, Tooltip, TooltipContent, TooltipTrigger, TypewriterText, VersionSelector, VideoPlayer, VoicePill, Waveform, altHintState, animatedTextVariants, avatarFallbackVariants, avatarImageVariants, avatarTokens, avatarVariants, badgeGridVariants, badgeItemVariants, badgeVariants, bottomNavTabVariants, bottomNavVariants, breadcrumbItemVariants, breadcrumbSeparatorStyles, breadcrumbsVariants, buttonTokens, buttonVariants, calendarVariants, canAccessAdmin, canAccessReviewer, cardContentVariants, cardDescriptionVariants, cardFooterVariants, cardHeaderVariants, cardTitleVariants, cardTokens, cardVariants, cellVariants, checkIconPath, checkboxTokens, checkboxVariants, clampVoicePillIntensity, codeEditorTokens, codeEditorVariants, collapsibleContentVariants, comboboxContentVariants, comboboxEmptyVariants, comboboxInputVariants, comboboxItemVariants, comboboxListVariants, comboboxTriggerVariants, commandGroupVariants, commandInputVariants, commandItemVariants, commandVariants, contentProtectionVariants, controlsVariants, createAnalytics, createAppInsightsSink, createConsoleSink, createGA4ClientSdkSink, createGA4HttpSink, createGA4Sink, createIntensitySamples, createPostHogClientSdkSink, createPostHogHttpSink, createPostHogSink, createSilentSamples, createTelemetry, createVoicePill, createWaveform, dayVariants, deviceFrameVariants, dialogContentVariants, drawWaveform, editorVariants, emojiPickerContainerStyles, emojiPickerEmojiButtonStyles, emojiPickerGridStyles, feedbackDialogVariants, fileUploadDropZoneVariants, fileUploadFileItemStyles, fileUploadFileListStyles, footerVariants, formatFileSize, formatRelativeTime, formatShortcut, formatTimestamp, getAssignableRoles, getDefaultPortal, getInitials, getVoicePillAriaLabel, getVoicePillInitials, getVoicePillPosition, getVoicePillPulseStyle, getVoicePillSpeakerKey, getVoicePillSpeakerLabel, getWaveformPeak, globalShortcutRegistry, hasAllRoles, hasAnyRole, hasRole, headerVariants, indeterminateIconPath, inputGroupAddonVariants, inputGroupButtonVariants, inputGroupTokens, inputGroupVariants, inputVariants, installPromptVariants, isWaveformSampleInput, latestBadgeVariants, markdownRendererTokens, menuContentVariants, menuItemVariants, mobileNavContentVariants, mobileNavLinkVariants, mobileNavTokens, mobileNavTriggerVariants, mobileNavVariants, navLinkVariants, navbarVariants, normalizeBarCount, normalizeIntensity, normalizeSmoothing, normalizeWaveformConfig, normalizeWaveformSamples, optionVariants, otpInputContainerVariants, otpInputSlotVariants, otpInputTokens, overlayStyles, overlayVariants, playerVariants, popoverContentVariants, prepareWaveformCanvas, previewVariants, progressBarVariants, proseVariants, radioCircleVariants, radioGroupVariants, radioItemVariants, reactionAddButtonStyles, reactionBarStyles, reactionCountStyles, reactionEmojiStyles, reactionPillVariants, resampleWaveformSamples, resizableDividerVariants, resizableLayoutTokens, resizableLayoutVariants, resizablePaneVariants, rowVariants, scaleWaveformSamples, searchBarVariants, searchResultVariants, selectContentVariants, selectItemVariants, selectTokens, selectTriggerVariants, selectorVariants, sheetContentVariants, sheetOverlayStyles, shortcutBadgeStyles, shortcutKeyStyles, shortcutSeparatorStyles, sidebarItemVariants, sidebarVariants, skeletonVariants, slideTypeBadgeVariants, slideViewerProgressBarVariants, slideViewerTokens, slideViewerVariants, smoothWaveformSamples, startSessionReplay, statCardVariants, statsGridVariants, statusContainerStyles, statusDotVariants, statusLabelStyles, statusPulseVariants, switchThumbVariants, switchTokens, switchVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, threadAuthorStyles, threadAvatarStyles, threadBodyStyles, threadContainerStyles, threadContentStyles, threadMessageStyles, threadReactionsStyles, threadTimestampStyles, toCssDimension, toastVariants, toolbarVariants, tooltipContentVariants, typewriterVariants, useAnalytics, useAuth, useLogger, useShortcut, useSpan, useTelemetry, useToast, useTrackEvent, versionSelectorOptionVariants, versionSelectorVariants, voicePillAvatarStyles, voicePillAvatarWrapStyles, voicePillLabelStyles, voicePillMuteButtonStyles, voicePillPositionVariants, voicePillPulseRingStyles, voicePillRootStyles, voicePillSpeakerStyles, voicePillSubStyles, voicePillTextStyles, voicePillTokens, watermarkVariants, waveformCanvasVariants, waveformVariants };
|
|
16836
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AltHintState, AnalyticsProvider, AnimatedText, AppShell, AuthGuard, AuthProvider, Avatar2 as Avatar, AvatarFallback, AvatarGroup, AvatarImage, Badge, BadgeDisplay, BottomNav, Breadcrumbs, Button, CATEGORY_LABELS, Calendar, CalendarHeader, Callout, CalloutContent, CalloutDescription, CalloutIcon, CalloutTitle, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselTrigger, Chat, Checkbox, CodeBlock, CodeBlockContent, CodeBlockHeader, CodeEditor, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, Composer, ContentProtection, CookieConsent, DEFAULT_CATEGORIES, DEFAULT_VOICE_PILL_POSITION, DEFAULT_VOICE_PILL_SPEAKER, DEFAULT_WAVEFORM_BAR_COUNT, DEFAULT_WAVEFORM_COLOR, DEFAULT_WAVEFORM_HEIGHT, DEFAULT_WAVEFORM_INTENSITY, DEFAULT_WAVEFORM_SMOOTHING, DataTable, DatePicker, DeviceFrame, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EMOJI_CATEGORIES, EMOJI_DATA, EmojiPicker, FeedbackButton, FeedbackDialog, FileTree, FileUpload, Footer, IconSystem, InlineEditor, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InstallPrompt, KeyboardShortcut, LanguageSelector, LinkCard, MarkdownRenderer, MobileNav, MobileNavContent, MobileNavLink, MobileNavTrigger, Navbar, OtpInput, STATUS_COLORS as PRESENCE_STATUS_COLORS, STATUS_LABELS as PRESENCE_STATUS_LABELS, Pagination, Payment, Popover, PopoverClose, PopoverContent, PopoverTrigger, PresenceIndicator, ProgressBar, RadioGroup, RadioItem, ReactionBar, ResizableDivider, ResizableLayout, ResizablePane, SANE_DEFAULTS, STATUS_INDICATOR_COLORS as STATUS_COLORS, STATUS_INDICATOR_LABELS as STATUS_LABELS, SearchBar, SearchResultItem, SearchResults, Select, SelectContent, SelectItem, SelectTrigger, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetTitle, SheetTrigger, ShortcutBadge, ShortcutContext, ShortcutHint, ShortcutProvider, ShortcutRegistry, Sidebar, Skeleton, SkeletonText, SkipToContent, SlideViewer, StatsGrid, StatusIndicator, Step, StepContent, StepDescription, StepIndicator, StepTitle, Steps, Switch, TableOfContents, Tabs, TabsContent, TabsList, TabsTrigger, TelemetryErrorBoundary, TelemetryProvider, Textarea, ThreadView, Toast, ToastProvider, Toaster, Tooltip, TooltipContent, TooltipTrigger, TypewriterText, VersionSelector, VideoPlayer, VoicePill, Waveform, altHintState, animatedTextVariants, avatarFallbackVariants, avatarImageVariants, avatarTokens, avatarVariants, badgeGridVariants, badgeItemVariants, badgeVariants, bottomNavTabVariants, bottomNavVariants, breadcrumbItemVariants, breadcrumbSeparatorStyles, breadcrumbsVariants, buttonTokens, buttonVariants, calendarVariants, canAccessAdmin, canAccessReviewer, cardContentVariants, cardDescriptionVariants, cardFooterVariants, cardHeaderVariants, cardTitleVariants, cardTokens, cardVariants, cellVariants, checkIconPath, checkboxTokens, checkboxVariants, clampVoicePillIntensity, codeEditorTokens, codeEditorVariants, collapsibleContentVariants, comboboxContentVariants, comboboxEmptyVariants, comboboxInputVariants, comboboxItemVariants, comboboxListVariants, comboboxTriggerVariants, commandGroupVariants, commandInputVariants, commandItemVariants, commandVariants, contentProtectionVariants, controlsVariants, createAnalytics, createAppInsightsSink, createConsoleSink, createConversation, createCookieConsent, createGA4ClientSdkSink, createGA4HttpSink, createGA4Sink, createIntensitySamples, createPostHogClientSdkSink, createPostHogHttpSink, createPostHogSink, createSilentSamples, createTelemetry, createVoicePill, createWaveform, dayVariants, deviceFrameVariants, dialogContentVariants, drawWaveform, editorVariants, emojiPickerContainerStyles, emojiPickerEmojiButtonStyles, emojiPickerGridStyles, feedbackDialogVariants, fileUploadDropZoneVariants, fileUploadFileItemStyles, fileUploadFileListStyles, findMessage, footerVariants, formatFileSize, formatRelativeTime, formatShortcut, formatTimestamp, getAssignableRoles, getDefaultPortal, getInitials, getReplyCount, getVoicePillAriaLabel, getVoicePillInitials, getVoicePillPosition, getVoicePillPulseStyle, getVoicePillSpeakerKey, getVoicePillSpeakerLabel, getWaveformPeak, globalShortcutRegistry, hasAllRoles, hasAnyRole, hasRole, headerVariants, indeterminateIconPath, inputGroupAddonVariants, inputGroupButtonVariants, inputGroupTokens, inputGroupVariants, inputVariants, installPromptVariants, isWaveformSampleInput, latestBadgeVariants, markdownRendererTokens, menuContentVariants, menuItemVariants, mobileNavContentVariants, mobileNavLinkVariants, mobileNavTokens, mobileNavTriggerVariants, mobileNavVariants, navLinkVariants, navbarVariants, normalizeBarCount, normalizeIntensity, normalizeSmoothing, normalizeWaveformConfig, normalizeWaveformSamples, optionVariants, otpInputContainerVariants, otpInputSlotVariants, otpInputTokens, overlayStyles, overlayVariants, playerVariants, popoverContentVariants, prepareWaveformCanvas, previewVariants, progressBarVariants, proseVariants, radioCircleVariants, radioGroupVariants, radioItemVariants, reactionAddButtonStyles, reactionBarStyles, reactionCountStyles, reactionEmojiStyles, reactionPillVariants, resampleWaveformSamples, resizableDividerVariants, resizableLayoutTokens, resizableLayoutVariants, resizablePaneVariants, rootIdOf, rowVariants, scaleWaveformSamples, searchBarVariants, searchResultVariants, selectContentVariants, selectItemVariants, selectMainTimeline, selectReplies, selectRoots, selectThreadMessages, selectTimelineFromState, selectTokens, selectTriggerVariants, selectorVariants, sheetContentVariants, sheetOverlayStyles, shortcutBadgeStyles, shortcutKeyStyles, shortcutSeparatorStyles, sidebarItemVariants, sidebarVariants, skeletonVariants, slideTypeBadgeVariants, slideViewerProgressBarVariants, slideViewerTokens, slideViewerVariants, smoothWaveformSamples, startSessionReplay, statCardVariants, statsGridVariants, statusContainerStyles, statusDotVariants, statusLabelStyles, statusPulseVariants, switchThumbVariants, switchTokens, switchVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, threadAuthorStyles, threadAvatarStyles, threadBodyStyles, threadContainerStyles, threadContentStyles, threadMessageStyles, threadReactionsStyles, threadTimestampStyles, toCssDimension, toastVariants, toolbarVariants, tooltipContentVariants, typewriterVariants, useAnalytics, useAuth, useConversation, useCookieConsent, useLogger, useShortcut, useSpan, useTelemetry, useToast, useTrackEvent, versionSelectorOptionVariants, versionSelectorVariants, voicePillAvatarStyles, voicePillAvatarWrapStyles, voicePillLabelStyles, voicePillMuteButtonStyles, voicePillPositionVariants, voicePillPulseRingStyles, voicePillRootStyles, voicePillSpeakerStyles, voicePillSubStyles, voicePillTextStyles, voicePillTokens, watermarkVariants, waveformCanvasVariants, waveformVariants };
|
|
15519
16837
|
//# sourceMappingURL=index.js.map
|
|
15520
16838
|
//# sourceMappingURL=index.js.map
|