@mrrocket/sdk 0.0.0-stage → 0.2.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/README.md +284 -2
  4. package/dist/api.d.ts +113 -0
  5. package/dist/api.js +71 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/browser.d.ts +11 -0
  8. package/dist/browser.js +25 -0
  9. package/dist/browser.js.map +1 -0
  10. package/dist/capture.d.ts +50 -0
  11. package/dist/capture.js +91 -0
  12. package/dist/capture.js.map +1 -0
  13. package/dist/client.d.ts +83 -0
  14. package/dist/client.js +468 -0
  15. package/dist/client.js.map +1 -0
  16. package/dist/context.d.ts +33 -0
  17. package/dist/context.js +15 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/core.d.ts +132 -0
  20. package/dist/core.js +104 -0
  21. package/dist/core.js.map +1 -0
  22. package/dist/feedback.d.ts +28 -0
  23. package/dist/feedback.js +459 -0
  24. package/dist/feedback.js.map +1 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.js +58 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/proxy.d.ts +28 -0
  29. package/dist/proxy.js +12 -0
  30. package/dist/proxy.js.map +1 -0
  31. package/dist/referral.d.ts +86 -0
  32. package/dist/referral.js +128 -0
  33. package/dist/referral.js.map +1 -0
  34. package/dist/replay-core.d.ts +93 -0
  35. package/dist/replay-core.js +122 -0
  36. package/dist/replay-core.js.map +1 -0
  37. package/dist/replay.d.ts +34 -0
  38. package/dist/replay.js +200 -0
  39. package/dist/replay.js.map +1 -0
  40. package/dist/server.d.ts +47 -0
  41. package/dist/server.js +43 -0
  42. package/dist/server.js.map +1 -0
  43. package/dist/styles.d.ts +4 -0
  44. package/dist/styles.js +147 -0
  45. package/dist/styles.js.map +1 -0
  46. package/dist/survey.d.ts +4 -0
  47. package/dist/survey.js +201 -0
  48. package/dist/survey.js.map +1 -0
  49. package/dist/ui.d.ts +29 -0
  50. package/dist/ui.js +77 -0
  51. package/dist/ui.js.map +1 -0
  52. package/package.json +96 -5
@@ -0,0 +1,459 @@
1
+ "use client";
2
+
3
+ // src/feedback.tsx
4
+ import { useCallback, useEffect, useId, useRef, useState } from "react";
5
+ import { useApi } from "./api.js";
6
+ import { Chat, ChevronUp, Cross, Plus, Root, StatusPill, VoteButton, similarPosts, timeAgo, useEscape } from "./ui.js";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ var useFeedbackList = (opts) => {
9
+ const api = useApi();
10
+ const [posts, setPosts] = useState([]);
11
+ const [boards, setBoards] = useState([]);
12
+ const [loading, setLoading] = useState(true);
13
+ const [error, setError] = useState("");
14
+ const [tick, setTick] = useState(0);
15
+ const { board, sort, q } = opts;
16
+ useEffect(() => {
17
+ const ctl = new AbortController();
18
+ setLoading(true);
19
+ const wait = window.setTimeout(
20
+ () => {
21
+ api.list({ board, sort, q: q?.trim() || void 0 }, ctl.signal).then((r) => {
22
+ setPosts(r.posts);
23
+ setBoards(r.boards);
24
+ setError("");
25
+ setLoading(false);
26
+ }).catch((e) => {
27
+ if (e.name === "AbortError") return;
28
+ setError(e.message);
29
+ setLoading(false);
30
+ });
31
+ },
32
+ q ? 250 : 0
33
+ );
34
+ return () => {
35
+ window.clearTimeout(wait);
36
+ ctl.abort();
37
+ };
38
+ }, [api, board, sort, q, tick]);
39
+ const patch = useCallback((id, fn) => setPosts((all) => all.map((p) => p.id === id ? fn(p) : p)), []);
40
+ const vote = useCallback(
41
+ (post) => {
42
+ const flip = (p) => ({ ...p, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });
43
+ patch(post.id, flip);
44
+ api.vote(post.id).then((r) => patch(post.id, (p) => ({ ...p, voted: r.voted, votes: r.votes }))).catch((e) => {
45
+ patch(post.id, flip);
46
+ setError(`Your vote was not saved. ${e.message}`);
47
+ });
48
+ },
49
+ [api, patch]
50
+ );
51
+ return { api, posts, setPosts, patch, boards, loading, error, setError, vote, reload: () => setTick((t) => t + 1) };
52
+ };
53
+ var SubmitForm = ({
54
+ api,
55
+ boards,
56
+ posts,
57
+ onCreated,
58
+ onVote,
59
+ onCancel,
60
+ compact
61
+ }) => {
62
+ const id = useId();
63
+ const [title, setTitle] = useState("");
64
+ const [body, setBody] = useState("");
65
+ const [board, setBoard] = useState("");
66
+ const [busy, setBusy] = useState(false);
67
+ const [error, setError] = useState("");
68
+ const chosen = board || boards[0]?.id || "";
69
+ const dupes = similarPosts(title, posts);
70
+ const submit = async (e) => {
71
+ e.preventDefault();
72
+ if (!title.trim() || busy) return;
73
+ setBusy(true);
74
+ setError("");
75
+ try {
76
+ const created = await api.submit({ title: title.trim(), body: body.trim() || void 0, board: chosen });
77
+ setTitle("");
78
+ setBody("");
79
+ onCreated(created);
80
+ } catch (err) {
81
+ setError(err.message);
82
+ } finally {
83
+ setBusy(false);
84
+ }
85
+ };
86
+ return /* @__PURE__ */ jsxs("form", { className: "ckw-form", onSubmit: submit, children: [
87
+ /* @__PURE__ */ jsxs("div", { className: "ckw-field", children: [
88
+ /* @__PURE__ */ jsx("label", { className: "ckw-label", htmlFor: `${id}-t`, children: "Title" }),
89
+ /* @__PURE__ */ jsx("input", { id: `${id}-t`, className: "ckw-input", value: title, maxLength: 140, required: true, autoFocus: true, onChange: (e) => setTitle(e.target.value), placeholder: "Short, specific summary" })
90
+ ] }),
91
+ dupes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ckw-dupes", role: "status", children: [
92
+ /* @__PURE__ */ jsx("p", { children: "Similar requests. Vote instead of adding a duplicate:" }),
93
+ dupes.map((d) => /* @__PURE__ */ jsxs("div", { className: "ckw-dupe", children: [
94
+ /* @__PURE__ */ jsx("span", { title: d.title, children: d.title }),
95
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn", disabled: d.voted, onClick: () => onVote(d), children: d.voted ? "Voted" : "Vote instead" })
96
+ ] }, d.id))
97
+ ] }),
98
+ !compact && /* @__PURE__ */ jsxs("div", { className: "ckw-field", children: [
99
+ /* @__PURE__ */ jsx("label", { className: "ckw-label", htmlFor: `${id}-b`, children: "Details (optional)" }),
100
+ /* @__PURE__ */ jsx("textarea", { id: `${id}-b`, className: "ckw-textarea", value: body, maxLength: 2e3, onChange: (e) => setBody(e.target.value), placeholder: "What are you trying to do?" })
101
+ ] }),
102
+ boards.length > 1 && /* @__PURE__ */ jsxs("div", { className: "ckw-field", children: [
103
+ /* @__PURE__ */ jsx("label", { className: "ckw-label", htmlFor: `${id}-c`, children: "Board" }),
104
+ /* @__PURE__ */ jsx("select", { id: `${id}-c`, className: "ckw-select", value: chosen, onChange: (e) => setBoard(e.target.value), children: boards.map((b) => /* @__PURE__ */ jsx("option", { value: b.id, children: b.label }, b.id)) })
105
+ ] }),
106
+ error && /* @__PURE__ */ jsx("div", { className: "ckw-error", role: "alert", children: error }),
107
+ /* @__PURE__ */ jsxs("div", { className: "ckw-actions", children: [
108
+ onCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn ckw-btn-ghost", onClick: onCancel, children: "Cancel" }),
109
+ /* @__PURE__ */ jsx("button", { type: "submit", className: "ckw-btn ckw-btn-primary", disabled: busy || !title.trim(), children: busy ? "Sending\u2026" : "Submit request" })
110
+ ] })
111
+ ] });
112
+ };
113
+ var PostRow = ({ post, onOpen, onVote }) => /* @__PURE__ */ jsxs("li", { className: "ckw-row", children: [
114
+ /* @__PURE__ */ jsx(VoteButton, { post, onVote }),
115
+ /* @__PURE__ */ jsxs("div", { className: "ckw-main", children: [
116
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-link", onClick: () => onOpen(post), children: post.title }),
117
+ post.body && /* @__PURE__ */ jsx("p", { className: "ckw-excerpt", children: post.body }),
118
+ /* @__PURE__ */ jsxs("div", { className: "ckw-meta", children: [
119
+ /* @__PURE__ */ jsx(StatusPill, { status: post.status }),
120
+ /* @__PURE__ */ jsxs("span", { className: "ckw-stat", children: [
121
+ /* @__PURE__ */ jsx(Chat, {}),
122
+ " ",
123
+ post.comments
124
+ ] }),
125
+ /* @__PURE__ */ jsx("span", { children: timeAgo(post.createdAt) })
126
+ ] })
127
+ ] })
128
+ ] });
129
+ var Skeleton = () => /* @__PURE__ */ jsx("div", { "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("div", { className: "ckw-skel" }, i)) });
130
+ var ErrorBar = ({ message, onRetry, onClose }) => /* @__PURE__ */ jsxs("div", { className: "ckw-error", role: "alert", children: [
131
+ /* @__PURE__ */ jsx("span", { children: message }),
132
+ onRetry ? /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn", onClick: onRetry, children: "Retry" }) : onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn ckw-btn-ghost", onClick: onClose, "aria-label": "Dismiss", children: /* @__PURE__ */ jsx(Cross, {}) })
133
+ ] });
134
+ var PostDetail = ({ post, onBack, onVote }) => {
135
+ const api = useApi();
136
+ const id = useId();
137
+ const [comments, setComments] = useState(null);
138
+ const [error, setError] = useState("");
139
+ const [text, setText] = useState("");
140
+ const [busy, setBusy] = useState(false);
141
+ const [added, setAdded] = useState(0);
142
+ useEffect(() => {
143
+ const ctl = new AbortController();
144
+ api.comments(post.id, ctl.signal).then((r) => setComments(r.comments)).catch((e) => e.name !== "AbortError" && setError(e.message));
145
+ return () => ctl.abort();
146
+ }, [api, post.id]);
147
+ const send = async (e) => {
148
+ e.preventDefault();
149
+ const body = text.trim();
150
+ if (!body || busy) return;
151
+ setBusy(true);
152
+ setError("");
153
+ const temp = { id: `tmp-${Date.now()}`, body, author: "You", isTeam: false, postedAt: (/* @__PURE__ */ new Date()).toISOString() };
154
+ setComments((c) => [...c ?? [], temp]);
155
+ setText("");
156
+ try {
157
+ const real = await api.comment(post.id, body);
158
+ setComments((c) => (c ?? []).map((x) => x.id === temp.id ? real : x));
159
+ setAdded((n) => n + 1);
160
+ } catch (err) {
161
+ setComments((c) => (c ?? []).filter((x) => x.id !== temp.id));
162
+ setText(body);
163
+ setError(err.message);
164
+ } finally {
165
+ setBusy(false);
166
+ }
167
+ };
168
+ return /* @__PURE__ */ jsxs("div", { children: [
169
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "ckw-btn ckw-btn-ghost ckw-back", onClick: onBack, children: [
170
+ /* @__PURE__ */ jsx("span", { style: { display: "inline-block", transform: "rotate(-90deg)", lineHeight: 0 }, children: /* @__PURE__ */ jsx(ChevronUp, {}) }),
171
+ "All requests"
172
+ ] }),
173
+ /* @__PURE__ */ jsxs("div", { className: "ckw-detail-head", children: [
174
+ /* @__PURE__ */ jsx(VoteButton, { post, onVote }),
175
+ /* @__PURE__ */ jsxs("div", { className: "ckw-main", children: [
176
+ /* @__PURE__ */ jsx("h2", { children: post.title }),
177
+ /* @__PURE__ */ jsxs("div", { className: "ckw-meta", style: { marginTop: 0 }, children: [
178
+ /* @__PURE__ */ jsx(StatusPill, { status: post.status }),
179
+ /* @__PURE__ */ jsx("span", { children: timeAgo(post.createdAt) })
180
+ ] })
181
+ ] })
182
+ ] }),
183
+ post.body && /* @__PURE__ */ jsx("p", { className: "ckw-body", children: post.body }),
184
+ /* @__PURE__ */ jsxs("h3", { className: "ckw-h", children: [
185
+ "Comments (",
186
+ Math.max(post.comments + added, comments?.length ?? 0),
187
+ ")"
188
+ ] }),
189
+ error && /* @__PURE__ */ jsx(ErrorBar, { message: error, onClose: () => setError("") }),
190
+ /* @__PURE__ */ jsxs("div", { "aria-live": "polite", children: [
191
+ comments === null && !error && /* @__PURE__ */ jsx(Skeleton, {}),
192
+ comments?.length === 0 && /* @__PURE__ */ jsx("p", { className: "ckw-sub", children: "No comments yet. Be the first." }),
193
+ comments?.map((c) => /* @__PURE__ */ jsxs("div", { className: "ckw-comment", children: [
194
+ /* @__PURE__ */ jsx("b", { children: c.author }),
195
+ c.isTeam && /* @__PURE__ */ jsx("span", { className: "ckw-team", children: "Team" }),
196
+ /* @__PURE__ */ jsx("span", { className: "ckw-time", children: timeAgo(c.postedAt) }),
197
+ /* @__PURE__ */ jsx("p", { children: c.body })
198
+ ] }, c.id))
199
+ ] }),
200
+ /* @__PURE__ */ jsxs("form", { className: "ckw-form", onSubmit: send, style: { marginTop: 12 }, children: [
201
+ /* @__PURE__ */ jsx("label", { className: "ckw-label", htmlFor: id, children: "Add a comment" }),
202
+ /* @__PURE__ */ jsx("textarea", { id, className: "ckw-textarea", value: text, maxLength: 2e3, onChange: (e) => setText(e.target.value) }),
203
+ /* @__PURE__ */ jsx("div", { className: "ckw-actions", children: /* @__PURE__ */ jsx("button", { type: "submit", className: "ckw-btn ckw-btn-primary", disabled: busy || !text.trim(), children: "Comment" }) })
204
+ ] })
205
+ ] });
206
+ };
207
+ var Roadmap = ({ onOpen }) => {
208
+ const api = useApi();
209
+ const [data, setData] = useState(null);
210
+ const [error, setError] = useState("");
211
+ const [tick, setTick] = useState(0);
212
+ useEffect(() => {
213
+ const ctl = new AbortController();
214
+ api.roadmap(ctl.signal).then((r) => (setData(r), setError(""))).catch((e) => e.name !== "AbortError" && setError(e.message));
215
+ return () => ctl.abort();
216
+ }, [api, tick]);
217
+ if (error) return /* @__PURE__ */ jsx(ErrorBar, { message: error, onRetry: () => setTick((t) => t + 1) });
218
+ if (!data) return /* @__PURE__ */ jsx(Skeleton, {});
219
+ const cols = [
220
+ ["planned", "Planned"],
221
+ ["progress", "In progress"],
222
+ ["shipped", "Shipped"]
223
+ ];
224
+ return /* @__PURE__ */ jsx("div", { className: "ckw-cols", children: cols.map(([k, label]) => /* @__PURE__ */ jsxs("section", { className: "ckw-col", "aria-label": label, children: [
225
+ /* @__PURE__ */ jsxs("h3", { children: [
226
+ label,
227
+ " ",
228
+ /* @__PURE__ */ jsx("span", { children: data.columns[k].length })
229
+ ] }),
230
+ data.columns[k].length === 0 && /* @__PURE__ */ jsx("p", { className: "ckw-sub", children: "Nothing here yet." }),
231
+ data.columns[k].map((p) => /* @__PURE__ */ jsxs("div", { className: "ckw-card", children: [
232
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-link", onClick: () => onOpen(p), children: p.title }),
233
+ /* @__PURE__ */ jsxs("div", { className: "ckw-meta", style: { marginTop: 0 }, children: [
234
+ /* @__PURE__ */ jsxs("span", { className: "ckw-stat", children: [
235
+ /* @__PURE__ */ jsx(ChevronUp, {}),
236
+ " ",
237
+ p.votes
238
+ ] }),
239
+ /* @__PURE__ */ jsxs("span", { className: "ckw-stat", children: [
240
+ /* @__PURE__ */ jsx(Chat, {}),
241
+ " ",
242
+ p.comments
243
+ ] })
244
+ ] })
245
+ ] }, p.id))
246
+ ] }, k)) });
247
+ };
248
+ var Changelog = () => {
249
+ const api = useApi();
250
+ const [entries, setEntries] = useState(null);
251
+ const [error, setError] = useState("");
252
+ const [tick, setTick] = useState(0);
253
+ useEffect(() => {
254
+ const ctl = new AbortController();
255
+ api.changelog(ctl.signal).then((r) => (setEntries(r.entries), setError(""))).catch((e) => e.name !== "AbortError" && setError(e.message));
256
+ return () => ctl.abort();
257
+ }, [api, tick]);
258
+ if (error) return /* @__PURE__ */ jsx(ErrorBar, { message: error, onRetry: () => setTick((t) => t + 1) });
259
+ if (!entries) return /* @__PURE__ */ jsx(Skeleton, {});
260
+ if (entries.length === 0) return /* @__PURE__ */ jsx("div", { className: "ckw-empty", children: "No updates published yet." });
261
+ return /* @__PURE__ */ jsx("div", { children: entries.map((e) => /* @__PURE__ */ jsxs("article", { className: "ckw-entry", children: [
262
+ /* @__PURE__ */ jsx("time", { dateTime: e.publishedAt, children: new Date(e.publishedAt).toLocaleDateString(void 0, { month: "long", day: "numeric", year: "numeric" }) }),
263
+ /* @__PURE__ */ jsx("h3", { children: e.title }),
264
+ /* @__PURE__ */ jsx("p", { children: e.body })
265
+ ] }, e.id)) });
266
+ };
267
+ var FeedbackBoard = ({ title = "Feedback", subtitle = "Tell us what to build next and vote on what matters to you.", theme, accent }) => {
268
+ const [tab, setTab] = useState("requests");
269
+ const [sort, setSort] = useState("top");
270
+ const [board, setBoard] = useState();
271
+ const [q, setQ] = useState("");
272
+ const [creating, setCreating] = useState(false);
273
+ const [opened, setOpened] = useState(null);
274
+ const list = useFeedbackList({ board, sort, q });
275
+ const { posts, setPosts, vote } = list;
276
+ const current = opened && (posts.find((p) => p.id === opened.id) ?? opened);
277
+ const voteOpened = (p) => {
278
+ if (!posts.some((x) => x.id === p.id)) {
279
+ setOpened((o) => o ? { ...o, voted: !o.voted, votes: o.votes + (o.voted ? -1 : 1) } : o);
280
+ list.api.vote(p.id).then((r) => setOpened((o) => o ? { ...o, voted: r.voted, votes: r.votes } : o)).catch((e) => {
281
+ setOpened((o) => o ? { ...o, voted: p.voted, votes: p.votes } : o);
282
+ list.setError(`Your vote was not saved. ${e.message}`);
283
+ });
284
+ return;
285
+ }
286
+ vote(p);
287
+ };
288
+ const tabs = [
289
+ ["requests", "Requests"],
290
+ ["roadmap", "Roadmap"],
291
+ ["changelog", "Changelog"]
292
+ ];
293
+ const onTabKey = (e) => {
294
+ const i = tabs.findIndex(([k]) => k === tab);
295
+ const n = e.key === "ArrowRight" ? i + 1 : e.key === "ArrowLeft" ? i - 1 : null;
296
+ if (n === null) return;
297
+ e.preventDefault();
298
+ setTab(tabs[(n + tabs.length) % tabs.length][0]);
299
+ setOpened(null);
300
+ };
301
+ return /* @__PURE__ */ jsxs(Root, { theme, accent, className: "ckw-board", children: [
302
+ /* @__PURE__ */ jsxs("div", { className: "ckw-head", children: [
303
+ /* @__PURE__ */ jsxs("div", { children: [
304
+ /* @__PURE__ */ jsx("h2", { className: "ckw-title", children: title }),
305
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ckw-sub", children: subtitle })
306
+ ] }),
307
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "ckw-btn ckw-btn-primary", onClick: () => (setCreating((c) => !c), setOpened(null), setTab("requests")), "aria-expanded": creating, children: [
308
+ /* @__PURE__ */ jsx(Plus, {}),
309
+ " Request a feature"
310
+ ] })
311
+ ] }),
312
+ /* @__PURE__ */ jsx("div", { className: "ckw-tabs", role: "tablist", "aria-label": "Feedback sections", onKeyDown: onTabKey, children: tabs.map(([k, label]) => /* @__PURE__ */ jsx(
313
+ "button",
314
+ {
315
+ type: "button",
316
+ role: "tab",
317
+ id: `ckw-tab-${k}`,
318
+ "aria-selected": tab === k,
319
+ tabIndex: tab === k ? 0 : -1,
320
+ className: "ckw-tab",
321
+ onClick: () => (setTab(k), setOpened(null)),
322
+ children: label
323
+ },
324
+ k
325
+ )) }),
326
+ /* @__PURE__ */ jsxs("div", { role: "tabpanel", "aria-labelledby": `ckw-tab-${tab}`, children: [
327
+ list.error && /* @__PURE__ */ jsx(ErrorBar, { message: list.error, onRetry: tab === "requests" && !current ? list.reload : void 0, onClose: () => list.setError("") }),
328
+ current ? /* @__PURE__ */ jsx(PostDetail, { post: current, onBack: () => setOpened(null), onVote: voteOpened }) : tab === "requests" ? /* @__PURE__ */ jsxs(Fragment, { children: [
329
+ creating && /* @__PURE__ */ jsx(
330
+ SubmitForm,
331
+ {
332
+ api: list.api,
333
+ boards: list.boards,
334
+ posts,
335
+ onVote: vote,
336
+ onCancel: () => setCreating(false),
337
+ onCreated: (p) => {
338
+ setPosts((all) => [p, ...all]);
339
+ setCreating(false);
340
+ }
341
+ }
342
+ ),
343
+ /* @__PURE__ */ jsxs("div", { className: "ckw-tools", children: [
344
+ /* @__PURE__ */ jsx("input", { className: "ckw-input ckw-search", type: "search", "aria-label": "Search requests", placeholder: "Search requests", value: q, onChange: (e) => setQ(e.target.value) }),
345
+ /* @__PURE__ */ jsx("div", { className: "ckw-seg", role: "group", "aria-label": "Sort", children: ["top", "new"].map((s) => /* @__PURE__ */ jsx("button", { type: "button", "aria-pressed": sort === s, onClick: () => setSort(s), children: s === "top" ? "Top" : "New" }, s)) })
346
+ ] }),
347
+ list.boards.length > 1 && /* @__PURE__ */ jsxs("div", { className: "ckw-chips", role: "group", "aria-label": "Boards", children: [
348
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-chip", "aria-pressed": !board, onClick: () => setBoard(void 0), children: "All" }),
349
+ list.boards.map((b) => /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-chip", "aria-pressed": board === b.id, onClick: () => setBoard(b.id), children: b.label }, b.id))
350
+ ] }),
351
+ /* @__PURE__ */ jsx("div", { "aria-live": "polite", "aria-busy": list.loading, children: list.loading && posts.length === 0 ? /* @__PURE__ */ jsx(Skeleton, {}) : posts.length === 0 && !list.error ? /* @__PURE__ */ jsx("div", { className: "ckw-empty", children: q ? "No requests match your search." : "No requests yet. Be the first to suggest something." }) : /* @__PURE__ */ jsx("ul", { className: "ckw-list", children: posts.map((p) => /* @__PURE__ */ jsx(PostRow, { post: p, onOpen: setOpened, onVote: vote }, p.id)) }) })
352
+ ] }) : tab === "roadmap" ? /* @__PURE__ */ jsx(Roadmap, { onOpen: setOpened }) : /* @__PURE__ */ jsx(Changelog, {})
353
+ ] })
354
+ ] });
355
+ };
356
+ var listeners = /* @__PURE__ */ new Set();
357
+ var widgetOpen = false;
358
+ var setWidgetOpen = (v) => {
359
+ widgetOpen = v;
360
+ listeners.forEach((l) => l(v));
361
+ };
362
+ var useFeedback = () => ({ open: () => setWidgetOpen(true), close: () => setWidgetOpen(false) });
363
+ var WidgetPanel = ({ boardUrl, onClose }) => {
364
+ const [suggesting, setSuggesting] = useState(false);
365
+ const [thanks, setThanks] = useState(false);
366
+ const list = useFeedbackList({ sort: "top" });
367
+ const { posts, setPosts } = list;
368
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
369
+ /* @__PURE__ */ jsxs("div", { className: "ckw-pop-head", children: [
370
+ /* @__PURE__ */ jsx("span", { children: suggesting ? "Suggest something" : "Top requests" }),
371
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn ckw-btn-ghost", onClick: onClose, "aria-label": "Close feedback", children: /* @__PURE__ */ jsx(Cross, {}) })
372
+ ] }),
373
+ /* @__PURE__ */ jsxs("div", { className: "ckw-pop-body", children: [
374
+ list.error && /* @__PURE__ */ jsx(ErrorBar, { message: list.error, onClose: () => list.setError("") }),
375
+ thanks ? /* @__PURE__ */ jsx("div", { className: "ckw-empty", role: "status", children: "Thanks, your request is in." }) : suggesting ? /* @__PURE__ */ jsx(
376
+ SubmitForm,
377
+ {
378
+ compact: true,
379
+ api: list.api,
380
+ boards: list.boards,
381
+ posts,
382
+ onVote: list.vote,
383
+ onCancel: () => setSuggesting(false),
384
+ onCreated: (p) => {
385
+ setPosts((all) => [p, ...all]);
386
+ setSuggesting(false);
387
+ setThanks(true);
388
+ }
389
+ }
390
+ ) : list.loading && posts.length === 0 ? /* @__PURE__ */ jsx(Skeleton, {}) : posts.length === 0 && !list.error ? /* @__PURE__ */ jsx("div", { className: "ckw-empty", children: "No requests yet. Suggest the first one." }) : /* @__PURE__ */ jsx("ul", { className: "ckw-list", "aria-live": "polite", children: posts.slice(0, 5).map((p) => /* @__PURE__ */ jsxs("li", { className: "ckw-row", children: [
391
+ /* @__PURE__ */ jsx(VoteButton, { post: p, onVote: list.vote }),
392
+ /* @__PURE__ */ jsxs("div", { className: "ckw-main", children: [
393
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, overflowWrap: "anywhere" }, children: p.title }),
394
+ /* @__PURE__ */ jsx("div", { className: "ckw-meta", children: /* @__PURE__ */ jsx(StatusPill, { status: p.status }) })
395
+ ] })
396
+ ] }, p.id)) })
397
+ ] }),
398
+ /* @__PURE__ */ jsxs("div", { className: "ckw-pop-foot", children: [
399
+ boardUrl ? /* @__PURE__ */ jsx("a", { href: boardUrl, children: "See all" }) : /* @__PURE__ */ jsx("span", {}),
400
+ !suggesting && !thanks && /* @__PURE__ */ jsxs("button", { type: "button", className: "ckw-btn ckw-btn-primary", onClick: () => setSuggesting(true), children: [
401
+ /* @__PURE__ */ jsx(Plus, {}),
402
+ " Suggest something"
403
+ ] }),
404
+ thanks && /* @__PURE__ */ jsx("button", { type: "button", className: "ckw-btn", onClick: () => setThanks(false), children: "Back" })
405
+ ] })
406
+ ] });
407
+ };
408
+ var FeedbackWidget = ({ position = "bottom-right", label = "Feedback", boardUrl, theme, accent }) => {
409
+ const [open, setOpen] = useState(false);
410
+ const fab = useRef(null);
411
+ const pop = useRef(null);
412
+ useEffect(() => {
413
+ const l = (v) => setOpen(v);
414
+ listeners.add(l);
415
+ setOpen(widgetOpen);
416
+ const click = (e) => {
417
+ if (e.target?.closest("[data-ck-feedback]")) {
418
+ e.preventDefault();
419
+ setWidgetOpen(true);
420
+ }
421
+ };
422
+ document.addEventListener("click", click);
423
+ return () => {
424
+ listeners.delete(l);
425
+ document.removeEventListener("click", click);
426
+ };
427
+ }, []);
428
+ const close = useCallback(() => {
429
+ setWidgetOpen(false);
430
+ fab.current?.focus();
431
+ }, []);
432
+ useEscape(() => open && close());
433
+ useEffect(() => {
434
+ if (open) pop.current?.querySelector("button, input")?.focus();
435
+ }, [open]);
436
+ const trap = (e) => {
437
+ if (e.key !== "Tab" || !pop.current) return;
438
+ const f = [...pop.current.querySelectorAll("a[href], button:not([disabled]), input, select, textarea")];
439
+ if (!f.length) return;
440
+ const first = f[0];
441
+ const last = f[f.length - 1];
442
+ if (e.shiftKey && document.activeElement === first) e.preventDefault(), last.focus();
443
+ else if (!e.shiftKey && document.activeElement === last) e.preventDefault(), first.focus();
444
+ };
445
+ return /* @__PURE__ */ jsxs(Root, { theme, accent, children: [
446
+ /* @__PURE__ */ jsxs("button", { ref: fab, type: "button", className: "ckw-fab", "data-pos": position, "aria-haspopup": "dialog", "aria-expanded": open, onClick: () => open ? close() : setWidgetOpen(true), children: [
447
+ /* @__PURE__ */ jsx(Chat, {}),
448
+ " ",
449
+ label
450
+ ] }),
451
+ open && /* @__PURE__ */ jsx("div", { ref: pop, className: "ckw-pop", "data-pos": position, role: "dialog", "aria-label": "Feedback", onKeyDown: trap, children: /* @__PURE__ */ jsx(WidgetPanel, { boardUrl, onClose: close }) })
452
+ ] });
453
+ };
454
+ export {
455
+ FeedbackBoard,
456
+ FeedbackWidget,
457
+ useFeedback
458
+ };
459
+ //# sourceMappingURL=feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/feedback.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FormEvent, useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport { type ChangelogEntry, type FeedbackBoardInfo, type FeedbackComment, type FeedbackPost, type FeedbackRoadmap, useApi } from \"./api\";\nimport { Chat, ChevronUp, Cross, Plus, Root, StatusPill, type Theme, VoteButton, similarPosts, timeAgo, useEscape } from \"./ui\";\n\n/** Loads the post list and owns optimistic voting, so the board and the widget behave the same. */\nconst useFeedbackList = (opts: { board?: string; sort?: \"top\" | \"new\"; q?: string; limit?: number }) => {\n const api = useApi();\n const [posts, setPosts] = useState<FeedbackPost[]>([]);\n const [boards, setBoards] = useState<FeedbackBoardInfo[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n const { board, sort, q } = opts;\n\n useEffect(() => {\n const ctl = new AbortController();\n setLoading(true);\n const wait = window.setTimeout(\n () => {\n api.list({ board, sort, q: q?.trim() || undefined }, ctl.signal)\n .then((r) => {\n setPosts(r.posts);\n setBoards(r.boards);\n setError(\"\");\n setLoading(false);\n })\n .catch((e: Error) => {\n if (e.name === \"AbortError\") return;\n setError(e.message);\n setLoading(false);\n });\n },\n q ? 250 : 0,\n );\n return () => {\n window.clearTimeout(wait);\n ctl.abort();\n };\n }, [api, board, sort, q, tick]);\n\n const patch = useCallback((id: string, fn: (p: FeedbackPost) => FeedbackPost) => setPosts((all) => all.map((p) => (p.id === id ? fn(p) : p))), []);\n\n /** Flips the vote at once, then confirms with the server; on failure it flips back. */\n const vote = useCallback(\n (post: FeedbackPost) => {\n const flip = (p: FeedbackPost) => ({ ...p, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n patch(post.id, flip);\n api.vote(post.id)\n .then((r) => patch(post.id, (p) => ({ ...p, voted: r.voted, votes: r.votes })))\n .catch((e: Error) => {\n patch(post.id, flip);\n setError(`Your vote was not saved. ${e.message}`);\n });\n },\n [api, patch],\n );\n\n return { api, posts, setPosts, patch, boards, loading, error, setError, vote, reload: () => setTick((t) => t + 1) };\n};\n\n/** Title, details and board, with up to three similar requests to vote on instead. */\nconst SubmitForm = ({\n api,\n boards,\n posts,\n onCreated,\n onVote,\n onCancel,\n compact,\n}: {\n api: ReturnType<typeof useApi>;\n boards: FeedbackBoardInfo[];\n posts: FeedbackPost[];\n onCreated: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onCancel?: () => void;\n compact?: boolean;\n}) => {\n const id = useId();\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [board, setBoard] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(\"\");\n const chosen = board || boards[0]?.id || \"\";\n const dupes = similarPosts(title, posts);\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n if (!title.trim() || busy) return;\n setBusy(true);\n setError(\"\");\n try {\n const created = await api.submit({ title: title.trim(), body: body.trim() || undefined, board: chosen });\n setTitle(\"\");\n setBody(\"\");\n onCreated(created);\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <form className=\"ckw-form\" onSubmit={submit}>\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-t`}>\n Title\n </label>\n <input id={`${id}-t`} className=\"ckw-input\" value={title} maxLength={140} required autoFocus onChange={(e) => setTitle(e.target.value)} placeholder=\"Short, specific summary\" />\n </div>\n {dupes.length > 0 && (\n <div className=\"ckw-dupes\" role=\"status\">\n <p>Similar requests. Vote instead of adding a duplicate:</p>\n {dupes.map((d) => (\n <div className=\"ckw-dupe\" key={d.id}>\n <span title={d.title}>{d.title}</span>\n <button type=\"button\" className=\"ckw-btn\" disabled={d.voted} onClick={() => onVote(d)}>\n {d.voted ? \"Voted\" : \"Vote instead\"}\n </button>\n </div>\n ))}\n </div>\n )}\n {!compact && (\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-b`}>\n Details (optional)\n </label>\n <textarea id={`${id}-b`} className=\"ckw-textarea\" value={body} maxLength={2000} onChange={(e) => setBody(e.target.value)} placeholder=\"What are you trying to do?\" />\n </div>\n )}\n {boards.length > 1 && (\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-c`}>\n Board\n </label>\n <select id={`${id}-c`} className=\"ckw-select\" value={chosen} onChange={(e) => setBoard(e.target.value)}>\n {boards.map((b) => (\n <option key={b.id} value={b.id}>\n {b.label}\n </option>\n ))}\n </select>\n </div>\n )}\n {error && (\n <div className=\"ckw-error\" role=\"alert\">\n {error}\n </div>\n )}\n <div className=\"ckw-actions\">\n {onCancel && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onCancel}>\n Cancel\n </button>\n )}\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !title.trim()}>\n {busy ? \"Sending…\" : \"Submit request\"}\n </button>\n </div>\n </form>\n );\n};\n\nconst PostRow = ({ post, onOpen, onVote }: { post: FeedbackPost; onOpen: (p: FeedbackPost) => void; onVote: (p: FeedbackPost) => void }) => (\n <li className=\"ckw-row\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <button type=\"button\" className=\"ckw-link\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-meta\">\n <StatusPill status={post.status} />\n <span className=\"ckw-stat\">\n <Chat /> {post.comments}\n </span>\n <span>{timeAgo(post.createdAt)}</span>\n </div>\n </div>\n </li>\n);\n\nconst Skeleton = () => (\n <div aria-hidden=\"true\">\n {[0, 1, 2].map((i) => (\n <div className=\"ckw-skel\" key={i} />\n ))}\n </div>\n);\n\nconst ErrorBar = ({ message, onRetry, onClose }: { message: string; onRetry?: () => void; onClose?: () => void }) => (\n <div className=\"ckw-error\" role=\"alert\">\n <span>{message}</span>\n {onRetry ? (\n <button type=\"button\" className=\"ckw-btn\" onClick={onRetry}>\n Retry\n </button>\n ) : (\n onClose && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onClose} aria-label=\"Dismiss\">\n <Cross />\n </button>\n )\n )}\n </div>\n);\n\nconst PostDetail = ({ post, onBack, onVote }: { post: FeedbackPost; onBack: () => void; onVote: (p: FeedbackPost) => void }) => {\n const api = useApi();\n const id = useId();\n const [comments, setComments] = useState<FeedbackComment[] | null>(null);\n const [error, setError] = useState(\"\");\n const [text, setText] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [added, setAdded] = useState(0);\n\n useEffect(() => {\n const ctl = new AbortController();\n api.comments(post.id, ctl.signal)\n .then((r) => setComments(r.comments))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, post.id]);\n\n const send = async (e: FormEvent) => {\n e.preventDefault();\n const body = text.trim();\n if (!body || busy) return;\n setBusy(true);\n setError(\"\");\n // Show it at once; take it back if the server says no.\n const temp: FeedbackComment = { id: `tmp-${Date.now()}`, body, author: \"You\", isTeam: false, postedAt: new Date().toISOString() };\n setComments((c) => [...(c ?? []), temp]);\n setText(\"\");\n try {\n const real = await api.comment(post.id, body);\n setComments((c) => (c ?? []).map((x) => (x.id === temp.id ? real : x)));\n setAdded((n) => n + 1);\n } catch (err) {\n setComments((c) => (c ?? []).filter((x) => x.id !== temp.id));\n setText(body);\n setError((err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div>\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost ckw-back\" onClick={onBack}>\n <span style={{ display: \"inline-block\", transform: \"rotate(-90deg)\", lineHeight: 0 }}>\n <ChevronUp />\n </span>\n All requests\n </button>\n <div className=\"ckw-detail-head\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <h2>{post.title}</h2>\n <div className=\"ckw-meta\" style={{ marginTop: 0 }}>\n <StatusPill status={post.status} />\n <span>{timeAgo(post.createdAt)}</span>\n </div>\n </div>\n </div>\n {post.body && <p className=\"ckw-body\">{post.body}</p>}\n <h3 className=\"ckw-h\">Comments ({Math.max(post.comments + added, comments?.length ?? 0)})</h3>\n {error && <ErrorBar message={error} onClose={() => setError(\"\")} />}\n <div aria-live=\"polite\">\n {comments === null && !error && <Skeleton />}\n {comments?.length === 0 && <p className=\"ckw-sub\">No comments yet. Be the first.</p>}\n {comments?.map((c) => (\n <div className=\"ckw-comment\" key={c.id}>\n <b>{c.author}</b>\n {c.isTeam && <span className=\"ckw-team\">Team</span>}\n <span className=\"ckw-time\">{timeAgo(c.postedAt)}</span>\n <p>{c.body}</p>\n </div>\n ))}\n </div>\n <form className=\"ckw-form\" onSubmit={send} style={{ marginTop: 12 }}>\n <label className=\"ckw-label\" htmlFor={id}>\n Add a comment\n </label>\n <textarea id={id} className=\"ckw-textarea\" value={text} maxLength={2000} onChange={(e) => setText(e.target.value)} />\n <div className=\"ckw-actions\">\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !text.trim()}>\n Comment\n </button>\n </div>\n </form>\n </div>\n );\n};\n\ntype Tab = \"requests\" | \"roadmap\" | \"changelog\";\n\nconst Roadmap = ({ onOpen }: { onOpen: (p: FeedbackPost) => void }) => {\n const api = useApi();\n const [data, setData] = useState<FeedbackRoadmap | null>(null);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n useEffect(() => {\n const ctl = new AbortController();\n api.roadmap(ctl.signal)\n .then((r) => (setData(r), setError(\"\")))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, tick]);\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!data) return <Skeleton />;\n const cols: [keyof FeedbackRoadmap[\"columns\"], string][] = [\n [\"planned\", \"Planned\"],\n [\"progress\", \"In progress\"],\n [\"shipped\", \"Shipped\"],\n ];\n return (\n <div className=\"ckw-cols\">\n {cols.map(([k, label]) => (\n <section className=\"ckw-col\" key={k} aria-label={label}>\n <h3>\n {label} <span>{data.columns[k].length}</span>\n </h3>\n {data.columns[k].length === 0 && <p className=\"ckw-sub\">Nothing here yet.</p>}\n {data.columns[k].map((p) => (\n <div className=\"ckw-card\" key={p.id}>\n <button type=\"button\" className=\"ckw-link\" onClick={() => onOpen(p)}>\n {p.title}\n </button>\n <div className=\"ckw-meta\" style={{ marginTop: 0 }}>\n <span className=\"ckw-stat\">\n <ChevronUp /> {p.votes}\n </span>\n <span className=\"ckw-stat\">\n <Chat /> {p.comments}\n </span>\n </div>\n </div>\n ))}\n </section>\n ))}\n </div>\n );\n};\n\nconst Changelog = () => {\n const api = useApi();\n const [entries, setEntries] = useState<ChangelogEntry[] | null>(null);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n useEffect(() => {\n const ctl = new AbortController();\n api.changelog(ctl.signal)\n .then((r) => (setEntries(r.entries), setError(\"\")))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, tick]);\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!entries) return <Skeleton />;\n if (entries.length === 0) return <div className=\"ckw-empty\">No updates published yet.</div>;\n return (\n <div>\n {entries.map((e) => (\n <article className=\"ckw-entry\" key={e.id}>\n <time dateTime={e.publishedAt}>{new Date(e.publishedAt).toLocaleDateString(undefined, { month: \"long\", day: \"numeric\", year: \"numeric\" })}</time>\n <h3>{e.title}</h3>\n <p>{e.body}</p>\n </article>\n ))}\n </div>\n );\n};\n\nexport interface FeedbackBoardProps {\n /** Heading above the board. */\n title?: string;\n /** Line under the heading. */\n subtitle?: string;\n theme?: Theme;\n /** Accent color for buttons and votes. Default #3f76ff. */\n accent?: string;\n}\n\n/** The full board for a /feedback page: requests, roadmap and changelog, with voting, comments and a submit form. */\nexport const FeedbackBoard = ({ title = \"Feedback\", subtitle = \"Tell us what to build next and vote on what matters to you.\", theme, accent }: FeedbackBoardProps) => {\n const [tab, setTab] = useState<Tab>(\"requests\");\n const [sort, setSort] = useState<\"top\" | \"new\">(\"top\");\n const [board, setBoard] = useState<string | undefined>();\n const [q, setQ] = useState(\"\");\n const [creating, setCreating] = useState(false);\n const [opened, setOpened] = useState<FeedbackPost | null>(null);\n const list = useFeedbackList({ board, sort, q });\n const { posts, setPosts, vote } = list;\n\n // The open post follows the list's optimistic votes when it is in the list.\n const current = opened && (posts.find((p) => p.id === opened.id) ?? opened);\n const voteOpened = (p: FeedbackPost) => {\n if (!posts.some((x) => x.id === p.id)) {\n // Opened from the roadmap: it is not in this list, so vote through the list's server call and mirror it locally.\n setOpened((o) => (o ? { ...o, voted: !o.voted, votes: o.votes + (o.voted ? -1 : 1) } : o));\n list.api\n .vote(p.id)\n .then((r) => setOpened((o) => (o ? { ...o, voted: r.voted, votes: r.votes } : o)))\n .catch((e: Error) => {\n setOpened((o) => (o ? { ...o, voted: p.voted, votes: p.votes } : o));\n list.setError(`Your vote was not saved. ${e.message}`);\n });\n return;\n }\n vote(p);\n };\n\n const tabs: [Tab, string][] = [\n [\"requests\", \"Requests\"],\n [\"roadmap\", \"Roadmap\"],\n [\"changelog\", \"Changelog\"],\n ];\n const onTabKey = (e: React.KeyboardEvent) => {\n const i = tabs.findIndex(([k]) => k === tab);\n const n = e.key === \"ArrowRight\" ? i + 1 : e.key === \"ArrowLeft\" ? i - 1 : null;\n if (n === null) return;\n e.preventDefault();\n setTab(tabs[(n + tabs.length) % tabs.length][0]);\n setOpened(null);\n };\n\n return (\n <Root theme={theme} accent={accent} className=\"ckw-board\">\n <div className=\"ckw-head\">\n <div>\n <h2 className=\"ckw-title\">{title}</h2>\n {subtitle && <p className=\"ckw-sub\">{subtitle}</p>}\n </div>\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={() => (setCreating((c) => !c), setOpened(null), setTab(\"requests\"))} aria-expanded={creating}>\n <Plus /> Request a feature\n </button>\n </div>\n\n <div className=\"ckw-tabs\" role=\"tablist\" aria-label=\"Feedback sections\" onKeyDown={onTabKey}>\n {tabs.map(([k, label]) => (\n <button\n key={k}\n type=\"button\"\n role=\"tab\"\n id={`ckw-tab-${k}`}\n aria-selected={tab === k}\n tabIndex={tab === k ? 0 : -1}\n className=\"ckw-tab\"\n onClick={() => (setTab(k), setOpened(null))}\n >\n {label}\n </button>\n ))}\n </div>\n\n <div role=\"tabpanel\" aria-labelledby={`ckw-tab-${tab}`}>\n {list.error && <ErrorBar message={list.error} onRetry={tab === \"requests\" && !current ? list.reload : undefined} onClose={() => list.setError(\"\")} />}\n\n {current ? (\n <PostDetail post={current} onBack={() => setOpened(null)} onVote={voteOpened} />\n ) : tab === \"requests\" ? (\n <>\n {creating && (\n <SubmitForm\n api={list.api}\n boards={list.boards}\n posts={posts}\n onVote={vote}\n onCancel={() => setCreating(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all]);\n setCreating(false);\n }}\n />\n )}\n <div className=\"ckw-tools\">\n <input className=\"ckw-input ckw-search\" type=\"search\" aria-label=\"Search requests\" placeholder=\"Search requests\" value={q} onChange={(e) => setQ(e.target.value)} />\n <div className=\"ckw-seg\" role=\"group\" aria-label=\"Sort\">\n {([\"top\", \"new\"] as const).map((s) => (\n <button key={s} type=\"button\" aria-pressed={sort === s} onClick={() => setSort(s)}>\n {s === \"top\" ? \"Top\" : \"New\"}\n </button>\n ))}\n </div>\n </div>\n {list.boards.length > 1 && (\n <div className=\"ckw-chips\" role=\"group\" aria-label=\"Boards\">\n <button type=\"button\" className=\"ckw-chip\" aria-pressed={!board} onClick={() => setBoard(undefined)}>\n All\n </button>\n {list.boards.map((b) => (\n <button key={b.id} type=\"button\" className=\"ckw-chip\" aria-pressed={board === b.id} onClick={() => setBoard(b.id)}>\n {b.label}\n </button>\n ))}\n </div>\n )}\n <div aria-live=\"polite\" aria-busy={list.loading}>\n {list.loading && posts.length === 0 ? (\n <Skeleton />\n ) : posts.length === 0 && !list.error ? (\n <div className=\"ckw-empty\">{q ? \"No requests match your search.\" : \"No requests yet. Be the first to suggest something.\"}</div>\n ) : (\n <ul className=\"ckw-list\">\n {posts.map((p) => (\n <PostRow key={p.id} post={p} onOpen={setOpened} onVote={vote} />\n ))}\n </ul>\n )}\n </div>\n </>\n ) : tab === \"roadmap\" ? (\n <Roadmap onOpen={setOpened} />\n ) : (\n <Changelog />\n )}\n </div>\n </Root>\n );\n};\n\n// ---------- Floating widget ----------\n\nconst listeners = new Set<(open: boolean) => void>();\nlet widgetOpen = false;\nconst setWidgetOpen = (v: boolean) => {\n widgetOpen = v;\n listeners.forEach((l) => l(v));\n};\n\n/** Open or close the feedback widget from your own button. */\nexport const useFeedback = () => ({ open: () => setWidgetOpen(true), close: () => setWidgetOpen(false) });\n\nexport interface FeedbackWidgetProps {\n position?: \"bottom-right\" | \"bottom-left\";\n /** Text on the floating button. */\n label?: string;\n /** Where \"See all\" goes, for example your /feedback page. */\n boardUrl?: string;\n theme?: Theme;\n accent?: string;\n}\n\n/** The popover content. Mounted only while open, so a closed widget costs no request. */\nconst WidgetPanel = ({ boardUrl, onClose }: { boardUrl?: string; onClose: () => void }) => {\n const [suggesting, setSuggesting] = useState(false);\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList({ sort: \"top\" });\n const { posts, setPosts } = list;\n return (\n <>\n <div className=\"ckw-pop-head\">\n <span>{suggesting ? \"Suggest something\" : \"Top requests\"}</span>\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onClose} aria-label=\"Close feedback\">\n <Cross />\n </button>\n </div>\n <div className=\"ckw-pop-body\">\n {list.error && <ErrorBar message={list.error} onClose={() => list.setError(\"\")} />}\n {thanks ? (\n <div className=\"ckw-empty\" role=\"status\">\n Thanks, your request is in.\n </div>\n ) : suggesting ? (\n <SubmitForm\n compact\n api={list.api}\n boards={list.boards}\n posts={posts}\n onVote={list.vote}\n onCancel={() => setSuggesting(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all]);\n setSuggesting(false);\n setThanks(true);\n }}\n />\n ) : list.loading && posts.length === 0 ? (\n <Skeleton />\n ) : posts.length === 0 && !list.error ? (\n <div className=\"ckw-empty\">No requests yet. Suggest the first one.</div>\n ) : (\n <ul className=\"ckw-list\" aria-live=\"polite\">\n {posts.slice(0, 5).map((p) => (\n <li className=\"ckw-row\" key={p.id}>\n <VoteButton post={p} onVote={list.vote} />\n <div className=\"ckw-main\">\n <span style={{ fontWeight: 600, overflowWrap: \"anywhere\" }}>{p.title}</span>\n <div className=\"ckw-meta\">\n <StatusPill status={p.status} />\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n <div className=\"ckw-pop-foot\">\n {boardUrl ? <a href={boardUrl}>See all</a> : <span />}\n {!suggesting && !thanks && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={() => setSuggesting(true)}>\n <Plus /> Suggest something\n </button>\n )}\n {thanks && (\n <button type=\"button\" className=\"ckw-btn\" onClick={() => setThanks(false)}>\n Back\n </button>\n )}\n </div>\n </>\n );\n};\n\n/** A floating button that opens a small popover with the top requests and a quick suggest form. */\nexport const FeedbackWidget = ({ position = \"bottom-right\", label = \"Feedback\", boardUrl, theme, accent }: FeedbackWidgetProps) => {\n const [open, setOpen] = useState(false);\n const fab = useRef<HTMLButtonElement>(null);\n const pop = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const l = (v: boolean) => setOpen(v);\n listeners.add(l);\n setOpen(widgetOpen);\n const click = (e: MouseEvent) => {\n if ((e.target as HTMLElement | null)?.closest(\"[data-ck-feedback]\")) {\n e.preventDefault();\n setWidgetOpen(true);\n }\n };\n document.addEventListener(\"click\", click);\n return () => {\n listeners.delete(l);\n document.removeEventListener(\"click\", click);\n };\n }, []);\n\n const close = useCallback(() => {\n setWidgetOpen(false);\n fab.current?.focus();\n }, []);\n useEscape(() => open && close());\n\n // Move focus into the popover when it opens.\n useEffect(() => {\n if (open) pop.current?.querySelector<HTMLElement>(\"button, input\")?.focus();\n }, [open]);\n\n // Keep Tab inside the popover while it is open.\n const trap = (e: React.KeyboardEvent) => {\n if (e.key !== \"Tab\" || !pop.current) return;\n const f = [...pop.current.querySelectorAll<HTMLElement>(\"a[href], button:not([disabled]), input, select, textarea\")];\n if (!f.length) return;\n const first = f[0];\n const last = f[f.length - 1];\n if (e.shiftKey && document.activeElement === first) (e.preventDefault(), last.focus());\n else if (!e.shiftKey && document.activeElement === last) (e.preventDefault(), first.focus());\n };\n\n return (\n <Root theme={theme} accent={accent}>\n <button ref={fab} type=\"button\" className=\"ckw-fab\" data-pos={position} aria-haspopup=\"dialog\" aria-expanded={open} onClick={() => (open ? close() : setWidgetOpen(true))}>\n <Chat /> {label}\n </button>\n {open && (\n <div ref={pop} className=\"ckw-pop\" data-pos={position} role=\"dialog\" aria-label=\"Feedback\" onKeyDown={trap}>\n <WidgetPanel boardUrl={boardUrl} onClose={close} />\n </div>\n )}\n </Root>\n );\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,3 @@
1
+ export { type ChangelogEntry, type CockpitProviderProps, type CockpitUser, type FeedbackBoardInfo, type FeedbackBoardProps, type FeedbackComment, type FeedbackList, type FeedbackPost, type FeedbackRoadmap, type FeedbackWidgetProps, type PostStatus, type SurveyAnswer, type SurveyDefinition, type SurveyQuestion, type SurveyQuestionKind, CockpitProvider, Experiment, FeedbackBoard, FeedbackWidget, Survey, Text, WIDGET_CSS, createApi, useCockpit, useFeedback, useStyles, useVariant, } from "./browser.js";
2
+ export { type CockpitConfig, type CockpitEvent, type ConsentChoice, type ConsentMode, type ReplayConfig, type ExperimentConfig, type VariantConfig, type VariantId, EMBED_PARAM, ID_COOKIE, PREVIEW_PARAM, SESSION_COOKIE, assign, parsePreview, previewHref, } from "./core.js";
3
+ export { type AttributionMode, type CheckoutReferral, type Referral, REFERRAL_COOKIE, getReferral, readReferralCookie, referralForCheckout, referralLink, } from "./referral.js";
package/dist/index.js ADDED
@@ -0,0 +1,58 @@
1
+ // src/index.ts
2
+ import {
3
+ CockpitProvider,
4
+ Experiment,
5
+ FeedbackBoard,
6
+ FeedbackWidget,
7
+ Survey,
8
+ Text,
9
+ WIDGET_CSS,
10
+ createApi,
11
+ useCockpit,
12
+ useFeedback,
13
+ useStyles,
14
+ useVariant
15
+ } from "./browser.js";
16
+ import {
17
+ EMBED_PARAM,
18
+ ID_COOKIE,
19
+ PREVIEW_PARAM,
20
+ SESSION_COOKIE,
21
+ assign,
22
+ parsePreview,
23
+ previewHref
24
+ } from "./core.js";
25
+ import {
26
+ REFERRAL_COOKIE,
27
+ getReferral,
28
+ readReferralCookie,
29
+ referralForCheckout,
30
+ referralLink
31
+ } from "./referral.js";
32
+ export {
33
+ CockpitProvider,
34
+ EMBED_PARAM,
35
+ Experiment,
36
+ FeedbackBoard,
37
+ FeedbackWidget,
38
+ ID_COOKIE,
39
+ PREVIEW_PARAM,
40
+ REFERRAL_COOKIE,
41
+ SESSION_COOKIE,
42
+ Survey,
43
+ Text,
44
+ WIDGET_CSS,
45
+ assign,
46
+ createApi,
47
+ getReferral,
48
+ parsePreview,
49
+ previewHref,
50
+ readReferralCookie,
51
+ referralForCheckout,
52
+ referralLink,
53
+ useCockpit,
54
+ useFeedback,
55
+ useStyles,
56
+ useVariant
57
+ };
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n type ChangelogEntry,\n type CockpitProviderProps,\n type CockpitUser,\n type FeedbackBoardInfo,\n type FeedbackBoardProps,\n type FeedbackComment,\n type FeedbackList,\n type FeedbackPost,\n type FeedbackRoadmap,\n type FeedbackWidgetProps,\n type PostStatus,\n type SurveyAnswer,\n type SurveyDefinition,\n type SurveyQuestion,\n type SurveyQuestionKind,\n CockpitProvider,\n Experiment,\n FeedbackBoard,\n FeedbackWidget,\n Survey,\n Text,\n WIDGET_CSS,\n createApi,\n useCockpit,\n useFeedback,\n useStyles,\n useVariant,\n} from \"./browser\";\nexport {\n type CockpitConfig,\n type CockpitEvent,\n type ConsentChoice,\n type ConsentMode,\n type ReplayConfig,\n type ExperimentConfig,\n type VariantConfig,\n type VariantId,\n EMBED_PARAM,\n ID_COOKIE,\n PREVIEW_PARAM,\n SESSION_COOKIE,\n assign,\n parsePreview,\n previewHref,\n} from \"./core\";\nexport {\n type AttributionMode,\n type CheckoutReferral,\n type Referral,\n REFERRAL_COOKIE,\n getReferral,\n readReferralCookie,\n referralForCheckout,\n referralLink,\n} from \"./referral\";\n"],"mappings":";AAAA;AAAA,EAgBI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP;AAAA,EASI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP;AAAA,EAII;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;","names":[]}