@jamwidgets/solid 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # @jamwidgets/solid
2
+
3
+ > **Note:** This repo is a read-only mirror. Source lives in a private monorepo.
4
+ > For issues/PRs, please open them here and we'll sync changes back.
5
+
6
+ SolidJS primitives for [JamWidgets](https://jamwidgets.com) widgets - comments, reactions, forms, subscriptions, and more.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @jamwidgets/solid
12
+ ```
13
+
14
+ Works with SolidJS 1.8+. Compatible with SolidStart, Astro, and standalone apps.
15
+
16
+ ## Primitives
17
+
18
+ ### createSubscribe
19
+
20
+ Email subscription form:
21
+
22
+ ```tsx
23
+ import { createSubscribe } from "@jamwidgets/solid";
24
+
25
+ function SubscribeForm() {
26
+ const [email, setEmail] = createSignal("");
27
+ const { submit, status, message, error } = createSubscribe({
28
+ siteKey: "your-key",
29
+ });
30
+
31
+ const handleSubmit = async (e) => {
32
+ e.preventDefault();
33
+ await submit(email());
34
+ };
35
+
36
+ return (
37
+ <form onSubmit={handleSubmit}>
38
+ <input
39
+ type="email"
40
+ value={email()}
41
+ onInput={(e) => setEmail(e.target.value)}
42
+ placeholder="your@email.com"
43
+ />
44
+ <button disabled={status() === "loading"}>
45
+ {status() === "loading" ? "Subscribing..." : "Subscribe"}
46
+ </button>
47
+ <Show when={status() === "success"}>
48
+ <p>{message()}</p>
49
+ </Show>
50
+ <Show when={status() === "error"}>
51
+ <p>{error()?.message}</p>
52
+ </Show>
53
+ </form>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### createReactions
59
+
60
+ Reaction buttons (like, love, clap, etc.):
61
+
62
+ ```tsx
63
+ import { createReactions } from "@jamwidgets/solid";
64
+
65
+ function LikeButton() {
66
+ const { counts, userReactions, add, remove, status } = createReactions({
67
+ siteKey: "your-key",
68
+ pageId: "my-page",
69
+ });
70
+
71
+ const hasLiked = () => userReactions().includes("like");
72
+
73
+ return (
74
+ <button onClick={() => (hasLiked() ? remove("like") : add("like"))}>
75
+ {hasLiked() ? "Unlike" : "Like"} ({counts().like || 0})
76
+ </button>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ### createComments
82
+
83
+ Threaded comments:
84
+
85
+ ```tsx
86
+ import { createComments } from "@jamwidgets/solid";
87
+
88
+ function Comments() {
89
+ const { comments, post, status, error } = createComments({
90
+ siteKey: "your-key",
91
+ pageId: "my-page",
92
+ });
93
+
94
+ return (
95
+ <div>
96
+ <For each={comments()}>
97
+ {(comment) => (
98
+ <div>
99
+ <strong>{comment.authorName}</strong>
100
+ <p>{comment.content}</p>
101
+ </div>
102
+ )}
103
+ </For>
104
+ </div>
105
+ );
106
+ }
107
+ ```
108
+
109
+ ### createForm
110
+
111
+ Contact forms with spam protection:
112
+
113
+ ```tsx
114
+ import { createForm } from "@jamwidgets/solid";
115
+
116
+ function ContactForm() {
117
+ const { submit, status, message } = createForm({
118
+ siteKey: "your-key",
119
+ formSlug: "contact",
120
+ });
121
+
122
+ const handleSubmit = async (e) => {
123
+ e.preventDefault();
124
+ const data = Object.fromEntries(new FormData(e.target));
125
+ await submit(data);
126
+ };
127
+
128
+ return (
129
+ <form onSubmit={handleSubmit}>
130
+ <input name="email" type="email" required />
131
+ <textarea name="message" required />
132
+ <button type="submit">Send</button>
133
+ <Show when={status() === "success"}>
134
+ <p>{message()}</p>
135
+ </Show>
136
+ </form>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ### createWaitlist
142
+
143
+ Waitlist signups:
144
+
145
+ ```tsx
146
+ import { createWaitlist } from "@jamwidgets/solid";
147
+
148
+ function WaitlistForm() {
149
+ const { join, status, message, position } = createWaitlist({
150
+ siteKey: "your-key",
151
+ });
152
+
153
+ const handleSubmit = async (e) => {
154
+ e.preventDefault();
155
+ await join(email(), { name: name(), source: "homepage" });
156
+ };
157
+
158
+ return (
159
+ <form onSubmit={handleSubmit}>
160
+ <input name="email" type="email" required />
161
+ <button type="submit">Join Waitlist</button>
162
+ <Show when={status() === "success"}>
163
+ <p>{message()}</p>
164
+ </Show>
165
+ </form>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ### createFeedback
171
+
172
+ Feedback forms:
173
+
174
+ ```tsx
175
+ import { createFeedback } from "@jamwidgets/solid";
176
+
177
+ function FeedbackWidget() {
178
+ const { submit, status, message } = createFeedback({
179
+ siteKey: "your-key",
180
+ });
181
+
182
+ const handleSubmit = async (type, content) => {
183
+ await submit(type, content, { email: email(), pageUrl: window.location.href });
184
+ };
185
+
186
+ // ...
187
+ }
188
+ ```
189
+
190
+ ### createPoll
191
+
192
+ Polls and voting:
193
+
194
+ ```tsx
195
+ import { createPoll } from "@jamwidgets/solid";
196
+
197
+ function Poll() {
198
+ const { poll, vote, hasVoted, status } = createPoll({
199
+ siteKey: "your-key",
200
+ pollId: 123,
201
+ });
202
+
203
+ return (
204
+ <Show when={poll()} fallback={<div>Loading...</div>}>
205
+ <div>
206
+ <h3>{poll().question}</h3>
207
+ <For each={poll().options}>
208
+ {(option) => (
209
+ <button onClick={() => vote([option.id])} disabled={hasVoted()}>
210
+ {option.text} ({poll().results?.[option.id] || 0})
211
+ </button>
212
+ )}
213
+ </For>
214
+ </div>
215
+ </Show>
216
+ );
217
+ }
218
+ ```
219
+
220
+ ### createAnnouncements
221
+
222
+ Site announcements:
223
+
224
+ ```tsx
225
+ import { createAnnouncements } from "@jamwidgets/solid";
226
+
227
+ function AnnouncementBanner() {
228
+ const { announcements, dismiss, status } = createAnnouncements({
229
+ siteKey: "your-key",
230
+ });
231
+
232
+ const visible = () => announcements().filter((a) => !a.dismissed);
233
+
234
+ return (
235
+ <For each={visible()}>
236
+ {(announcement) => (
237
+ <div>
238
+ <p>{announcement.content}</p>
239
+ <Show when={announcement.isDismissible}>
240
+ <button onClick={() => dismiss(announcement.id)}>Dismiss</button>
241
+ </Show>
242
+ </div>
243
+ )}
244
+ </For>
245
+ );
246
+ }
247
+ ```
248
+
249
+ ### createViewCounts
250
+
251
+ Page view tracking:
252
+
253
+ ```tsx
254
+ import { createViewCounts } from "@jamwidgets/solid";
255
+ import { onMount } from "solid-js";
256
+
257
+ function PageViews() {
258
+ const { views, uniqueVisitors, record, status } = createViewCounts({
259
+ siteKey: "your-key",
260
+ pageId: "my-page",
261
+ });
262
+
263
+ // Record view on mount
264
+ onMount(() => {
265
+ record();
266
+ });
267
+
268
+ return (
269
+ <span>
270
+ {views()} views ({uniqueVisitors()} unique)
271
+ </span>
272
+ );
273
+ }
274
+ ```
275
+
276
+ ## All Primitives
277
+
278
+ | Primitive | Purpose |
279
+ |-----------|---------|
280
+ | `createSubscribe` | Email subscriptions |
281
+ | `createReactions` | Page reactions |
282
+ | `createComments` | Threaded comments |
283
+ | `createForm` | Form submissions |
284
+ | `createWaitlist` | Waitlist signups |
285
+ | `createFeedback` | Feedback forms |
286
+ | `createPoll` | Polls and voting |
287
+ | `createAnnouncements` | Site announcements |
288
+ | `createViewCounts` | Page view tracking |
289
+
290
+ ## License
291
+
292
+ MIT
@@ -0,0 +1,310 @@
1
+ /**
2
+ * @jamwidgets/solid - SolidJS primitives for Jamwidgets
3
+ *
4
+ * @example Subscribe form
5
+ * ```tsx
6
+ * import { createSubscribe } from '@jamwidgets/solid';
7
+ *
8
+ * function Newsletter() {
9
+ * const { subscribe, status, error } = createSubscribe({
10
+ * siteKey: 'your-site-key',
11
+ * });
12
+ *
13
+ * const handleSubmit = (e: SubmitEvent) => {
14
+ * e.preventDefault();
15
+ * const email = new FormData(e.currentTarget as HTMLFormElement).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 Accessor } from "solid-js";
33
+ import { type JamWidgetsConfig, type Comment, type Announcement, type PollWithResults, type FeedbackType, type ControllerStatus } from "@jamwidgets/core";
34
+ export type { JamWidgetsConfig, SubscribeState, FormState, ReactionsState, CommentsState, WaitlistState, ViewCountsState, FeedbackState, PollState, AnnouncementsState, Comment, Announcement, PollWithResults, FeedbackType, ReactionCounts, JamwidgetsPost, SeriphPost, // deprecated alias
35
+ FetchPostsOptions, FetchPostOptions, ControllerStatus, } from "@jamwidgets/core";
36
+ export { fetchPosts, fetchPost, getConfigFromMeta, resolveConfig, DEFAULT_ENDPOINT, API_PATH, } from "@jamwidgets/core";
37
+ type OptionalSiteKey<T extends JamWidgetsConfig> = Omit<T, "siteKey"> & {
38
+ /** Site key - optional if <meta name="jamwidgets-site-key"> is set */
39
+ siteKey?: string;
40
+ };
41
+ export interface CreateSubscribeOptions extends OptionalSiteKey<JamWidgetsConfig> {
42
+ }
43
+ export interface CreateSubscribeReturn {
44
+ status: Accessor<ControllerStatus>;
45
+ message: Accessor<string | null>;
46
+ error: Accessor<Error | null>;
47
+ subscribe: (email: string) => Promise<void>;
48
+ reset: () => void;
49
+ }
50
+ /**
51
+ * Primitive for handling email subscriptions.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * // With explicit siteKey:
56
+ * const { subscribe, status } = createSubscribe({ siteKey: 'your-key' });
57
+ *
58
+ * // Or with meta tag (add to document head):
59
+ * // <meta name="jamwidgets-site-key" content="your-key" />
60
+ * const { subscribe, status } = createSubscribe({});
61
+ * ```
62
+ */
63
+ export declare function createSubscribe(options: CreateSubscribeOptions): CreateSubscribeReturn;
64
+ export interface CreateFormOptions extends OptionalSiteKey<JamWidgetsConfig> {
65
+ /** Form slug/identifier */
66
+ formSlug: string;
67
+ }
68
+ export interface CreateFormReturn {
69
+ status: Accessor<ControllerStatus>;
70
+ message: Accessor<string | null>;
71
+ error: Accessor<Error | null>;
72
+ submit: (data: Record<string, unknown>) => Promise<void>;
73
+ reset: () => void;
74
+ }
75
+ /**
76
+ * Primitive for handling form submissions.
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * const { submit, status, error } = createForm({
81
+ * siteKey: 'your-site-key', // optional with meta tag
82
+ * formSlug: 'contact',
83
+ * });
84
+ *
85
+ * const handleSubmit = (e: SubmitEvent) => {
86
+ * e.preventDefault();
87
+ * const formData = new FormData(e.currentTarget as HTMLFormElement);
88
+ * submit(Object.fromEntries(formData));
89
+ * };
90
+ * ```
91
+ */
92
+ export declare function createForm(options: CreateFormOptions): CreateFormReturn;
93
+ export interface CreateReactionsOptions extends OptionalSiteKey<JamWidgetsConfig> {
94
+ /** Content identifier (e.g., post slug) */
95
+ contentId: string;
96
+ /** Auto-fetch reactions on mount (default: true) */
97
+ autoFetch?: boolean;
98
+ }
99
+ export interface CreateReactionsReturn {
100
+ counts: Accessor<Record<string, number>>;
101
+ userReactions: Accessor<string[]>;
102
+ status: Accessor<ControllerStatus>;
103
+ error: Accessor<Error | null>;
104
+ addReaction: (type: string) => Promise<void>;
105
+ removeReaction: (type: string) => Promise<void>;
106
+ refresh: () => Promise<void>;
107
+ }
108
+ /**
109
+ * Primitive for handling reactions (likes, claps, etc.).
110
+ *
111
+ * @example
112
+ * ```tsx
113
+ * const { counts, userReactions, addReaction, removeReaction } = createReactions({
114
+ * contentId: 'my-post-slug',
115
+ * });
116
+ *
117
+ * <button onClick={() => addReaction('like')}>
118
+ * Like ({counts().like || 0})
119
+ * </button>
120
+ * ```
121
+ */
122
+ export declare function createReactions(options: CreateReactionsOptions): CreateReactionsReturn;
123
+ export interface CreateCommentsOptions extends OptionalSiteKey<JamWidgetsConfig> {
124
+ /** Content identifier (e.g., post slug) */
125
+ contentId: string;
126
+ /** Auto-fetch comments on mount (default: true) */
127
+ autoFetch?: boolean;
128
+ }
129
+ export interface CreateCommentsReturn {
130
+ comments: Accessor<Comment[]>;
131
+ status: Accessor<ControllerStatus>;
132
+ error: Accessor<Error | null>;
133
+ postComment: (author: string, content: string, options?: {
134
+ authorEmail?: string;
135
+ parentId?: string;
136
+ }) => Promise<void>;
137
+ refresh: () => Promise<void>;
138
+ }
139
+ /**
140
+ * Primitive for handling comments.
141
+ *
142
+ * @example
143
+ * ```tsx
144
+ * const { comments, status, postComment } = createComments({
145
+ * contentId: 'my-post-slug',
146
+ * });
147
+ *
148
+ * <For each={comments()}>
149
+ * {(comment) => (
150
+ * <div>
151
+ * <strong>{comment.authorName}</strong>: {comment.content}
152
+ * </div>
153
+ * )}
154
+ * </For>
155
+ *
156
+ * <button onClick={() => postComment('Anonymous', 'Great post!')}>
157
+ * Add Comment
158
+ * </button>
159
+ * ```
160
+ */
161
+ export declare function createComments(options: CreateCommentsOptions): CreateCommentsReturn;
162
+ export interface CreateWaitlistOptions extends OptionalSiteKey<JamWidgetsConfig> {
163
+ }
164
+ export interface CreateWaitlistReturn {
165
+ status: Accessor<ControllerStatus>;
166
+ message: Accessor<string | null>;
167
+ position: Accessor<number | null>;
168
+ error: Accessor<Error | null>;
169
+ join: (email: string, options?: {
170
+ name?: string;
171
+ source?: string;
172
+ }) => Promise<void>;
173
+ reset: () => void;
174
+ }
175
+ /**
176
+ * Primitive for handling waitlist signups.
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * const { join, status, position } = createWaitlist({});
181
+ *
182
+ * <button onClick={() => join('user@example.com')}>Join Waitlist</button>
183
+ * {status() === 'success' && <p>You're #{position()} on the list!</p>}
184
+ * ```
185
+ */
186
+ export declare function createWaitlist(options: CreateWaitlistOptions): CreateWaitlistReturn;
187
+ export interface CreateViewsOptions extends OptionalSiteKey<JamWidgetsConfig> {
188
+ /** Page identifier (e.g., slug or URL path) */
189
+ pageId: string;
190
+ /** Auto-record view on mount (default: true) */
191
+ autoRecord?: boolean;
192
+ }
193
+ export interface CreateViewsReturn {
194
+ views: Accessor<number>;
195
+ uniqueVisitors: Accessor<number>;
196
+ status: Accessor<ControllerStatus>;
197
+ error: Accessor<Error | null>;
198
+ record: () => Promise<void>;
199
+ refresh: () => Promise<void>;
200
+ }
201
+ /**
202
+ * Primitive for tracking and displaying page views.
203
+ *
204
+ * @example
205
+ * ```tsx
206
+ * const { views, uniqueVisitors } = createViews({
207
+ * pageId: '/blog/my-post',
208
+ * });
209
+ *
210
+ * <span>{views()} views ({uniqueVisitors()} unique)</span>
211
+ * ```
212
+ */
213
+ export declare function createViews(options: CreateViewsOptions): CreateViewsReturn;
214
+ export interface CreateFeedbackOptions extends OptionalSiteKey<JamWidgetsConfig> {
215
+ }
216
+ export interface CreateFeedbackReturn {
217
+ status: Accessor<ControllerStatus>;
218
+ message: Accessor<string | null>;
219
+ error: Accessor<Error | null>;
220
+ submit: (type: FeedbackType, content: string, options?: {
221
+ email?: string;
222
+ pageUrl?: string;
223
+ }) => Promise<void>;
224
+ reset: () => void;
225
+ }
226
+ /**
227
+ * Primitive for handling feedback submissions.
228
+ *
229
+ * @example
230
+ * ```tsx
231
+ * const { submit, status } = createFeedback({});
232
+ *
233
+ * <button onClick={() => submit('feature', 'Add dark mode!')}>
234
+ * Submit Feedback
235
+ * </button>
236
+ * ```
237
+ */
238
+ export declare function createFeedback(options: CreateFeedbackOptions): CreateFeedbackReturn;
239
+ export interface CreatePollOptions extends OptionalSiteKey<JamWidgetsConfig> {
240
+ /** Poll slug */
241
+ slug: string;
242
+ /** Auto-fetch poll on mount (default: true) */
243
+ autoFetch?: boolean;
244
+ }
245
+ export interface CreatePollReturn {
246
+ poll: Accessor<PollWithResults | null>;
247
+ status: Accessor<ControllerStatus>;
248
+ error: Accessor<Error | null>;
249
+ vote: (selectedOptions: string[]) => Promise<void>;
250
+ hasVoted: Accessor<boolean>;
251
+ refresh: () => Promise<void>;
252
+ }
253
+ /**
254
+ * Primitive for displaying and voting on polls.
255
+ *
256
+ * @example
257
+ * ```tsx
258
+ * // With meta tag: <meta name="jamwidgets-site-key" content="your-key" />
259
+ * const { poll, vote, hasVoted } = createPoll({ slug: 'favorite-framework' });
260
+ *
261
+ * <Show when={poll()}>
262
+ * {(p) => (
263
+ * <div>
264
+ * <h3>{p().question}</h3>
265
+ * <For each={p().options}>
266
+ * {(opt) => (
267
+ * <button onClick={() => vote([opt.id])} disabled={hasVoted()}>
268
+ * {opt.text} ({p().results[opt.id] || 0} votes)
269
+ * </button>
270
+ * )}
271
+ * </For>
272
+ * </div>
273
+ * )}
274
+ * </Show>
275
+ * ```
276
+ */
277
+ export declare function createPoll(options: CreatePollOptions): CreatePollReturn;
278
+ export interface CreateAnnouncementsOptions extends OptionalSiteKey<JamWidgetsConfig> {
279
+ /** Auto-fetch announcements on mount (default: true) */
280
+ autoFetch?: boolean;
281
+ }
282
+ export interface CreateAnnouncementsReturn {
283
+ announcements: Accessor<Announcement[]>;
284
+ status: Accessor<ControllerStatus>;
285
+ error: Accessor<Error | null>;
286
+ dismiss: (announcementId: number) => Promise<void>;
287
+ refresh: () => Promise<void>;
288
+ }
289
+ /**
290
+ * Primitive for displaying site announcements.
291
+ *
292
+ * @example
293
+ * ```tsx
294
+ * // With meta tag: <meta name="jamwidgets-site-key" content="your-key" />
295
+ * const { announcements, dismiss } = createAnnouncements({});
296
+ *
297
+ * <For each={announcements()}>
298
+ * {(ann) => (
299
+ * <div class={`announcement-${ann.announcementType}`}>
300
+ * {ann.content}
301
+ * {ann.isDismissible && (
302
+ * <button onClick={() => dismiss(ann.id)}>Dismiss</button>
303
+ * )}
304
+ * </div>
305
+ * )}
306
+ * </For>
307
+ * ```
308
+ */
309
+ export declare function createAnnouncements(options: CreateAnnouncementsOptions): CreateAnnouncementsReturn;
310
+ //# 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,409 @@
1
+ /**
2
+ * @jamwidgets/solid - SolidJS primitives for Jamwidgets
3
+ *
4
+ * @example Subscribe form
5
+ * ```tsx
6
+ * import { createSubscribe } from '@jamwidgets/solid';
7
+ *
8
+ * function Newsletter() {
9
+ * const { subscribe, status, error } = createSubscribe({
10
+ * siteKey: 'your-site-key',
11
+ * });
12
+ *
13
+ * const handleSubmit = (e: SubmitEvent) => {
14
+ * e.preventDefault();
15
+ * const email = new FormData(e.currentTarget as HTMLFormElement).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 { createSignal, createEffect, onCleanup } from "solid-js";
33
+ import { SubscribeController, FormController, ReactionsController, CommentsController, WaitlistController, ViewCountsController, FeedbackController, PollController, AnnouncementsController, resolveConfig, } from "@jamwidgets/core";
34
+ // Re-export API functions and helpers from core
35
+ export { fetchPosts, fetchPost, getConfigFromMeta, resolveConfig, DEFAULT_ENDPOINT, API_PATH, } from "@jamwidgets/core";
36
+ /**
37
+ * Primitive for handling email subscriptions.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * // With explicit siteKey:
42
+ * const { subscribe, status } = createSubscribe({ siteKey: 'your-key' });
43
+ *
44
+ * // Or with meta tag (add to document head):
45
+ * // <meta name="jamwidgets-site-key" content="your-key" />
46
+ * const { subscribe, status } = createSubscribe({});
47
+ * ```
48
+ */
49
+ export function createSubscribe(options) {
50
+ const [status, setStatus] = createSignal("idle");
51
+ const [message, setMessage] = createSignal(null);
52
+ const [error, setError] = createSignal(null);
53
+ const config = resolveConfig(options);
54
+ const controller = new SubscribeController(config);
55
+ createEffect(() => {
56
+ const unsubscribe = controller.subscribe((state) => {
57
+ setStatus(state.status);
58
+ setMessage(state.message);
59
+ setError(state.error);
60
+ });
61
+ onCleanup(unsubscribe);
62
+ });
63
+ const subscribe = async (email) => {
64
+ await controller.submit(email);
65
+ };
66
+ const reset = () => {
67
+ controller.reset();
68
+ };
69
+ return { status, message, error, subscribe, reset };
70
+ }
71
+ /**
72
+ * Primitive for handling form submissions.
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * const { submit, status, error } = createForm({
77
+ * siteKey: 'your-site-key', // optional with meta tag
78
+ * formSlug: 'contact',
79
+ * });
80
+ *
81
+ * const handleSubmit = (e: SubmitEvent) => {
82
+ * e.preventDefault();
83
+ * const formData = new FormData(e.currentTarget as HTMLFormElement);
84
+ * submit(Object.fromEntries(formData));
85
+ * };
86
+ * ```
87
+ */
88
+ export function createForm(options) {
89
+ const [status, setStatus] = createSignal("idle");
90
+ const [message, setMessage] = createSignal(null);
91
+ const [error, setError] = createSignal(null);
92
+ const config = resolveConfig(options);
93
+ const controller = new FormController(config, options.formSlug);
94
+ createEffect(() => {
95
+ const unsubscribe = controller.subscribe((state) => {
96
+ setStatus(state.status);
97
+ setMessage(state.message);
98
+ setError(state.error);
99
+ });
100
+ onCleanup(unsubscribe);
101
+ });
102
+ const submit = async (data) => {
103
+ await controller.submit(data);
104
+ };
105
+ const reset = () => {
106
+ controller.reset();
107
+ };
108
+ return { status, message, error, submit, reset };
109
+ }
110
+ /**
111
+ * Primitive for handling reactions (likes, claps, etc.).
112
+ *
113
+ * @example
114
+ * ```tsx
115
+ * const { counts, userReactions, addReaction, removeReaction } = createReactions({
116
+ * contentId: 'my-post-slug',
117
+ * });
118
+ *
119
+ * <button onClick={() => addReaction('like')}>
120
+ * Like ({counts().like || 0})
121
+ * </button>
122
+ * ```
123
+ */
124
+ export function createReactions(options) {
125
+ const [counts, setCounts] = createSignal({});
126
+ const [userReactions, setUserReactions] = createSignal([]);
127
+ const [status, setStatus] = createSignal("idle");
128
+ const [error, setError] = createSignal(null);
129
+ const config = resolveConfig(options);
130
+ const controller = new ReactionsController(config, options.contentId);
131
+ createEffect(() => {
132
+ const unsubscribe = controller.subscribe((state) => {
133
+ setCounts(state.counts);
134
+ setUserReactions(state.userReactions);
135
+ setStatus(state.status);
136
+ setError(state.error);
137
+ });
138
+ // Auto-fetch on mount (default: true)
139
+ if (options.autoFetch !== false) {
140
+ controller.fetch();
141
+ }
142
+ onCleanup(unsubscribe);
143
+ });
144
+ const addReaction = async (type) => {
145
+ await controller.add(type);
146
+ };
147
+ const removeReaction = async (type) => {
148
+ await controller.remove(type);
149
+ };
150
+ const refresh = async () => {
151
+ await controller.fetch();
152
+ };
153
+ return { counts, userReactions, status, error, addReaction, removeReaction, refresh };
154
+ }
155
+ /**
156
+ * Primitive for handling comments.
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * const { comments, status, postComment } = createComments({
161
+ * contentId: 'my-post-slug',
162
+ * });
163
+ *
164
+ * <For each={comments()}>
165
+ * {(comment) => (
166
+ * <div>
167
+ * <strong>{comment.authorName}</strong>: {comment.content}
168
+ * </div>
169
+ * )}
170
+ * </For>
171
+ *
172
+ * <button onClick={() => postComment('Anonymous', 'Great post!')}>
173
+ * Add Comment
174
+ * </button>
175
+ * ```
176
+ */
177
+ export function createComments(options) {
178
+ const [comments, setComments] = createSignal([]);
179
+ const [status, setStatus] = createSignal("idle");
180
+ const [error, setError] = createSignal(null);
181
+ const config = resolveConfig(options);
182
+ const controller = new CommentsController(config, options.contentId);
183
+ createEffect(() => {
184
+ const unsubscribe = controller.subscribe((state) => {
185
+ setComments(state.comments);
186
+ setStatus(state.status);
187
+ setError(state.error);
188
+ });
189
+ // Auto-fetch on mount (default: true)
190
+ if (options.autoFetch !== false) {
191
+ controller.fetch();
192
+ }
193
+ onCleanup(unsubscribe);
194
+ });
195
+ const postComment = async (author, content, options) => {
196
+ await controller.post(author, content, options);
197
+ };
198
+ const refresh = async () => {
199
+ await controller.fetch();
200
+ };
201
+ return { comments, status, error, postComment, refresh };
202
+ }
203
+ /**
204
+ * Primitive for handling waitlist signups.
205
+ *
206
+ * @example
207
+ * ```tsx
208
+ * const { join, status, position } = createWaitlist({});
209
+ *
210
+ * <button onClick={() => join('user@example.com')}>Join Waitlist</button>
211
+ * {status() === 'success' && <p>You're #{position()} on the list!</p>}
212
+ * ```
213
+ */
214
+ export function createWaitlist(options) {
215
+ const [status, setStatus] = createSignal("idle");
216
+ const [message, setMessage] = createSignal(null);
217
+ const [position, setPosition] = createSignal(null);
218
+ const [error, setError] = createSignal(null);
219
+ const config = resolveConfig(options);
220
+ const controller = new WaitlistController(config);
221
+ createEffect(() => {
222
+ const unsubscribe = controller.subscribe((state) => {
223
+ setStatus(state.status);
224
+ setMessage(state.message);
225
+ setPosition(state.position);
226
+ setError(state.error);
227
+ });
228
+ onCleanup(unsubscribe);
229
+ });
230
+ const join = async (email, opts) => {
231
+ await controller.join(email, opts);
232
+ };
233
+ const reset = () => {
234
+ controller.reset();
235
+ };
236
+ return { status, message, position, error, join, reset };
237
+ }
238
+ /**
239
+ * Primitive for tracking and displaying page views.
240
+ *
241
+ * @example
242
+ * ```tsx
243
+ * const { views, uniqueVisitors } = createViews({
244
+ * pageId: '/blog/my-post',
245
+ * });
246
+ *
247
+ * <span>{views()} views ({uniqueVisitors()} unique)</span>
248
+ * ```
249
+ */
250
+ export function createViews(options) {
251
+ const [views, setViews] = createSignal(0);
252
+ const [uniqueVisitors, setUniqueVisitors] = createSignal(0);
253
+ const [status, setStatus] = createSignal("idle");
254
+ const [error, setError] = createSignal(null);
255
+ const config = resolveConfig(options);
256
+ const controller = new ViewCountsController(config, options.pageId);
257
+ createEffect(() => {
258
+ const unsubscribe = controller.subscribe((state) => {
259
+ setViews(state.views);
260
+ setUniqueVisitors(state.uniqueVisitors);
261
+ setStatus(state.status);
262
+ setError(state.error);
263
+ });
264
+ // Auto-record view on mount (default: true)
265
+ if (options.autoRecord !== false) {
266
+ controller.record();
267
+ }
268
+ onCleanup(unsubscribe);
269
+ });
270
+ const record = async () => {
271
+ await controller.record();
272
+ };
273
+ const refresh = async () => {
274
+ await controller.fetch();
275
+ };
276
+ return { views, uniqueVisitors, status, error, record, refresh };
277
+ }
278
+ /**
279
+ * Primitive for handling feedback submissions.
280
+ *
281
+ * @example
282
+ * ```tsx
283
+ * const { submit, status } = createFeedback({});
284
+ *
285
+ * <button onClick={() => submit('feature', 'Add dark mode!')}>
286
+ * Submit Feedback
287
+ * </button>
288
+ * ```
289
+ */
290
+ export function createFeedback(options) {
291
+ const [status, setStatus] = createSignal("idle");
292
+ const [message, setMessage] = createSignal(null);
293
+ const [error, setError] = createSignal(null);
294
+ const config = resolveConfig(options);
295
+ const controller = new FeedbackController(config);
296
+ createEffect(() => {
297
+ const unsubscribe = controller.subscribe((state) => {
298
+ setStatus(state.status);
299
+ setMessage(state.message);
300
+ setError(state.error);
301
+ });
302
+ onCleanup(unsubscribe);
303
+ });
304
+ const submit = async (type, content, opts) => {
305
+ await controller.submit(type, content, opts);
306
+ };
307
+ const reset = () => {
308
+ controller.reset();
309
+ };
310
+ return { status, message, error, submit, reset };
311
+ }
312
+ /**
313
+ * Primitive for displaying and voting on polls.
314
+ *
315
+ * @example
316
+ * ```tsx
317
+ * // With meta tag: <meta name="jamwidgets-site-key" content="your-key" />
318
+ * const { poll, vote, hasVoted } = createPoll({ slug: 'favorite-framework' });
319
+ *
320
+ * <Show when={poll()}>
321
+ * {(p) => (
322
+ * <div>
323
+ * <h3>{p().question}</h3>
324
+ * <For each={p().options}>
325
+ * {(opt) => (
326
+ * <button onClick={() => vote([opt.id])} disabled={hasVoted()}>
327
+ * {opt.text} ({p().results[opt.id] || 0} votes)
328
+ * </button>
329
+ * )}
330
+ * </For>
331
+ * </div>
332
+ * )}
333
+ * </Show>
334
+ * ```
335
+ */
336
+ export function createPoll(options) {
337
+ const [poll, setPoll] = createSignal(null);
338
+ const [status, setStatus] = createSignal("idle");
339
+ const [error, setError] = createSignal(null);
340
+ const config = resolveConfig(options);
341
+ const controller = new PollController(config, options.slug);
342
+ createEffect(() => {
343
+ const unsubscribe = controller.subscribe((state) => {
344
+ setPoll(state.poll);
345
+ setStatus(state.status);
346
+ setError(state.error);
347
+ });
348
+ // Auto-fetch on mount (default: true)
349
+ if (options.autoFetch !== false) {
350
+ controller.fetch();
351
+ }
352
+ onCleanup(unsubscribe);
353
+ });
354
+ const vote = async (selectedOptions) => {
355
+ await controller.vote(selectedOptions);
356
+ };
357
+ const refresh = async () => {
358
+ await controller.fetch();
359
+ };
360
+ const hasVoted = () => controller.hasVoted();
361
+ return { poll, status, error, vote, hasVoted, refresh };
362
+ }
363
+ /**
364
+ * Primitive for displaying site announcements.
365
+ *
366
+ * @example
367
+ * ```tsx
368
+ * // With meta tag: <meta name="jamwidgets-site-key" content="your-key" />
369
+ * const { announcements, dismiss } = createAnnouncements({});
370
+ *
371
+ * <For each={announcements()}>
372
+ * {(ann) => (
373
+ * <div class={`announcement-${ann.announcementType}`}>
374
+ * {ann.content}
375
+ * {ann.isDismissible && (
376
+ * <button onClick={() => dismiss(ann.id)}>Dismiss</button>
377
+ * )}
378
+ * </div>
379
+ * )}
380
+ * </For>
381
+ * ```
382
+ */
383
+ export function createAnnouncements(options) {
384
+ const [announcements, setAnnouncements] = createSignal([]);
385
+ const [status, setStatus] = createSignal("idle");
386
+ const [error, setError] = createSignal(null);
387
+ const config = resolveConfig(options);
388
+ const controller = new AnnouncementsController(config);
389
+ createEffect(() => {
390
+ const unsubscribe = controller.subscribe((state) => {
391
+ // Only show non-dismissed announcements
392
+ setAnnouncements(controller.getVisibleAnnouncements());
393
+ setStatus(state.status);
394
+ setError(state.error);
395
+ });
396
+ // Auto-fetch on mount (default: true)
397
+ if (options.autoFetch !== false) {
398
+ controller.fetch();
399
+ }
400
+ onCleanup(unsubscribe);
401
+ });
402
+ const dismiss = async (announcementId) => {
403
+ await controller.dismiss(announcementId);
404
+ };
405
+ const refresh = async () => {
406
+ await controller.fetch();
407
+ };
408
+ return { announcements, status, error, dismiss, refresh };
409
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@jamwidgets/solid",
3
+ "version": "0.1.0",
4
+ "description": "SolidJS primitives for Jamwidgets (forms, comments, reactions, subscriptions)",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/jamwidgets/solid.git"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "homepage": "https://jamwidgets.com",
13
+ "author": "Tim Marks <tim@imothee.xyz>",
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "keywords": [
27
+ "solid",
28
+ "solidjs",
29
+ "jamwidgets",
30
+ "forms",
31
+ "comments",
32
+ "reactions",
33
+ "subscribe",
34
+ "primitives"
35
+ ],
36
+ "license": "MIT",
37
+ "dependencies": {
38
+ "@jamwidgets/core": "0.1.0"
39
+ },
40
+ "peerDependencies": {
41
+ "solid-js": "^1.8.0"
42
+ },
43
+ "devDependencies": {
44
+ "solid-js": "^1.9.0",
45
+ "typescript": "^5.7.3"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc",
49
+ "dev": "tsc --watch"
50
+ }
51
+ }