@mrrocket/sdk 0.8.0 → 0.10.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 (45) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +35 -1
  3. package/dist/api-client.d.ts +221 -0
  4. package/dist/api-client.js +79 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api.d.ts +2 -122
  7. package/dist/api.js +2 -61
  8. package/dist/api.js.map +1 -1
  9. package/dist/browser/mrrocket-messenger.js +348 -0
  10. package/dist/browser/mrrocket-replay.js +3 -3
  11. package/dist/browser/mrrocket.js +1 -1
  12. package/dist/browser.d.ts +2 -1
  13. package/dist/browser.js +3 -0
  14. package/dist/browser.js.map +1 -1
  15. package/dist/capture.d.ts +1 -13
  16. package/dist/capture.js +1 -22
  17. package/dist/capture.js.map +1 -1
  18. package/dist/core.d.ts +1 -1
  19. package/dist/core.js +1 -1
  20. package/dist/core.js.map +1 -1
  21. package/dist/feedback.js +132 -24
  22. package/dist/feedback.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +4 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/messenger-ui.d.ts +49 -0
  27. package/dist/messenger-ui.js +619 -0
  28. package/dist/messenger-ui.js.map +1 -0
  29. package/dist/messenger.d.ts +37 -0
  30. package/dist/messenger.js +69 -0
  31. package/dist/messenger.js.map +1 -0
  32. package/dist/rage.d.ts +14 -0
  33. package/dist/rage.js +27 -0
  34. package/dist/rage.js.map +1 -0
  35. package/dist/react-native/index.d.cts +349 -4
  36. package/dist/react-native/index.d.ts +349 -4
  37. package/dist/react-native/index.js +1345 -31
  38. package/dist/react-native/index.js.map +1 -1
  39. package/dist/styles-css.d.ts +6 -0
  40. package/dist/styles-css.js +362 -0
  41. package/dist/styles-css.js.map +1 -0
  42. package/dist/styles.d.ts +1 -2
  43. package/dist/styles.js +3 -237
  44. package/dist/styles.js.map +1 -1
  45. package/package.json +17 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/feedback.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FormEvent, type ReactNode, useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport {\n type Api,\n type ChangelogEntry,\n type FeedbackBoardInfo,\n type FeedbackComment,\n type FeedbackPost,\n type FeedbackProduct,\n type FeedbackRoadmap,\n type PostStatus,\n type Writer,\n createApi,\n useApi,\n} from \"./api\";\nimport { useCtx } from \"./context\";\nimport { Chat, ChevronUp, Cross, Moon, Plus, Root, Search, StatusPill, Sun, type Theme, VoteButton, similarPosts, timeAgo, useEscape } from \"./ui\";\n\n// ---------- Who writes ----------\n\ninterface Who {\n id: string;\n name: string;\n email: string;\n}\n\nconst whoKey = (apiKey: string) => `ckw-board-who:${apiKey}`;\nconst readWho = (apiKey: string): Who | null => {\n try {\n const raw = window.localStorage.getItem(whoKey(apiKey));\n const w = raw ? (JSON.parse(raw) as Who) : null;\n return w && typeof w.id === \"string\" && typeof w.name === \"string\" && typeof w.email === \"string\" ? w : null;\n } catch {\n return null;\n }\n};\nconst newWhoId = () => {\n try {\n return `fb_${crypto.randomUUID()}`;\n } catch {\n return `fb_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;\n }\n};\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Who posts, votes and comments. A signed-in user from `identify()` (with a name or email) writes as themselves; any\n * other visitor gives a name and email once, which this browser keeps for this board (localStorage, nothing else),\n * so their votes are still theirs on the next visit. `need` runs a write at once when the visitor is known, else\n * asks first and runs it with the new identity.\n */\nconst useIdentity = () => {\n const ctx = useCtx();\n const [saved, setSaved] = useState<Who | null>(null);\n const [asking, setAsking] = useState<((api: Api) => void) | null>(null);\n useEffect(() => setSaved(readWho(ctx.apiKey)), [ctx.apiKey]);\n const fromApp = !!ctx.user && (!!ctx.user.email || !!ctx.user.name);\n const writer: Writer | null = useMemo(\n () => (fromApp || !saved ? null : { distinctId: saved.id, user: { name: saved.name, email: saved.email } }),\n [fromApp, saved],\n );\n const api = useApi(writer);\n const known = fromApp || !!saved;\n\n /** Keeps the name and email and returns a client that writes as them, for the call that is waiting. */\n const save = useCallback(\n (name: string, email: string): Api => {\n const who: Who = { id: saved?.id ?? newWhoId(), name: name.trim(), email: email.trim().toLowerCase() };\n try {\n window.localStorage.setItem(whoKey(ctx.apiKey), JSON.stringify(who));\n } catch {\n // Private mode: the identity lasts for this page.\n }\n setSaved(who);\n return createApi({ apiKey: ctx.apiKey, host: ctx.host, distinctId: who.id, user: { name: who.name, email: who.email } });\n },\n [ctx.apiKey, ctx.host, saved],\n );\n\n const forget = useCallback(() => {\n try {\n window.localStorage.removeItem(whoKey(ctx.apiKey));\n } catch {\n // Nothing stored.\n }\n setSaved(null);\n }, [ctx.apiKey]);\n\n const need = useCallback((fn: (api: Api) => void) => (known ? fn(api) : setAsking(() => fn)), [known, api]);\n const name = fromApp ? String(ctx.user?.name ?? ctx.user?.email ?? \"\") : (saved?.name ?? \"\");\n return { api, known, fromApp, name, save, forget, need, asking, cancel: () => setAsking(null) };\n};\n\ntype Identity = ReturnType<typeof useIdentity>;\n\n// ---------- Data ----------\n\n/** Loads the post list and owns optimistic voting, so the board and the widget behave the same. */\nconst useFeedbackList = (api: Api, opts: { board?: string; sort?: \"top\" | \"new\"; q?: string }) => {\n const [posts, setPosts] = useState<FeedbackPost[]>([]);\n const [boards, setBoards] = useState<FeedbackBoardInfo[]>([]);\n const [product, setProduct] = useState<FeedbackProduct | null>(null);\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 if (r.product) setProduct(r.product);\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, as: Api = api) => {\n const flip = (p: FeedbackPost) => ({ ...p, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n patch(post.id, flip);\n as.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 { posts, setPosts, patch, boards, product, loading, error, setError, vote, reload: () => setTick((t) => t + 1) };\n};\n\n// ---------- Small parts ----------\n\nconst BOARD_TONE: Record<string, string> = { feature: \"blue\", bug: \"red\", integration: \"violet\", improvement: \"green\" };\n\nconst TypeChip = ({ board, boards }: { board: string; boards: FeedbackBoardInfo[] }) => (\n <span className=\"ckw-type\" data-tone={BOARD_TONE[board] ?? \"gray\"}>\n {boards.find((b) => b.id === board)?.label ?? board}\n </span>\n);\n\nconst Avatar = ({ name, team }: { name: string; team?: boolean }) => (\n <span className=\"ckw-av\" data-team={team || undefined} aria-hidden=\"true\">\n {(name.trim()[0] ?? \"?\").toUpperCase()}\n </span>\n);\n\nconst Skeleton = ({ rows = 3 }: { rows?: number }) => (\n <div aria-hidden=\"true\">\n {Array.from({ length: rows }, (_, 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\n/** A dialog inside the widget's root: dimmed page, Esc and the backdrop close it, Tab stays inside. A sheet on phones. */\nconst Modal = ({ title, onClose, children }: { title: string; onClose: () => void; children: ReactNode }) => {\n const box = useRef<HTMLDivElement>(null);\n const id = useId();\n useEscape(onClose);\n useEffect(() => {\n const before = document.activeElement as HTMLElement | null;\n box.current?.querySelector<HTMLElement>(\"input, textarea, button\")?.focus();\n return () => before?.focus?.();\n }, []);\n const trap = (e: React.KeyboardEvent) => {\n if (e.key !== \"Tab\" || !box.current) return;\n const f = [...box.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 return (\n <div className=\"ckw-scrim\" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>\n <div ref={box} className=\"ckw-modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby={id} onKeyDown={trap}>\n <div className=\"ckw-modal-head\">\n <h2 id={id}>{title}</h2>\n <button type=\"button\" className=\"ckw-icon-btn\" onClick={onClose} aria-label=\"Close\">\n <Cross />\n </button>\n </div>\n {children}\n </div>\n </div>\n );\n};\n\n/** Name and email, with the one line on what happens to them. */\nconst IdentityFields = ({ name, email, setName, setEmail }: { name: string; email: string; setName: (v: string) => void; setEmail: (v: string) => void }) => {\n const id = useId();\n return (\n <>\n <div className=\"ckw-pair\">\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-n`}>\n Your name\n </label>\n <input id={`${id}-n`} className=\"ckw-input\" value={name} maxLength={80} required autoComplete=\"name\" onChange={(e) => setName(e.target.value)} />\n </div>\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-e`}>\n Email\n </label>\n <input id={`${id}-e`} className=\"ckw-input\" type=\"email\" value={email} maxLength={200} required autoComplete=\"email\" onChange={(e) => setEmail(e.target.value)} />\n </div>\n </div>\n <p className=\"ckw-fine\">Others see your first name and last initial. Your email is only for updates on what you posted or voted for.</p>\n </>\n );\n};\n\n/** Asked once before the first vote or comment of a visitor the app has not identified. */\nconst IdentityDialog = ({ identity }: { identity: Identity }) => {\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const ok = name.trim().length > 0 && EMAIL.test(email.trim());\n const run = identity.asking;\n if (!run) return null;\n return (\n <Modal title=\"Before you vote or comment\" onClose={identity.cancel}>\n <form\n className=\"ckw-modal-body\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!ok) return;\n const api = identity.save(name, email);\n identity.cancel();\n run(api);\n }}\n >\n <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />\n <div className=\"ckw-actions\">\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={identity.cancel}>\n Cancel\n </button>\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={!ok}>\n Continue\n </button>\n </div>\n </form>\n </Modal>\n );\n};\n\n/** Title, details and board, with up to three similar requests to vote on instead; name and email when not known yet. */\nconst SubmitForm = ({\n identity,\n boards,\n posts,\n onCreated,\n onVote,\n onCancel,\n compact,\n bare,\n}: {\n identity: Identity;\n boards: FeedbackBoardInfo[];\n posts: FeedbackPost[];\n onCreated: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onCancel?: () => void;\n compact?: boolean;\n /** Inside a dialog: no frame of its own. */\n bare?: boolean;\n}) => {\n const id = useId();\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [board, setBoard] = useState(\"\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = 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 const ask = !identity.known;\n const ready = title.trim().length >= 3 && (!ask || (name.trim().length > 0 && EMAIL.test(email.trim())));\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n if (!ready || busy) return;\n setBusy(true);\n setError(\"\");\n try {\n const api = ask ? identity.save(name, email) : identity.api;\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={bare ? \"ckw-modal-body\" : \"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={120} 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 <span className=\"ckw-opt-l\">optional</span>\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? What gets in the way?\" />\n </div>\n )}\n {boards.length > 1 && (\n <div className=\"ckw-field\">\n <span className=\"ckw-label\" id={`${id}-c`}>\n Type\n </span>\n <div className=\"ckw-chips\" role=\"radiogroup\" aria-labelledby={`${id}-c`} style={{ marginBottom: 0 }}>\n {boards.map((b) => (\n <button key={b.id} type=\"button\" role=\"radio\" aria-checked={chosen === b.id} className=\"ckw-chip\" onClick={() => setBoard(b.id)}>\n {b.label}\n </button>\n ))}\n </div>\n </div>\n )}\n {ask && <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />}\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 || !ready}>\n {busy ? \"Sending…\" : \"Submit\"}\n </button>\n </div>\n </form>\n );\n};\n\n// ---------- Requests ----------\n\nconst PostCard = ({ post, boards, onOpen, onVote }: { post: FeedbackPost; boards: FeedbackBoardInfo[]; onOpen: (p: FeedbackPost) => void; onVote: (p: FeedbackPost) => void }) => (\n <li className=\"ckw-post\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <button type=\"button\" className=\"ckw-link ckw-stretch\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-meta\">\n <TypeChip board={post.board} boards={boards} />\n {post.status !== \"review\" && <StatusPill status={post.status} />}\n <span className=\"ckw-stat\" aria-label={`${post.comments} comments`}>\n <Chat /> {post.comments}\n </span>\n <span className=\"ckw-dot-sep\">{[post.author, timeAgo(post.createdAt)].filter(Boolean).join(\" · \")}</span>\n </div>\n </div>\n </li>\n);\n\nconst Requests = ({\n list,\n sort,\n setSort,\n board,\n setBoard,\n q,\n onOpen,\n onVote,\n onNew,\n}: {\n list: ReturnType<typeof useFeedbackList>;\n sort: \"top\" | \"new\";\n setSort: (s: \"top\" | \"new\") => void;\n board?: string;\n setBoard: (b?: string) => void;\n q: string;\n onOpen: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onNew: () => void;\n}) => {\n const { posts, boards } = list;\n return (\n <div>\n <div>\n <div className=\"ckw-tools\">\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 {boards.length > 1 && (\n <div className=\"ckw-chips ckw-chips-inline\" role=\"group\" aria-label=\"Type\">\n <button type=\"button\" className=\"ckw-chip\" aria-pressed={!board} onClick={() => setBoard(undefined)}>\n All\n </button>\n {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>\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\">\n <p>{q ? \"No request matches your search.\" : board ? \"Nothing of this type yet.\" : \"No requests yet.\"}</p>\n {!q && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={onNew}>\n <Plus /> Suggest the first one\n </button>\n )}\n </div>\n ) : (\n <ul className=\"ckw-posts\">\n {posts.map((p) => (\n <PostCard key={p.id} post={p} boards={boards} onOpen={onOpen} onVote={onVote} />\n ))}\n </ul>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n// ---------- Post ----------\n\nconst PostDetail = ({\n post,\n boards,\n identity,\n onBack,\n onVote,\n backLabel,\n}: {\n post: FeedbackPost;\n boards: FeedbackBoardInfo[];\n identity: Identity;\n onBack: () => void;\n onVote: (p: FeedbackPost) => void;\n backLabel: string;\n}) => {\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 const { api } = identity;\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 = (e: FormEvent) => {\n e.preventDefault();\n const body = text.trim();\n if (!body || busy) return;\n identity.need(async (as) => {\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 as.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\n const count = Math.max(post.comments + added, comments?.length ?? 0);\n return (\n <article className=\"ckw-detail\">\n <button type=\"button\" className=\"ckw-back\" onClick={onBack}>\n <span className=\"ckw-back-icon\">\n <ChevronUp />\n </span>\n {backLabel}\n </button>\n <div className=\"ckw-detail-grid\">\n <div className=\"ckw-detail-main\">\n <h2 className=\"ckw-detail-title\">{post.title}</h2>\n <div className=\"ckw-byline\">\n <Avatar name={post.author ?? \"?\"} team={post.author === \"Team\"} />\n <span>{post.author ?? \"Someone\"}</span>\n <span className=\"ckw-dot-sep\">{timeAgo(post.createdAt)}</span>\n </div>\n {post.body && <p className=\"ckw-body\">{post.body}</p>}\n\n <h3 className=\"ckw-h\">\n Comments <span className=\"ckw-count\">{count}</span>\n </h3>\n <form className=\"ckw-composer\" onSubmit={send}>\n <label className=\"ckw-sr\" htmlFor={id}>\n Leave a comment\n </label>\n <textarea id={id} className=\"ckw-textarea\" value={text} maxLength={1000} placeholder=\"Leave a comment\" onChange={(e) => setText(e.target.value)} />\n <div className=\"ckw-actions\">\n {identity.known && identity.name && <span className=\"ckw-fine ckw-as\">Commenting as {identity.name}</span>}\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !text.trim()}>\n Comment\n </button>\n </div>\n </form>\n {error && <ErrorBar message={error} onClose={() => setError(\"\")} />}\n <div aria-live=\"polite\">\n {comments === null && !error && <Skeleton rows={2} />}\n {comments?.length === 0 && <p className=\"ckw-sub\">No comments yet.</p>}\n {comments?.map((c) => (\n <div className=\"ckw-comment\" key={c.id}>\n <Avatar name={c.author} team={c.isTeam} />\n <div className=\"ckw-main\">\n <div>\n <b>{c.author}</b>\n {c.isTeam && <span className=\"ckw-team\">Team</span>}\n <span className=\"ckw-time\">{timeAgo(c.postedAt)}</span>\n </div>\n <p>{c.body}</p>\n </div>\n </div>\n ))}\n </div>\n </div>\n <aside className=\"ckw-side\" aria-label=\"About this request\">\n <button\n type=\"button\"\n className=\"ckw-upvote\"\n aria-pressed={post.voted}\n aria-label={`${post.voted ? \"Remove your vote\" : \"Upvote\"}. ${post.votes} votes`}\n onClick={() => onVote(post)}\n >\n <ChevronUp />\n <span>{post.voted ? \"Upvoted\" : \"Upvote\"}</span>\n <b>{post.votes}</b>\n </button>\n <dl className=\"ckw-facts\">\n <div>\n <dt>Status</dt>\n <dd>\n <StatusPill status={post.status} />\n </dd>\n </div>\n <div>\n <dt>Type</dt>\n <dd>\n <TypeChip board={post.board} boards={boards} />\n </dd>\n </div>\n <div>\n <dt>Posted</dt>\n <dd>{new Date(post.createdAt).toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" })}</dd>\n </div>\n </dl>\n </aside>\n </div>\n </article>\n );\n};\n\n// ---------- Roadmap ----------\n\nconst COLUMNS: { status: PostStatus; label: string; note: string }[] = [\n { status: \"review\", label: \"Backlog\", note: \"Under consideration\" },\n { status: \"planned\", label: \"Next up\", note: \"Committed and queued\" },\n { status: \"progress\", label: \"In progress\", note: \"Actively being built\" },\n { status: \"shipped\", label: \"Done\", note: \"Recently shipped\" },\n];\n\nconst matchesQ = (q: string, ...texts: string[]) => {\n const t = q.trim().toLowerCase();\n return !t || texts.some((x) => x.toLowerCase().includes(t));\n};\n\nconst RoadmapCard = ({ post, boards, onOpen, onVote }: { post: FeedbackPost; boards: FeedbackBoardInfo[]; onOpen: (p: FeedbackPost) => void; onVote: (p: FeedbackPost) => void }) => (\n <li className=\"ckw-card\">\n <TypeChip board={post.board} boards={boards} />\n <button type=\"button\" className=\"ckw-link ckw-stretch\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-card-foot\">\n <span className=\"ckw-who\">\n <Avatar name={post.author ?? \"?\"} team={post.author === \"Team\"} />\n <span>{post.author ?? \"\"}</span>\n </span>\n <VoteButton post={post} onVote={onVote} small />\n </div>\n </li>\n);\n\nconst Roadmap = ({\n api,\n boards,\n q,\n onOpen,\n voteRef,\n}: {\n api: Api;\n boards: FeedbackBoardInfo[];\n q: string;\n onOpen: (p: FeedbackPost) => void;\n /** The board's vote, which asks who the visitor is first; the roadmap keeps its own counts in step. */\n voteRef: (p: FeedbackPost, done: (r: { voted: boolean; votes: number } | null) => void) => void;\n}) => {\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 const patch = (id: string, fn: (p: FeedbackPost) => FeedbackPost) =>\n setData((d) => {\n if (!d) return d;\n const columns = { ...d.columns };\n for (const k of Object.keys(columns) as (keyof FeedbackRoadmap[\"columns\"])[]) columns[k] = columns[k]?.map((p) => (p.id === id ? fn(p) : p)) as FeedbackPost[];\n return { columns };\n });\n const vote = (post: FeedbackPost) =>\n voteRef(post, (r) => {\n if (r) patch(post.id, (p) => ({ ...p, ...r }));\n });\n\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!data)\n return (\n <div className=\"ckw-cols\" aria-hidden=\"true\">\n {COLUMNS.map((c) => (\n <div className=\"ckw-col\" key={c.status}>\n <Skeleton rows={2} />\n </div>\n ))}\n </div>\n );\n return (\n <div className=\"ckw-cols\">\n {COLUMNS.map((c) => {\n const cards = (data.columns[c.status as keyof FeedbackRoadmap[\"columns\"]] ?? []).filter((p) => matchesQ(q, p.title, p.body));\n return (\n <section className=\"ckw-col\" key={c.status} aria-label={c.label}>\n <header className=\"ckw-col-head\">\n <h3>\n <span className=\"ckw-sdot\" data-s={c.status} />\n {c.label}\n <span className=\"ckw-count\">{cards.length}</span>\n </h3>\n <p>{c.note}</p>\n </header>\n {cards.length === 0 ? (\n <p className=\"ckw-col-empty\">{q ? \"No match\" : \"Nothing here yet\"}</p>\n ) : (\n <ul className=\"ckw-col-list\">\n {cards.map((p) => (\n <RoadmapCard key={p.id} post={p} boards={boards} onOpen={onOpen} onVote={vote} />\n ))}\n </ul>\n )}\n </section>\n );\n })}\n </div>\n );\n};\n\n// ---------- Changelog ----------\n\nconst Changelog = ({ api, q }: { api: Api; q: string }) => {\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 const shown = entries.filter((e) => matchesQ(q, e.title, e.body));\n if (shown.length === 0) return <div className=\"ckw-empty\">{q ? \"No update matches your search.\" : \"No updates published yet.\"}</div>;\n return (\n <div className=\"ckw-log\">\n {shown.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 <div>\n <h3>{e.title}</h3>\n <p>{e.body}</p>\n </div>\n </article>\n ))}\n </div>\n );\n};\n\n// ---------- The board ----------\n\ntype Tab = \"requests\" | \"roadmap\" | \"changelog\";\nconst TABS: [Tab, string][] = [\n [\"requests\", \"Feedback\"],\n [\"roadmap\", \"Roadmap\"],\n [\"changelog\", \"Changelog\"],\n];\n\n/** The page's ?view= and ?post=, when the board owns the address bar. */\nconst readUrl = () => {\n const p = new URLSearchParams(window.location.search);\n const v = p.get(\"view\");\n return { tab: (v === \"roadmap\" || v === \"changelog\" ? v : \"requests\") as Tab, post: p.get(\"post\") };\n};\nconst writeUrl = (tab: Tab, post: string | null, push: boolean) => {\n const url = new URL(window.location.href);\n if (tab === \"requests\") url.searchParams.delete(\"view\");\n else url.searchParams.set(\"view\", tab);\n if (post) url.searchParams.set(\"post\", post);\n else url.searchParams.delete(\"post\");\n if (url.href === window.location.href) return;\n if (push) window.history.pushState(null, \"\", url);\n else window.history.replaceState(null, \"\", url);\n};\n\nconst THEME_KEY = \"ckw-theme\";\nconst systemDark = () => typeof window !== \"undefined\" && !!window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches;\n\nexport interface FeedbackBoardProps {\n /** Heading when the board has no header (`header={false}`). */\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 /** The top bar with your product's logo and name, search, light/dark and \"Submit feedback\". Default true. */\n header?: boolean;\n /** Keep the open tab and post in the address (?view=roadmap, ?post=…), so links can be shared. Default false. */\n syncUrl?: boolean;\n /** Fill the page: the board's background covers the whole window, as on a hosted board. Default false. */\n fullPage?: boolean;\n /** Which tab opens first. Default \"requests\". */\n initialTab?: Tab;\n}\n\n/**\n * The full board for a /feedback page, after Featurebase: your product's logo and name, Feedback (requests with\n * Top/New and type filter), Roadmap (Backlog, Next up, In progress, Done) and Changelog, a post page with comments,\n * search, light/dark. Visitors give a name and email once before they post, vote or comment, unless your app\n * called `identify()` with a name or email.\n */\nexport const FeedbackBoard = ({\n title = \"Feedback\",\n subtitle = \"Tell us what to build next and vote on what matters to you.\",\n theme,\n accent,\n header = true,\n syncUrl = false,\n fullPage = false,\n initialTab = \"requests\",\n}: FeedbackBoardProps) => {\n const { host } = useCtx();\n const identity = useIdentity();\n const [tab, setTab] = useState<Tab>(initialTab);\n const [sort, setSort] = useState<\"top\" | \"new\">(\"top\");\n const [board, setBoard] = useState<string | undefined>();\n const [q, setQ] = useState(\"\");\n const [searching, setSearching] = useState(false);\n const [creating, setCreating] = useState(false);\n const [opened, setOpened] = useState<FeedbackPost | null>(null);\n const [openId, setOpenId] = useState<string | null>(null);\n const [mode, setMode] = useState<Theme>(theme ?? \"auto\");\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList(identity.api, { board, sort, q: tab === \"requests\" ? q : \"\" });\n const { posts, setPosts, vote } = list;\n const searchRef = useRef<HTMLInputElement>(null);\n\n // The visitor's own light/dark choice, from the header's toggle.\n useEffect(() => {\n if (!header) return;\n try {\n const t = window.localStorage.getItem(THEME_KEY);\n if (t === \"light\" || t === \"dark\") setMode(t);\n } catch {\n // Storage blocked: the prop's theme stays.\n }\n }, [header]);\n const dark = mode === \"dark\" || (mode === \"auto\" && systemDark());\n const flipTheme = () => {\n const next = dark ? \"light\" : \"dark\";\n setMode(next);\n try {\n window.localStorage.setItem(THEME_KEY, next);\n } catch {\n // Lasts for this page.\n }\n };\n\n // The address bar: ?view= and ?post= in, and back out on every change.\n useEffect(() => {\n if (!syncUrl) return;\n const sync = () => {\n const u = readUrl();\n setTab(u.tab);\n setOpenId(u.post);\n if (!u.post) setOpened(null);\n };\n sync();\n window.addEventListener(\"popstate\", sync);\n return () => window.removeEventListener(\"popstate\", sync);\n }, [syncUrl]);\n const go = (next: Tab, post: FeedbackPost | null = null) => {\n setTab(next);\n setOpened(post);\n setOpenId(post?.id ?? null);\n if (syncUrl) writeUrl(next, post?.id ?? null, true);\n };\n\n // A post named in the address: from the list when it is there, else asked for on its own.\n useEffect(() => {\n if (!openId || opened?.id === openId) return;\n const inList = posts.find((p) => p.id === openId);\n if (inList) return setOpened(inList);\n if (list.loading) return;\n const ctl = new AbortController();\n identity.api\n .post(openId, ctl.signal)\n .then(setOpened)\n .catch((e: Error) => {\n if (e.name === \"AbortError\") return;\n setOpenId(null);\n if (syncUrl) writeUrl(tab, null, false);\n });\n return () => ctl.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [openId, posts, list.loading]);\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\n /** Votes as the known visitor, or asks for a name and email first. `done` hears the server's count. */\n const voteAny = (p: FeedbackPost, done?: (r: { voted: boolean; votes: number } | null) => void) =>\n identity.need((as) => {\n const flip = (o: FeedbackPost | null) => (o && o.id === p.id ? { ...o, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) } : o);\n const inList = posts.some((x) => x.id === p.id);\n if (inList && !done) {\n vote(p, as);\n return;\n }\n setOpened(flip);\n done?.({ voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n as.vote(p.id)\n .then((r) => {\n setOpened((o) => (o && o.id === p.id ? { ...o, ...r } : o));\n if (inList) list.patch(p.id, (x) => ({ ...x, ...r }));\n done?.(r);\n })\n .catch((e: Error) => {\n setOpened((o) => (o && o.id === p.id ? { ...o, voted: p.voted, votes: p.votes } : o));\n done?.({ voted: p.voted, votes: p.votes });\n list.setError(`Your vote was not saved. ${e.message}`);\n });\n });\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 go(TABS[(n + TABS.length) % TABS.length][0]);\n };\n\n const product = list.product;\n const logo = product?.logo ? (product.logo.startsWith(\"/\") ? `${host}${product.logo}` : product.logo) : null;\n const name = product?.name ?? title;\n const newPost = () => (setThanks(false), setCreating(true));\n const searchLabel = tab === \"roadmap\" ? \"Search roadmap\" : tab === \"changelog\" ? \"Search updates\" : \"Search requests\";\n\n return (\n <Root theme={header ? (dark ? \"dark\" : \"light\") : theme} accent={accent} className={`ckw-board${fullPage ? \" ckw-full\" : \"\"}`}>\n {header ? (\n <header className=\"ckw-top\">\n <div className=\"ckw-top-row\">\n <button type=\"button\" className=\"ckw-brand\" onClick={() => go(\"requests\")}>\n {logo ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={logo} alt=\"\" width={28} height={28} />\n ) : (\n <span className=\"ckw-brand-mark\" aria-hidden=\"true\">\n {name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <span>{name}</span>\n </button>\n <nav className=\"ckw-nav\" role=\"tablist\" aria-label=\"Board 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 && !current}\n tabIndex={tab === k ? 0 : -1}\n className=\"ckw-nav-tab\"\n onClick={() => go(k)}\n >\n {label}\n </button>\n ))}\n </nav>\n <div className=\"ckw-top-tools\">\n <div className=\"ckw-searchbox\" data-open={searching || !!q || undefined}>\n <button\n type=\"button\"\n className=\"ckw-icon-btn\"\n aria-label={searchLabel}\n onClick={() => {\n setSearching(true);\n window.setTimeout(() => searchRef.current?.focus(), 0);\n }}\n >\n <Search />\n </button>\n <input\n ref={searchRef}\n type=\"search\"\n className=\"ckw-search-input\"\n aria-label={searchLabel}\n placeholder=\"Search…\"\n value={q}\n onChange={(e) => {\n setQ(e.target.value);\n if (current) go(tab);\n }}\n onBlur={() => setSearching(false)}\n onKeyDown={(e) => e.key === \"Escape\" && (setQ(\"\"), (e.target as HTMLInputElement).blur())}\n />\n </div>\n <button type=\"button\" className=\"ckw-icon-btn\" onClick={flipTheme} aria-label={dark ? \"Switch to light mode\" : \"Switch to dark mode\"}>\n {dark ? <Sun /> : <Moon />}\n </button>\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary ckw-submit\" aria-label=\"Submit feedback\" onClick={newPost}>\n <Plus /> <span>Submit feedback</span>\n </button>\n </div>\n </div>\n </header>\n ) : (\n <>\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={newPost}>\n <Plus /> Request a feature\n </button>\n </div>\n <div className=\"ckw-tabs\" role=\"tablist\" aria-label=\"Feedback sections\" onKeyDown={onTabKey}>\n {TABS.map(([k, label]) => (\n <button key={k} type=\"button\" role=\"tab\" id={`ckw-tab-${k}`} aria-selected={tab === k} tabIndex={tab === k ? 0 : -1} className=\"ckw-tab\" onClick={() => go(k)}>\n {k === \"requests\" ? \"Requests\" : label}\n </button>\n ))}\n </div>\n <input\n className=\"ckw-input ckw-search\"\n type=\"search\"\n aria-label={searchLabel}\n placeholder={searchLabel}\n value={q}\n onChange={(e) => setQ(e.target.value)}\n style={{ marginBottom: 12 }}\n />\n </>\n )}\n\n <div className=\"ckw-body-wrap\" role=\"tabpanel\" aria-labelledby={`ckw-tab-${tab}`}>\n {header && !current && (\n <div className=\"ckw-intro\">\n <h1>{tab === \"roadmap\" ? \"Roadmap\" : tab === \"changelog\" ? \"Changelog\" : \"Feedback\"}</h1>\n <p>{tab === \"roadmap\" ? \"What we are considering, building next and shipped.\" : tab === \"changelog\" ? \"New and improved, newest first.\" : subtitle}</p>\n </div>\n )}\n {thanks && !current && (\n <div className=\"ckw-note\" role=\"status\">\n Thanks, your request is in. You can follow it here.\n <button type=\"button\" className=\"ckw-icon-btn\" aria-label=\"Dismiss\" onClick={() => setThanks(false)}>\n <Cross />\n </button>\n </div>\n )}\n {list.error && <ErrorBar message={list.error} onRetry={tab === \"requests\" && !current ? list.reload : undefined} onClose={() => list.setError(\"\")} />}\n\n {current ? (\n <PostDetail\n post={current}\n boards={list.boards}\n identity={identity}\n backLabel={tab === \"roadmap\" ? \"Roadmap\" : \"All requests\"}\n onBack={() => go(tab)}\n onVote={(p) => voteAny(p)}\n />\n ) : tab === \"requests\" ? (\n <Requests\n list={list}\n sort={sort}\n setSort={setSort}\n board={board}\n setBoard={setBoard}\n q={q}\n onOpen={(p) => go(\"requests\", p)}\n onVote={(p) => voteAny(p)}\n onNew={newPost}\n />\n ) : tab === \"roadmap\" ? (\n <Roadmap api={identity.api} boards={list.boards} q={q} onOpen={(p) => go(\"roadmap\", p)} voteRef={(p, done) => voteAny(p, done)} />\n ) : (\n <Changelog api={identity.api} q={q} />\n )}\n </div>\n\n {creating && (\n <Modal title=\"Submit feedback\" onClose={() => setCreating(false)}>\n <SubmitForm\n bare\n identity={identity}\n boards={list.boards}\n posts={posts}\n onVote={(p) => voteAny(p)}\n onCancel={() => setCreating(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all.filter((x) => x.id !== p.id)]);\n setCreating(false);\n setThanks(true);\n go(\"requests\");\n }}\n />\n </Modal>\n )}\n <IdentityDialog identity={identity} />\n {identity.known && !identity.fromApp && header && (\n <p className=\"ckw-foot\">\n Posting as {identity.name}.{\" \"}\n <button type=\"button\" className=\"ckw-linkish\" onClick={identity.forget}>\n Not you?\n </button>\n </p>\n )}\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 or MRRocket's hosted board. */\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 identity = useIdentity();\n const [suggesting, setSuggesting] = useState(false);\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList(identity.api, { sort: \"top\" });\n const { posts, setPosts } = list;\n const vote = (p: FeedbackPost) => identity.need((as) => list.vote(p, as));\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 {identity.asking ? (\n <WidgetIdentity identity={identity} />\n ) : thanks ? (\n <div className=\"ckw-empty\" role=\"status\">\n Thanks, your request is in.\n </div>\n ) : suggesting ? (\n <SubmitForm\n compact\n identity={identity}\n boards={list.boards}\n posts={posts}\n onVote={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={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 && !identity.asking && (\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/** The widget asks for a name and email in place, not in a second dialog. */\nconst WidgetIdentity = ({ identity }: { identity: Identity }) => {\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const ok = name.trim().length > 0 && EMAIL.test(email.trim());\n return (\n <form\n className=\"ckw-form\"\n onSubmit={(e) => {\n e.preventDefault();\n const run = identity.asking;\n if (!ok || !run) return;\n const api = identity.save(name, email);\n identity.cancel();\n run(api);\n }}\n >\n <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />\n <div className=\"ckw-actions\">\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={identity.cancel}>\n Cancel\n </button>\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={!ok}>\n Continue\n </button>\n </div>\n </form>\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\n"],"mappings":"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","names":["name"]}
1
+ {"version":3,"sources":["../src/feedback.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FormEvent, type ReactNode, useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport {\n type Api,\n type ChangelogEntry,\n type FeedbackBoardInfo,\n type FeedbackComment,\n type FeedbackPost,\n type FeedbackProduct,\n type FeedbackRoadmap,\n type PostStatus,\n type Writer,\n createApi,\n useApi,\n} from \"./api\";\nimport { useCtx } from \"./context\";\nimport { Chat, ChevronUp, Cross, Moon, Plus, Root, Search, StatusPill, Sun, type Theme, VoteButton, similarPosts, timeAgo, useEscape } from \"./ui\";\n\n// ---------- Who writes ----------\n\ninterface Who {\n id: string;\n name: string;\n email: string;\n}\n\nconst whoKey = (apiKey: string) => `ckw-board-who:${apiKey}`;\nconst readWho = (apiKey: string): Who | null => {\n try {\n const raw = window.localStorage.getItem(whoKey(apiKey));\n const w = raw ? (JSON.parse(raw) as Who) : null;\n return w && typeof w.id === \"string\" && typeof w.name === \"string\" && typeof w.email === \"string\" ? w : null;\n } catch {\n return null;\n }\n};\nconst newWhoId = () => {\n try {\n return `fb_${crypto.randomUUID()}`;\n } catch {\n return `fb_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;\n }\n};\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Who posts, votes and comments. A signed-in user from `identify()` (with a name or email) writes as themselves; any\n * other visitor gives a name and email once, which this browser keeps for this board (localStorage, nothing else),\n * so their votes are still theirs on the next visit. `need` runs a write at once when the visitor is known, else\n * asks first and runs it with the new identity.\n */\nconst useIdentity = () => {\n const ctx = useCtx();\n const [saved, setSaved] = useState<Who | null>(null);\n const [asking, setAsking] = useState<((api: Api) => void) | null>(null);\n useEffect(() => setSaved(readWho(ctx.apiKey)), [ctx.apiKey]);\n const fromApp = !!ctx.user && (!!ctx.user.email || !!ctx.user.name);\n const writer: Writer | null = useMemo(\n () => (fromApp || !saved ? null : { distinctId: saved.id, user: { name: saved.name, email: saved.email } }),\n [fromApp, saved],\n );\n const api = useApi(writer);\n const known = fromApp || !!saved;\n\n /** Keeps the name and email and returns a client that writes as them, for the call that is waiting. */\n const save = useCallback(\n (name: string, email: string): Api => {\n const who: Who = { id: saved?.id ?? newWhoId(), name: name.trim(), email: email.trim().toLowerCase() };\n try {\n window.localStorage.setItem(whoKey(ctx.apiKey), JSON.stringify(who));\n } catch {\n // Private mode: the identity lasts for this page.\n }\n setSaved(who);\n return createApi({ apiKey: ctx.apiKey, host: ctx.host, distinctId: who.id, user: { name: who.name, email: who.email } });\n },\n [ctx.apiKey, ctx.host, saved],\n );\n\n const forget = useCallback(() => {\n try {\n window.localStorage.removeItem(whoKey(ctx.apiKey));\n } catch {\n // Nothing stored.\n }\n setSaved(null);\n }, [ctx.apiKey]);\n\n const need = useCallback((fn: (api: Api) => void) => (known ? fn(api) : setAsking(() => fn)), [known, api]);\n const name = fromApp ? String(ctx.user?.name ?? ctx.user?.email ?? \"\") : (saved?.name ?? \"\");\n return { api, known, fromApp, name, save, forget, need, asking, cancel: () => setAsking(null) };\n};\n\ntype Identity = ReturnType<typeof useIdentity>;\n\n// ---------- Data ----------\n\n/** Loads the post list and owns optimistic voting, so the board and the widget behave the same. */\nconst useFeedbackList = (api: Api, opts: { board?: string; sort?: \"top\" | \"new\"; q?: string }) => {\n const [posts, setPosts] = useState<FeedbackPost[]>([]);\n const [boards, setBoards] = useState<FeedbackBoardInfo[]>([]);\n const [product, setProduct] = useState<FeedbackProduct | null>(null);\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 if (r.product) setProduct(r.product);\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, as: Api = api) => {\n const flip = (p: FeedbackPost) => ({ ...p, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n patch(post.id, flip);\n as.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 { posts, setPosts, patch, boards, product, loading, error, setError, vote, reload: () => setTick((t) => t + 1) };\n};\n\n// ---------- Small parts ----------\n\nconst BOARD_TONE: Record<string, string> = { feature: \"blue\", bug: \"red\", integration: \"violet\", improvement: \"green\" };\n\nconst TypeChip = ({ board, boards }: { board: string; boards: FeedbackBoardInfo[] }) => (\n <span className=\"ckw-type\" data-tone={BOARD_TONE[board] ?? \"gray\"}>\n {boards.find((b) => b.id === board)?.label ?? board}\n </span>\n);\n\nconst Avatar = ({ name, team }: { name: string; team?: boolean }) => (\n <span className=\"ckw-av\" data-team={team || undefined} aria-hidden=\"true\">\n {(name.trim()[0] ?? \"?\").toUpperCase()}\n </span>\n);\n\nconst Skeleton = ({ rows = 3 }: { rows?: number }) => (\n <div aria-hidden=\"true\">\n {Array.from({ length: rows }, (_, 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\n/** A dialog inside the widget's root: dimmed page, Esc and the backdrop close it, Tab stays inside. A sheet on phones. */\nconst Modal = ({ title, onClose, children }: { title: string; onClose: () => void; children: ReactNode }) => {\n const box = useRef<HTMLDivElement>(null);\n const id = useId();\n useEscape(onClose);\n useEffect(() => {\n const before = document.activeElement as HTMLElement | null;\n box.current?.querySelector<HTMLElement>(\"input, textarea, button\")?.focus();\n return () => before?.focus?.();\n }, []);\n const trap = (e: React.KeyboardEvent) => {\n if (e.key !== \"Tab\" || !box.current) return;\n const f = [...box.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 return (\n <div className=\"ckw-scrim\" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>\n <div ref={box} className=\"ckw-modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby={id} onKeyDown={trap}>\n <div className=\"ckw-modal-head\">\n <h2 id={id}>{title}</h2>\n <button type=\"button\" className=\"ckw-icon-btn\" onClick={onClose} aria-label=\"Close\">\n <Cross />\n </button>\n </div>\n {children}\n </div>\n </div>\n );\n};\n\n/** Name and email, with the one line on what happens to them. */\nconst IdentityFields = ({ name, email, setName, setEmail }: { name: string; email: string; setName: (v: string) => void; setEmail: (v: string) => void }) => {\n const id = useId();\n return (\n <>\n <div className=\"ckw-pair\">\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-n`}>\n Your name\n </label>\n <input\n id={`${id}-n`}\n className=\"ckw-input\"\n value={name}\n maxLength={80}\n required\n autoComplete=\"name\"\n onChange={(e) => setName(e.target.value)}\n />\n </div>\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-e`}>\n Email\n </label>\n <input\n id={`${id}-e`}\n className=\"ckw-input\"\n type=\"email\"\n value={email}\n maxLength={200}\n required\n autoComplete=\"email\"\n onChange={(e) => setEmail(e.target.value)}\n />\n </div>\n </div>\n <p className=\"ckw-fine\">Others see your first name and last initial. Your email is only for updates on what you posted or voted for.</p>\n </>\n );\n};\n\n/** Asked once before the first vote or comment of a visitor the app has not identified. */\nconst IdentityDialog = ({ identity }: { identity: Identity }) => {\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const ok = name.trim().length > 0 && EMAIL.test(email.trim());\n const run = identity.asking;\n if (!run) return null;\n return (\n <Modal title=\"Before you vote or comment\" onClose={identity.cancel}>\n <form\n className=\"ckw-modal-body\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!ok) return;\n const api = identity.save(name, email);\n identity.cancel();\n run(api);\n }}\n >\n <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />\n <div className=\"ckw-actions\">\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={identity.cancel}>\n Cancel\n </button>\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={!ok}>\n Continue\n </button>\n </div>\n </form>\n </Modal>\n );\n};\n\n/** Title, details and board, with up to three similar requests to vote on instead; name and email when not known yet. */\nconst SubmitForm = ({\n identity,\n boards,\n posts,\n onCreated,\n onVote,\n onCancel,\n compact,\n bare,\n}: {\n identity: Identity;\n boards: FeedbackBoardInfo[];\n posts: FeedbackPost[];\n onCreated: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onCancel?: () => void;\n compact?: boolean;\n /** Inside a dialog: no frame of its own. */\n bare?: boolean;\n}) => {\n const id = useId();\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [board, setBoard] = useState(\"\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = 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 const ask = !identity.known;\n const ready = title.trim().length >= 3 && (!ask || (name.trim().length > 0 && EMAIL.test(email.trim())));\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n if (!ready || busy) return;\n setBusy(true);\n setError(\"\");\n try {\n const api = ask ? identity.save(name, email) : identity.api;\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={bare ? \"ckw-modal-body\" : \"ckw-form\"} onSubmit={submit}>\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-t`}>\n Title\n </label>\n <input\n id={`${id}-t`}\n className=\"ckw-input\"\n value={title}\n maxLength={120}\n required\n autoFocus\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Short, specific summary\"\n />\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 <span className=\"ckw-opt-l\">optional</span>\n </label>\n <textarea\n id={`${id}-b`}\n className=\"ckw-textarea\"\n value={body}\n maxLength={2000}\n onChange={(e) => setBody(e.target.value)}\n placeholder=\"What are you trying to do? What gets in the way?\"\n />\n </div>\n )}\n {boards.length > 1 && (\n <div className=\"ckw-field\">\n <span className=\"ckw-label\" id={`${id}-c`}>\n Type\n </span>\n <div className=\"ckw-chips\" role=\"radiogroup\" aria-labelledby={`${id}-c`} style={{ marginBottom: 0 }}>\n {boards.map((b) => (\n <button key={b.id} type=\"button\" role=\"radio\" aria-checked={chosen === b.id} className=\"ckw-chip\" onClick={() => setBoard(b.id)}>\n {b.label}\n </button>\n ))}\n </div>\n </div>\n )}\n {ask && <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />}\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 || !ready}>\n {busy ? \"Sending…\" : \"Submit\"}\n </button>\n </div>\n </form>\n );\n};\n\n// ---------- Requests ----------\n\nconst PostCard = ({\n post,\n boards,\n onOpen,\n onVote,\n}: {\n post: FeedbackPost;\n boards: FeedbackBoardInfo[];\n onOpen: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n}) => (\n <li className=\"ckw-post\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <button type=\"button\" className=\"ckw-link ckw-stretch\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-meta\">\n <TypeChip board={post.board} boards={boards} />\n {post.status !== \"review\" && <StatusPill status={post.status} />}\n <span className=\"ckw-stat\" aria-label={`${post.comments} comments`}>\n <Chat /> {post.comments}\n </span>\n <span className=\"ckw-dot-sep\">{[post.author, timeAgo(post.createdAt)].filter(Boolean).join(\" · \")}</span>\n </div>\n </div>\n </li>\n);\n\nconst Requests = ({\n list,\n sort,\n setSort,\n board,\n setBoard,\n q,\n onOpen,\n onVote,\n onNew,\n}: {\n list: ReturnType<typeof useFeedbackList>;\n sort: \"top\" | \"new\";\n setSort: (s: \"top\" | \"new\") => void;\n board?: string;\n setBoard: (b?: string) => void;\n q: string;\n onOpen: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onNew: () => void;\n}) => {\n const { posts, boards } = list;\n return (\n <div>\n <div>\n <div className=\"ckw-tools\">\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 {boards.length > 1 && (\n <div className=\"ckw-chips ckw-chips-inline\" role=\"group\" aria-label=\"Type\">\n <button type=\"button\" className=\"ckw-chip\" aria-pressed={!board} onClick={() => setBoard(undefined)}>\n All\n </button>\n {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>\n <div aria-live=\"polite\" aria-busy={list.loading}>\n {list.loading && posts.length === 0 ? (\n <Skeleton />\n ) : posts.length === 0 && !list.error ? (\n // Things' empty look (owner, 2026-10-21): a large faint glyph, one line and the one next step, no frame.\n <div className=\"ckw-empty\">\n <EmptyGlyph />\n <p>{q ? \"No request matches your search.\" : board ? \"Nothing of this type yet.\" : \"No requests yet.\"}</p>\n {!q && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={onNew}>\n <Plus /> Suggest the first one\n </button>\n )}\n </div>\n ) : (\n <ul className=\"ckw-posts\">\n {posts.map((p) => (\n <PostCard key={p.id} post={p} boards={boards} onOpen={onOpen} onVote={onVote} />\n ))}\n </ul>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n// ---------- Post ----------\n\nconst PostDetail = ({\n post,\n boards,\n identity,\n onBack,\n onVote,\n backLabel,\n}: {\n post: FeedbackPost;\n boards: FeedbackBoardInfo[];\n identity: Identity;\n onBack: () => void;\n onVote: (p: FeedbackPost) => void;\n backLabel: string;\n}) => {\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 const { api } = identity;\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 = (e: FormEvent) => {\n e.preventDefault();\n const body = text.trim();\n if (!body || busy) return;\n identity.need(async (as) => {\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 as.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\n const count = Math.max(post.comments + added, comments?.length ?? 0);\n return (\n <article className=\"ckw-detail\">\n <button type=\"button\" className=\"ckw-back\" onClick={onBack}>\n <span className=\"ckw-back-icon\">\n <ChevronUp />\n </span>\n {backLabel}\n </button>\n <div className=\"ckw-detail-grid\">\n <div className=\"ckw-detail-main\">\n <h2 className=\"ckw-detail-title\">{post.title}</h2>\n <div className=\"ckw-byline\">\n <Avatar name={post.author ?? \"?\"} team={post.author === \"Team\"} />\n <span>{post.author ?? \"Someone\"}</span>\n <span className=\"ckw-dot-sep\">{timeAgo(post.createdAt)}</span>\n </div>\n {post.body && <p className=\"ckw-body\">{post.body}</p>}\n\n <h3 className=\"ckw-h\">\n Comments <span className=\"ckw-count\">{count}</span>\n </h3>\n <form className=\"ckw-composer\" onSubmit={send}>\n <label className=\"ckw-sr\" htmlFor={id}>\n Leave a comment\n </label>\n <textarea\n id={id}\n className=\"ckw-textarea\"\n value={text}\n maxLength={1000}\n placeholder=\"Leave a comment\"\n onChange={(e) => setText(e.target.value)}\n />\n <div className=\"ckw-actions\">\n {identity.known && identity.name && <span className=\"ckw-fine ckw-as\">Commenting as {identity.name}</span>}\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !text.trim()}>\n Comment\n </button>\n </div>\n </form>\n {error && <ErrorBar message={error} onClose={() => setError(\"\")} />}\n <div aria-live=\"polite\">\n {comments === null && !error && <Skeleton rows={2} />}\n {comments?.length === 0 && <p className=\"ckw-sub\">No comments yet.</p>}\n {comments?.map((c) => (\n <div className=\"ckw-comment\" key={c.id}>\n <Avatar name={c.author} team={c.isTeam} />\n <div className=\"ckw-main\">\n <div>\n <b>{c.author}</b>\n {c.isTeam && <span className=\"ckw-team\">Team</span>}\n <span className=\"ckw-time\">{timeAgo(c.postedAt)}</span>\n </div>\n <p>{c.body}</p>\n </div>\n </div>\n ))}\n </div>\n </div>\n <aside className=\"ckw-side\" aria-label=\"About this request\">\n <button\n type=\"button\"\n className=\"ckw-upvote\"\n aria-pressed={post.voted}\n aria-label={`${post.voted ? \"Remove your vote\" : \"Upvote\"}. ${post.votes} votes`}\n onClick={() => onVote(post)}\n >\n <ChevronUp />\n <span>{post.voted ? \"Upvoted\" : \"Upvote\"}</span>\n <b>{post.votes}</b>\n </button>\n <dl className=\"ckw-facts\">\n <div>\n <dt>Status</dt>\n <dd>\n <StatusPill status={post.status} />\n </dd>\n </div>\n <div>\n <dt>Type</dt>\n <dd>\n <TypeChip board={post.board} boards={boards} />\n </dd>\n </div>\n <div>\n <dt>Posted</dt>\n <dd>{new Date(post.createdAt).toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" })}</dd>\n </div>\n </dl>\n </aside>\n </div>\n </article>\n );\n};\n\n// ---------- Roadmap ----------\n\nconst COLUMNS: { status: PostStatus; label: string; note: string }[] = [\n { status: \"review\", label: \"Backlog\", note: \"Under consideration\" },\n { status: \"planned\", label: \"Next up\", note: \"Committed and queued\" },\n { status: \"progress\", label: \"In progress\", note: \"Actively being built\" },\n { status: \"shipped\", label: \"Done\", note: \"Recently shipped\" },\n];\n\nconst matchesQ = (q: string, ...texts: string[]) => {\n const t = q.trim().toLowerCase();\n return !t || texts.some((x) => x.toLowerCase().includes(t));\n};\n\nconst RoadmapCard = ({\n post,\n boards,\n onOpen,\n onVote,\n}: {\n post: FeedbackPost;\n boards: FeedbackBoardInfo[];\n onOpen: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n}) => (\n <li className=\"ckw-card\">\n <TypeChip board={post.board} boards={boards} />\n <button type=\"button\" className=\"ckw-link ckw-stretch\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-card-foot\">\n <span className=\"ckw-who\">\n <Avatar name={post.author ?? \"?\"} team={post.author === \"Team\"} />\n <span>{post.author ?? \"\"}</span>\n </span>\n <VoteButton post={post} onVote={onVote} small />\n </div>\n </li>\n);\n\nconst Roadmap = ({\n api,\n boards,\n q,\n onOpen,\n voteRef,\n}: {\n api: Api;\n boards: FeedbackBoardInfo[];\n q: string;\n onOpen: (p: FeedbackPost) => void;\n /** The board's vote, which asks who the visitor is first; the roadmap keeps its own counts in step. */\n voteRef: (p: FeedbackPost, done: (r: { voted: boolean; votes: number } | null) => void) => void;\n}) => {\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 const patch = (id: string, fn: (p: FeedbackPost) => FeedbackPost) =>\n setData((d) => {\n if (!d) return d;\n const columns = { ...d.columns };\n for (const k of Object.keys(columns) as (keyof FeedbackRoadmap[\"columns\"])[])\n columns[k] = columns[k]?.map((p) => (p.id === id ? fn(p) : p)) as FeedbackPost[];\n return { columns };\n });\n const vote = (post: FeedbackPost) =>\n voteRef(post, (r) => {\n if (r) patch(post.id, (p) => ({ ...p, ...r }));\n });\n\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!data)\n return (\n <div className=\"ckw-cols\" aria-hidden=\"true\">\n {COLUMNS.map((c) => (\n <div className=\"ckw-col\" key={c.status}>\n <Skeleton rows={2} />\n </div>\n ))}\n </div>\n );\n return (\n <div className=\"ckw-cols\">\n {COLUMNS.map((c) => {\n const cards = (data.columns[c.status as keyof FeedbackRoadmap[\"columns\"]] ?? []).filter((p) => matchesQ(q, p.title, p.body));\n return (\n <section className=\"ckw-col\" key={c.status} aria-label={c.label}>\n <header className=\"ckw-col-head\">\n <h3>\n <span className=\"ckw-sdot\" data-s={c.status} />\n {c.label}\n <span className=\"ckw-count\">{cards.length}</span>\n </h3>\n <p>{c.note}</p>\n </header>\n {cards.length === 0 ? (\n <p className=\"ckw-col-empty\">{q ? \"No match\" : \"Nothing here yet\"}</p>\n ) : (\n <ul className=\"ckw-col-list\">\n {cards.map((p) => (\n <RoadmapCard key={p.id} post={p} boards={boards} onOpen={onOpen} onVote={vote} />\n ))}\n </ul>\n )}\n </section>\n );\n })}\n </div>\n );\n};\n\n// ---------- Changelog ----------\n\nconst Changelog = ({ api, q }: { api: Api; q: string }) => {\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 const shown = entries.filter((e) => matchesQ(q, e.title, e.body));\n if (shown.length === 0) return <div className=\"ckw-empty\">{q ? \"No update matches your search.\" : \"No updates published yet.\"}</div>;\n return (\n <div className=\"ckw-log\">\n {shown.map((e) => (\n <article className=\"ckw-entry\" key={e.id}>\n <time dateTime={e.publishedAt}>\n {new Date(e.publishedAt).toLocaleDateString(undefined, { month: \"long\", day: \"numeric\", year: \"numeric\" })}\n </time>\n <div>\n <h3>{e.title}</h3>\n <p>{e.body}</p>\n </div>\n </article>\n ))}\n </div>\n );\n};\n\n// ---------- The board ----------\n\ntype Tab = \"requests\" | \"roadmap\" | \"changelog\";\nconst TABS: [Tab, string][] = [\n [\"requests\", \"Feedback\"],\n [\"roadmap\", \"Roadmap\"],\n [\"changelog\", \"Changelog\"],\n];\n\n/** The page's ?view= and ?post=, when the board owns the address bar. */\nconst readUrl = () => {\n const p = new URLSearchParams(window.location.search);\n const v = p.get(\"view\");\n return { tab: (v === \"roadmap\" || v === \"changelog\" ? v : \"requests\") as Tab, post: p.get(\"post\") };\n};\nconst writeUrl = (tab: Tab, post: string | null, push: boolean) => {\n const url = new URL(window.location.href);\n if (tab === \"requests\") url.searchParams.delete(\"view\");\n else url.searchParams.set(\"view\", tab);\n if (post) url.searchParams.set(\"post\", post);\n else url.searchParams.delete(\"post\");\n if (url.href === window.location.href) return;\n if (push) window.history.pushState(null, \"\", url);\n else window.history.replaceState(null, \"\", url);\n};\n\nconst THEME_KEY = \"ckw-theme\";\nconst systemDark = () => typeof window !== \"undefined\" && !!window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches;\n\n/** A speech bubble with a light bulb's spark, filled, in the text's color: the board's empty picture. */\nconst EmptyGlyph = () => (\n <svg className=\"ckw-empty-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12 2.5c-5.25 0-9.5 3.73-9.5 8.33 0 2.47 1.23 4.69 3.18 6.21-.17 1.33-.73 2.6-1.63 3.63a.6.6 0 0 0 .5 1c2.13-.12 4-.86 5.38-1.92.67.13 1.36.2 2.07.2 5.25 0 9.5-3.73 9.5-8.33S17.25 2.5 12 2.5Zm.9 4.2-.6 3.3h2.2a.5.5 0 0 1 .4.8l-3.5 4.5a.4.4 0 0 1-.7-.35l.6-3.15H9.1a.5.5 0 0 1-.4-.8l3.5-4.65a.4.4 0 0 1 .7.35Z\" />\n </svg>\n);\n\nexport interface FeedbackBoardProps {\n /** Heading when the board has no header (`header={false}`). */\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 /** The top bar with your product's logo and name, search, light/dark and \"Submit feedback\". Default true. */\n header?: boolean;\n /** Keep the open tab and post in the address (?view=roadmap, ?post=…), so links can be shared. Default false. */\n syncUrl?: boolean;\n /** Fill the page: the board's background covers the whole window, as on a hosted board. Default false. */\n fullPage?: boolean;\n /** Which tab opens first. Default \"requests\". */\n initialTab?: Tab;\n}\n\n/**\n * The full board for a /feedback page, after Featurebase: your product's logo and name, Feedback (requests with\n * Top/New and type filter), Roadmap (Backlog, Next up, In progress, Done) and Changelog, a post page with comments,\n * search, light/dark. Visitors give a name and email once before they post, vote or comment, unless your app\n * called `identify()` with a name or email.\n */\nexport const FeedbackBoard = ({\n title = \"Feedback\",\n subtitle = \"Tell us what to build next and vote on what matters to you.\",\n theme,\n accent,\n header = true,\n syncUrl = false,\n fullPage = false,\n initialTab = \"requests\",\n}: FeedbackBoardProps) => {\n const { host } = useCtx();\n const identity = useIdentity();\n const [tab, setTab] = useState<Tab>(initialTab);\n const [sort, setSort] = useState<\"top\" | \"new\">(\"top\");\n const [board, setBoard] = useState<string | undefined>();\n const [q, setQ] = useState(\"\");\n const [searching, setSearching] = useState(false);\n const [creating, setCreating] = useState(false);\n const [opened, setOpened] = useState<FeedbackPost | null>(null);\n const [openId, setOpenId] = useState<string | null>(null);\n const [mode, setMode] = useState<Theme>(theme ?? \"auto\");\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList(identity.api, { board, sort, q: tab === \"requests\" ? q : \"\" });\n const { posts, setPosts, vote } = list;\n const searchRef = useRef<HTMLInputElement>(null);\n\n // The visitor's own light/dark choice, from the header's toggle.\n useEffect(() => {\n if (!header) return;\n try {\n const t = window.localStorage.getItem(THEME_KEY);\n if (t === \"light\" || t === \"dark\") setMode(t);\n } catch {\n // Storage blocked: the prop's theme stays.\n }\n }, [header]);\n const dark = mode === \"dark\" || (mode === \"auto\" && systemDark());\n const flipTheme = () => {\n const next = dark ? \"light\" : \"dark\";\n setMode(next);\n try {\n window.localStorage.setItem(THEME_KEY, next);\n } catch {\n // Lasts for this page.\n }\n };\n\n // The address bar: ?view= and ?post= in, and back out on every change.\n useEffect(() => {\n if (!syncUrl) return;\n const sync = () => {\n const u = readUrl();\n setTab(u.tab);\n setOpenId(u.post);\n if (!u.post) setOpened(null);\n };\n sync();\n window.addEventListener(\"popstate\", sync);\n return () => window.removeEventListener(\"popstate\", sync);\n }, [syncUrl]);\n const go = (next: Tab, post: FeedbackPost | null = null) => {\n setTab(next);\n setOpened(post);\n setOpenId(post?.id ?? null);\n if (syncUrl) writeUrl(next, post?.id ?? null, true);\n };\n\n // A post named in the address: from the list when it is there, else asked for on its own.\n useEffect(() => {\n if (!openId || opened?.id === openId) return;\n const inList = posts.find((p) => p.id === openId);\n if (inList) return setOpened(inList);\n if (list.loading) return;\n const ctl = new AbortController();\n identity.api\n .post(openId, ctl.signal)\n .then(setOpened)\n .catch((e: Error) => {\n if (e.name === \"AbortError\") return;\n setOpenId(null);\n if (syncUrl) writeUrl(tab, null, false);\n });\n return () => ctl.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [openId, posts, list.loading]);\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\n /** Votes as the known visitor, or asks for a name and email first. `done` hears the server's count. */\n const voteAny = (p: FeedbackPost, done?: (r: { voted: boolean; votes: number } | null) => void) =>\n identity.need((as) => {\n const flip = (o: FeedbackPost | null) => (o && o.id === p.id ? { ...o, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) } : o);\n const inList = posts.some((x) => x.id === p.id);\n if (inList && !done) {\n vote(p, as);\n return;\n }\n setOpened(flip);\n done?.({ voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n as.vote(p.id)\n .then((r) => {\n setOpened((o) => (o && o.id === p.id ? { ...o, ...r } : o));\n if (inList) list.patch(p.id, (x) => ({ ...x, ...r }));\n done?.(r);\n })\n .catch((e: Error) => {\n setOpened((o) => (o && o.id === p.id ? { ...o, voted: p.voted, votes: p.votes } : o));\n done?.({ voted: p.voted, votes: p.votes });\n list.setError(`Your vote was not saved. ${e.message}`);\n });\n });\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 go(TABS[(n + TABS.length) % TABS.length][0]);\n };\n\n const product = list.product;\n const abs = (u: string | null | undefined) => (u ? (u.startsWith(\"/\") ? `${host}${u}` : u) : null);\n // The stored icon, else the domain's favicon once it fails to load, else the first letter.\n const marks = [abs(product?.logo), abs(product?.logoFallback)].filter((u, i, a): u is string => !!u && a.indexOf(u) === i);\n const [failed, setFailed] = useState(0);\n const logo = marks[failed] ?? null;\n const name = product?.name ?? title;\n const newPost = () => (setThanks(false), setCreating(true));\n const searchLabel = tab === \"roadmap\" ? \"Search roadmap\" : tab === \"changelog\" ? \"Search updates\" : \"Search requests\";\n\n return (\n <Root theme={header ? (dark ? \"dark\" : \"light\") : theme} accent={accent} className={`ckw-board${fullPage ? \"ckw-full\" : \"\"}`}>\n {header ? (\n <header className=\"ckw-top\">\n <div className=\"ckw-top-row\">\n <button type=\"button\" className=\"ckw-brand\" onClick={() => go(\"requests\")}>\n {logo ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img key={logo} src={logo} alt=\"\" width={28} height={28} onError={() => setFailed((n) => n + 1)} />\n ) : (\n <span className=\"ckw-brand-mark\" aria-hidden=\"true\">\n {name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <span>{name}</span>\n </button>\n <nav className=\"ckw-nav\" role=\"tablist\" aria-label=\"Board 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 && !current}\n tabIndex={tab === k ? 0 : -1}\n className=\"ckw-nav-tab\"\n onClick={() => go(k)}\n >\n {label}\n </button>\n ))}\n </nav>\n <div className=\"ckw-top-tools\">\n <div className=\"ckw-searchbox\" data-open={searching || !!q || undefined}>\n <button\n type=\"button\"\n className=\"ckw-icon-btn\"\n aria-label={searchLabel}\n onClick={() => {\n setSearching(true);\n window.setTimeout(() => searchRef.current?.focus(), 0);\n }}\n >\n <Search />\n </button>\n <input\n ref={searchRef}\n type=\"search\"\n className=\"ckw-search-input\"\n aria-label={searchLabel}\n placeholder=\"Search…\"\n value={q}\n onChange={(e) => {\n setQ(e.target.value);\n if (current) go(tab);\n }}\n onBlur={() => setSearching(false)}\n onKeyDown={(e) => e.key === \"Escape\" && (setQ(\"\"), (e.target as HTMLInputElement).blur())}\n />\n </div>\n <button\n type=\"button\"\n className=\"ckw-icon-btn\"\n onClick={flipTheme}\n aria-label={dark ? \"Switch to light mode\" : \"Switch to dark mode\"}\n >\n {dark ? <Sun /> : <Moon />}\n </button>\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary ckw-submit\" aria-label=\"Submit feedback\" onClick={newPost}>\n <Plus /> <span>Submit feedback</span>\n </button>\n </div>\n </div>\n </header>\n ) : (\n <>\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={newPost}>\n <Plus /> Request a feature\n </button>\n </div>\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={() => go(k)}\n >\n {k === \"requests\" ? \"Requests\" : label}\n </button>\n ))}\n </div>\n <input\n className=\"ckw-input ckw-search\"\n type=\"search\"\n aria-label={searchLabel}\n placeholder={searchLabel}\n value={q}\n onChange={(e) => setQ(e.target.value)}\n style={{ marginBottom: 12 }}\n />\n </>\n )}\n\n <div className=\"ckw-body-wrap\" role=\"tabpanel\" aria-labelledby={`ckw-tab-${tab}`}>\n {header && !current && (\n <div className=\"ckw-intro\">\n <h1>{tab === \"roadmap\" ? \"Roadmap\" : tab === \"changelog\" ? \"Changelog\" : \"Feedback\"}</h1>\n <p>\n {tab === \"roadmap\"\n ? \"What we are considering, building next and shipped.\"\n : tab === \"changelog\"\n ? \"New and improved, newest first.\"\n : subtitle}\n </p>\n </div>\n )}\n {thanks && !current && (\n <div className=\"ckw-note\" role=\"status\">\n Thanks, your request is in. You can follow it here.\n <button type=\"button\" className=\"ckw-icon-btn\" aria-label=\"Dismiss\" onClick={() => setThanks(false)}>\n <Cross />\n </button>\n </div>\n )}\n {list.error && (\n <ErrorBar message={list.error} onRetry={tab === \"requests\" && !current ? list.reload : undefined} onClose={() => list.setError(\"\")} />\n )}\n\n {current ? (\n <PostDetail\n post={current}\n boards={list.boards}\n identity={identity}\n backLabel={tab === \"roadmap\" ? \"Roadmap\" : \"All requests\"}\n onBack={() => go(tab)}\n onVote={(p) => voteAny(p)}\n />\n ) : tab === \"requests\" ? (\n <Requests\n list={list}\n sort={sort}\n setSort={setSort}\n board={board}\n setBoard={setBoard}\n q={q}\n onOpen={(p) => go(\"requests\", p)}\n onVote={(p) => voteAny(p)}\n onNew={newPost}\n />\n ) : tab === \"roadmap\" ? (\n <Roadmap api={identity.api} boards={list.boards} q={q} onOpen={(p) => go(\"roadmap\", p)} voteRef={(p, done) => voteAny(p, done)} />\n ) : (\n <Changelog api={identity.api} q={q} />\n )}\n </div>\n\n {creating && (\n <Modal title=\"Submit feedback\" onClose={() => setCreating(false)}>\n <SubmitForm\n bare\n identity={identity}\n boards={list.boards}\n posts={posts}\n onVote={(p) => voteAny(p)}\n onCancel={() => setCreating(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all.filter((x) => x.id !== p.id)]);\n setCreating(false);\n setThanks(true);\n go(\"requests\");\n }}\n />\n </Modal>\n )}\n <IdentityDialog identity={identity} />\n {identity.known && !identity.fromApp && header && (\n <p className=\"ckw-foot\">\n Posting as {identity.name}.{\" \"}\n <button type=\"button\" className=\"ckw-linkish\" onClick={identity.forget}>\n Not you?\n </button>\n </p>\n )}\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 or MRRocket's hosted board. */\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 identity = useIdentity();\n const [suggesting, setSuggesting] = useState(false);\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList(identity.api, { sort: \"top\" });\n const { posts, setPosts } = list;\n const vote = (p: FeedbackPost) => identity.need((as) => list.vote(p, as));\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 {identity.asking ? (\n <WidgetIdentity identity={identity} />\n ) : thanks ? (\n <div className=\"ckw-empty\" role=\"status\">\n Thanks, your request is in.\n </div>\n ) : suggesting ? (\n <SubmitForm\n compact\n identity={identity}\n boards={list.boards}\n posts={posts}\n onVote={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={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 && !identity.asking && (\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/** The widget asks for a name and email in place, not in a second dialog. */\nconst WidgetIdentity = ({ identity }: { identity: Identity }) => {\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const ok = name.trim().length > 0 && EMAIL.test(email.trim());\n return (\n <form\n className=\"ckw-form\"\n onSubmit={(e) => {\n e.preventDefault();\n const run = identity.asking;\n if (!ok || !run) return;\n const api = identity.save(name, email);\n identity.cancel();\n run(api);\n }}\n >\n <IdentityFields name={name} email={email} setName={setName} setEmail={setEmail} />\n <div className=\"ckw-actions\">\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={identity.cancel}>\n Cancel\n </button>\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={!ok}>\n Continue\n </button>\n </div>\n </form>\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\n ref={fab}\n type=\"button\"\n className=\"ckw-fab\"\n data-pos={position}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => (open ? close() : setWidgetOpen(true))}\n >\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":["name"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
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, useCancelFlow, useCockpit, useFeedback, useFlag, useFlagVariant, usePush, useStyles, useVariant, } from "./browser.js";
1
+ export { type ChangelogEntry, type ChatMessage, type ChatThread, type CockpitProviderProps, type CockpitUser, type FeedbackBoardInfo, type FeedbackBoardProps, type FeedbackComment, type FeedbackList, type FeedbackPost, type FeedbackRoadmap, type FeedbackWidgetProps, type MessengerProps, type PostStatus, type SurveyAnswer, type SurveyDefinition, type SurveyQuestion, type SurveyQuestionKind, CockpitProvider, Experiment, FeedbackBoard, FeedbackWidget, Messenger, Survey, Text, WIDGET_CSS, createApi, useCancelFlow, useCockpit, useFeedback, useFlag, useFlagVariant, useMessenger, usePush, useStyles, useVariant, } from "./browser.js";
2
2
  export type { PushResult, PushStatus, WebPushOptions } from "./push-web.js";
3
3
  export { type CockpitConfig, type CockpitEvent, type ConsentChoice, type ConsentMode, type ReplayConfig, type ErrorReport, type ExperimentConfig, type FlagCondition, type FlagConditionSet, type FlagConfig, type FlagPerson, type RedirectConfig, type RedirectDecision, type VariantConfig, type VariantId, EMBED_PARAM, EXPOSURE_PARAM, SDK_VERSION, ID_COOKIE, PREVIEW_PARAM, SESSION_COOKIE, assign, evaluateFlag, parsePreview, previewHref, redirectFor, } from "./core.js";
4
4
  export { type CancelFlowConfig, type CancelFlowOptions, type CancelFlowResult, type CancelOffer, type InAppMessage, type OnboardingFlow, type OnboardingStep, } from "./flows.js";
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  Experiment,
5
5
  FeedbackBoard,
6
6
  FeedbackWidget,
7
+ Messenger,
7
8
  Survey,
8
9
  Text,
9
10
  WIDGET_CSS,
@@ -13,6 +14,7 @@ import {
13
14
  useFeedback,
14
15
  useFlag,
15
16
  useFlagVariant,
17
+ useMessenger,
16
18
  usePush,
17
19
  useStyles,
18
20
  useVariant
@@ -45,6 +47,7 @@ export {
45
47
  FeedbackBoard,
46
48
  FeedbackWidget,
47
49
  ID_COOKIE,
50
+ Messenger,
48
51
  PREVIEW_PARAM,
49
52
  REFERRAL_COOKIE,
50
53
  SDK_VERSION,
@@ -67,6 +70,7 @@ export {
67
70
  useFeedback,
68
71
  useFlag,
69
72
  useFlagVariant,
73
+ useMessenger,
70
74
  usePush,
71
75
  useStyles,
72
76
  useVariant
package/dist/index.js.map CHANGED
@@ -1 +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 useCancelFlow,\n useCockpit,\n useFeedback,\n useFlag,\n useFlagVariant,\n usePush,\n useStyles,\n useVariant,\n} from \"./browser\";\nexport type { PushResult, PushStatus, WebPushOptions } from \"./push-web\";\nexport {\n type CockpitConfig,\n type CockpitEvent,\n type ConsentChoice,\n type ConsentMode,\n type ReplayConfig,\n type ErrorReport,\n type ExperimentConfig,\n type FlagCondition,\n type FlagConditionSet,\n type FlagConfig,\n type FlagPerson,\n type RedirectConfig,\n type RedirectDecision,\n type VariantConfig,\n type VariantId,\n EMBED_PARAM,\n EXPOSURE_PARAM,\n SDK_VERSION,\n ID_COOKIE,\n PREVIEW_PARAM,\n SESSION_COOKIE,\n assign,\n evaluateFlag,\n parsePreview,\n previewHref,\n redirectFor,\n} from \"./core\";\nexport {\n type CancelFlowConfig,\n type CancelFlowOptions,\n type CancelFlowResult,\n type CancelOffer,\n type InAppMessage,\n type OnboardingFlow,\n type OnboardingStep,\n} from \"./flows\";\nexport type { FlowsTheme } from \"./flows-ui\";\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,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAEP;AAAA,EAgBI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAWP;AAAA,EAII;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n type ChangelogEntry,\n type ChatMessage,\n type ChatThread,\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 MessengerProps,\n type PostStatus,\n type SurveyAnswer,\n type SurveyDefinition,\n type SurveyQuestion,\n type SurveyQuestionKind,\n CockpitProvider,\n Experiment,\n FeedbackBoard,\n FeedbackWidget,\n Messenger,\n Survey,\n Text,\n WIDGET_CSS,\n createApi,\n useCancelFlow,\n useCockpit,\n useFeedback,\n useFlag,\n useFlagVariant,\n useMessenger,\n usePush,\n useStyles,\n useVariant,\n} from \"./browser\";\nexport type { PushResult, PushStatus, WebPushOptions } from \"./push-web\";\nexport {\n type CockpitConfig,\n type CockpitEvent,\n type ConsentChoice,\n type ConsentMode,\n type ReplayConfig,\n type ErrorReport,\n type ExperimentConfig,\n type FlagCondition,\n type FlagConditionSet,\n type FlagConfig,\n type FlagPerson,\n type RedirectConfig,\n type RedirectDecision,\n type VariantConfig,\n type VariantId,\n EMBED_PARAM,\n EXPOSURE_PARAM,\n SDK_VERSION,\n ID_COOKIE,\n PREVIEW_PARAM,\n SESSION_COOKIE,\n assign,\n evaluateFlag,\n parsePreview,\n previewHref,\n redirectFor,\n} from \"./core\";\nexport {\n type CancelFlowConfig,\n type CancelFlowOptions,\n type CancelFlowResult,\n type CancelOffer,\n type InAppMessage,\n type OnboardingFlow,\n type OnboardingStep,\n} from \"./flows\";\nexport type { FlowsTheme } from \"./flows-ui\";\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,EAmBI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAEP;AAAA,EAgBI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAWP;AAAA,EAII;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;","names":[]}
@@ -0,0 +1,49 @@
1
+ export interface MessengerUiOptions {
2
+ host: string;
3
+ apiKey: string;
4
+ /** The visitor id now (it changes on identify and reset). */
5
+ distinctId: () => string;
6
+ /** The signed-in person's id, name and email, when the site called identify. */
7
+ user: () => {
8
+ id?: string;
9
+ name?: string;
10
+ email?: string;
11
+ } | undefined;
12
+ /** Show the round launcher (default true). Without it the panel opens only through `open()`. */
13
+ launcher?: boolean;
14
+ position?: "bottom-right" | "bottom-left";
15
+ /** The panel's title. */
16
+ title?: string;
17
+ /** The big line on Home and the first line of an empty chat. */
18
+ greeting?: string;
19
+ /** Ask anonymous visitors for an email (optional for them). Default true. */
20
+ askEmail?: boolean;
21
+ /** Text on the launcher; empty shows the icon only. */
22
+ label?: string;
23
+ /** How soon the team usually answers, said under "Send us a message" and in the chat's head. */
24
+ replyTime?: "minutes" | "hours" | "day";
25
+ /** The Help tab with the product's published help articles (default true; hidden while there are none). */
26
+ help?: boolean;
27
+ /** A short sound when an answer arrives (default true). */
28
+ sound?: boolean;
29
+ /** A preview of a new answer above the closed launcher (default true). */
30
+ preview?: boolean;
31
+ theme?: "light" | "dark" | "auto";
32
+ accent?: string;
33
+ }
34
+ export type MessengerView = "home" | "messages" | "help";
35
+ export interface MessengerHandle {
36
+ /** Opens the panel, on Home or the given tab; `{ article }` opens a help article. */
37
+ open(view?: MessengerView | {
38
+ article: string;
39
+ }): void;
40
+ close(): void;
41
+ toggle(): void;
42
+ /** Removes the launcher and the panel from the page. */
43
+ destroy(): void;
44
+ }
45
+ /**
46
+ * Mounts the messenger with its look from MRRocket (Support › Messenger) underneath what the code passes: an option the
47
+ * code sets wins, one it leaves out comes from MRRocket, then the default. Calls made before the look arrived wait.
48
+ */
49
+ export declare const mountMessenger: (o: MessengerUiOptions) => MessengerHandle;