@cstar.help/react 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -5
- package/dist/index.cjs +191 -0
- package/dist/index.d.cts +104 -1
- package/dist/index.d.ts +104 -1
- package/dist/index.js +184 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
React hooks for the [cStar](https://cstar.help) customer support platform. Build custom chat widgets and knowledge base UIs with type-safe, SSR-compatible hooks.
|
|
4
4
|
|
|
5
5
|
- **React 18+** — hooks with automatic loading states and error handling
|
|
6
|
-
- **
|
|
6
|
+
- **Three modules** — Chat (real-time messaging), Library (knowledge base), and Community (forum)
|
|
7
7
|
- **TypeScript-first** — full type definitions included
|
|
8
8
|
- **Tiny** — ~18 KB, tree-shakeable, only peer deps
|
|
9
9
|
|
|
@@ -182,6 +182,87 @@ function SearchBar() {
|
|
|
182
182
|
}
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
+
## Community
|
|
186
|
+
|
|
187
|
+
Wrap in `<CStarCommunityProvider>` for public community forum access — no auth required.
|
|
188
|
+
|
|
189
|
+
### Setup
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { CStarCommunityProvider } from '@cstar.help/react';
|
|
193
|
+
|
|
194
|
+
function App() {
|
|
195
|
+
return (
|
|
196
|
+
<CStarCommunityProvider teamSlug="acme">
|
|
197
|
+
<CommunityForum />
|
|
198
|
+
</CStarCommunityProvider>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Topics + Posts
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { useTopics, usePosts, usePost } from '@cstar.help/react';
|
|
207
|
+
|
|
208
|
+
function CommunityForum() {
|
|
209
|
+
const { topics, isLoading: topicsLoading } = useTopics();
|
|
210
|
+
const { posts, count, isLoading: postsLoading } = usePosts({ sort: 'votes' });
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<>
|
|
214
|
+
<nav>
|
|
215
|
+
{topics.map((topic) => (
|
|
216
|
+
<a key={topic.id}>{topic.name}</a>
|
|
217
|
+
))}
|
|
218
|
+
</nav>
|
|
219
|
+
<p>{count} posts</p>
|
|
220
|
+
<ul>
|
|
221
|
+
{posts.map((post) => (
|
|
222
|
+
<li key={post.id}>
|
|
223
|
+
{post.title} — {post.voteCount} votes
|
|
224
|
+
</li>
|
|
225
|
+
))}
|
|
226
|
+
</ul>
|
|
227
|
+
</>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Single post with comments
|
|
232
|
+
function PostPage({ slug }) {
|
|
233
|
+
const { data, isLoading, error } = usePost(slug);
|
|
234
|
+
if (isLoading) return <Spinner />;
|
|
235
|
+
if (!data) return <NotFound />;
|
|
236
|
+
return (
|
|
237
|
+
<>
|
|
238
|
+
<h1>{data.post.title}</h1>
|
|
239
|
+
{data.comments.map((c) => (
|
|
240
|
+
<p key={c.id}>{c.body}</p>
|
|
241
|
+
))}
|
|
242
|
+
</>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Search
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
import { useCommunitySearch } from '@cstar.help/react';
|
|
251
|
+
|
|
252
|
+
function CommunitySearch() {
|
|
253
|
+
const { results, isLoading, search } = useCommunitySearch();
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<>
|
|
257
|
+
<input onChange={(e) => search(e.target.value)} placeholder="Search posts..." />
|
|
258
|
+
{results?.data.map((post) => (
|
|
259
|
+
<a key={post.id}>{post.title}</a>
|
|
260
|
+
))}
|
|
261
|
+
</>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
185
266
|
## API Reference
|
|
186
267
|
|
|
187
268
|
### Chat Hooks
|
|
@@ -202,12 +283,22 @@ function SearchBar() {
|
|
|
202
283
|
| `useArticle(slug)` | `{ article, isLoading, error, refresh }` | Single article by slug |
|
|
203
284
|
| `useArticleSearch(query)` | `{ results, totalCount, isLoading, error }` | Search with 300ms debounce |
|
|
204
285
|
|
|
286
|
+
### Community Hooks
|
|
287
|
+
|
|
288
|
+
| Hook | Returns | Description |
|
|
289
|
+
| ---------------------- | --------------------------------------------- | ----------------------------------------------------- |
|
|
290
|
+
| `useTopics()` | `{ topics, isLoading, error, refresh }` | Community discussion topics |
|
|
291
|
+
| `usePosts(params?)` | `{ posts, count, isLoading, error, refresh }` | Posts with optional filters (topicSlug, status, sort) |
|
|
292
|
+
| `usePost(slug)` | `{ data, isLoading, error, refresh }` | Single post with comments |
|
|
293
|
+
| `useCommunitySearch()` | `{ results, isLoading, error, search }` | On-demand search across posts |
|
|
294
|
+
|
|
205
295
|
### Context Accessors
|
|
206
296
|
|
|
207
|
-
| Function
|
|
208
|
-
|
|
|
209
|
-
| `useChatClient()`
|
|
210
|
-
| `useLibraryClient()`
|
|
297
|
+
| Function | Returns | Description |
|
|
298
|
+
| ---------------------- | ----------------- | ------------------------------------------------ |
|
|
299
|
+
| `useChatClient()` | `ChatClient` | Raw client from nearest `CStarChatProvider` |
|
|
300
|
+
| `useLibraryClient()` | `LibraryClient` | Raw client from nearest `CStarLibraryProvider` |
|
|
301
|
+
| `useCommunityClient()` | `CommunityClient` | Raw client from nearest `CStarCommunityProvider` |
|
|
211
302
|
|
|
212
303
|
## Requirements
|
|
213
304
|
|
package/dist/index.cjs
CHANGED
|
@@ -22,6 +22,8 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
CStarChatContext: () => CStarChatContext,
|
|
24
24
|
CStarChatProvider: () => CStarChatProvider,
|
|
25
|
+
CStarCommunityContext: () => CStarCommunityContext,
|
|
26
|
+
CStarCommunityProvider: () => CStarCommunityProvider,
|
|
25
27
|
CStarLibraryContext: () => CStarLibraryContext,
|
|
26
28
|
CStarLibraryProvider: () => CStarLibraryProvider,
|
|
27
29
|
useArticle: () => useArticle,
|
|
@@ -30,9 +32,14 @@ __export(src_exports, {
|
|
|
30
32
|
useCategories: () => useCategories,
|
|
31
33
|
useChat: () => useChat,
|
|
32
34
|
useChatClient: () => useChatClient,
|
|
35
|
+
useCommunityClient: () => useCommunityClient,
|
|
36
|
+
useCommunitySearch: () => useCommunitySearch,
|
|
33
37
|
useConversations: () => useConversations,
|
|
34
38
|
useLibraryClient: () => useLibraryClient,
|
|
35
39
|
useMessages: () => useMessages,
|
|
40
|
+
usePost: () => usePost,
|
|
41
|
+
usePosts: () => usePosts,
|
|
42
|
+
useTopics: () => useTopics,
|
|
36
43
|
useTyping: () => useTyping
|
|
37
44
|
});
|
|
38
45
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -41,6 +48,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
41
48
|
var import_react = require("react");
|
|
42
49
|
var CStarChatContext = (0, import_react.createContext)(null);
|
|
43
50
|
var CStarLibraryContext = (0, import_react.createContext)(null);
|
|
51
|
+
var CStarCommunityContext = (0, import_react.createContext)(null);
|
|
44
52
|
function useChatClient() {
|
|
45
53
|
const client = (0, import_react.useContext)(CStarChatContext);
|
|
46
54
|
if (!client) {
|
|
@@ -55,6 +63,13 @@ function useLibraryClient() {
|
|
|
55
63
|
}
|
|
56
64
|
return client;
|
|
57
65
|
}
|
|
66
|
+
function useCommunityClient() {
|
|
67
|
+
const client = (0, import_react.useContext)(CStarCommunityContext);
|
|
68
|
+
if (!client) {
|
|
69
|
+
throw new Error("useCommunityClient must be used within a <CStarCommunityProvider>");
|
|
70
|
+
}
|
|
71
|
+
return client;
|
|
72
|
+
}
|
|
58
73
|
|
|
59
74
|
// src/chat/CStarChatProvider.tsx
|
|
60
75
|
var import_react2 = require("react");
|
|
@@ -480,10 +495,181 @@ function useArticleSearch(query) {
|
|
|
480
495
|
}, [client, query]);
|
|
481
496
|
return { results, totalCount, isLoading, error };
|
|
482
497
|
}
|
|
498
|
+
|
|
499
|
+
// src/community/CStarCommunityProvider.tsx
|
|
500
|
+
var import_react12 = require("react");
|
|
501
|
+
var import_community = require("@cstar.help/js/community");
|
|
502
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
503
|
+
function CStarCommunityProvider({ children, ...config }) {
|
|
504
|
+
const clientRef = (0, import_react12.useRef)(null);
|
|
505
|
+
if (!clientRef.current) {
|
|
506
|
+
clientRef.current = new import_community.CommunityClient(config);
|
|
507
|
+
}
|
|
508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CStarCommunityContext.Provider, { value: clientRef.current, children });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/community/useTopics.ts
|
|
512
|
+
var import_react13 = require("react");
|
|
513
|
+
function useTopics() {
|
|
514
|
+
const client = useCommunityClient();
|
|
515
|
+
const [topics, setTopics] = (0, import_react13.useState)([]);
|
|
516
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
517
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
518
|
+
const mountedRef = (0, import_react13.useRef)(true);
|
|
519
|
+
const refresh = (0, import_react13.useCallback)(async () => {
|
|
520
|
+
setIsLoading(true);
|
|
521
|
+
setError(null);
|
|
522
|
+
try {
|
|
523
|
+
const data = await client.topics();
|
|
524
|
+
if (mountedRef.current) {
|
|
525
|
+
setTopics(data);
|
|
526
|
+
}
|
|
527
|
+
} catch (err) {
|
|
528
|
+
if (mountedRef.current) {
|
|
529
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
530
|
+
}
|
|
531
|
+
} finally {
|
|
532
|
+
if (mountedRef.current) {
|
|
533
|
+
setIsLoading(false);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}, [client]);
|
|
537
|
+
(0, import_react13.useEffect)(() => {
|
|
538
|
+
mountedRef.current = true;
|
|
539
|
+
refresh();
|
|
540
|
+
return () => {
|
|
541
|
+
mountedRef.current = false;
|
|
542
|
+
};
|
|
543
|
+
}, [refresh]);
|
|
544
|
+
return { topics, isLoading, error, refresh };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/community/usePosts.ts
|
|
548
|
+
var import_react14 = require("react");
|
|
549
|
+
function usePosts(params) {
|
|
550
|
+
const client = useCommunityClient();
|
|
551
|
+
const [posts, setPosts] = (0, import_react14.useState)([]);
|
|
552
|
+
const [count, setCount] = (0, import_react14.useState)(0);
|
|
553
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
554
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
555
|
+
const mountedRef = (0, import_react14.useRef)(true);
|
|
556
|
+
const topicSlug = params?.topicSlug;
|
|
557
|
+
const status = params?.status;
|
|
558
|
+
const sort = params?.sort;
|
|
559
|
+
const limit = params?.limit;
|
|
560
|
+
const offset = params?.offset;
|
|
561
|
+
const refresh = (0, import_react14.useCallback)(async () => {
|
|
562
|
+
setIsLoading(true);
|
|
563
|
+
setError(null);
|
|
564
|
+
try {
|
|
565
|
+
const result = await client.posts({ topicSlug, status, sort, limit, offset });
|
|
566
|
+
if (mountedRef.current) {
|
|
567
|
+
setPosts(result.posts);
|
|
568
|
+
setCount(result.count);
|
|
569
|
+
}
|
|
570
|
+
} catch (err) {
|
|
571
|
+
if (mountedRef.current) {
|
|
572
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
573
|
+
}
|
|
574
|
+
} finally {
|
|
575
|
+
if (mountedRef.current) {
|
|
576
|
+
setIsLoading(false);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}, [client, topicSlug, status, sort, limit, offset]);
|
|
580
|
+
(0, import_react14.useEffect)(() => {
|
|
581
|
+
mountedRef.current = true;
|
|
582
|
+
refresh();
|
|
583
|
+
return () => {
|
|
584
|
+
mountedRef.current = false;
|
|
585
|
+
};
|
|
586
|
+
}, [refresh]);
|
|
587
|
+
return { posts, count, isLoading, error, refresh };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/community/usePost.ts
|
|
591
|
+
var import_react15 = require("react");
|
|
592
|
+
function usePost(slug) {
|
|
593
|
+
const client = useCommunityClient();
|
|
594
|
+
const [data, setData] = (0, import_react15.useState)(null);
|
|
595
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
|
|
596
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
597
|
+
const mountedRef = (0, import_react15.useRef)(true);
|
|
598
|
+
const refresh = (0, import_react15.useCallback)(async () => {
|
|
599
|
+
setIsLoading(true);
|
|
600
|
+
setError(null);
|
|
601
|
+
try {
|
|
602
|
+
const result = await client.post(slug);
|
|
603
|
+
if (mountedRef.current) {
|
|
604
|
+
setData(result);
|
|
605
|
+
}
|
|
606
|
+
} catch (err) {
|
|
607
|
+
if (mountedRef.current) {
|
|
608
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
609
|
+
}
|
|
610
|
+
} finally {
|
|
611
|
+
if (mountedRef.current) {
|
|
612
|
+
setIsLoading(false);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}, [client, slug]);
|
|
616
|
+
(0, import_react15.useEffect)(() => {
|
|
617
|
+
mountedRef.current = true;
|
|
618
|
+
refresh();
|
|
619
|
+
return () => {
|
|
620
|
+
mountedRef.current = false;
|
|
621
|
+
};
|
|
622
|
+
}, [refresh]);
|
|
623
|
+
return { data, isLoading, error, refresh };
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/community/useCommunitySearch.ts
|
|
627
|
+
var import_react16 = require("react");
|
|
628
|
+
function useCommunitySearch() {
|
|
629
|
+
const client = useCommunityClient();
|
|
630
|
+
const [results, setResults] = (0, import_react16.useState)(null);
|
|
631
|
+
const [isLoading, setIsLoading] = (0, import_react16.useState)(false);
|
|
632
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
633
|
+
const mountedRef = (0, import_react16.useRef)(true);
|
|
634
|
+
(0, import_react16.useEffect)(() => {
|
|
635
|
+
mountedRef.current = true;
|
|
636
|
+
return () => {
|
|
637
|
+
mountedRef.current = false;
|
|
638
|
+
};
|
|
639
|
+
}, []);
|
|
640
|
+
const search = (0, import_react16.useCallback)(
|
|
641
|
+
async (query) => {
|
|
642
|
+
if (!query.trim()) {
|
|
643
|
+
setResults(null);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
setIsLoading(true);
|
|
647
|
+
setError(null);
|
|
648
|
+
try {
|
|
649
|
+
const data = await client.search(query);
|
|
650
|
+
if (mountedRef.current) {
|
|
651
|
+
setResults(data);
|
|
652
|
+
}
|
|
653
|
+
} catch (err) {
|
|
654
|
+
if (mountedRef.current) {
|
|
655
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
656
|
+
}
|
|
657
|
+
} finally {
|
|
658
|
+
if (mountedRef.current) {
|
|
659
|
+
setIsLoading(false);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
[client]
|
|
664
|
+
);
|
|
665
|
+
return { results, isLoading, error, search };
|
|
666
|
+
}
|
|
483
667
|
// Annotate the CommonJS export names for ESM import in node:
|
|
484
668
|
0 && (module.exports = {
|
|
485
669
|
CStarChatContext,
|
|
486
670
|
CStarChatProvider,
|
|
671
|
+
CStarCommunityContext,
|
|
672
|
+
CStarCommunityProvider,
|
|
487
673
|
CStarLibraryContext,
|
|
488
674
|
CStarLibraryProvider,
|
|
489
675
|
useArticle,
|
|
@@ -492,8 +678,13 @@ function useArticleSearch(query) {
|
|
|
492
678
|
useCategories,
|
|
493
679
|
useChat,
|
|
494
680
|
useChatClient,
|
|
681
|
+
useCommunityClient,
|
|
682
|
+
useCommunitySearch,
|
|
495
683
|
useConversations,
|
|
496
684
|
useLibraryClient,
|
|
497
685
|
useMessages,
|
|
686
|
+
usePost,
|
|
687
|
+
usePosts,
|
|
688
|
+
useTopics,
|
|
498
689
|
useTyping
|
|
499
690
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -4,10 +4,13 @@ import { ChatClient, ChatConfig, IdentifyParams, IdentifyResult, Conversation, C
|
|
|
4
4
|
export { ChatConfig, Conversation, ConversationCreateParams, ConversationListResponse, IdentifyParams, IdentifyResult, TypingPayload, WidgetMessage } from '@cstar.help/js/chat';
|
|
5
5
|
import { LibraryClient, LibraryConfig, Category, LibraryArticle, LibraryArticleListParams } from '@cstar.help/js/library';
|
|
6
6
|
export { Category, LibraryArticle, LibraryArticleListParams, LibraryConfig, LibrarySearchParams, LibrarySearchResult } from '@cstar.help/js/library';
|
|
7
|
+
import { CommunityClient, CommunityConfig, CommunityTopic, CommunityPost, CommunityPostListParams, CommunityPostDetail, CommunitySearchResult } from '@cstar.help/js/community';
|
|
8
|
+
export { CommunityComment, CommunityConfig, CommunityPost, CommunityPostDetail, CommunityPostListParams, CommunitySearchResult, CommunityTopic } from '@cstar.help/js/community';
|
|
7
9
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
8
10
|
|
|
9
11
|
declare const CStarChatContext: react.Context<ChatClient | null>;
|
|
10
12
|
declare const CStarLibraryContext: react.Context<LibraryClient | null>;
|
|
13
|
+
declare const CStarCommunityContext: react.Context<CommunityClient | null>;
|
|
11
14
|
/**
|
|
12
15
|
* Access the ChatClient from the nearest CStarChatProvider.
|
|
13
16
|
* Throws if used outside a provider.
|
|
@@ -18,6 +21,11 @@ declare function useChatClient(): ChatClient;
|
|
|
18
21
|
* Throws if used outside a provider.
|
|
19
22
|
*/
|
|
20
23
|
declare function useLibraryClient(): LibraryClient;
|
|
24
|
+
/**
|
|
25
|
+
* Access the CommunityClient from the nearest CStarCommunityProvider.
|
|
26
|
+
* Throws if used outside a provider.
|
|
27
|
+
*/
|
|
28
|
+
declare function useCommunityClient(): CommunityClient;
|
|
21
29
|
|
|
22
30
|
interface CStarChatProviderProps extends ChatConfig {
|
|
23
31
|
children: ReactNode;
|
|
@@ -217,4 +225,99 @@ interface UseArticleSearchReturn {
|
|
|
217
225
|
*/
|
|
218
226
|
declare function useArticleSearch(query: string): UseArticleSearchReturn;
|
|
219
227
|
|
|
220
|
-
|
|
228
|
+
interface CStarCommunityProviderProps extends CommunityConfig {
|
|
229
|
+
children: ReactNode;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Provides a CommunityClient instance to all child components.
|
|
233
|
+
*
|
|
234
|
+
* ```tsx
|
|
235
|
+
* <CStarCommunityProvider teamSlug="acme">
|
|
236
|
+
* <CommunityForum />
|
|
237
|
+
* </CStarCommunityProvider>
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
declare function CStarCommunityProvider({ children, ...config }: CStarCommunityProviderProps): react_jsx_runtime.JSX.Element;
|
|
241
|
+
|
|
242
|
+
interface UseTopicsReturn {
|
|
243
|
+
/** Community discussion topics. */
|
|
244
|
+
topics: CommunityTopic[];
|
|
245
|
+
/** Whether the fetch is in progress. */
|
|
246
|
+
isLoading: boolean;
|
|
247
|
+
/** The last error, or null. */
|
|
248
|
+
error: Error | null;
|
|
249
|
+
/** Re-fetch topics. */
|
|
250
|
+
refresh: () => Promise<void>;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Fetch community discussion topics.
|
|
254
|
+
*
|
|
255
|
+
* ```tsx
|
|
256
|
+
* const { topics, isLoading } = useTopics();
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
declare function useTopics(): UseTopicsReturn;
|
|
260
|
+
|
|
261
|
+
interface UsePostsReturn {
|
|
262
|
+
/** Community posts. */
|
|
263
|
+
posts: CommunityPost[];
|
|
264
|
+
/** Total count of matching posts (for pagination). */
|
|
265
|
+
count: number;
|
|
266
|
+
/** Whether the fetch is in progress. */
|
|
267
|
+
isLoading: boolean;
|
|
268
|
+
/** The last error, or null. */
|
|
269
|
+
error: Error | null;
|
|
270
|
+
/** Re-fetch posts with the current params. */
|
|
271
|
+
refresh: () => Promise<void>;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Fetch community posts with optional filters.
|
|
275
|
+
*
|
|
276
|
+
* ```tsx
|
|
277
|
+
* const { posts, isLoading } = usePosts({ topicSlug: 'feedback', sort: 'votes' });
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
declare function usePosts(params?: CommunityPostListParams): UsePostsReturn;
|
|
281
|
+
|
|
282
|
+
interface UsePostReturn {
|
|
283
|
+
/** The post with comments, or null if not loaded. */
|
|
284
|
+
data: CommunityPostDetail | null;
|
|
285
|
+
/** Whether the fetch is in progress. */
|
|
286
|
+
isLoading: boolean;
|
|
287
|
+
/** The last error, or null. */
|
|
288
|
+
error: Error | null;
|
|
289
|
+
/** Re-fetch the post. */
|
|
290
|
+
refresh: () => Promise<void>;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Fetch a single community post by slug, including all comments.
|
|
294
|
+
*
|
|
295
|
+
* ```tsx
|
|
296
|
+
* const { data, isLoading } = usePost('dark-mode-support');
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
declare function usePost(slug: string): UsePostReturn;
|
|
300
|
+
|
|
301
|
+
interface UseCommunitySearchReturn {
|
|
302
|
+
/** Search results (null until first search). */
|
|
303
|
+
results: CommunitySearchResult | null;
|
|
304
|
+
/** Whether a search is in progress. */
|
|
305
|
+
isLoading: boolean;
|
|
306
|
+
/** The last error, or null. */
|
|
307
|
+
error: Error | null;
|
|
308
|
+
/** Execute a search query. */
|
|
309
|
+
search: (query: string) => Promise<void>;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Search community posts by title and body content.
|
|
313
|
+
*
|
|
314
|
+
* ```tsx
|
|
315
|
+
* const { results, isLoading, search } = useCommunitySearch();
|
|
316
|
+
*
|
|
317
|
+
* <input onChange={(e) => search(e.target.value)} />
|
|
318
|
+
* {results?.data.map(post => <PostCard key={post.id} post={post} />)}
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
declare function useCommunitySearch(): UseCommunitySearchReturn;
|
|
322
|
+
|
|
323
|
+
export { CStarChatContext, CStarChatProvider, type CStarChatProviderProps, CStarCommunityContext, CStarCommunityProvider, type CStarCommunityProviderProps, CStarLibraryContext, CStarLibraryProvider, type CStarLibraryProviderProps, type TypingAgent, type UseArticleReturn, type UseArticleSearchReturn, type UseArticlesReturn, type UseCategoriesReturn, type UseChatReturn, type UseCommunitySearchReturn, type UseConversationsReturn, type UseMessagesReturn, type UsePostReturn, type UsePostsReturn, type UseTopicsReturn, type UseTypingReturn, useArticle, useArticleSearch, useArticles, useCategories, useChat, useChatClient, useCommunityClient, useCommunitySearch, useConversations, useLibraryClient, useMessages, usePost, usePosts, useTopics, useTyping };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,13 @@ import { ChatClient, ChatConfig, IdentifyParams, IdentifyResult, Conversation, C
|
|
|
4
4
|
export { ChatConfig, Conversation, ConversationCreateParams, ConversationListResponse, IdentifyParams, IdentifyResult, TypingPayload, WidgetMessage } from '@cstar.help/js/chat';
|
|
5
5
|
import { LibraryClient, LibraryConfig, Category, LibraryArticle, LibraryArticleListParams } from '@cstar.help/js/library';
|
|
6
6
|
export { Category, LibraryArticle, LibraryArticleListParams, LibraryConfig, LibrarySearchParams, LibrarySearchResult } from '@cstar.help/js/library';
|
|
7
|
+
import { CommunityClient, CommunityConfig, CommunityTopic, CommunityPost, CommunityPostListParams, CommunityPostDetail, CommunitySearchResult } from '@cstar.help/js/community';
|
|
8
|
+
export { CommunityComment, CommunityConfig, CommunityPost, CommunityPostDetail, CommunityPostListParams, CommunitySearchResult, CommunityTopic } from '@cstar.help/js/community';
|
|
7
9
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
8
10
|
|
|
9
11
|
declare const CStarChatContext: react.Context<ChatClient | null>;
|
|
10
12
|
declare const CStarLibraryContext: react.Context<LibraryClient | null>;
|
|
13
|
+
declare const CStarCommunityContext: react.Context<CommunityClient | null>;
|
|
11
14
|
/**
|
|
12
15
|
* Access the ChatClient from the nearest CStarChatProvider.
|
|
13
16
|
* Throws if used outside a provider.
|
|
@@ -18,6 +21,11 @@ declare function useChatClient(): ChatClient;
|
|
|
18
21
|
* Throws if used outside a provider.
|
|
19
22
|
*/
|
|
20
23
|
declare function useLibraryClient(): LibraryClient;
|
|
24
|
+
/**
|
|
25
|
+
* Access the CommunityClient from the nearest CStarCommunityProvider.
|
|
26
|
+
* Throws if used outside a provider.
|
|
27
|
+
*/
|
|
28
|
+
declare function useCommunityClient(): CommunityClient;
|
|
21
29
|
|
|
22
30
|
interface CStarChatProviderProps extends ChatConfig {
|
|
23
31
|
children: ReactNode;
|
|
@@ -217,4 +225,99 @@ interface UseArticleSearchReturn {
|
|
|
217
225
|
*/
|
|
218
226
|
declare function useArticleSearch(query: string): UseArticleSearchReturn;
|
|
219
227
|
|
|
220
|
-
|
|
228
|
+
interface CStarCommunityProviderProps extends CommunityConfig {
|
|
229
|
+
children: ReactNode;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Provides a CommunityClient instance to all child components.
|
|
233
|
+
*
|
|
234
|
+
* ```tsx
|
|
235
|
+
* <CStarCommunityProvider teamSlug="acme">
|
|
236
|
+
* <CommunityForum />
|
|
237
|
+
* </CStarCommunityProvider>
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
declare function CStarCommunityProvider({ children, ...config }: CStarCommunityProviderProps): react_jsx_runtime.JSX.Element;
|
|
241
|
+
|
|
242
|
+
interface UseTopicsReturn {
|
|
243
|
+
/** Community discussion topics. */
|
|
244
|
+
topics: CommunityTopic[];
|
|
245
|
+
/** Whether the fetch is in progress. */
|
|
246
|
+
isLoading: boolean;
|
|
247
|
+
/** The last error, or null. */
|
|
248
|
+
error: Error | null;
|
|
249
|
+
/** Re-fetch topics. */
|
|
250
|
+
refresh: () => Promise<void>;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Fetch community discussion topics.
|
|
254
|
+
*
|
|
255
|
+
* ```tsx
|
|
256
|
+
* const { topics, isLoading } = useTopics();
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
declare function useTopics(): UseTopicsReturn;
|
|
260
|
+
|
|
261
|
+
interface UsePostsReturn {
|
|
262
|
+
/** Community posts. */
|
|
263
|
+
posts: CommunityPost[];
|
|
264
|
+
/** Total count of matching posts (for pagination). */
|
|
265
|
+
count: number;
|
|
266
|
+
/** Whether the fetch is in progress. */
|
|
267
|
+
isLoading: boolean;
|
|
268
|
+
/** The last error, or null. */
|
|
269
|
+
error: Error | null;
|
|
270
|
+
/** Re-fetch posts with the current params. */
|
|
271
|
+
refresh: () => Promise<void>;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Fetch community posts with optional filters.
|
|
275
|
+
*
|
|
276
|
+
* ```tsx
|
|
277
|
+
* const { posts, isLoading } = usePosts({ topicSlug: 'feedback', sort: 'votes' });
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
declare function usePosts(params?: CommunityPostListParams): UsePostsReturn;
|
|
281
|
+
|
|
282
|
+
interface UsePostReturn {
|
|
283
|
+
/** The post with comments, or null if not loaded. */
|
|
284
|
+
data: CommunityPostDetail | null;
|
|
285
|
+
/** Whether the fetch is in progress. */
|
|
286
|
+
isLoading: boolean;
|
|
287
|
+
/** The last error, or null. */
|
|
288
|
+
error: Error | null;
|
|
289
|
+
/** Re-fetch the post. */
|
|
290
|
+
refresh: () => Promise<void>;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Fetch a single community post by slug, including all comments.
|
|
294
|
+
*
|
|
295
|
+
* ```tsx
|
|
296
|
+
* const { data, isLoading } = usePost('dark-mode-support');
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
declare function usePost(slug: string): UsePostReturn;
|
|
300
|
+
|
|
301
|
+
interface UseCommunitySearchReturn {
|
|
302
|
+
/** Search results (null until first search). */
|
|
303
|
+
results: CommunitySearchResult | null;
|
|
304
|
+
/** Whether a search is in progress. */
|
|
305
|
+
isLoading: boolean;
|
|
306
|
+
/** The last error, or null. */
|
|
307
|
+
error: Error | null;
|
|
308
|
+
/** Execute a search query. */
|
|
309
|
+
search: (query: string) => Promise<void>;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Search community posts by title and body content.
|
|
313
|
+
*
|
|
314
|
+
* ```tsx
|
|
315
|
+
* const { results, isLoading, search } = useCommunitySearch();
|
|
316
|
+
*
|
|
317
|
+
* <input onChange={(e) => search(e.target.value)} />
|
|
318
|
+
* {results?.data.map(post => <PostCard key={post.id} post={post} />)}
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
declare function useCommunitySearch(): UseCommunitySearchReturn;
|
|
322
|
+
|
|
323
|
+
export { CStarChatContext, CStarChatProvider, type CStarChatProviderProps, CStarCommunityContext, CStarCommunityProvider, type CStarCommunityProviderProps, CStarLibraryContext, CStarLibraryProvider, type CStarLibraryProviderProps, type TypingAgent, type UseArticleReturn, type UseArticleSearchReturn, type UseArticlesReturn, type UseCategoriesReturn, type UseChatReturn, type UseCommunitySearchReturn, type UseConversationsReturn, type UseMessagesReturn, type UsePostReturn, type UsePostsReturn, type UseTopicsReturn, type UseTypingReturn, useArticle, useArticleSearch, useArticles, useCategories, useChat, useChatClient, useCommunityClient, useCommunitySearch, useConversations, useLibraryClient, useMessages, usePost, usePosts, useTopics, useTyping };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
3
|
var CStarChatContext = createContext(null);
|
|
4
4
|
var CStarLibraryContext = createContext(null);
|
|
5
|
+
var CStarCommunityContext = createContext(null);
|
|
5
6
|
function useChatClient() {
|
|
6
7
|
const client = useContext(CStarChatContext);
|
|
7
8
|
if (!client) {
|
|
@@ -16,6 +17,13 @@ function useLibraryClient() {
|
|
|
16
17
|
}
|
|
17
18
|
return client;
|
|
18
19
|
}
|
|
20
|
+
function useCommunityClient() {
|
|
21
|
+
const client = useContext(CStarCommunityContext);
|
|
22
|
+
if (!client) {
|
|
23
|
+
throw new Error("useCommunityClient must be used within a <CStarCommunityProvider>");
|
|
24
|
+
}
|
|
25
|
+
return client;
|
|
26
|
+
}
|
|
19
27
|
|
|
20
28
|
// src/chat/CStarChatProvider.tsx
|
|
21
29
|
import { useEffect, useRef } from "react";
|
|
@@ -441,9 +449,180 @@ function useArticleSearch(query) {
|
|
|
441
449
|
}, [client, query]);
|
|
442
450
|
return { results, totalCount, isLoading, error };
|
|
443
451
|
}
|
|
452
|
+
|
|
453
|
+
// src/community/CStarCommunityProvider.tsx
|
|
454
|
+
import { useRef as useRef10 } from "react";
|
|
455
|
+
import { CommunityClient } from "@cstar.help/js/community";
|
|
456
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
457
|
+
function CStarCommunityProvider({ children, ...config }) {
|
|
458
|
+
const clientRef = useRef10(null);
|
|
459
|
+
if (!clientRef.current) {
|
|
460
|
+
clientRef.current = new CommunityClient(config);
|
|
461
|
+
}
|
|
462
|
+
return /* @__PURE__ */ jsx3(CStarCommunityContext.Provider, { value: clientRef.current, children });
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/community/useTopics.ts
|
|
466
|
+
import { useState as useState9, useEffect as useEffect9, useCallback as useCallback8, useRef as useRef11 } from "react";
|
|
467
|
+
function useTopics() {
|
|
468
|
+
const client = useCommunityClient();
|
|
469
|
+
const [topics, setTopics] = useState9([]);
|
|
470
|
+
const [isLoading, setIsLoading] = useState9(true);
|
|
471
|
+
const [error, setError] = useState9(null);
|
|
472
|
+
const mountedRef = useRef11(true);
|
|
473
|
+
const refresh = useCallback8(async () => {
|
|
474
|
+
setIsLoading(true);
|
|
475
|
+
setError(null);
|
|
476
|
+
try {
|
|
477
|
+
const data = await client.topics();
|
|
478
|
+
if (mountedRef.current) {
|
|
479
|
+
setTopics(data);
|
|
480
|
+
}
|
|
481
|
+
} catch (err) {
|
|
482
|
+
if (mountedRef.current) {
|
|
483
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
484
|
+
}
|
|
485
|
+
} finally {
|
|
486
|
+
if (mountedRef.current) {
|
|
487
|
+
setIsLoading(false);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}, [client]);
|
|
491
|
+
useEffect9(() => {
|
|
492
|
+
mountedRef.current = true;
|
|
493
|
+
refresh();
|
|
494
|
+
return () => {
|
|
495
|
+
mountedRef.current = false;
|
|
496
|
+
};
|
|
497
|
+
}, [refresh]);
|
|
498
|
+
return { topics, isLoading, error, refresh };
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/community/usePosts.ts
|
|
502
|
+
import { useState as useState10, useEffect as useEffect10, useCallback as useCallback9, useRef as useRef12 } from "react";
|
|
503
|
+
function usePosts(params) {
|
|
504
|
+
const client = useCommunityClient();
|
|
505
|
+
const [posts, setPosts] = useState10([]);
|
|
506
|
+
const [count, setCount] = useState10(0);
|
|
507
|
+
const [isLoading, setIsLoading] = useState10(true);
|
|
508
|
+
const [error, setError] = useState10(null);
|
|
509
|
+
const mountedRef = useRef12(true);
|
|
510
|
+
const topicSlug = params?.topicSlug;
|
|
511
|
+
const status = params?.status;
|
|
512
|
+
const sort = params?.sort;
|
|
513
|
+
const limit = params?.limit;
|
|
514
|
+
const offset = params?.offset;
|
|
515
|
+
const refresh = useCallback9(async () => {
|
|
516
|
+
setIsLoading(true);
|
|
517
|
+
setError(null);
|
|
518
|
+
try {
|
|
519
|
+
const result = await client.posts({ topicSlug, status, sort, limit, offset });
|
|
520
|
+
if (mountedRef.current) {
|
|
521
|
+
setPosts(result.posts);
|
|
522
|
+
setCount(result.count);
|
|
523
|
+
}
|
|
524
|
+
} catch (err) {
|
|
525
|
+
if (mountedRef.current) {
|
|
526
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
527
|
+
}
|
|
528
|
+
} finally {
|
|
529
|
+
if (mountedRef.current) {
|
|
530
|
+
setIsLoading(false);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}, [client, topicSlug, status, sort, limit, offset]);
|
|
534
|
+
useEffect10(() => {
|
|
535
|
+
mountedRef.current = true;
|
|
536
|
+
refresh();
|
|
537
|
+
return () => {
|
|
538
|
+
mountedRef.current = false;
|
|
539
|
+
};
|
|
540
|
+
}, [refresh]);
|
|
541
|
+
return { posts, count, isLoading, error, refresh };
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/community/usePost.ts
|
|
545
|
+
import { useState as useState11, useEffect as useEffect11, useCallback as useCallback10, useRef as useRef13 } from "react";
|
|
546
|
+
function usePost(slug) {
|
|
547
|
+
const client = useCommunityClient();
|
|
548
|
+
const [data, setData] = useState11(null);
|
|
549
|
+
const [isLoading, setIsLoading] = useState11(true);
|
|
550
|
+
const [error, setError] = useState11(null);
|
|
551
|
+
const mountedRef = useRef13(true);
|
|
552
|
+
const refresh = useCallback10(async () => {
|
|
553
|
+
setIsLoading(true);
|
|
554
|
+
setError(null);
|
|
555
|
+
try {
|
|
556
|
+
const result = await client.post(slug);
|
|
557
|
+
if (mountedRef.current) {
|
|
558
|
+
setData(result);
|
|
559
|
+
}
|
|
560
|
+
} catch (err) {
|
|
561
|
+
if (mountedRef.current) {
|
|
562
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
563
|
+
}
|
|
564
|
+
} finally {
|
|
565
|
+
if (mountedRef.current) {
|
|
566
|
+
setIsLoading(false);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}, [client, slug]);
|
|
570
|
+
useEffect11(() => {
|
|
571
|
+
mountedRef.current = true;
|
|
572
|
+
refresh();
|
|
573
|
+
return () => {
|
|
574
|
+
mountedRef.current = false;
|
|
575
|
+
};
|
|
576
|
+
}, [refresh]);
|
|
577
|
+
return { data, isLoading, error, refresh };
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/community/useCommunitySearch.ts
|
|
581
|
+
import { useState as useState12, useEffect as useEffect12, useCallback as useCallback11, useRef as useRef14 } from "react";
|
|
582
|
+
function useCommunitySearch() {
|
|
583
|
+
const client = useCommunityClient();
|
|
584
|
+
const [results, setResults] = useState12(null);
|
|
585
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
586
|
+
const [error, setError] = useState12(null);
|
|
587
|
+
const mountedRef = useRef14(true);
|
|
588
|
+
useEffect12(() => {
|
|
589
|
+
mountedRef.current = true;
|
|
590
|
+
return () => {
|
|
591
|
+
mountedRef.current = false;
|
|
592
|
+
};
|
|
593
|
+
}, []);
|
|
594
|
+
const search = useCallback11(
|
|
595
|
+
async (query) => {
|
|
596
|
+
if (!query.trim()) {
|
|
597
|
+
setResults(null);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
setIsLoading(true);
|
|
601
|
+
setError(null);
|
|
602
|
+
try {
|
|
603
|
+
const data = await client.search(query);
|
|
604
|
+
if (mountedRef.current) {
|
|
605
|
+
setResults(data);
|
|
606
|
+
}
|
|
607
|
+
} catch (err) {
|
|
608
|
+
if (mountedRef.current) {
|
|
609
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
610
|
+
}
|
|
611
|
+
} finally {
|
|
612
|
+
if (mountedRef.current) {
|
|
613
|
+
setIsLoading(false);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
},
|
|
617
|
+
[client]
|
|
618
|
+
);
|
|
619
|
+
return { results, isLoading, error, search };
|
|
620
|
+
}
|
|
444
621
|
export {
|
|
445
622
|
CStarChatContext,
|
|
446
623
|
CStarChatProvider,
|
|
624
|
+
CStarCommunityContext,
|
|
625
|
+
CStarCommunityProvider,
|
|
447
626
|
CStarLibraryContext,
|
|
448
627
|
CStarLibraryProvider,
|
|
449
628
|
useArticle,
|
|
@@ -452,8 +631,13 @@ export {
|
|
|
452
631
|
useCategories,
|
|
453
632
|
useChat,
|
|
454
633
|
useChatClient,
|
|
634
|
+
useCommunityClient,
|
|
635
|
+
useCommunitySearch,
|
|
455
636
|
useConversations,
|
|
456
637
|
useLibraryClient,
|
|
457
638
|
useMessages,
|
|
639
|
+
usePost,
|
|
640
|
+
usePosts,
|
|
641
|
+
useTopics,
|
|
458
642
|
useTyping
|
|
459
643
|
};
|