@hamzasaleemorg/convex-comments 1.0.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/CHANGELOG.md +17 -0
- package/LICENSE +201 -0
- package/README.md +581 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +3 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +745 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +579 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +44 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +673 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +3 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/lib.d.ts +17 -0
- package/dist/component/lib.d.ts.map +1 -0
- package/dist/component/lib.js +18 -0
- package/dist/component/lib.js.map +1 -0
- package/dist/component/messages.d.ts +173 -0
- package/dist/component/messages.d.ts.map +1 -0
- package/dist/component/messages.js +410 -0
- package/dist/component/messages.js.map +1 -0
- package/dist/component/reactions.d.ts +51 -0
- package/dist/component/reactions.d.ts.map +1 -0
- package/dist/component/reactions.js +191 -0
- package/dist/component/reactions.js.map +1 -0
- package/dist/component/schema.d.ts +274 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +159 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/threads.d.ts +110 -0
- package/dist/component/threads.d.ts.map +1 -0
- package/dist/component/threads.js +276 -0
- package/dist/component/threads.js.map +1 -0
- package/dist/component/typing.d.ts +31 -0
- package/dist/component/typing.d.ts.map +1 -0
- package/dist/component/typing.js +147 -0
- package/dist/component/typing.js.map +1 -0
- package/dist/component/zones.d.ts +63 -0
- package/dist/component/zones.d.ts.map +1 -0
- package/dist/component/zones.js +159 -0
- package/dist/component/zones.js.map +1 -0
- package/dist/react/AddComment.d.ts +57 -0
- package/dist/react/AddComment.d.ts.map +1 -0
- package/dist/react/AddComment.js +285 -0
- package/dist/react/AddComment.js.map +1 -0
- package/dist/react/Comment.d.ts +70 -0
- package/dist/react/Comment.d.ts.map +1 -0
- package/dist/react/Comment.js +259 -0
- package/dist/react/Comment.js.map +1 -0
- package/dist/react/Comments.d.ts +74 -0
- package/dist/react/Comments.d.ts.map +1 -0
- package/dist/react/Comments.js +108 -0
- package/dist/react/Comments.js.map +1 -0
- package/dist/react/CommentsProvider.d.ts +104 -0
- package/dist/react/CommentsProvider.d.ts.map +1 -0
- package/dist/react/CommentsProvider.js +98 -0
- package/dist/react/CommentsProvider.js.map +1 -0
- package/dist/react/ReactionPicker.d.ts +28 -0
- package/dist/react/ReactionPicker.d.ts.map +1 -0
- package/dist/react/ReactionPicker.js +56 -0
- package/dist/react/ReactionPicker.js.map +1 -0
- package/dist/react/Thread.d.ts +84 -0
- package/dist/react/Thread.d.ts.map +1 -0
- package/dist/react/Thread.js +124 -0
- package/dist/react/Thread.js.map +1 -0
- package/dist/react/TypingIndicator.d.ts +25 -0
- package/dist/react/TypingIndicator.d.ts.map +1 -0
- package/dist/react/TypingIndicator.js +99 -0
- package/dist/react/TypingIndicator.js.map +1 -0
- package/dist/react/index.d.ts +15 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +15 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +106 -0
- package/src/client/_generated/_ignore.ts +1 -0
- package/src/client/index.ts +813 -0
- package/src/component/_generated/api.ts +60 -0
- package/src/component/_generated/component.ts +784 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/lib.ts +57 -0
- package/src/component/messages.ts +476 -0
- package/src/component/reactions.ts +222 -0
- package/src/component/schema.ts +169 -0
- package/src/component/threads.ts +319 -0
- package/src/component/typing.ts +168 -0
- package/src/component/zones.ts +180 -0
- package/src/react/AddComment.tsx +463 -0
- package/src/react/Comment.tsx +519 -0
- package/src/react/Comments.tsx +276 -0
- package/src/react/CommentsProvider.tsx +197 -0
- package/src/react/ReactionPicker.tsx +95 -0
- package/src/react/Thread.tsx +336 -0
- package/src/react/TypingIndicator.tsx +144 -0
- package/src/react/index.ts +45 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Comments Context Provider
|
|
4
|
+
*
|
|
5
|
+
* Provides the Comments API instance to all child components.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext, useMemo } from "react";
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Default Theme
|
|
10
|
+
// ============================================================================
|
|
11
|
+
const defaultStyles = {
|
|
12
|
+
accentColor: "#3b82f6",
|
|
13
|
+
backgroundColor: "#ffffff",
|
|
14
|
+
textColor: "#1f2937",
|
|
15
|
+
textColorMuted: "#6b7280",
|
|
16
|
+
borderColor: "#e5e7eb",
|
|
17
|
+
borderRadius: "8px",
|
|
18
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
19
|
+
fontSize: "14px",
|
|
20
|
+
};
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Context
|
|
23
|
+
// ============================================================================
|
|
24
|
+
const CommentsContext = createContext(null);
|
|
25
|
+
/**
|
|
26
|
+
* Provider component that supplies comments configuration to all child components.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* ```tsx
|
|
30
|
+
* <CommentsProvider
|
|
31
|
+
* userId={currentUserId}
|
|
32
|
+
* resolveUser={async (id) => ({ name: users[id].name, avatar: users[id].avatar })}
|
|
33
|
+
* reactionChoices={["👍", "❤️", "😄", "🎉", "😮", "😢"]}
|
|
34
|
+
* styles={{
|
|
35
|
+
* accentColor: "#8b5cf6",
|
|
36
|
+
* borderRadius: "12px",
|
|
37
|
+
* }}
|
|
38
|
+
* >
|
|
39
|
+
* <Comments threads={threads} />
|
|
40
|
+
* </CommentsProvider>
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* CSS Variables (can be set in your CSS):
|
|
44
|
+
* - --comments-accent-color
|
|
45
|
+
* - --comments-bg-color
|
|
46
|
+
* - --comments-text-color
|
|
47
|
+
* - --comments-text-color-muted
|
|
48
|
+
* - --comments-border-color
|
|
49
|
+
* - --comments-border-radius
|
|
50
|
+
* - --comments-font-family
|
|
51
|
+
* - --comments-font-size
|
|
52
|
+
*/
|
|
53
|
+
export function CommentsProvider({ userId, resolveUser, reactionChoices = ["👍", "❤️", "😄", "🎉", "😮", "😢", "👀", "🚀"], canModerate = false, styles, className, children, }) {
|
|
54
|
+
const mergedStyles = useMemo(() => ({
|
|
55
|
+
...defaultStyles,
|
|
56
|
+
...styles,
|
|
57
|
+
}), [styles]);
|
|
58
|
+
const cssVars = useMemo(() => ({
|
|
59
|
+
"--comments-accent-color": mergedStyles.accentColor,
|
|
60
|
+
"--comments-bg-color": mergedStyles.backgroundColor,
|
|
61
|
+
"--comments-text-color": mergedStyles.textColor,
|
|
62
|
+
"--comments-text-color-muted": mergedStyles.textColorMuted,
|
|
63
|
+
"--comments-border-color": mergedStyles.borderColor,
|
|
64
|
+
"--comments-border-radius": mergedStyles.borderRadius,
|
|
65
|
+
"--comments-font-family": mergedStyles.fontFamily,
|
|
66
|
+
"--comments-font-size": mergedStyles.fontSize,
|
|
67
|
+
}), [mergedStyles]);
|
|
68
|
+
const value = useMemo(() => ({
|
|
69
|
+
userId,
|
|
70
|
+
resolveUser,
|
|
71
|
+
reactionChoices,
|
|
72
|
+
canModerate,
|
|
73
|
+
styles: mergedStyles,
|
|
74
|
+
cssVars,
|
|
75
|
+
}), [userId, resolveUser, reactionChoices, canModerate, mergedStyles, cssVars]);
|
|
76
|
+
const wrapperStyle = {
|
|
77
|
+
...cssVars,
|
|
78
|
+
fontFamily: mergedStyles.fontFamily,
|
|
79
|
+
fontSize: mergedStyles.fontSize,
|
|
80
|
+
color: mergedStyles.textColor,
|
|
81
|
+
};
|
|
82
|
+
return (_jsx(CommentsContext.Provider, { value: value, children: _jsx("div", { className: `comments-provider ${className ?? ""}`, style: wrapperStyle, "data-comments-provider": "", children: children }) }));
|
|
83
|
+
}
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// Hook
|
|
86
|
+
// ============================================================================
|
|
87
|
+
/**
|
|
88
|
+
* Hook to access the comments context.
|
|
89
|
+
* Must be used within a CommentsProvider.
|
|
90
|
+
*/
|
|
91
|
+
export function useComments() {
|
|
92
|
+
const context = useContext(CommentsContext);
|
|
93
|
+
if (!context) {
|
|
94
|
+
throw new Error("useComments must be used within a CommentsProvider");
|
|
95
|
+
}
|
|
96
|
+
return context;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=CommentsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommentsProvider.js","sourceRoot":"","sources":["../../src/react/CommentsProvider.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAsC,MAAM,OAAO,CAAC;AAwC/F,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E,MAAM,aAAa,GAA6B;IAC5C,WAAW,EAAE,SAAS;IACtB,eAAe,EAAE,SAAS;IAC1B,SAAS,EAAE,SAAS;IACpB,cAAc,EAAE,SAAS;IACzB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,KAAK;IACnB,UAAU,EAAE,sCAAsC;IAClD,QAAQ,EAAE,MAAM;CACnB,CAAC;AAEF,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,eAAe,GAAG,aAAa,CAA8B,IAAI,CAAC,CAAC;AA0BzE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC7B,MAAM,EACN,WAAW,EACX,eAAe,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAClE,WAAW,GAAG,KAAK,EACnB,MAAM,EACN,SAAS,EACT,QAAQ,GACY;IACpB,MAAM,YAAY,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,CAAC;QACH,GAAG,aAAa;QAChB,GAAG,MAAM;KACZ,CAAC,EACF,CAAC,MAAM,CAAC,CACX,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACH,yBAAyB,EAAE,YAAY,CAAC,WAAW;QACnD,qBAAqB,EAAE,YAAY,CAAC,eAAe;QACnD,uBAAuB,EAAE,YAAY,CAAC,SAAS;QAC/C,6BAA6B,EAAE,YAAY,CAAC,cAAc;QAC1D,yBAAyB,EAAE,YAAY,CAAC,WAAW;QACnD,0BAA0B,EAAE,YAAY,CAAC,YAAY;QACrD,wBAAwB,EAAE,YAAY,CAAC,UAAU;QACjD,sBAAsB,EAAE,YAAY,CAAC,QAAQ;KAChD,CAAC,EACF,CAAC,YAAY,CAAC,CACjB,CAAC;IAEF,MAAM,KAAK,GAAG,OAAO,CACjB,GAAG,EAAE,CAAC,CAAC;QACH,MAAM;QACN,WAAW;QACX,eAAe;QACf,WAAW;QACX,MAAM,EAAE,YAAY;QACpB,OAAO;KACV,CAAC,EACF,CAAC,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,CAC7E,CAAC;IAEF,MAAM,YAAY,GAAkB;QAChC,GAAG,OAAwB;QAC3B,UAAU,EAAE,YAAY,CAAC,UAAU;QACnC,QAAQ,EAAE,YAAY,CAAC,QAAQ;QAC/B,KAAK,EAAE,YAAY,CAAC,SAAS;KAChC,CAAC;IAEF,OAAO,CACH,KAAC,eAAe,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAClC,cACI,SAAS,EAAE,qBAAqB,SAAS,IAAI,EAAE,EAAE,EACjD,KAAK,EAAE,YAAY,4BACI,EAAE,YAExB,QAAQ,GACP,GACiB,CAC9B,CAAC;AACN,CAAC;AAED,+EAA+E;AAC/E,OAAO;AACP,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,WAAW;IACvB,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReactionPicker Component
|
|
3
|
+
*
|
|
4
|
+
* A popup picker for selecting emoji reactions.
|
|
5
|
+
*/
|
|
6
|
+
export interface ReactionPickerProps {
|
|
7
|
+
/** Callback when an emoji is selected */
|
|
8
|
+
onSelect: (emoji: string) => void;
|
|
9
|
+
/** Callback when the picker is closed */
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
/** Custom reaction choices (overrides provider) */
|
|
12
|
+
reactionChoices?: string[];
|
|
13
|
+
/** CSS class name */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Emoji reaction picker popup.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <ReactionPicker
|
|
22
|
+
* onSelect={(emoji) => toggleReaction({ messageId, emoji })}
|
|
23
|
+
* onClose={() => setShowPicker(false)}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function ReactionPicker({ onSelect, onClose, reactionChoices: customChoices, className, }: ReactionPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=ReactionPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactionPicker.d.ts","sourceRoot":"","sources":["../../src/react/ReactionPicker.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,WAAW,mBAAmB;IAChC,yCAAyC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,eAAe,EAAE,aAAa,EAC9B,SAAc,GACjB,EAAE,mBAAmB,2CAmDrB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ReactionPicker Component
|
|
4
|
+
*
|
|
5
|
+
* A popup picker for selecting emoji reactions.
|
|
6
|
+
*/
|
|
7
|
+
import { useComments } from "./CommentsProvider";
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Component
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Emoji reaction picker popup.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <ReactionPicker
|
|
17
|
+
* onSelect={(emoji) => toggleReaction({ messageId, emoji })}
|
|
18
|
+
* onClose={() => setShowPicker(false)}
|
|
19
|
+
* />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function ReactionPicker({ onSelect, onClose, reactionChoices: customChoices, className = "", }) {
|
|
23
|
+
const { reactionChoices: providerChoices, styles } = useComments();
|
|
24
|
+
const choices = customChoices ?? providerChoices;
|
|
25
|
+
return (_jsx("div", { className: `reaction-picker ${className}`, style: {
|
|
26
|
+
display: "flex",
|
|
27
|
+
flexWrap: "wrap",
|
|
28
|
+
gap: "4px",
|
|
29
|
+
padding: "8px",
|
|
30
|
+
backgroundColor: "white",
|
|
31
|
+
borderRadius: styles?.borderRadius ?? "8px",
|
|
32
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
33
|
+
border: "1px solid #e5e7eb",
|
|
34
|
+
maxWidth: "200px",
|
|
35
|
+
}, children: choices.map((emoji) => (_jsx("button", { onClick: () => {
|
|
36
|
+
onSelect(emoji);
|
|
37
|
+
onClose?.();
|
|
38
|
+
}, style: {
|
|
39
|
+
width: "32px",
|
|
40
|
+
height: "32px",
|
|
41
|
+
display: "flex",
|
|
42
|
+
alignItems: "center",
|
|
43
|
+
justifyContent: "center",
|
|
44
|
+
border: "none",
|
|
45
|
+
background: "transparent",
|
|
46
|
+
borderRadius: "4px",
|
|
47
|
+
cursor: "pointer",
|
|
48
|
+
fontSize: "18px",
|
|
49
|
+
transition: "background-color 0.15s",
|
|
50
|
+
}, onMouseEnter: (e) => {
|
|
51
|
+
e.currentTarget.style.backgroundColor = "#f3f4f6";
|
|
52
|
+
}, onMouseLeave: (e) => {
|
|
53
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
54
|
+
}, children: emoji }, emoji))) }));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ReactionPicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactionPicker.js","sourceRoot":"","sources":["../../src/react/ReactionPicker.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAiBjD,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,eAAe,EAAE,aAAa,EAC9B,SAAS,GAAG,EAAE,GACI;IAClB,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,aAAa,IAAI,eAAe,CAAC;IAEjD,OAAO,CACH,cACI,SAAS,EAAE,mBAAmB,SAAS,EAAE,EACzC,KAAK,EAAE;YACH,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,MAAM;YAChB,GAAG,EAAE,KAAK;YACV,OAAO,EAAE,KAAK;YACd,eAAe,EAAE,OAAO;YACxB,YAAY,EAAE,MAAM,EAAE,YAAY,IAAI,KAAK;YAC3C,SAAS,EAAE,6BAA6B;YACxC,MAAM,EAAE,mBAAmB;YAC3B,QAAQ,EAAE,OAAO;SACpB,YAEA,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACpB,iBAEI,OAAO,EAAE,GAAG,EAAE;gBACV,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAChB,OAAO,EAAE,EAAE,CAAC;YAChB,CAAC,EACD,KAAK,EAAE;gBACH,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,MAAM;gBACf,UAAU,EAAE,QAAQ;gBACpB,cAAc,EAAE,QAAQ;gBACxB,MAAM,EAAE,MAAM;gBACd,UAAU,EAAE,aAAa;gBACzB,YAAY,EAAE,KAAK;gBACnB,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,wBAAwB;aACvC,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;gBAChB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC;YACtD,CAAC,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;gBAChB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,eAAe,GAAG,aAAa,CAAC;YAC1D,CAAC,YAEA,KAAK,IAzBD,KAAK,CA0BL,CACZ,CAAC,GACA,CACT,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thread Component
|
|
3
|
+
*
|
|
4
|
+
* Displays a single thread with all its messages.
|
|
5
|
+
*/
|
|
6
|
+
import { type ReactNode } from "react";
|
|
7
|
+
import { type MessageData } from "./Comment";
|
|
8
|
+
export interface ThreadInfo {
|
|
9
|
+
_id: string;
|
|
10
|
+
zoneId: string;
|
|
11
|
+
resolved: boolean;
|
|
12
|
+
resolvedBy?: string;
|
|
13
|
+
resolvedAt?: number;
|
|
14
|
+
createdAt: number;
|
|
15
|
+
lastActivityAt: number;
|
|
16
|
+
position?: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
anchor?: string;
|
|
20
|
+
};
|
|
21
|
+
metadata?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface ThreadProps {
|
|
24
|
+
/** Thread data */
|
|
25
|
+
thread: ThreadInfo;
|
|
26
|
+
/** Messages in this thread */
|
|
27
|
+
messages: MessageData[];
|
|
28
|
+
/** Typing users in this thread */
|
|
29
|
+
typingUsers?: Array<{
|
|
30
|
+
userId: string;
|
|
31
|
+
updatedAt: number;
|
|
32
|
+
}>;
|
|
33
|
+
/** Whether there are more messages to load */
|
|
34
|
+
hasMore?: boolean;
|
|
35
|
+
/** Loading state */
|
|
36
|
+
isLoading?: boolean;
|
|
37
|
+
/** Callback when load more is triggered */
|
|
38
|
+
onLoadMore?: () => void;
|
|
39
|
+
/** Callback when a new message is submitted */
|
|
40
|
+
onSubmit?: (body: string, attachments?: Array<{
|
|
41
|
+
type: "url" | "file" | "image";
|
|
42
|
+
url: string;
|
|
43
|
+
name?: string;
|
|
44
|
+
}>) => void;
|
|
45
|
+
/** Callback when typing state changes */
|
|
46
|
+
onTypingChange?: (isTyping: boolean) => void;
|
|
47
|
+
/** Callback when a reaction is toggled */
|
|
48
|
+
onToggleReaction?: (messageId: string, emoji: string) => void;
|
|
49
|
+
/** Callback when a message is edited */
|
|
50
|
+
onEditMessage?: (messageId: string, newBody: string) => void;
|
|
51
|
+
/** Callback when a message is deleted */
|
|
52
|
+
onDeleteMessage?: (messageId: string) => void;
|
|
53
|
+
/** Callback to resolve the thread */
|
|
54
|
+
onResolve?: () => void;
|
|
55
|
+
/** Callback to unresolve the thread */
|
|
56
|
+
onUnresolve?: () => void;
|
|
57
|
+
/** Callback to close/go back */
|
|
58
|
+
onClose?: () => void;
|
|
59
|
+
/** Whether editing is allowed */
|
|
60
|
+
allowEditing?: boolean;
|
|
61
|
+
/** Whether to auto-scroll to bottom on new messages */
|
|
62
|
+
autoScroll?: boolean;
|
|
63
|
+
/** Custom message renderer */
|
|
64
|
+
renderMessage?: (message: MessageData, mine: boolean) => ReactNode;
|
|
65
|
+
/** CSS class name */
|
|
66
|
+
className?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Component to display a single thread with its messages.
|
|
70
|
+
*
|
|
71
|
+
* Usage:
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <Thread
|
|
74
|
+
* thread={thread}
|
|
75
|
+
* messages={messages}
|
|
76
|
+
* typingUsers={typingUsers}
|
|
77
|
+
* onSubmit={(body) => addComment({ threadId: thread._id, body })}
|
|
78
|
+
* onTypingChange={(isTyping) => setIsTyping({ threadId: thread._id, isTyping })}
|
|
79
|
+
* onToggleReaction={(messageId, emoji) => toggleReaction({ messageId, emoji })}
|
|
80
|
+
* />
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function Thread({ thread, messages, typingUsers, hasMore, isLoading, onLoadMore, onSubmit, onTypingChange, onToggleReaction, onEditMessage, onDeleteMessage, onResolve, onUnresolve, onClose, allowEditing, autoScroll, renderMessage, className, }: ThreadProps): import("react/jsx-runtime").JSX.Element;
|
|
84
|
+
//# sourceMappingURL=Thread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../src/react/Thread.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAQtD,MAAM,WAAW,UAAU;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IACxB,kBAAkB;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,kCAAkC;IAClC,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,IAAI,CAAC;IACvH,yCAAyC;IACzC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,wCAAwC;IACxC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,yCAAyC;IACzC,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iCAAiC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8BAA8B;IAC9B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,KAAK,SAAS,CAAC;IACnE,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,EACnB,MAAM,EACN,QAAQ,EACR,WAAgB,EAChB,OAAe,EACf,SAAiB,EACjB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,SAAS,EACT,WAAW,EACX,OAAO,EACP,YAAmB,EACnB,UAAiB,EACjB,aAAa,EACb,SAAc,GACjB,EAAE,WAAW,2CAsOb"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Thread Component
|
|
4
|
+
*
|
|
5
|
+
* Displays a single thread with all its messages.
|
|
6
|
+
*/
|
|
7
|
+
import { useEffect, useRef } from "react";
|
|
8
|
+
import { useComments } from "./CommentsProvider";
|
|
9
|
+
import { Comment } from "./Comment";
|
|
10
|
+
import { AddComment } from "./AddComment";
|
|
11
|
+
import { TypingIndicator } from "./TypingIndicator";
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Component
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Component to display a single thread with its messages.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <Thread
|
|
21
|
+
* thread={thread}
|
|
22
|
+
* messages={messages}
|
|
23
|
+
* typingUsers={typingUsers}
|
|
24
|
+
* onSubmit={(body) => addComment({ threadId: thread._id, body })}
|
|
25
|
+
* onTypingChange={(isTyping) => setIsTyping({ threadId: thread._id, isTyping })}
|
|
26
|
+
* onToggleReaction={(messageId, emoji) => toggleReaction({ messageId, emoji })}
|
|
27
|
+
* />
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function Thread({ thread, messages, typingUsers = [], hasMore = false, isLoading = false, onLoadMore, onSubmit, onTypingChange, onToggleReaction, onEditMessage, onDeleteMessage, onResolve, onUnresolve, onClose, allowEditing = true, autoScroll = true, renderMessage, className = "", }) {
|
|
31
|
+
const { userId, styles } = useComments();
|
|
32
|
+
const messagesEndRef = useRef(null);
|
|
33
|
+
const prevMessageCount = useRef(messages.length);
|
|
34
|
+
// Auto-scroll to bottom on new messages
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (autoScroll && messages.length > prevMessageCount.current) {
|
|
37
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
38
|
+
}
|
|
39
|
+
prevMessageCount.current = messages.length;
|
|
40
|
+
}, [messages.length, autoScroll]);
|
|
41
|
+
const handleSubmit = (body, attachments) => {
|
|
42
|
+
onSubmit?.(body, attachments);
|
|
43
|
+
};
|
|
44
|
+
return (_jsxs("div", { className: `thread-container ${className}`, style: {
|
|
45
|
+
fontFamily: styles?.fontFamily ?? "system-ui, -apple-system, sans-serif",
|
|
46
|
+
display: "flex",
|
|
47
|
+
flexDirection: "column",
|
|
48
|
+
height: "100%",
|
|
49
|
+
border: "1px solid #e5e7eb",
|
|
50
|
+
borderRadius: styles?.borderRadius ?? "8px",
|
|
51
|
+
overflow: "hidden",
|
|
52
|
+
}, children: [_jsxs("div", { style: {
|
|
53
|
+
padding: "12px 16px",
|
|
54
|
+
borderBottom: "1px solid #e5e7eb",
|
|
55
|
+
display: "flex",
|
|
56
|
+
justifyContent: "space-between",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
backgroundColor: thread.resolved ? "#f0fdf4" : "#f9fafb",
|
|
59
|
+
}, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [onClose && (_jsx("button", { onClick: onClose, style: {
|
|
60
|
+
padding: "4px 8px",
|
|
61
|
+
border: "none",
|
|
62
|
+
background: "transparent",
|
|
63
|
+
cursor: "pointer",
|
|
64
|
+
fontSize: "16px",
|
|
65
|
+
}, children: "\u2190" })), _jsxs("span", { style: { fontWeight: 600, fontSize: "14px" }, children: ["Thread", thread.resolved && (_jsx("span", { style: { color: "#16a34a", marginLeft: "8px", fontWeight: 400 }, children: "\u2713 Resolved" }))] })] }), _jsxs("div", { style: { display: "flex", gap: "8px" }, children: [thread.resolved && onUnresolve && (_jsx("button", { onClick: onUnresolve, style: {
|
|
66
|
+
padding: "6px 12px",
|
|
67
|
+
fontSize: "13px",
|
|
68
|
+
border: "1px solid #d1d5db",
|
|
69
|
+
borderRadius: "6px",
|
|
70
|
+
background: "white",
|
|
71
|
+
cursor: "pointer",
|
|
72
|
+
}, children: "Reopen" })), !thread.resolved && onResolve && userId && (_jsx("button", { onClick: onResolve, style: {
|
|
73
|
+
padding: "6px 12px",
|
|
74
|
+
fontSize: "13px",
|
|
75
|
+
fontWeight: 500,
|
|
76
|
+
border: "none",
|
|
77
|
+
borderRadius: "6px",
|
|
78
|
+
backgroundColor: "#16a34a",
|
|
79
|
+
color: "white",
|
|
80
|
+
cursor: "pointer",
|
|
81
|
+
}, children: "Resolve" }))] })] }), _jsxs("div", { style: {
|
|
82
|
+
flex: 1,
|
|
83
|
+
overflowY: "auto",
|
|
84
|
+
padding: "16px",
|
|
85
|
+
}, children: [hasMore && (_jsx("div", { style: { textAlign: "center", marginBottom: "16px" }, children: _jsx("button", { onClick: onLoadMore, disabled: isLoading, style: {
|
|
86
|
+
padding: "8px 16px",
|
|
87
|
+
fontSize: "13px",
|
|
88
|
+
border: "1px solid #d1d5db",
|
|
89
|
+
borderRadius: "6px",
|
|
90
|
+
background: "white",
|
|
91
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
92
|
+
opacity: isLoading ? 0.6 : 1,
|
|
93
|
+
}, children: isLoading ? "Loading..." : "Load Earlier Messages" }) })), messages.length === 0 ? (_jsx("div", { style: {
|
|
94
|
+
textAlign: "center",
|
|
95
|
+
color: "#6b7280",
|
|
96
|
+
fontSize: "14px",
|
|
97
|
+
padding: "40px 0",
|
|
98
|
+
}, children: "No messages yet. Start the conversation!" })) : (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: messages.map((message) => {
|
|
99
|
+
const isMine = userId === message.message.authorId;
|
|
100
|
+
return renderMessage ? (renderMessage(message, isMine)) : (_jsx(Comment, { comment: message, mine: isMine, onToggleReaction: onToggleReaction
|
|
101
|
+
? (emoji) => onToggleReaction(message.message._id, emoji)
|
|
102
|
+
: undefined, onEdit: onEditMessage && isMine
|
|
103
|
+
? (newBody) => onEditMessage(message.message._id, newBody)
|
|
104
|
+
: undefined, onDelete: onDeleteMessage && isMine
|
|
105
|
+
? () => onDeleteMessage(message.message._id)
|
|
106
|
+
: undefined }, message.message._id));
|
|
107
|
+
}) })), typingUsers.length > 0 && (_jsx("div", { style: { marginTop: "12px" }, children: _jsx(TypingIndicator, { users: typingUsers.map((u) => u.userId) }) })), _jsx("div", { ref: messagesEndRef })] }), userId && !thread.resolved && (_jsx("div", { style: { borderTop: "1px solid #e5e7eb" }, children: _jsx(AddComment, { onSubmit: handleSubmit, onTypingChange: onTypingChange, allowEditing: allowEditing, placeholder: "Write a reply..." }) })), thread.resolved && (_jsxs("div", { style: {
|
|
108
|
+
padding: "12px 16px",
|
|
109
|
+
borderTop: "1px solid #e5e7eb",
|
|
110
|
+
textAlign: "center",
|
|
111
|
+
color: "#6b7280",
|
|
112
|
+
fontSize: "13px",
|
|
113
|
+
backgroundColor: "#f9fafb",
|
|
114
|
+
}, children: ["This thread has been resolved.", onUnresolve && (_jsx("button", { onClick: onUnresolve, style: {
|
|
115
|
+
marginLeft: "8px",
|
|
116
|
+
padding: "0",
|
|
117
|
+
border: "none",
|
|
118
|
+
background: "transparent",
|
|
119
|
+
color: styles?.accentColor ?? "#3b82f6",
|
|
120
|
+
cursor: "pointer",
|
|
121
|
+
textDecoration: "underline",
|
|
122
|
+
}, children: "Reopen" }))] }))] }));
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=Thread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.js","sourceRoot":"","sources":["../../src/react/Thread.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypingIndicator Component
|
|
3
|
+
*
|
|
4
|
+
* Shows who is currently typing in a thread.
|
|
5
|
+
*/
|
|
6
|
+
export interface TypingIndicatorProps {
|
|
7
|
+
/** User IDs currently typing */
|
|
8
|
+
users: string[];
|
|
9
|
+
/** Max number of names to show before "and X others" */
|
|
10
|
+
maxNamesToShow?: number;
|
|
11
|
+
/** CSS class name */
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Animated typing indicator showing who is typing.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const typingUsers = useQuery(api.comments.getTypingUsers, { threadId });
|
|
20
|
+
*
|
|
21
|
+
* <TypingIndicator users={typingUsers.map(u => u.userId)} />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function TypingIndicator({ users, maxNamesToShow, className, }: TypingIndicatorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
25
|
+
//# sourceMappingURL=TypingIndicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypingIndicator.d.ts","sourceRoot":"","sources":["../../src/react/TypingIndicator.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,WAAW,oBAAoB;IACjC,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,EAC5B,KAAK,EACL,cAAkB,EAClB,SAAc,GACjB,EAAE,oBAAoB,kDAuGtB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TypingIndicator Component
|
|
4
|
+
*
|
|
5
|
+
* Shows who is currently typing in a thread.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useEffect } from "react";
|
|
8
|
+
import { useComments } from "./CommentsProvider";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Component
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Animated typing indicator showing who is typing.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const typingUsers = useQuery(api.comments.getTypingUsers, { threadId });
|
|
18
|
+
*
|
|
19
|
+
* <TypingIndicator users={typingUsers.map(u => u.userId)} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function TypingIndicator({ users, maxNamesToShow = 3, className = "", }) {
|
|
23
|
+
const { resolveUser } = useComments();
|
|
24
|
+
const [userNames, setUserNames] = useState({});
|
|
25
|
+
// Resolve user names
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (resolveUser) {
|
|
28
|
+
users.forEach(async (userId) => {
|
|
29
|
+
if (!userNames[userId]) {
|
|
30
|
+
const info = await resolveUser(userId);
|
|
31
|
+
setUserNames((prev) => ({ ...prev, [userId]: info.name }));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}, [users, resolveUser, userNames]);
|
|
36
|
+
if (users.length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// Format the typing message
|
|
40
|
+
const names = users.map((id) => userNames[id] ?? id);
|
|
41
|
+
let message;
|
|
42
|
+
if (names.length === 1) {
|
|
43
|
+
message = `${names[0]} is typing`;
|
|
44
|
+
}
|
|
45
|
+
else if (names.length <= maxNamesToShow) {
|
|
46
|
+
const lastN = names[names.length - 1];
|
|
47
|
+
const restNames = names.slice(0, -1).join(", ");
|
|
48
|
+
message = `${restNames} and ${lastN} are typing`;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const shown = names.slice(0, maxNamesToShow).join(", ");
|
|
52
|
+
const remaining = names.length - maxNamesToShow;
|
|
53
|
+
message = `${shown} and ${remaining} others are typing`;
|
|
54
|
+
}
|
|
55
|
+
return (_jsxs("div", { className: `typing-indicator ${className}`, style: {
|
|
56
|
+
display: "flex",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
gap: "8px",
|
|
59
|
+
fontSize: "13px",
|
|
60
|
+
color: "#6b7280",
|
|
61
|
+
fontStyle: "italic",
|
|
62
|
+
}, children: [_jsxs("span", { style: {
|
|
63
|
+
display: "inline-flex",
|
|
64
|
+
gap: "2px",
|
|
65
|
+
}, children: [_jsx("span", { style: {
|
|
66
|
+
width: "4px",
|
|
67
|
+
height: "4px",
|
|
68
|
+
borderRadius: "50%",
|
|
69
|
+
backgroundColor: "#9ca3af",
|
|
70
|
+
animation: "typingDot 1.4s infinite ease-in-out",
|
|
71
|
+
animationDelay: "0s",
|
|
72
|
+
} }), _jsx("span", { style: {
|
|
73
|
+
width: "4px",
|
|
74
|
+
height: "4px",
|
|
75
|
+
borderRadius: "50%",
|
|
76
|
+
backgroundColor: "#9ca3af",
|
|
77
|
+
animation: "typingDot 1.4s infinite ease-in-out",
|
|
78
|
+
animationDelay: "0.2s",
|
|
79
|
+
} }), _jsx("span", { style: {
|
|
80
|
+
width: "4px",
|
|
81
|
+
height: "4px",
|
|
82
|
+
borderRadius: "50%",
|
|
83
|
+
backgroundColor: "#9ca3af",
|
|
84
|
+
animation: "typingDot 1.4s infinite ease-in-out",
|
|
85
|
+
animationDelay: "0.4s",
|
|
86
|
+
} })] }), _jsx("span", { children: message }), _jsx("style", { children: `
|
|
87
|
+
@keyframes typingDot {
|
|
88
|
+
0%, 80%, 100% {
|
|
89
|
+
transform: scale(1);
|
|
90
|
+
opacity: 0.5;
|
|
91
|
+
}
|
|
92
|
+
40% {
|
|
93
|
+
transform: scale(1.2);
|
|
94
|
+
opacity: 1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
` })] }));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=TypingIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypingIndicator.js","sourceRoot":"","sources":["../../src/react/TypingIndicator.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comments Component - React UI
|
|
3
|
+
*
|
|
4
|
+
* Drop-in React components for the comments system.
|
|
5
|
+
* These components provide a fully managed UI for comments,
|
|
6
|
+
* threads, reactions, and typing indicators.
|
|
7
|
+
*/
|
|
8
|
+
export { CommentsProvider, useComments, type CommentsContextValue, type CommentsStyles, type CommentsProviderProps, } from "./CommentsProvider";
|
|
9
|
+
export { Comments, type CommentsProps, } from "./Comments";
|
|
10
|
+
export { Thread, type ThreadProps, } from "./Thread";
|
|
11
|
+
export { Comment, type CommentProps, } from "./Comment";
|
|
12
|
+
export { AddComment, type AddCommentProps, } from "./AddComment";
|
|
13
|
+
export { ReactionPicker, type ReactionPickerProps, } from "./ReactionPicker";
|
|
14
|
+
export { TypingIndicator, type TypingIndicatorProps, } from "./TypingIndicator";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,QAAQ,EACR,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,MAAM,EACN,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,OAAO,EACP,KAAK,YAAY,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comments Component - React UI
|
|
3
|
+
*
|
|
4
|
+
* Drop-in React components for the comments system.
|
|
5
|
+
* These components provide a fully managed UI for comments,
|
|
6
|
+
* threads, reactions, and typing indicators.
|
|
7
|
+
*/
|
|
8
|
+
export { CommentsProvider, useComments, } from "./CommentsProvider";
|
|
9
|
+
export { Comments, } from "./Comments";
|
|
10
|
+
export { Thread, } from "./Thread";
|
|
11
|
+
export { Comment, } from "./Comment";
|
|
12
|
+
export { AddComment, } from "./AddComment";
|
|
13
|
+
export { ReactionPicker, } from "./ReactionPicker";
|
|
14
|
+
export { TypingIndicator, } from "./TypingIndicator";
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,gBAAgB,EAChB,WAAW,GAIZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,QAAQ,GAET,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,MAAM,GAEP,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,OAAO,GAER,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,UAAU,GAEX,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,cAAc,GAEf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,eAAe,GAEhB,MAAM,mBAAmB,CAAC"}
|