@mrrocket/sdk 0.4.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/README.md +137 -8
- package/dist/api-client.d.ts +213 -0
- package/dist/api-client.js +67 -0
- package/dist/api-client.js.map +1 -0
- package/dist/api.d.ts +9 -109
- package/dist/api.js +7 -62
- package/dist/api.js.map +1 -1
- package/dist/browser/mrrocket-flows.js +64 -0
- package/dist/browser/mrrocket-messenger.js +313 -0
- package/dist/browser/mrrocket-push.js +1 -0
- package/dist/browser/mrrocket-replay.js +3 -3
- package/dist/browser/mrrocket-sw.js +1 -0
- package/dist/browser/mrrocket.js +2 -1
- package/dist/browser.d.ts +3 -2
- package/dist/browser.js +6 -1
- package/dist/browser.js.map +1 -1
- package/dist/capture.d.ts +1 -13
- package/dist/capture.js +1 -22
- package/dist/capture.js.map +1 -1
- package/dist/client.d.ts +36 -1
- package/dist/client.js +161 -6
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +10 -0
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +64 -3
- package/dist/core.js +54 -2
- package/dist/core.js.map +1 -1
- package/dist/feedback.d.ts +19 -4
- package/dist/feedback.js +655 -190
- package/dist/feedback.js.map +1 -1
- package/dist/flows-ui.d.ts +23 -0
- package/dist/flows-ui.js +384 -0
- package/dist/flows-ui.js.map +1 -0
- package/dist/flows-web.d.ts +19 -0
- package/dist/flows-web.js +42 -0
- package/dist/flows-web.js.map +1 -0
- package/dist/flows.d.ts +222 -0
- package/dist/flows.js +409 -0
- package/dist/flows.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +47 -0
- package/dist/messenger-ui.js +583 -0
- package/dist/messenger-ui.js.map +1 -0
- package/dist/messenger.d.ts +37 -0
- package/dist/messenger.js +69 -0
- package/dist/messenger.js.map +1 -0
- package/dist/proxy.d.ts +34 -1
- package/dist/proxy.js +14 -1
- package/dist/proxy.js.map +1 -1
- package/dist/push-web.d.ts +43 -0
- package/dist/push-web.js +81 -0
- package/dist/push-web.js.map +1 -0
- package/dist/rage.d.ts +14 -0
- package/dist/rage.js +27 -0
- package/dist/rage.js.map +1 -0
- package/dist/react-native/index.d.cts +640 -3
- package/dist/react-native/index.d.ts +640 -3
- package/dist/react-native/index.js +2015 -34
- package/dist/react-native/index.js.map +1 -1
- package/dist/styles-css.d.ts +6 -0
- package/dist/styles-css.js +327 -0
- package/dist/styles-css.js.map +1 -0
- package/dist/styles.d.ts +1 -2
- package/dist/styles.js +3 -134
- package/dist/styles.js.map +1 -1
- package/dist/ui.d.ts +3 -0
- package/dist/ui.js +12 -0
- package/dist/ui.js.map +1 -1
- package/package.json +20 -4
package/dist/feedback.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feedback.tsx"],"sourcesContent":["\"use client\";\n\nimport { type FormEvent, useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport { type ChangelogEntry, type FeedbackBoardInfo, type FeedbackComment, type FeedbackPost, type FeedbackRoadmap, useApi } from \"./api\";\nimport { Chat, ChevronUp, Cross, Plus, Root, StatusPill, type Theme, VoteButton, similarPosts, timeAgo, useEscape } from \"./ui\";\n\n/** Loads the post list and owns optimistic voting, so the board and the widget behave the same. */\nconst useFeedbackList = (opts: { board?: string; sort?: \"top\" | \"new\"; q?: string; limit?: number }) => {\n const api = useApi();\n const [posts, setPosts] = useState<FeedbackPost[]>([]);\n const [boards, setBoards] = useState<FeedbackBoardInfo[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n const { board, sort, q } = opts;\n\n useEffect(() => {\n const ctl = new AbortController();\n setLoading(true);\n const wait = window.setTimeout(\n () => {\n api.list({ board, sort, q: q?.trim() || undefined }, ctl.signal)\n .then((r) => {\n setPosts(r.posts);\n setBoards(r.boards);\n setError(\"\");\n setLoading(false);\n })\n .catch((e: Error) => {\n if (e.name === \"AbortError\") return;\n setError(e.message);\n setLoading(false);\n });\n },\n q ? 250 : 0,\n );\n return () => {\n window.clearTimeout(wait);\n ctl.abort();\n };\n }, [api, board, sort, q, tick]);\n\n const patch = useCallback((id: string, fn: (p: FeedbackPost) => FeedbackPost) => setPosts((all) => all.map((p) => (p.id === id ? fn(p) : p))), []);\n\n /** Flips the vote at once, then confirms with the server; on failure it flips back. */\n const vote = useCallback(\n (post: FeedbackPost) => {\n const flip = (p: FeedbackPost) => ({ ...p, voted: !p.voted, votes: p.votes + (p.voted ? -1 : 1) });\n patch(post.id, flip);\n api.vote(post.id)\n .then((r) => patch(post.id, (p) => ({ ...p, voted: r.voted, votes: r.votes })))\n .catch((e: Error) => {\n patch(post.id, flip);\n setError(`Your vote was not saved. ${e.message}`);\n });\n },\n [api, patch],\n );\n\n return { api, posts, setPosts, patch, boards, loading, error, setError, vote, reload: () => setTick((t) => t + 1) };\n};\n\n/** Title, details and board, with up to three similar requests to vote on instead. */\nconst SubmitForm = ({\n api,\n boards,\n posts,\n onCreated,\n onVote,\n onCancel,\n compact,\n}: {\n api: ReturnType<typeof useApi>;\n boards: FeedbackBoardInfo[];\n posts: FeedbackPost[];\n onCreated: (p: FeedbackPost) => void;\n onVote: (p: FeedbackPost) => void;\n onCancel?: () => void;\n compact?: boolean;\n}) => {\n const id = useId();\n const [title, setTitle] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [board, setBoard] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(\"\");\n const chosen = board || boards[0]?.id || \"\";\n const dupes = similarPosts(title, posts);\n\n const submit = async (e: FormEvent) => {\n e.preventDefault();\n if (!title.trim() || busy) return;\n setBusy(true);\n setError(\"\");\n try {\n const created = await api.submit({ title: title.trim(), body: body.trim() || undefined, board: chosen });\n setTitle(\"\");\n setBody(\"\");\n onCreated(created);\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <form className=\"ckw-form\" onSubmit={submit}>\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-t`}>\n Title\n </label>\n <input id={`${id}-t`} className=\"ckw-input\" value={title} maxLength={140} required autoFocus onChange={(e) => setTitle(e.target.value)} placeholder=\"Short, specific summary\" />\n </div>\n {dupes.length > 0 && (\n <div className=\"ckw-dupes\" role=\"status\">\n <p>Similar requests. Vote instead of adding a duplicate:</p>\n {dupes.map((d) => (\n <div className=\"ckw-dupe\" key={d.id}>\n <span title={d.title}>{d.title}</span>\n <button type=\"button\" className=\"ckw-btn\" disabled={d.voted} onClick={() => onVote(d)}>\n {d.voted ? \"Voted\" : \"Vote instead\"}\n </button>\n </div>\n ))}\n </div>\n )}\n {!compact && (\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-b`}>\n Details (optional)\n </label>\n <textarea id={`${id}-b`} className=\"ckw-textarea\" value={body} maxLength={2000} onChange={(e) => setBody(e.target.value)} placeholder=\"What are you trying to do?\" />\n </div>\n )}\n {boards.length > 1 && (\n <div className=\"ckw-field\">\n <label className=\"ckw-label\" htmlFor={`${id}-c`}>\n Board\n </label>\n <select id={`${id}-c`} className=\"ckw-select\" value={chosen} onChange={(e) => setBoard(e.target.value)}>\n {boards.map((b) => (\n <option key={b.id} value={b.id}>\n {b.label}\n </option>\n ))}\n </select>\n </div>\n )}\n {error && (\n <div className=\"ckw-error\" role=\"alert\">\n {error}\n </div>\n )}\n <div className=\"ckw-actions\">\n {onCancel && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onCancel}>\n Cancel\n </button>\n )}\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !title.trim()}>\n {busy ? \"Sending…\" : \"Submit request\"}\n </button>\n </div>\n </form>\n );\n};\n\nconst PostRow = ({ post, onOpen, onVote }: { post: FeedbackPost; onOpen: (p: FeedbackPost) => void; onVote: (p: FeedbackPost) => void }) => (\n <li className=\"ckw-row\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <button type=\"button\" className=\"ckw-link\" onClick={() => onOpen(post)}>\n {post.title}\n </button>\n {post.body && <p className=\"ckw-excerpt\">{post.body}</p>}\n <div className=\"ckw-meta\">\n <StatusPill status={post.status} />\n <span className=\"ckw-stat\">\n <Chat /> {post.comments}\n </span>\n <span>{timeAgo(post.createdAt)}</span>\n </div>\n </div>\n </li>\n);\n\nconst Skeleton = () => (\n <div aria-hidden=\"true\">\n {[0, 1, 2].map((i) => (\n <div className=\"ckw-skel\" key={i} />\n ))}\n </div>\n);\n\nconst ErrorBar = ({ message, onRetry, onClose }: { message: string; onRetry?: () => void; onClose?: () => void }) => (\n <div className=\"ckw-error\" role=\"alert\">\n <span>{message}</span>\n {onRetry ? (\n <button type=\"button\" className=\"ckw-btn\" onClick={onRetry}>\n Retry\n </button>\n ) : (\n onClose && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onClose} aria-label=\"Dismiss\">\n <Cross />\n </button>\n )\n )}\n </div>\n);\n\nconst PostDetail = ({ post, onBack, onVote }: { post: FeedbackPost; onBack: () => void; onVote: (p: FeedbackPost) => void }) => {\n const api = useApi();\n const id = useId();\n const [comments, setComments] = useState<FeedbackComment[] | null>(null);\n const [error, setError] = useState(\"\");\n const [text, setText] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [added, setAdded] = useState(0);\n\n useEffect(() => {\n const ctl = new AbortController();\n api.comments(post.id, ctl.signal)\n .then((r) => setComments(r.comments))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, post.id]);\n\n const send = async (e: FormEvent) => {\n e.preventDefault();\n const body = text.trim();\n if (!body || busy) return;\n setBusy(true);\n setError(\"\");\n // Show it at once; take it back if the server says no.\n const temp: FeedbackComment = { id: `tmp-${Date.now()}`, body, author: \"You\", isTeam: false, postedAt: new Date().toISOString() };\n setComments((c) => [...(c ?? []), temp]);\n setText(\"\");\n try {\n const real = await api.comment(post.id, body);\n setComments((c) => (c ?? []).map((x) => (x.id === temp.id ? real : x)));\n setAdded((n) => n + 1);\n } catch (err) {\n setComments((c) => (c ?? []).filter((x) => x.id !== temp.id));\n setText(body);\n setError((err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div>\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost ckw-back\" onClick={onBack}>\n <span style={{ display: \"inline-block\", transform: \"rotate(-90deg)\", lineHeight: 0 }}>\n <ChevronUp />\n </span>\n All requests\n </button>\n <div className=\"ckw-detail-head\">\n <VoteButton post={post} onVote={onVote} />\n <div className=\"ckw-main\">\n <h2>{post.title}</h2>\n <div className=\"ckw-meta\" style={{ marginTop: 0 }}>\n <StatusPill status={post.status} />\n <span>{timeAgo(post.createdAt)}</span>\n </div>\n </div>\n </div>\n {post.body && <p className=\"ckw-body\">{post.body}</p>}\n <h3 className=\"ckw-h\">Comments ({Math.max(post.comments + added, comments?.length ?? 0)})</h3>\n {error && <ErrorBar message={error} onClose={() => setError(\"\")} />}\n <div aria-live=\"polite\">\n {comments === null && !error && <Skeleton />}\n {comments?.length === 0 && <p className=\"ckw-sub\">No comments yet. Be the first.</p>}\n {comments?.map((c) => (\n <div className=\"ckw-comment\" key={c.id}>\n <b>{c.author}</b>\n {c.isTeam && <span className=\"ckw-team\">Team</span>}\n <span className=\"ckw-time\">{timeAgo(c.postedAt)}</span>\n <p>{c.body}</p>\n </div>\n ))}\n </div>\n <form className=\"ckw-form\" onSubmit={send} style={{ marginTop: 12 }}>\n <label className=\"ckw-label\" htmlFor={id}>\n Add a comment\n </label>\n <textarea id={id} className=\"ckw-textarea\" value={text} maxLength={2000} onChange={(e) => setText(e.target.value)} />\n <div className=\"ckw-actions\">\n <button type=\"submit\" className=\"ckw-btn ckw-btn-primary\" disabled={busy || !text.trim()}>\n Comment\n </button>\n </div>\n </form>\n </div>\n );\n};\n\ntype Tab = \"requests\" | \"roadmap\" | \"changelog\";\n\nconst Roadmap = ({ onOpen }: { onOpen: (p: FeedbackPost) => void }) => {\n const api = useApi();\n const [data, setData] = useState<FeedbackRoadmap | null>(null);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n useEffect(() => {\n const ctl = new AbortController();\n api.roadmap(ctl.signal)\n .then((r) => (setData(r), setError(\"\")))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, tick]);\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!data) return <Skeleton />;\n const cols: [keyof FeedbackRoadmap[\"columns\"], string][] = [\n [\"planned\", \"Planned\"],\n [\"progress\", \"In progress\"],\n [\"shipped\", \"Shipped\"],\n ];\n return (\n <div className=\"ckw-cols\">\n {cols.map(([k, label]) => (\n <section className=\"ckw-col\" key={k} aria-label={label}>\n <h3>\n {label} <span>{data.columns[k].length}</span>\n </h3>\n {data.columns[k].length === 0 && <p className=\"ckw-sub\">Nothing here yet.</p>}\n {data.columns[k].map((p) => (\n <div className=\"ckw-card\" key={p.id}>\n <button type=\"button\" className=\"ckw-link\" onClick={() => onOpen(p)}>\n {p.title}\n </button>\n <div className=\"ckw-meta\" style={{ marginTop: 0 }}>\n <span className=\"ckw-stat\">\n <ChevronUp /> {p.votes}\n </span>\n <span className=\"ckw-stat\">\n <Chat /> {p.comments}\n </span>\n </div>\n </div>\n ))}\n </section>\n ))}\n </div>\n );\n};\n\nconst Changelog = () => {\n const api = useApi();\n const [entries, setEntries] = useState<ChangelogEntry[] | null>(null);\n const [error, setError] = useState(\"\");\n const [tick, setTick] = useState(0);\n useEffect(() => {\n const ctl = new AbortController();\n api.changelog(ctl.signal)\n .then((r) => (setEntries(r.entries), setError(\"\")))\n .catch((e: Error) => e.name !== \"AbortError\" && setError(e.message));\n return () => ctl.abort();\n }, [api, tick]);\n if (error) return <ErrorBar message={error} onRetry={() => setTick((t) => t + 1)} />;\n if (!entries) return <Skeleton />;\n if (entries.length === 0) return <div className=\"ckw-empty\">No updates published yet.</div>;\n return (\n <div>\n {entries.map((e) => (\n <article className=\"ckw-entry\" key={e.id}>\n <time dateTime={e.publishedAt}>{new Date(e.publishedAt).toLocaleDateString(undefined, { month: \"long\", day: \"numeric\", year: \"numeric\" })}</time>\n <h3>{e.title}</h3>\n <p>{e.body}</p>\n </article>\n ))}\n </div>\n );\n};\n\nexport interface FeedbackBoardProps {\n /** Heading above the board. */\n title?: string;\n /** Line under the heading. */\n subtitle?: string;\n theme?: Theme;\n /** Accent color for buttons and votes. Default #3f76ff. */\n accent?: string;\n}\n\n/** The full board for a /feedback page: requests, roadmap and changelog, with voting, comments and a submit form. */\nexport const FeedbackBoard = ({ title = \"Feedback\", subtitle = \"Tell us what to build next and vote on what matters to you.\", theme, accent }: FeedbackBoardProps) => {\n const [tab, setTab] = useState<Tab>(\"requests\");\n const [sort, setSort] = useState<\"top\" | \"new\">(\"top\");\n const [board, setBoard] = useState<string | undefined>();\n const [q, setQ] = useState(\"\");\n const [creating, setCreating] = useState(false);\n const [opened, setOpened] = useState<FeedbackPost | null>(null);\n const list = useFeedbackList({ board, sort, q });\n const { posts, setPosts, vote } = list;\n\n // The open post follows the list's optimistic votes when it is in the list.\n const current = opened && (posts.find((p) => p.id === opened.id) ?? opened);\n const voteOpened = (p: FeedbackPost) => {\n if (!posts.some((x) => x.id === p.id)) {\n // Opened from the roadmap: it is not in this list, so vote through the list's server call and mirror it locally.\n setOpened((o) => (o ? { ...o, voted: !o.voted, votes: o.votes + (o.voted ? -1 : 1) } : o));\n list.api\n .vote(p.id)\n .then((r) => setOpened((o) => (o ? { ...o, voted: r.voted, votes: r.votes } : o)))\n .catch((e: Error) => {\n setOpened((o) => (o ? { ...o, voted: p.voted, votes: p.votes } : o));\n list.setError(`Your vote was not saved. ${e.message}`);\n });\n return;\n }\n vote(p);\n };\n\n const tabs: [Tab, string][] = [\n [\"requests\", \"Requests\"],\n [\"roadmap\", \"Roadmap\"],\n [\"changelog\", \"Changelog\"],\n ];\n const onTabKey = (e: React.KeyboardEvent) => {\n const i = tabs.findIndex(([k]) => k === tab);\n const n = e.key === \"ArrowRight\" ? i + 1 : e.key === \"ArrowLeft\" ? i - 1 : null;\n if (n === null) return;\n e.preventDefault();\n setTab(tabs[(n + tabs.length) % tabs.length][0]);\n setOpened(null);\n };\n\n return (\n <Root theme={theme} accent={accent} className=\"ckw-board\">\n <div className=\"ckw-head\">\n <div>\n <h2 className=\"ckw-title\">{title}</h2>\n {subtitle && <p className=\"ckw-sub\">{subtitle}</p>}\n </div>\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={() => (setCreating((c) => !c), setOpened(null), setTab(\"requests\"))} aria-expanded={creating}>\n <Plus /> Request a feature\n </button>\n </div>\n\n <div className=\"ckw-tabs\" role=\"tablist\" aria-label=\"Feedback sections\" onKeyDown={onTabKey}>\n {tabs.map(([k, label]) => (\n <button\n key={k}\n type=\"button\"\n role=\"tab\"\n id={`ckw-tab-${k}`}\n aria-selected={tab === k}\n tabIndex={tab === k ? 0 : -1}\n className=\"ckw-tab\"\n onClick={() => (setTab(k), setOpened(null))}\n >\n {label}\n </button>\n ))}\n </div>\n\n <div role=\"tabpanel\" aria-labelledby={`ckw-tab-${tab}`}>\n {list.error && <ErrorBar message={list.error} onRetry={tab === \"requests\" && !current ? list.reload : undefined} onClose={() => list.setError(\"\")} />}\n\n {current ? (\n <PostDetail post={current} onBack={() => setOpened(null)} onVote={voteOpened} />\n ) : tab === \"requests\" ? (\n <>\n {creating && (\n <SubmitForm\n api={list.api}\n boards={list.boards}\n posts={posts}\n onVote={vote}\n onCancel={() => setCreating(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all]);\n setCreating(false);\n }}\n />\n )}\n <div className=\"ckw-tools\">\n <input className=\"ckw-input ckw-search\" type=\"search\" aria-label=\"Search requests\" placeholder=\"Search requests\" value={q} onChange={(e) => setQ(e.target.value)} />\n <div className=\"ckw-seg\" role=\"group\" aria-label=\"Sort\">\n {([\"top\", \"new\"] as const).map((s) => (\n <button key={s} type=\"button\" aria-pressed={sort === s} onClick={() => setSort(s)}>\n {s === \"top\" ? \"Top\" : \"New\"}\n </button>\n ))}\n </div>\n </div>\n {list.boards.length > 1 && (\n <div className=\"ckw-chips\" role=\"group\" aria-label=\"Boards\">\n <button type=\"button\" className=\"ckw-chip\" aria-pressed={!board} onClick={() => setBoard(undefined)}>\n All\n </button>\n {list.boards.map((b) => (\n <button key={b.id} type=\"button\" className=\"ckw-chip\" aria-pressed={board === b.id} onClick={() => setBoard(b.id)}>\n {b.label}\n </button>\n ))}\n </div>\n )}\n <div aria-live=\"polite\" aria-busy={list.loading}>\n {list.loading && posts.length === 0 ? (\n <Skeleton />\n ) : posts.length === 0 && !list.error ? (\n <div className=\"ckw-empty\">{q ? \"No requests match your search.\" : \"No requests yet. Be the first to suggest something.\"}</div>\n ) : (\n <ul className=\"ckw-list\">\n {posts.map((p) => (\n <PostRow key={p.id} post={p} onOpen={setOpened} onVote={vote} />\n ))}\n </ul>\n )}\n </div>\n </>\n ) : tab === \"roadmap\" ? (\n <Roadmap onOpen={setOpened} />\n ) : (\n <Changelog />\n )}\n </div>\n </Root>\n );\n};\n\n// ---------- Floating widget ----------\n\nconst listeners = new Set<(open: boolean) => void>();\nlet widgetOpen = false;\nconst setWidgetOpen = (v: boolean) => {\n widgetOpen = v;\n listeners.forEach((l) => l(v));\n};\n\n/** Open or close the feedback widget from your own button. */\nexport const useFeedback = () => ({ open: () => setWidgetOpen(true), close: () => setWidgetOpen(false) });\n\nexport interface FeedbackWidgetProps {\n position?: \"bottom-right\" | \"bottom-left\";\n /** Text on the floating button. */\n label?: string;\n /** Where \"See all\" goes, for example your /feedback page. */\n boardUrl?: string;\n theme?: Theme;\n accent?: string;\n}\n\n/** The popover content. Mounted only while open, so a closed widget costs no request. */\nconst WidgetPanel = ({ boardUrl, onClose }: { boardUrl?: string; onClose: () => void }) => {\n const [suggesting, setSuggesting] = useState(false);\n const [thanks, setThanks] = useState(false);\n const list = useFeedbackList({ sort: \"top\" });\n const { posts, setPosts } = list;\n return (\n <>\n <div className=\"ckw-pop-head\">\n <span>{suggesting ? \"Suggest something\" : \"Top requests\"}</span>\n <button type=\"button\" className=\"ckw-btn ckw-btn-ghost\" onClick={onClose} aria-label=\"Close feedback\">\n <Cross />\n </button>\n </div>\n <div className=\"ckw-pop-body\">\n {list.error && <ErrorBar message={list.error} onClose={() => list.setError(\"\")} />}\n {thanks ? (\n <div className=\"ckw-empty\" role=\"status\">\n Thanks, your request is in.\n </div>\n ) : suggesting ? (\n <SubmitForm\n compact\n api={list.api}\n boards={list.boards}\n posts={posts}\n onVote={list.vote}\n onCancel={() => setSuggesting(false)}\n onCreated={(p) => {\n setPosts((all) => [p, ...all]);\n setSuggesting(false);\n setThanks(true);\n }}\n />\n ) : list.loading && posts.length === 0 ? (\n <Skeleton />\n ) : posts.length === 0 && !list.error ? (\n <div className=\"ckw-empty\">No requests yet. Suggest the first one.</div>\n ) : (\n <ul className=\"ckw-list\" aria-live=\"polite\">\n {posts.slice(0, 5).map((p) => (\n <li className=\"ckw-row\" key={p.id}>\n <VoteButton post={p} onVote={list.vote} />\n <div className=\"ckw-main\">\n <span style={{ fontWeight: 600, overflowWrap: \"anywhere\" }}>{p.title}</span>\n <div className=\"ckw-meta\">\n <StatusPill status={p.status} />\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n <div className=\"ckw-pop-foot\">\n {boardUrl ? <a href={boardUrl}>See all</a> : <span />}\n {!suggesting && !thanks && (\n <button type=\"button\" className=\"ckw-btn ckw-btn-primary\" onClick={() => setSuggesting(true)}>\n <Plus /> Suggest something\n </button>\n )}\n {thanks && (\n <button type=\"button\" className=\"ckw-btn\" onClick={() => setThanks(false)}>\n Back\n </button>\n )}\n </div>\n </>\n );\n};\n\n/** A floating button that opens a small popover with the top requests and a quick suggest form. */\nexport const FeedbackWidget = ({ position = \"bottom-right\", label = \"Feedback\", boardUrl, theme, accent }: FeedbackWidgetProps) => {\n const [open, setOpen] = useState(false);\n const fab = useRef<HTMLButtonElement>(null);\n const pop = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const l = (v: boolean) => setOpen(v);\n listeners.add(l);\n setOpen(widgetOpen);\n const click = (e: MouseEvent) => {\n if ((e.target as HTMLElement | null)?.closest(\"[data-ck-feedback]\")) {\n e.preventDefault();\n setWidgetOpen(true);\n }\n };\n document.addEventListener(\"click\", click);\n return () => {\n listeners.delete(l);\n document.removeEventListener(\"click\", click);\n };\n }, []);\n\n const close = useCallback(() => {\n setWidgetOpen(false);\n fab.current?.focus();\n }, []);\n useEscape(() => open && close());\n\n // Move focus into the popover when it opens.\n useEffect(() => {\n if (open) pop.current?.querySelector<HTMLElement>(\"button, input\")?.focus();\n }, [open]);\n\n // Keep Tab inside the popover while it is open.\n const trap = (e: React.KeyboardEvent) => {\n if (e.key !== \"Tab\" || !pop.current) return;\n const f = [...pop.current.querySelectorAll<HTMLElement>(\"a[href], button:not([disabled]), input, select, textarea\")];\n if (!f.length) return;\n const first = f[0];\n const last = f[f.length - 1];\n if (e.shiftKey && document.activeElement === first) (e.preventDefault(), last.focus());\n else if (!e.shiftKey && document.activeElement === last) (e.preventDefault(), first.focus());\n };\n\n return (\n <Root theme={theme} accent={accent}>\n <button ref={fab} type=\"button\" className=\"ckw-fab\" data-pos={position} aria-haspopup=\"dialog\" aria-expanded={open} onClick={() => (open ? close() : setWidgetOpen(true))}>\n <Chat /> {label}\n </button>\n {open && (\n <div ref={pop} className=\"ckw-pop\" data-pos={position} role=\"dialog\" aria-label=\"Feedback\" onKeyDown={trap}>\n <WidgetPanel boardUrl={boardUrl} onClose={close} />\n </div>\n )}\n </Root>\n );\n};\n"],"mappings":"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","names":[]}
|
|
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 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 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"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The web renderer of the cancel flow, onboarding and in-app messages (flows.ts): plain DOM, no React, so the Next.js
|
|
3
|
+
* provider and the script tag share it. Both load it only when something is about to show (a dynamic import, and
|
|
4
|
+
* `sdk-flows.js` for the script tag), so pages that show nothing never download it.
|
|
5
|
+
*
|
|
6
|
+
* Themeable three ways: `theme` ("light", "dark", "auto") and `accent` from the SDK's options, and CSS variables on
|
|
7
|
+
* `.ckf-root` in the site's own stylesheet (`--ckf-accent`, `--ckf-bg`, `--ckf-fg`, `--ckf-muted`, `--ckf-line`,
|
|
8
|
+
* `--ckf-radius`, `--ckf-font`). Every text is set with textContent; nothing from the server is parsed as HTML.
|
|
9
|
+
*/
|
|
10
|
+
import { type FlowsController } from "./flows.js";
|
|
11
|
+
export interface FlowsTheme {
|
|
12
|
+
theme?: "light" | "dark" | "auto";
|
|
13
|
+
/** The main color of buttons and highlights, like "#3f76ff". */
|
|
14
|
+
accent?: string;
|
|
15
|
+
/** An extra class on the root, for the site's own CSS. */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const FLOWS_CSS = "\n.ckf-root{--ckf-accent:#3f76ff;--ckf-accent-ink:#fff;--ckf-bg:#fff;--ckf-fg:#1c1d20;--ckf-muted:#5d6068;--ckf-soft:#f4f5f7;--ckf-line:#e4e5e8;--ckf-danger:#d92d20;--ckf-radius:14px;--ckf-font:inherit;--ckf-shadow:0 16px 40px -12px rgba(16,18,24,.28),0 0 0 1px rgba(16,18,24,.07)}\n.ckf-root[data-theme=dark]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}\n@media (prefers-color-scheme:dark){.ckf-root[data-theme=auto]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}}\n.ckf-root,.ckf-root *{box-sizing:border-box}\n.ckf-root{font-family:var(--ckf-font);font-size:14px;line-height:1.45;color:var(--ckf-fg);-webkit-font-smoothing:antialiased}\n.ckf-root :where(button,textarea){font:inherit;color:inherit;margin:0}\n.ckf-root :focus-visible{outline:2px solid var(--ckf-accent);outline-offset:2px}\n.ckf-scrim{position:fixed;inset:0;z-index:2147483002;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;padding:16px;animation:ckf-fade .15s ease-out}\n.ckf-card{position:relative;width:100%;max-width:400px;max-height:calc(100dvh - 32px);overflow-y:auto;background:var(--ckf-bg);color:var(--ckf-fg);border-radius:var(--ckf-radius);box-shadow:var(--ckf-shadow);padding:18px 20px 20px;display:flex;flex-direction:column;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-float{position:fixed;z-index:2147483001;right:20px;bottom:20px;width:340px;max-width:calc(100vw - 24px)}\n.ckf-top{display:flex;align-items:center;gap:8px;min-height:20px}\n.ckf-dots{display:flex;gap:4px}\n.ckf-dot{width:16px;height:4px;border-radius:4px;background:var(--ckf-line)}\n.ckf-dot[data-on]{background:var(--ckf-accent)}\n.ckf-x{margin-left:auto;width:28px;height:28px;border:0;border-radius:8px;background:none;color:var(--ckf-muted);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:18px;line-height:1}\n.ckf-x:hover{background:var(--ckf-soft);color:var(--ckf-fg)}\n.ckf-h{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;text-wrap:balance}\n.ckf-p{margin:0;color:var(--ckf-muted);text-wrap:pretty;white-space:pre-wrap}\n.ckf-small{margin:0;font-size:12px;color:var(--ckf-muted)}\n.ckf-opts{display:flex;flex-direction:column;gap:6px;margin:0;padding:0;list-style:none}\n.ckf-opt{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:8px 12px;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);text-align:left;cursor:pointer;font-weight:500}\n.ckf-opt:hover{background:var(--ckf-soft)}\n.ckf-opt[aria-checked=true]{border-color:var(--ckf-accent);background:color-mix(in srgb,var(--ckf-accent) 8%,var(--ckf-bg))}\n.ckf-radio{width:16px;height:16px;flex:none;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center}\n.ckf-opt[aria-checked=true] .ckf-radio{border-color:var(--ckf-accent)}\n.ckf-opt[aria-checked=true] .ckf-radio::after{content:\"\";width:8px;height:8px;border-radius:50%;background:var(--ckf-accent)}\n.ckf-box{border-radius:10px;background:var(--ckf-soft);padding:12px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}\n.ckf-big{font-size:22px;font-weight:650;font-variant-numeric:tabular-nums}\n.ckf-strike{color:var(--ckf-muted);text-decoration:line-through;font-variant-numeric:tabular-nums}\n.ckf-text{width:100%;min-height:64px;resize:vertical;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);padding:8px 10px}\n.ckf-text::placeholder{color:var(--ckf-muted)}\n.ckf-btns{display:flex;flex-direction:column;gap:6px}\n.ckf-btn{height:38px;padding:0 14px;border-radius:10px;border:1px solid var(--ckf-line);background:var(--ckf-bg);font-weight:600;cursor:pointer;transition:filter .1s linear,background-color .1s linear}\n.ckf-btn:hover{background:var(--ckf-soft)}\n.ckf-btn[disabled]{opacity:.55;cursor:not-allowed}\n.ckf-primary{background:var(--ckf-accent);border-color:var(--ckf-accent);color:var(--ckf-accent-ink)}\n.ckf-primary:hover{background:var(--ckf-accent);filter:brightness(1.07)}\n.ckf-danger{background:var(--ckf-danger);border-color:var(--ckf-danger);color:#fff}\n.ckf-danger:hover{background:var(--ckf-danger);filter:brightness(1.07)}\n.ckf-quiet{border-color:transparent;background:none;color:var(--ckf-muted);height:30px;font-weight:500}\n.ckf-quiet:hover{background:none;color:var(--ckf-fg)}\n.ckf-err{margin:0;color:var(--ckf-danger);font-size:13px;font-weight:500}\n.ckf-row{display:flex;justify-content:flex-end;gap:8px;align-items:center}\n.ckf-row .ckf-small{margin-right:auto}\n.ckf-ring{position:fixed;z-index:2147483000;pointer-events:none;border-radius:10px;box-shadow:0 0 0 2px var(--ckf-accent),0 0 0 6px color-mix(in srgb,var(--ckf-accent) 25%,transparent);transition:all .15s ease-out}\n.ckf-check{display:flex;align-items:flex-start;gap:10px;width:100%;padding:8px 6px;border:0;border-radius:8px;background:none;text-align:left}\n.ckf-check:where(button){cursor:pointer}\n.ckf-check:where(button):hover{background:var(--ckf-soft)}\n.ckf-tick{width:18px;height:18px;flex:none;margin-top:1px;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent-ink);font-size:11px;font-weight:700}\n.ckf-check[data-done] .ckf-tick{background:var(--ckf-accent);border-color:var(--ckf-accent)}\n.ckf-check[data-done] b{color:var(--ckf-muted);text-decoration:line-through}\n.ckf-check span{display:flex;flex-direction:column;gap:2px;min-width:0}\n.ckf-bar{height:4px;border-radius:4px;background:var(--ckf-soft);overflow:hidden}\n.ckf-bar i{display:block;height:100%;background:var(--ckf-accent)}\n.ckf-banner{position:fixed;z-index:2147483001;left:50%;top:12px;transform:translateX(-50%);width:min(640px,calc(100vw - 24px));background:var(--ckf-bg);border-radius:12px;box-shadow:var(--ckf-shadow);padding:10px 10px 10px 16px;display:flex;align-items:center;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-banner>span{flex:1;min-width:0;display:flex;flex-direction:column}\n.ckf-banner .ckf-btn{height:32px}\n@keyframes ckf-fade{from{opacity:0}}\n@keyframes ckf-in{from{opacity:0;transform:translateY(6px)}}\n.ckf-banner{animation-name:ckf-fade}\n@media (max-width:520px){.ckf-scrim{align-items:flex-end;padding:0}.ckf-scrim .ckf-card{max-width:none;border-radius:var(--ckf-radius) var(--ckf-radius) 0 0;max-height:92dvh}.ckf-float{right:12px;bottom:12px}}\n@media (prefers-reduced-motion:reduce){.ckf-root *{animation:none!important;transition:none!important}}\n";
|
|
19
|
+
/**
|
|
20
|
+
* Draws the controller's view into the page until the returned function is called. One root element under <body>;
|
|
21
|
+
* nothing is drawn while there is nothing to show.
|
|
22
|
+
*/
|
|
23
|
+
export declare const mountFlows: (ctl: FlowsController, theme?: FlowsTheme) => (() => void);
|