@seriphxyz/react 0.1.2

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.
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @seriphxyz/react - React hooks for Seriph widgets
3
+ *
4
+ * @example Subscribe form
5
+ * ```tsx
6
+ * import { useSubscribe } from '@seriphxyz/react';
7
+ *
8
+ * function Newsletter() {
9
+ * const { subscribe, status, error } = useSubscribe({
10
+ * siteKey: 'your-site-key',
11
+ * });
12
+ *
13
+ * const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
14
+ * e.preventDefault();
15
+ * const email = new FormData(e.currentTarget).get('email') as string;
16
+ * subscribe(email);
17
+ * };
18
+ *
19
+ * return (
20
+ * <form onSubmit={handleSubmit}>
21
+ * <input type="email" name="email" required />
22
+ * <button disabled={status === 'loading'}>
23
+ * {status === 'loading' ? 'Subscribing...' : 'Subscribe'}
24
+ * </button>
25
+ * {status === 'success' && <p>Thanks for subscribing!</p>}
26
+ * {status === 'error' && <p>Error: {error?.message}</p>}
27
+ * </form>
28
+ * );
29
+ * }
30
+ * ```
31
+ */
32
+ import { type SeriphConfig, type Comment, type ControllerStatus } from "@seriphxyz/core";
33
+ export type { SeriphConfig, SubscribeState, FormState, ReactionsState, CommentsState, Comment, ReactionCounts, SeriphPost, FetchPostsOptions, FetchPostOptions, ControllerStatus, } from "@seriphxyz/core";
34
+ export { fetchPosts, fetchPost, DEFAULT_ENDPOINT, API_PATH, } from "@seriphxyz/core";
35
+ export interface UseSubscribeOptions extends SeriphConfig {
36
+ }
37
+ export interface UseSubscribeReturn {
38
+ status: ControllerStatus;
39
+ message: string | null;
40
+ error: Error | null;
41
+ subscribe: (email: string) => Promise<void>;
42
+ reset: () => void;
43
+ }
44
+ /**
45
+ * Hook for handling email subscriptions.
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * const { subscribe, status, message, error } = useSubscribe({
50
+ * siteKey: 'your-site-key',
51
+ * });
52
+ *
53
+ * <button onClick={() => subscribe('user@example.com')}>Subscribe</button>
54
+ * ```
55
+ */
56
+ export declare function useSubscribe(options: UseSubscribeOptions): UseSubscribeReturn;
57
+ export interface UseFormOptions extends SeriphConfig {
58
+ /** Form slug/identifier */
59
+ formSlug: string;
60
+ }
61
+ export interface UseFormReturn {
62
+ status: ControllerStatus;
63
+ message: string | null;
64
+ error: Error | null;
65
+ submit: (data: Record<string, unknown>) => Promise<void>;
66
+ reset: () => void;
67
+ }
68
+ /**
69
+ * Hook for handling form submissions.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * const { submit, status, error } = useForm({
74
+ * siteKey: 'your-site-key',
75
+ * formSlug: 'contact',
76
+ * });
77
+ *
78
+ * const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
79
+ * e.preventDefault();
80
+ * const formData = new FormData(e.currentTarget);
81
+ * submit(Object.fromEntries(formData));
82
+ * };
83
+ * ```
84
+ */
85
+ export declare function useForm(options: UseFormOptions): UseFormReturn;
86
+ export interface UseReactionsOptions extends SeriphConfig {
87
+ /** Content identifier (e.g., post slug) */
88
+ contentId: string;
89
+ /** Auto-fetch reactions on mount (default: true) */
90
+ autoFetch?: boolean;
91
+ }
92
+ export interface UseReactionsReturn {
93
+ counts: Record<string, number>;
94
+ userReactions: string[];
95
+ status: ControllerStatus;
96
+ error: Error | null;
97
+ addReaction: (type: string) => Promise<void>;
98
+ removeReaction: (type: string) => Promise<void>;
99
+ refresh: () => Promise<void>;
100
+ }
101
+ /**
102
+ * Hook for handling reactions (likes, claps, etc.).
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * const { counts, userReactions, addReaction, removeReaction } = useReactions({
107
+ * siteKey: 'your-site-key',
108
+ * contentId: 'my-post-slug',
109
+ * });
110
+ *
111
+ * <button onClick={() => addReaction('like')}>
112
+ * Like ({counts.like || 0})
113
+ * </button>
114
+ * ```
115
+ */
116
+ export declare function useReactions(options: UseReactionsOptions): UseReactionsReturn;
117
+ export interface UseCommentsOptions extends SeriphConfig {
118
+ /** Content identifier (e.g., post slug) */
119
+ contentId: string;
120
+ /** Auto-fetch comments on mount (default: true) */
121
+ autoFetch?: boolean;
122
+ }
123
+ export interface UseCommentsReturn {
124
+ comments: Comment[];
125
+ status: ControllerStatus;
126
+ error: Error | null;
127
+ postComment: (author: string, content: string) => Promise<void>;
128
+ refresh: () => Promise<void>;
129
+ }
130
+ /**
131
+ * Hook for handling comments.
132
+ *
133
+ * @example
134
+ * ```tsx
135
+ * const { comments, status, postComment } = useComments({
136
+ * siteKey: 'your-site-key',
137
+ * contentId: 'my-post-slug',
138
+ * });
139
+ *
140
+ * {comments.map(comment => (
141
+ * <div key={comment.id}>
142
+ * <strong>{comment.authorName}</strong>: {comment.content}
143
+ * </div>
144
+ * ))}
145
+ *
146
+ * <button onClick={() => postComment('Anonymous', 'Great post!')}>
147
+ * Add Comment
148
+ * </button>
149
+ * ```
150
+ */
151
+ export declare function useComments(options: UseCommentsOptions): UseCommentsReturn;
152
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @seriphxyz/react - React hooks for Seriph widgets
3
+ *
4
+ * @example Subscribe form
5
+ * ```tsx
6
+ * import { useSubscribe } from '@seriphxyz/react';
7
+ *
8
+ * function Newsletter() {
9
+ * const { subscribe, status, error } = useSubscribe({
10
+ * siteKey: 'your-site-key',
11
+ * });
12
+ *
13
+ * const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
14
+ * e.preventDefault();
15
+ * const email = new FormData(e.currentTarget).get('email') as string;
16
+ * subscribe(email);
17
+ * };
18
+ *
19
+ * return (
20
+ * <form onSubmit={handleSubmit}>
21
+ * <input type="email" name="email" required />
22
+ * <button disabled={status === 'loading'}>
23
+ * {status === 'loading' ? 'Subscribing...' : 'Subscribe'}
24
+ * </button>
25
+ * {status === 'success' && <p>Thanks for subscribing!</p>}
26
+ * {status === 'error' && <p>Error: {error?.message}</p>}
27
+ * </form>
28
+ * );
29
+ * }
30
+ * ```
31
+ */
32
+ import { useState, useCallback, useEffect, useRef } from "react";
33
+ import { SubscribeController, FormController, ReactionsController, CommentsController, } from "@seriphxyz/core";
34
+ // Re-export API functions from core
35
+ export { fetchPosts, fetchPost, DEFAULT_ENDPOINT, API_PATH, } from "@seriphxyz/core";
36
+ /**
37
+ * Hook for handling email subscriptions.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * const { subscribe, status, message, error } = useSubscribe({
42
+ * siteKey: 'your-site-key',
43
+ * });
44
+ *
45
+ * <button onClick={() => subscribe('user@example.com')}>Subscribe</button>
46
+ * ```
47
+ */
48
+ export function useSubscribe(options) {
49
+ const controllerRef = useRef(null);
50
+ const [state, setState] = useState({
51
+ status: "idle",
52
+ message: null,
53
+ error: null,
54
+ });
55
+ useEffect(() => {
56
+ const controller = new SubscribeController(options);
57
+ controllerRef.current = controller;
58
+ const unsubscribe = controller.subscribe(setState);
59
+ return unsubscribe;
60
+ }, [options.siteKey, options.endpoint]);
61
+ const subscribe = useCallback(async (email) => {
62
+ await controllerRef.current?.submit(email);
63
+ }, []);
64
+ const reset = useCallback(() => {
65
+ controllerRef.current?.reset();
66
+ }, []);
67
+ return { ...state, subscribe, reset };
68
+ }
69
+ /**
70
+ * Hook for handling form submissions.
71
+ *
72
+ * @example
73
+ * ```tsx
74
+ * const { submit, status, error } = useForm({
75
+ * siteKey: 'your-site-key',
76
+ * formSlug: 'contact',
77
+ * });
78
+ *
79
+ * const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
80
+ * e.preventDefault();
81
+ * const formData = new FormData(e.currentTarget);
82
+ * submit(Object.fromEntries(formData));
83
+ * };
84
+ * ```
85
+ */
86
+ export function useForm(options) {
87
+ const controllerRef = useRef(null);
88
+ const [state, setState] = useState({
89
+ status: "idle",
90
+ message: null,
91
+ error: null,
92
+ });
93
+ useEffect(() => {
94
+ const controller = new FormController(options, options.formSlug);
95
+ controllerRef.current = controller;
96
+ const unsubscribe = controller.subscribe(setState);
97
+ return unsubscribe;
98
+ }, [options.siteKey, options.endpoint, options.formSlug]);
99
+ const submit = useCallback(async (data) => {
100
+ await controllerRef.current?.submit(data);
101
+ }, []);
102
+ const reset = useCallback(() => {
103
+ controllerRef.current?.reset();
104
+ }, []);
105
+ return { ...state, submit, reset };
106
+ }
107
+ /**
108
+ * Hook for handling reactions (likes, claps, etc.).
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * const { counts, userReactions, addReaction, removeReaction } = useReactions({
113
+ * siteKey: 'your-site-key',
114
+ * contentId: 'my-post-slug',
115
+ * });
116
+ *
117
+ * <button onClick={() => addReaction('like')}>
118
+ * Like ({counts.like || 0})
119
+ * </button>
120
+ * ```
121
+ */
122
+ export function useReactions(options) {
123
+ const controllerRef = useRef(null);
124
+ const [state, setState] = useState({
125
+ counts: {},
126
+ userReactions: [],
127
+ status: "idle",
128
+ error: null,
129
+ });
130
+ useEffect(() => {
131
+ const controller = new ReactionsController(options, options.contentId);
132
+ controllerRef.current = controller;
133
+ const unsubscribe = controller.subscribe(setState);
134
+ // Auto-fetch on mount (default: true)
135
+ if (options.autoFetch !== false) {
136
+ controller.fetch();
137
+ }
138
+ return unsubscribe;
139
+ }, [options.siteKey, options.endpoint, options.contentId]);
140
+ const addReaction = useCallback(async (type) => {
141
+ await controllerRef.current?.add(type);
142
+ }, []);
143
+ const removeReaction = useCallback(async (type) => {
144
+ await controllerRef.current?.remove(type);
145
+ }, []);
146
+ const refresh = useCallback(async () => {
147
+ await controllerRef.current?.fetch();
148
+ }, []);
149
+ return { ...state, addReaction, removeReaction, refresh };
150
+ }
151
+ /**
152
+ * Hook for handling comments.
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * const { comments, status, postComment } = useComments({
157
+ * siteKey: 'your-site-key',
158
+ * contentId: 'my-post-slug',
159
+ * });
160
+ *
161
+ * {comments.map(comment => (
162
+ * <div key={comment.id}>
163
+ * <strong>{comment.authorName}</strong>: {comment.content}
164
+ * </div>
165
+ * ))}
166
+ *
167
+ * <button onClick={() => postComment('Anonymous', 'Great post!')}>
168
+ * Add Comment
169
+ * </button>
170
+ * ```
171
+ */
172
+ export function useComments(options) {
173
+ const controllerRef = useRef(null);
174
+ const [state, setState] = useState({
175
+ comments: [],
176
+ status: "idle",
177
+ error: null,
178
+ });
179
+ useEffect(() => {
180
+ const controller = new CommentsController(options, options.contentId);
181
+ controllerRef.current = controller;
182
+ const unsubscribe = controller.subscribe(setState);
183
+ // Auto-fetch on mount (default: true)
184
+ if (options.autoFetch !== false) {
185
+ controller.fetch();
186
+ }
187
+ return unsubscribe;
188
+ }, [options.siteKey, options.endpoint, options.contentId]);
189
+ const postComment = useCallback(async (author, content) => {
190
+ await controllerRef.current?.post(author, content);
191
+ }, []);
192
+ const refresh = useCallback(async () => {
193
+ await controllerRef.current?.fetch();
194
+ }, []);
195
+ return { ...state, postComment, refresh };
196
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@seriphxyz/react",
3
+ "version": "0.1.2",
4
+ "description": "React hooks for Seriph widgets (forms, comments, reactions, subscriptions)",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/seriphxyz/react.git"
8
+ },
9
+ "homepage": "https://seriph.xyz",
10
+ "author": "Tim Shedor",
11
+ "type": "module",
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "react",
25
+ "seriph",
26
+ "forms",
27
+ "comments",
28
+ "reactions",
29
+ "subscribe",
30
+ "hooks"
31
+ ],
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "@seriphxyz/core": "0.1.2"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^18.0.0 || ^19.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^18.3.0",
41
+ "react": "^18.3.0",
42
+ "typescript": "^5.7.3"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc",
46
+ "dev": "tsc --watch"
47
+ }
48
+ }