@fewchurs/react 1.5.0 → 1.6.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/dist/core.d.mts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/core.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +99 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +101 -16
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -0
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context/provider.tsx","../src/client/version.ts","../src/client/constants.ts","../src/client/errors.ts","../src/client/normalize.ts","../src/client/validate.ts","../src/client/client.ts","../src/identity/deviceId.ts","../src/store/keys.ts","../src/store/store.ts","../src/components/Board.tsx","../src/hooks/useFewchursConfig.ts","../src/hooks/useStoreState.ts","../src/components/BoardContext.tsx","../src/components/labels.ts","../src/components/Branding.tsx","../src/hooks/useFeature.ts","../src/hooks/useFeatures.ts","../src/hooks/useFollow.ts","../src/hooks/useVote.ts","../src/components/FeatureCard.tsx","../src/components/Comments.tsx","../src/hooks/useComments.ts","../src/components/time.ts","../src/components/FollowForm.tsx","../src/components/StatusBadge.tsx","../src/components/VoteButton.tsx","../src/components/Skeleton.tsx","../src/components/FeatureList.tsx","../src/components/SubmitForm.tsx","../src/hooks/useSubmitFeature.ts","../src/components/theme.ts","../src/components/BoardDialog.tsx","../src/components/BoardButton.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createFewchursClient, type FewchursClient } from \"../client/client\";\nimport { readDeviceId, resolveDeviceId } from \"../identity/deviceId\";\nimport { createStore, type EventHandler, type Store, type StoreState } from \"../store/store\";\n\nexport interface FewchursContextValue {\n client: FewchursClient;\n store: Store;\n deviceId: string | null;\n /** False only while a direct-to-API board is still waiting for its device id. */\n isReady: boolean;\n}\n\nconst FewchursContext = createContext<FewchursContextValue | null>(null);\n\nexport interface FewchursProviderProps {\n /** Publishable key for direct API calls. Omit when `baseUrl` points at your own proxy. */\n apiKey?: string;\n baseUrl?: string;\n /** A stable per-visitor id — hash it if it comes from your auth. */\n deviceId?: string;\n language?: string;\n pageSize?: number;\n /** Server-rendered data, so the first paint has real content. Set by `@fewchurs/next`. */\n initialState?: Partial<StoreState>;\n onEvent?: EventHandler;\n client?: FewchursClient;\n children: ReactNode;\n}\n\nexport function FewchursProvider({\n apiKey,\n baseUrl,\n deviceId: deviceIdProp,\n language,\n pageSize = 20,\n initialState,\n onEvent,\n client: clientProp,\n children,\n}: FewchursProviderProps): React.JSX.Element {\n // Read during the first render, not in an effect: child hooks fetch in effects that run\n // before this component's own effect, and a request without a device id is rejected.\n const [deviceId, setDeviceId] = useState<string | null>(() => deviceIdProp ?? readDeviceId());\n const deviceIdRef = useRef(deviceId);\n deviceIdRef.current = deviceIdProp ?? deviceId;\n\n const eventRef = useRef(onEvent);\n eventRef.current = onEvent;\n\n useEffect(() => {\n if (deviceIdProp) return;\n setDeviceId(resolveDeviceId());\n }, [deviceIdProp]);\n\n const client = useMemo(\n () =>\n clientProp ??\n createFewchursClient({\n apiKey,\n baseUrl,\n language,\n deviceId: () => deviceIdRef.current,\n }),\n [clientProp, apiKey, baseUrl, language],\n );\n\n const store = useMemo(\n () =>\n createStore(client, {\n pageSize,\n initialState,\n onEvent: (event) => eventRef.current?.(event),\n }),\n // initialState is a first-paint seed; a new object identity must not wipe live state.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, pageSize],\n );\n\n const value = useMemo<FewchursContextValue>(\n () => ({\n client,\n store,\n deviceId: deviceIdProp ?? deviceId,\n isReady: Boolean(deviceIdProp ?? deviceId) || !apiKey,\n }),\n [client, store, deviceIdProp, deviceId, apiKey],\n );\n\n return <FewchursContext.Provider value={value}>{children}</FewchursContext.Provider>;\n}\n\nexport function useFewchurs(): FewchursContextValue {\n const value = useContext(FewchursContext);\n if (!value) {\n throw new Error(\n \"Fewchurs components must be rendered inside <FewchursProvider>. In Next.js, <FewchursBoard> from @fewchurs/next provides one for you.\",\n );\n }\n return value;\n}\n","// Generated by tools/stamp-version.mjs from @fewchurs/react's package.json. Do not edit by hand.\nexport const SDK_VERSION = \"1.5.0\";\n","import type { FeatureStatus } from \"../types\";\nimport { SDK_VERSION } from \"./version\";\n\nexport { SDK_VERSION };\nexport const SDK_HEADER = `react/${SDK_VERSION}`;\nexport const DEFAULT_BASE_URL = \"https://www.fewchurs.com/api/v1\";\nexport const DEFAULT_PAGE_SIZE = 20;\n\n/** Mirrors the server's zod schemas, so the UI can reject input before a round trip. */\nexport const LIMITS = {\n titleMin: 3,\n titleMax: 100,\n descriptionMax: 1000,\n commentMin: 1,\n commentMax: 1000,\n authorNameMax: 60,\n} as const;\n\n/** Deliberately loose: the server owns the real check, this only catches obvious typos. */\nexport const EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/** What the Roadmap tab asks for, and what it keeps if the server ignores the filter. */\nexport const ROADMAP_STATUSES: FeatureStatus[] = [\"planned\", \"in_progress\", \"done\"];\n","export type FewchursError =\n | { code: \"invalid_key\"; status: 401 | 403; message: string }\n | { code: \"validation_failed\"; status: 400; message: string }\n | { code: \"rate_limited\"; status: 429; message: string }\n | { code: \"not_found\"; status: 404; message: string }\n | { code: \"limit_reached\"; status: 402; message: string }\n | { code: \"server\"; status: number; message: string }\n | { code: \"network\"; message: string };\n\nexport type Result<T> = { ok: true; data: T } | { ok: false; error: FewchursError };\n\ninterface ServerErrorBody {\n error?: { code?: string; message?: string };\n}\n\nexport const NOT_CONFIGURED_MESSAGE = \"Fewchurs is not configured.\";\n\nconst USER_MESSAGES: Record<FewchursError[\"code\"], string> = {\n invalid_key: \"Invalid API key. Check the key in your Fewchurs dashboard.\",\n validation_failed: \"Invalid input.\",\n rate_limited: \"You've reached today's limit. Try again tomorrow.\",\n not_found: \"This request no longer exists.\",\n limit_reached: \"This board isn't accepting requests right now.\",\n server: \"Something went wrong. Try again.\",\n network: \"You're offline.\",\n};\n\nexport function isWrongApp(error: FewchursError): boolean {\n return error.code === \"invalid_key\" && error.status === 403;\n}\n\nexport function isNotConfigured(error: FewchursError): boolean {\n return error.code === \"server\" && error.message === NOT_CONFIGURED_MESSAGE;\n}\n\nexport function notConfiguredError(): FewchursError {\n return { code: \"server\", status: 500, message: NOT_CONFIGURED_MESSAGE };\n}\n\n/** Safe to show a visitor. Only validation and `wrong_app` use the server's own text. */\nexport function userMessage(error: FewchursError): string {\n if (error.code === \"validation_failed\" && error.message) return error.message;\n if (isWrongApp(error) && error.message) return error.message;\n return USER_MESSAGES[error.code];\n}\n\nexport function networkError(message = \"Network request failed.\"): FewchursError {\n return { code: \"network\", message };\n}\n\nexport function validationError(message: string): FewchursError {\n return { code: \"validation_failed\", status: 400, message };\n}\n\nexport function errorFromResponse(status: number, body: unknown): FewchursError {\n const code = (body as ServerErrorBody | null)?.error?.code;\n const serverMessage = (body as ServerErrorBody | null)?.error?.message;\n const message = serverMessage ?? `Request failed (${status}).`;\n\n switch (code) {\n case \"invalid_key\":\n return { code: \"invalid_key\", status: 401, message };\n case \"wrong_app\":\n return { code: \"invalid_key\", status: 403, message };\n case \"missing_device_id\":\n return { code: \"server\", status: 400, message };\n case \"validation_failed\":\n return { code: \"validation_failed\", status: 400, message: serverMessage ?? \"Invalid input.\" };\n case \"rate_limited\":\n return { code: \"rate_limited\", status: 429, message };\n case \"not_found\":\n return { code: \"not_found\", status: 404, message };\n case \"limit_reached\":\n return { code: \"limit_reached\", status: 402, message };\n default:\n return status === 401\n ? { code: \"invalid_key\", status: 401, message }\n : { code: \"server\", status, message };\n }\n}\n","import type {\n Comment,\n CommentPage,\n Feature,\n FeaturePage,\n FeatureStatus,\n FewchursConfig,\n} from \"../types\";\n\nconst KNOWN_STATUSES = new Set<string>([\"open\", \"planned\", \"in_progress\", \"done\", \"declined\"]);\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nfunction str(value: unknown, fallback = \"\"): string {\n return typeof value === \"string\" ? value : fallback;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction bool(value: unknown): boolean {\n return value === true;\n}\n\nexport function normalizeStatus(value: unknown): FeatureStatus {\n return typeof value === \"string\" && KNOWN_STATUSES.has(value)\n ? (value as FeatureStatus)\n : \"unknown\";\n}\n\n// `isMine` is the server's answer once it ships; until then the raw author device id is the\n// only signal, so it is compared here and never surfaced on the public type.\nfunction isMine(raw: Record<string, unknown>, ownerKey: string, deviceId: string | null): boolean {\n if (typeof raw.isMine === \"boolean\") return raw.isMine;\n const owner = raw[ownerKey];\n return typeof owner === \"string\" && owner.length > 0 && owner === deviceId;\n}\n\nexport function normalizeFeature(value: unknown, deviceId: string | null): Feature {\n const raw = asRecord(value);\n return {\n id: str(raw.id),\n title: str(raw.title),\n description: str(raw.description),\n status: normalizeStatus(raw.status),\n upvoteCount: num(raw.upvoteCount),\n commentCount: num(raw.commentCount),\n followerCount: num(raw.followerCount),\n hasVoted: bool(raw.hasVoted),\n isFollowing: bool(raw.isFollowing),\n isMine: isMine(raw, \"authorDeviceId\", deviceId),\n createdAt: str(raw.createdAt),\n updatedAt: str(raw.updatedAt, str(raw.createdAt)),\n };\n}\n\nexport function normalizeComment(value: unknown, deviceId: string | null): Comment {\n const raw = asRecord(value);\n return {\n id: str(raw.id),\n text: str(raw.text),\n authorName: str(raw.authorName, \"App User\"),\n isDeveloper: bool(raw.isDeveloper),\n isMine: isMine(raw, \"deviceId\", deviceId),\n createdAt: str(raw.createdAt),\n };\n}\n\nexport function normalizeFeaturePage(value: unknown, deviceId: string | null): FeaturePage {\n const raw = asRecord(value);\n const features = Array.isArray(raw.features) ? raw.features : [];\n return {\n features: features.map((feature) => normalizeFeature(feature, deviceId)),\n nextCursor: typeof raw.nextCursor === \"string\" ? raw.nextCursor : null,\n };\n}\n\nexport function normalizeCommentPage(value: unknown, deviceId: string | null): CommentPage {\n const raw = asRecord(value);\n const comments = Array.isArray(raw.comments) ? raw.comments : [];\n return {\n comments: comments.map((comment) => normalizeComment(comment, deviceId)),\n nextCursor: typeof raw.nextCursor === \"string\" ? raw.nextCursor : null,\n };\n}\n\nexport function normalizeConfig(value: unknown): FewchursConfig {\n const raw = asRecord(value);\n return {\n showBranding: raw.showBranding !== false,\n hideVoteCounts: bool(raw.hideVoteCounts),\n appName: typeof raw.appName === \"string\" && raw.appName ? raw.appName : null,\n };\n}\n\nexport function normalizeVote(value: unknown): { upvoteCount: number; hasVoted: boolean } {\n const raw = asRecord(value);\n return { upvoteCount: num(raw.upvoteCount), hasVoted: bool(raw.hasVoted) };\n}\n","import { EMAIL_PATTERN, LIMITS } from \"./constants\";\nimport { validationError, type FewchursError } from \"./errors\";\nimport type { CreateCommentInput, SubmitFeatureInput } from \"../types\";\n\nexport function validateFeatureInput(input: SubmitFeatureInput): FewchursError | null {\n const title = input.title.trim();\n if (title.length < LIMITS.titleMin || title.length > LIMITS.titleMax) {\n return validationError(`Title must be ${LIMITS.titleMin}–${LIMITS.titleMax} characters.`);\n }\n if ((input.description ?? \"\").trim().length > LIMITS.descriptionMax) {\n return validationError(`Description must be at most ${LIMITS.descriptionMax} characters.`);\n }\n if (input.email !== undefined && input.email !== \"\" && !isEmail(input.email)) {\n return validationError(\"Enter a valid email address.\");\n }\n return null;\n}\n\nexport function validateCommentInput(input: CreateCommentInput): FewchursError | null {\n const text = input.text.trim();\n if (text.length < LIMITS.commentMin || text.length > LIMITS.commentMax) {\n return validationError(`Comment must be ${LIMITS.commentMin}–${LIMITS.commentMax} characters.`);\n }\n if ((input.authorName ?? \"\").trim().length > LIMITS.authorNameMax) {\n return validationError(`Name must be at most ${LIMITS.authorNameMax} characters.`);\n }\n return null;\n}\n\nexport function validateEmail(email: string): FewchursError | null {\n return isEmail(email) ? null : validationError(\"Enter a valid email address.\");\n}\n\nfunction isEmail(email: string): boolean {\n return EMAIL_PATTERN.test(email.trim());\n}\n","import { DEFAULT_BASE_URL, DEFAULT_PAGE_SIZE, SDK_HEADER } from \"./constants\";\nimport {\n errorFromResponse,\n isNotConfigured,\n networkError,\n notConfiguredError,\n type FewchursError,\n type Result,\n} from \"./errors\";\nimport {\n normalizeComment,\n normalizeCommentPage,\n normalizeConfig,\n normalizeFeature,\n normalizeFeaturePage,\n normalizeVote,\n} from \"./normalize\";\nimport { validateCommentInput, validateEmail, validateFeatureInput } from \"./validate\";\nimport type {\n Comment,\n CommentPage,\n CreateCommentInput,\n Feature,\n FeaturePage,\n FewchursConfig,\n ListCommentsParams,\n ListFeaturesParams,\n SubmitFeatureInput,\n} from \"../types\";\n\nexport type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;\n\nexport interface FewchursClientOptions {\n /** Server-side, or in a SPA where the key is publishable. Omit when calling your own proxy. */\n apiKey?: string;\n /** `https://www.fewchurs.com/api/v1` by default, or a proxy path such as `/api/fewchurs`. */\n baseUrl?: string;\n deviceId?: string | null | (() => string | null);\n /** Sent as `Accept-Language`, so server-side copy and emails match the visitor. */\n language?: string;\n /**\n * The domain the API key is checked against, for calls made from a server. A browser reports\n * its own domain through `Origin`, which always wins, so leave this out in a SPA.\n */\n appId?: string;\n fetch?: FetchLike;\n retries?: number;\n retryDelayMs?: number;\n}\n\nexport interface FewchursClient {\n readonly baseUrl: string;\n getDeviceId(): string | null;\n getConfig(signal?: AbortSignal): Promise<Result<FewchursConfig>>;\n listFeatures(params?: ListFeaturesParams, signal?: AbortSignal): Promise<Result<FeaturePage>>;\n getFeature(featureId: string, signal?: AbortSignal): Promise<Result<Feature>>;\n submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;\n vote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n unvote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n follow(featureId: string, email: string): Promise<Result<{ following: boolean }>>;\n unfollow(featureId: string): Promise<Result<{ following: boolean }>>;\n listComments(\n featureId: string,\n params?: ListCommentsParams,\n signal?: AbortSignal,\n ): Promise<Result<CommentPage>>;\n createComment(input: CreateCommentInput): Promise<Result<Comment>>;\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: unknown;\n query?: Record<string, string | number | undefined | null>;\n signal?: AbortSignal;\n}\n\nexport function createFewchursClient(options: FewchursClientOptions = {}): FewchursClient {\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n const doFetch = options.fetch ?? globalThis.fetch?.bind(globalThis);\n const retries = options.retries ?? 1;\n const retryDelayMs = options.retryDelayMs ?? 250;\n\n if (options.apiKey && !options.apiKey.startsWith(\"fr_\")) logOnce(BAD_KEY_PREFIX);\n\n function getDeviceId(): string | null {\n return typeof options.deviceId === \"function\" ? options.deviceId() : (options.deviceId ?? null);\n }\n\n function headers(hasBody: boolean): Record<string, string> {\n const result: Record<string, string> = {\n Accept: \"application/json\",\n \"X-Fewchurs-Sdk\": SDK_HEADER,\n };\n if (hasBody) result[\"Content-Type\"] = \"application/json\";\n if (options.apiKey) result.Authorization = `Bearer ${options.apiKey}`;\n const deviceId = getDeviceId();\n if (deviceId) result[\"X-Device-Id\"] = deviceId;\n if (options.language) result[\"Accept-Language\"] = options.language;\n if (options.appId) result[\"X-Fewchurs-App-Id\"] = options.appId;\n return result;\n }\n\n function url(path: string, query?: RequestOptions[\"query\"]): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(query ?? {})) {\n if (value !== undefined && value !== null && value !== \"\") search.set(key, String(value));\n }\n const qs = search.toString();\n return `${baseUrl}${path}${qs ? `?${qs}` : \"\"}`;\n }\n\n async function request<T>(\n path: string,\n map: (body: unknown) => T,\n { method = \"GET\", body, query, signal }: RequestOptions = {},\n ): Promise<Result<T>> {\n if (!doFetch) return { ok: false, error: networkError(\"No fetch implementation available.\") };\n if (!options.apiKey && options.baseUrl === undefined) {\n const failure = notConfiguredError();\n logError(failure);\n return { ok: false, error: failure };\n }\n\n const target = url(path, query);\n const init: RequestInit = { method, headers: headers(body !== undefined) };\n if (body !== undefined) init.body = JSON.stringify(body);\n if (signal) init.signal = signal;\n\n // Only GETs are retried: a retried POST could double-submit a request or a comment.\n const attempts = method === \"GET\" ? retries + 1 : 1;\n\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n let response: Response;\n try {\n response = await doFetch(target, init);\n } catch (error) {\n if (signal?.aborted) return { ok: false, error: networkError(\"Request aborted.\") };\n if (attempt < attempts - 1) {\n await delay(retryDelayMs);\n continue;\n }\n const failure = networkError(messageOf(error));\n logError(failure);\n return { ok: false, error: failure };\n }\n\n if (response.ok) {\n const payload = await readJson(response);\n return { ok: true, data: map(payload) };\n }\n\n if (response.status >= 500 && attempt < attempts - 1) {\n await delay(retryDelayMs);\n continue;\n }\n\n const failure = errorFromResponse(response.status, await readJson(response));\n logError(failure);\n return { ok: false, error: failure };\n }\n\n return { ok: false, error: networkError() };\n }\n\n return {\n baseUrl,\n getDeviceId,\n\n getConfig: (signal) => request(\"/config\", normalizeConfig, { signal }),\n\n listFeatures: (params = {}, signal) =>\n request(\"/features\", (body) => normalizeFeaturePage(body, getDeviceId()), {\n query: {\n sort: params.sort ?? \"new\",\n limit: params.limit ?? DEFAULT_PAGE_SIZE,\n cursor: params.cursor ?? undefined,\n status: params.status?.length ? params.status.join(\",\") : undefined,\n },\n signal,\n }),\n\n getFeature: (featureId, signal) =>\n request(\n `/features/${encodeURIComponent(featureId)}`,\n (body) => normalizeFeature(body, getDeviceId()),\n { signal },\n ),\n\n submitFeature: async (input) => {\n const invalid = validateFeatureInput(input);\n if (invalid) return { ok: false, error: invalid };\n return request(\"/features\", (body) => normalizeFeature(body, getDeviceId()), {\n method: \"POST\",\n body: {\n title: input.title.trim(),\n description: (input.description ?? \"\").trim(),\n ...(input.email ? { email: input.email.trim() } : {}),\n isSubscriber: input.isSubscriber ?? false,\n },\n });\n },\n\n vote: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/vote`, normalizeVote, { method: \"POST\" }),\n\n unvote: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/vote`, normalizeVote, {\n method: \"DELETE\",\n }),\n\n follow: async (featureId, email) => {\n const invalid = validateEmail(email);\n if (invalid) return { ok: false, error: invalid };\n return request(\n `/features/${encodeURIComponent(featureId)}/follow`,\n () => ({ following: true }),\n {\n method: \"POST\",\n body: { email: email.trim() },\n },\n );\n },\n\n unfollow: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/follow`, () => ({ following: false }), {\n method: \"DELETE\",\n }),\n\n listComments: (featureId, params = {}, signal) =>\n request(\n `/features/${encodeURIComponent(featureId)}/comments`,\n (body) => normalizeCommentPage(body, getDeviceId()),\n {\n query: { limit: params.limit ?? DEFAULT_PAGE_SIZE, cursor: params.cursor ?? undefined },\n signal,\n },\n ),\n\n // The server takes the feature id in the body here; POST /features/{id}/comments is a 405.\n createComment: async (input) => {\n const invalid = validateCommentInput(input);\n if (invalid) return { ok: false, error: invalid };\n return request(\"/comments\", (body) => normalizeComment(body, getDeviceId()), {\n method: \"POST\",\n body: {\n featureId: input.featureId,\n text: input.text.trim(),\n ...(input.authorName?.trim() ? { authorName: input.authorName.trim() } : {}),\n },\n });\n },\n };\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : \"Network request failed.\";\n}\n\n// Declared, not imported from @types/node: this is a browser package, and bundlers replace\n// `process.env.NODE_ENV` inline, so the check costs nothing in a production build.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\n\nconst INVALID_KEY_HELP =\n \"Fewchurs rejected the API key. Check the key in your dashboard (Apps → API keys).\";\n\nconst NOT_CONFIGURED_HELP =\n \"Fewchurs is not configured. Pass apiKey to FewchursProvider, or set FEWCHURS_API_KEY on your server.\";\n\nconst BAD_KEY_PREFIX = 'The Fewchurs API key should start with \"fr_\". Copy it from your dashboard.';\n\nconst loggedErrors = new Set<string>();\n\nfunction logOnce(detail: string): void {\n if (typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\") return;\n if (loggedErrors.has(detail)) return;\n loggedErrors.add(detail);\n console.warn(`[fewchurs] : ${detail}`);\n}\n\nfunction logError(error: FewchursError): void {\n if (isNotConfigured(error)) return logOnce(NOT_CONFIGURED_HELP);\n const isInvalidKey = error.code === \"invalid_key\" && error.status === 401;\n logOnce(isInvalidKey ? INVALID_KEY_HELP : error.message);\n}\n","const COOKIE_NAME = \"fewchurs_did\";\nconst STORAGE_KEY = \"fewchurs_device_id\";\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 365;\n\nexport function createDeviceId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `fw-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n}\n\nexport function readDeviceId(): string | null {\n if (typeof document === \"undefined\") return null;\n return readCookie() ?? readStorage();\n}\n\n/**\n * Cookie first, storage second: a cookie is the only copy a same-origin server can read, so\n * the board renders with the same identity on both sides and never mismatches on hydration.\n */\nexport function resolveDeviceId(): string {\n const existing = readDeviceId();\n if (existing) {\n persist(existing);\n return existing;\n }\n const created = createDeviceId();\n persist(created);\n return created;\n}\n\nfunction persist(deviceId: string): void {\n if (typeof document === \"undefined\") return;\n try {\n document.cookie = `${COOKIE_NAME}=${encodeURIComponent(deviceId)}; path=/; max-age=${COOKIE_MAX_AGE}; SameSite=Lax`;\n } catch {\n // Cookies can be blocked entirely; storage below is the fallback.\n }\n try {\n localStorage.setItem(STORAGE_KEY, deviceId);\n } catch {\n // Private-mode storage throws on write; the cookie or a fresh id per visit still works.\n }\n}\n\nfunction readCookie(): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|; )${COOKIE_NAME}=([^;]*)`));\n return match?.[1] ? decodeURIComponent(match[1]) : null;\n}\n\nfunction readStorage(): string | null {\n try {\n return localStorage.getItem(STORAGE_KEY);\n } catch {\n return null;\n }\n}\n\nexport { COOKIE_NAME as DEVICE_ID_COOKIE };\n","import type { FeatureStatus, FeatureSort } from \"../types\";\n\nexport interface ListQuery {\n sort: FeatureSort;\n status?: FeatureStatus[];\n}\n\nexport function listKey({ sort, status }: ListQuery): string {\n return status?.length ? `${sort}:${[...status].sort().join(\",\")}` : sort;\n}\n\n/**\n * One feature, fetched by id, kept in `lists` beside the real lists. That way a deep-linked\n * request goes through the same vote, comment and follow updates as a row in a list.\n */\nexport function featureKey(featureId: string): string {\n return `feature:${featureId}`;\n}\n","import type { FewchursClient } from \"../client/client\";\nimport type { FewchursError, Result } from \"../client/errors\";\nimport type {\n Comment,\n CreateCommentInput,\n Feature,\n FewchursConfig,\n SubmitFeatureInput,\n} from \"../types\";\nimport { featureKey, listKey, type ListQuery } from \"./keys\";\n\nexport type LoadStatus = \"idle\" | \"loading\" | \"loadingMore\" | \"ready\" | \"error\";\n\nexport interface ListState {\n features: Feature[];\n cursor: string | null;\n status: LoadStatus;\n error: FewchursError | null;\n}\n\nexport interface CommentsState {\n comments: Comment[];\n cursor: string | null;\n status: LoadStatus;\n error: FewchursError | null;\n}\n\nexport interface StoreState {\n config: FewchursConfig | null;\n lists: Record<string, ListState>;\n comments: Record<string, CommentsState>;\n}\n\nexport type FewchursEventName =\n \"boardOpened\" | \"featureSubmitted\" | \"voted\" | \"commented\" | \"followed\" | \"error\";\n\nexport interface FewchursEvent {\n name: FewchursEventName;\n featureId?: string;\n hasVoted?: boolean;\n following?: boolean;\n error?: FewchursError;\n}\n\nexport type EventHandler = (event: FewchursEvent) => void;\n\nexport interface StoreOptions {\n pageSize?: number;\n initialState?: Partial<StoreState>;\n onEvent?: EventHandler;\n}\n\nexport interface Store {\n subscribe(listener: () => void): () => void;\n getState(): StoreState;\n ensureConfig(): void;\n ensureFeatures(query: ListQuery, pageSize?: number): void;\n ensureFeature(featureId: string): void;\n refreshFeature(featureId: string): Promise<void>;\n refresh(query: ListQuery, pageSize?: number): Promise<void>;\n loadMore(query: ListQuery, pageSize?: number): Promise<void>;\n ensureComments(featureId: string): void;\n refreshComments(featureId: string): Promise<void>;\n loadMoreComments(featureId: string): Promise<void>;\n toggleVote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;\n addComment(input: CreateCommentInput): Promise<Result<Comment>>;\n setFollowing(featureId: string, email: string | null): Promise<Result<{ following: boolean }>>;\n emit(event: FewchursEvent): void;\n}\n\nconst EMPTY_LIST: ListState = { features: [], cursor: null, status: \"idle\", error: null };\nconst EMPTY_COMMENTS: CommentsState = { comments: [], cursor: null, status: \"idle\", error: null };\n\n// The server filters deleted comments after paging, so a page can come back empty while a\n// cursor remains. Follow the cursor a few times before showing \"no comments yet\".\nconst MAX_EMPTY_PAGES = 5;\n\nexport function createStore(\n client: FewchursClient,\n { pageSize = 20, initialState, onEvent }: StoreOptions = {},\n): Store {\n let state: StoreState = {\n config: initialState?.config ?? null,\n lists: initialState?.lists ?? {},\n comments: initialState?.comments ?? {},\n };\n\n const listeners = new Set<() => void>();\n const inFlight = new Map<string, Promise<void>>();\n\n function setState(next: Partial<StoreState>): void {\n state = { ...state, ...next };\n for (const listener of listeners) listener();\n }\n\n function setList(key: string, patch: Partial<ListState>): void {\n const current = state.lists[key] ?? EMPTY_LIST;\n setState({ lists: { ...state.lists, [key]: { ...current, ...patch } } });\n }\n\n function setComments(featureId: string, patch: Partial<CommentsState>): void {\n const current = state.comments[featureId] ?? EMPTY_COMMENTS;\n setState({ comments: { ...state.comments, [featureId]: { ...current, ...patch } } });\n }\n\n function emit(event: FewchursEvent): void {\n onEvent?.(event);\n }\n\n function fail(error: FewchursError): void {\n emit({ name: \"error\", error });\n }\n\n /** One request per key at a time: a remounting board must not double-fetch page one. */\n function dedupe(key: string, run: () => Promise<void>): Promise<void> {\n const existing = inFlight.get(key);\n if (existing) return existing;\n const promise = run().finally(() => inFlight.delete(key));\n inFlight.set(key, promise);\n return promise;\n }\n\n function mapFeature(featureId: string, update: (feature: Feature) => Feature): void {\n const lists: Record<string, ListState> = {};\n let changed = false;\n for (const [key, list] of Object.entries(state.lists)) {\n const index = list.features.findIndex((feature) => feature.id === featureId);\n if (index === -1) {\n lists[key] = list;\n continue;\n }\n changed = true;\n const features = [...list.features];\n features[index] = update(features[index] as Feature);\n lists[key] = { ...list, features };\n }\n if (changed) setState({ lists });\n }\n\n async function fetchFeatures(query: ListQuery, append: boolean, size: number): Promise<void> {\n const key = listKey(query);\n const current = state.lists[key] ?? EMPTY_LIST;\n if (append && !current.cursor) return;\n\n setList(key, { status: append ? \"loadingMore\" : \"loading\", error: null });\n\n const result = await client.listFeatures({\n sort: query.sort,\n status: query.status,\n limit: size,\n cursor: append ? current.cursor : null,\n });\n\n if (!result.ok) {\n setList(key, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n\n const previous = append ? (state.lists[key]?.features ?? []) : [];\n setList(key, {\n features: dedupeById([...previous, ...result.data.features]),\n cursor: result.data.nextCursor,\n status: \"ready\",\n error: null,\n });\n }\n\n async function fetchFeature(featureId: string): Promise<void> {\n const key = featureKey(featureId);\n setList(key, { status: \"loading\", error: null });\n\n const result = await client.getFeature(featureId);\n if (!result.ok) {\n setList(key, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n\n setList(key, { features: [result.data], cursor: null, status: \"ready\", error: null });\n }\n\n async function fetchComments(featureId: string, append: boolean): Promise<void> {\n const current = state.comments[featureId] ?? EMPTY_COMMENTS;\n if (append && !current.cursor) return;\n\n setComments(featureId, { status: append ? \"loadingMore\" : \"loading\", error: null });\n\n let cursor = append ? current.cursor : null;\n const collected: Comment[] = [];\n\n for (let page = 0; page < MAX_EMPTY_PAGES; page += 1) {\n const result = await client.listComments(featureId, { limit: pageSize, cursor });\n if (!result.ok) {\n setComments(featureId, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n collected.push(...result.data.comments);\n cursor = result.data.nextCursor;\n if (collected.length > 0 || !cursor) break;\n }\n\n const previous = append ? (state.comments[featureId]?.comments ?? []) : [];\n setComments(featureId, {\n comments: dedupeById([...previous, ...collected]),\n cursor,\n status: \"ready\",\n error: null,\n });\n }\n\n return {\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n getState: () => state,\n\n emit,\n\n ensureConfig() {\n if (state.config) return;\n void dedupe(\"config\", async () => {\n const result = await client.getConfig();\n if (result.ok) setState({ config: result.data });\n });\n },\n\n ensureFeatures(query, size = pageSize) {\n const key = listKey(query);\n if ((state.lists[key] ?? EMPTY_LIST).status !== \"idle\") return;\n void dedupe(`features:${key}`, () => fetchFeatures(query, false, size));\n },\n\n refresh(query, size = pageSize) {\n return dedupe(`features:${listKey(query)}`, () => fetchFeatures(query, false, size));\n },\n\n loadMore(query, size = pageSize) {\n return dedupe(`features:more:${listKey(query)}`, () => fetchFeatures(query, true, size));\n },\n\n ensureFeature(featureId) {\n if ((state.lists[featureKey(featureId)] ?? EMPTY_LIST).status !== \"idle\") return;\n void dedupe(`feature:${featureId}`, () => fetchFeature(featureId));\n },\n\n refreshFeature(featureId) {\n return dedupe(`feature:${featureId}`, () => fetchFeature(featureId));\n },\n\n ensureComments(featureId) {\n if ((state.comments[featureId] ?? EMPTY_COMMENTS).status !== \"idle\") return;\n void dedupe(`comments:${featureId}`, () => fetchComments(featureId, false));\n },\n\n refreshComments(featureId) {\n return dedupe(`comments:${featureId}`, () => fetchComments(featureId, false));\n },\n\n loadMoreComments(featureId) {\n return dedupe(`comments:more:${featureId}`, () => fetchComments(featureId, true));\n },\n\n async toggleVote(featureId) {\n const before = findFeature(state, featureId);\n if (!before)\n return {\n ok: false,\n error: { code: \"not_found\", status: 404, message: \"Unknown feature.\" },\n };\n\n const nextVoted = !before.hasVoted;\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: nextVoted,\n upvoteCount: Math.max(0, feature.upvoteCount + (nextVoted ? 1 : -1)),\n }));\n\n const result = nextVoted ? await client.vote(featureId) : await client.unvote(featureId);\n\n if (!result.ok) {\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: before.hasVoted,\n upvoteCount: before.upvoteCount,\n }));\n fail(result.error);\n return result;\n }\n\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: result.data.hasVoted,\n upvoteCount: result.data.upvoteCount,\n }));\n emit({ name: \"voted\", featureId, hasVoted: result.data.hasVoted });\n return result;\n },\n\n async submitFeature(input) {\n const result = await client.submitFeature(input);\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n const lists: Record<string, ListState> = {};\n for (const [key, list] of Object.entries(state.lists)) {\n // A brand-new request has no votes, so it only belongs at the top of the \"new\" list.\n lists[key] = key.startsWith(\"new\")\n ? { ...list, features: dedupeById([result.data, ...list.features]) }\n : list;\n }\n setState({ lists });\n emit({ name: \"featureSubmitted\", featureId: result.data.id });\n return result;\n },\n\n async addComment(input) {\n const result = await client.createComment(input);\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n const current = state.comments[input.featureId] ?? EMPTY_COMMENTS;\n setComments(input.featureId, { comments: [...current.comments, result.data] });\n mapFeature(input.featureId, (feature) => ({\n ...feature,\n commentCount: feature.commentCount + 1,\n }));\n emit({ name: \"commented\", featureId: input.featureId });\n return result;\n },\n\n async setFollowing(featureId, email) {\n const result = email\n ? await client.follow(featureId, email)\n : await client.unfollow(featureId);\n\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n mapFeature(featureId, (feature) => ({\n ...feature,\n isFollowing: result.data.following,\n followerCount: Math.max(0, feature.followerCount + (result.data.following ? 1 : -1)),\n }));\n emit({ name: \"followed\", featureId, following: result.data.following });\n return result;\n },\n };\n}\n\nexport function listStateOf(state: StoreState, key: string): ListState {\n return state.lists[key] ?? EMPTY_LIST;\n}\n\nexport function commentsStateOf(state: StoreState, featureId: string): CommentsState {\n return state.comments[featureId] ?? EMPTY_COMMENTS;\n}\n\nfunction findFeature(state: StoreState, featureId: string): Feature | null {\n for (const list of Object.values(state.lists)) {\n const found = list.features.find((feature) => feature.id === featureId);\n if (found) return found;\n }\n return null;\n}\n\nfunction dedupeById<T extends { id: string }>(items: T[]): T[] {\n const seen = new Set<string>();\n const result: T[] = [];\n for (const item of items) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n result.push(item);\n }\n return result;\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useFewchursConfig } from \"../hooks/useFewchursConfig\";\nimport {\n BoardContextProvider,\n makeClassName,\n useBoard,\n type BoardContextValue,\n type BoardTab,\n type EmailFieldMode,\n type FeatureActions,\n} from \"./BoardContext\";\nimport { Branding } from \"./Branding\";\nimport { FeatureList } from \"./FeatureList\";\nimport { SubmitForm } from \"./SubmitForm\";\nimport { mergeLabels, type BoardLabels } from \"./labels\";\nimport { themeToStyle, type BoardTheme } from \"./theme\";\nimport type { Feature } from \"../types\";\n\nexport interface FewchursBoardProps {\n tabs?: BoardTab[];\n defaultTab?: BoardTab;\n /** Shows this request above the list, for a link straight to one request. */\n initialFeatureId?: string;\n showDeclined?: boolean;\n allowComments?: boolean;\n emailField?: EmailFieldMode;\n pageSize?: number;\n labels?: Partial<BoardLabels>;\n theme?: BoardTheme;\n /** Drops every class name but keeps behaviour, ARIA and keyboard handling. */\n unstyled?: boolean;\n colorScheme?: \"light\" | \"dark\" | \"system\";\n className?: string;\n style?: CSSProperties;\n /** Prefills the submit and follow forms. */\n userEmail?: string;\n isSubscriber?: boolean;\n renderHeader?: () => ReactNode;\n renderEmpty?: () => ReactNode;\n renderFeature?: (feature: Feature, actions: FeatureActions) => ReactNode;\n children?: ReactNode;\n}\n\n/** Hoisted so the default does not hand the context a new array identity every render. */\n// Top and New, like the Flutter and Laravel boards. Roadmap is opt-in: tabs={[\"top\", \"new\", \"roadmap\"]}.\nconst DEFAULT_TABS: BoardTab[] = [\"top\", \"new\"];\n\nexport function BoardRoot({\n tabs = DEFAULT_TABS,\n defaultTab,\n initialFeatureId,\n showDeclined = false,\n allowComments = true,\n emailField = \"optional\",\n pageSize,\n labels,\n theme,\n unstyled = false,\n colorScheme = \"system\",\n className,\n style,\n userEmail,\n isSubscriber = false,\n renderHeader,\n renderEmpty,\n renderFeature,\n children,\n}: FewchursBoardProps): React.JSX.Element {\n const { store } = useFewchurs();\n const { hideVoteCounts } = useFewchursConfig();\n const [tab, setTab] = useState<BoardTab>(defaultTab ?? tabs[0] ?? \"top\");\n const [isFormOpen, setFormOpen] = useState(false);\n const [justSubmitted, setJustSubmitted] = useState(false);\n\n useEffect(() => {\n store.emit({ name: \"boardOpened\" });\n }, [store]);\n\n const value = useMemo<BoardContextValue>(\n () => ({\n labels: mergeLabels(labels),\n unstyled,\n allowComments,\n emailField,\n showDeclined,\n hideVoteCounts,\n pageSize,\n userEmail,\n isSubscriber,\n tab,\n setTab,\n tabs,\n initialFeatureId,\n isFormOpen,\n setFormOpen,\n justSubmitted,\n setJustSubmitted,\n renderFeature,\n renderEmpty,\n renderHeader,\n cx: makeClassName(unstyled),\n }),\n [\n labels,\n unstyled,\n allowComments,\n emailField,\n showDeclined,\n hideVoteCounts,\n pageSize,\n userEmail,\n isSubscriber,\n tab,\n tabs,\n initialFeatureId,\n isFormOpen,\n justSubmitted,\n renderFeature,\n renderEmpty,\n renderHeader,\n ],\n );\n\n return (\n <BoardContextProvider value={value}>\n <section\n className={[unstyled ? \"\" : \"fewchurs\", className].filter(Boolean).join(\" \") || undefined}\n style={{ ...themeToStyle(theme), ...style }}\n data-theme={colorScheme === \"system\" ? undefined : colorScheme}\n >\n {children ?? <DefaultBoard />}\n </section>\n </BoardContextProvider>\n );\n}\n\nfunction DefaultBoard(): React.JSX.Element {\n const { isFormOpen, justSubmitted, labels, renderHeader, cx } = useBoard();\n\n return (\n <>\n {renderHeader ? renderHeader() : <BoardHeading />}\n <div className={cx(\"fw-toolbar\")}>\n <BoardTabs />\n <SubmitTrigger />\n </div>\n {justSubmitted && (\n <p className={cx(\"fw-alert\")} role=\"status\">\n {labels.submitted}\n </p>\n )}\n {isFormOpen && <SubmitForm />}\n <FeatureList />\n <Branding />\n </>\n );\n}\n\nfunction BoardHeading(): React.JSX.Element {\n const { labels, cx } = useBoard();\n return <h2 className={cx(\"fw-heading\")}>{labels.title}</h2>;\n}\n\nexport function BoardTabs(): React.JSX.Element | null {\n const { tabs, tab, setTab, labels, cx } = useBoard();\n if (tabs.length < 2) return null;\n\n const labelOf: Record<BoardTab, string> = {\n top: labels.tabTop,\n new: labels.tabNew,\n roadmap: labels.tabRoadmap,\n };\n\n return (\n <div className={cx(\"fw-tabs\")} role=\"tablist\" aria-label={labels.title}>\n {tabs.map((name) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n id={`fw-tab-${name}`}\n className={cx(\"fw-tab\")}\n aria-selected={tab === name}\n tabIndex={tab === name ? 0 : -1}\n onClick={() => setTab(name)}\n onKeyDown={(event) => {\n const step = event.key === \"ArrowRight\" ? 1 : event.key === \"ArrowLeft\" ? -1 : 0;\n if (step === 0) return;\n event.preventDefault();\n const next = tabs[(tabs.indexOf(tab) + step + tabs.length) % tabs.length];\n if (next) {\n setTab(next);\n document.getElementById(`fw-tab-${next}`)?.focus();\n }\n }}\n >\n {labelOf[name]}\n </button>\n ))}\n </div>\n );\n}\n\nexport function SubmitTrigger(): React.JSX.Element {\n const { isFormOpen, setFormOpen, setJustSubmitted, labels, cx } = useBoard();\n\n return (\n <button\n type=\"button\"\n className={cx(\"fw-btn\")}\n aria-expanded={isFormOpen}\n onClick={() => {\n if (!isFormOpen) setJustSubmitted(false);\n setFormOpen(!isFormOpen);\n }}\n >\n {isFormOpen ? labels.cancel : labels.newRequest}\n </button>\n );\n}\n\n/** Level 1 by default, level 5 when given children to compose. */\nexport const FewchursBoard = Object.assign(BoardRoot, {\n Root: BoardRoot,\n Tabs: BoardTabs,\n List: FeatureList,\n SubmitTrigger,\n SubmitForm,\n Branding,\n});\n","\"use client\";\n\nimport { useEffect } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\n\nexport interface UseFewchursConfigResult {\n showBranding: boolean;\n hideVoteCounts: boolean;\n appName: string | null;\n isLoading: boolean;\n}\n\nexport function useFewchursConfig(): UseFewchursConfigResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n\n useEffect(() => {\n store.ensureConfig();\n }, [store]);\n\n return {\n showBranding: state.config?.showBranding ?? false,\n hideVoteCounts: state.config?.hideVoteCounts ?? false,\n appName: state.config?.appName ?? null,\n isLoading: state.config === null,\n };\n}\n","\"use client\";\n\nimport { useSyncExternalStore } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport type { StoreState } from \"../store/store\";\n\nexport function useStoreState(): StoreState {\n const { store } = useFewchurs();\n // The same snapshot on the server and the first client render: the store is seeded with\n // whatever was rendered server-side, so nothing re-renders into different markup.\n return useSyncExternalStore(store.subscribe, store.getState, store.getState);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { DEFAULT_LABELS, type BoardLabels } from \"./labels\";\nimport type { Feature, FeatureSort } from \"../types\";\n\nexport type BoardTab = FeatureSort | \"roadmap\";\nexport type EmailFieldMode = \"off\" | \"optional\" | \"required\";\n\nexport interface FeatureActions {\n toggleVote: () => Promise<void>;\n follow: (email: string) => Promise<boolean>;\n unfollow: () => Promise<boolean>;\n}\n\nexport interface BoardContextValue {\n labels: BoardLabels;\n unstyled: boolean;\n allowComments: boolean;\n emailField: EmailFieldMode;\n showDeclined: boolean;\n hideVoteCounts: boolean;\n pageSize?: number;\n userEmail?: string;\n isSubscriber: boolean;\n tab: BoardTab;\n setTab: (tab: BoardTab) => void;\n tabs: BoardTab[];\n /** A request to show above the list, for a deep link into the board. */\n initialFeatureId?: string;\n isFormOpen: boolean;\n setFormOpen: (open: boolean) => void;\n /** Survives the submit form closing, so the confirmation is not unmounted with it. */\n justSubmitted: boolean;\n setJustSubmitted: (submitted: boolean) => void;\n renderFeature?: (feature: Feature, actions: FeatureActions) => React.ReactNode;\n renderEmpty?: () => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n /** Returns a class name, or undefined in unstyled mode. */\n cx: (...names: string[]) => string | undefined;\n}\n\nconst BoardContext = createContext<BoardContextValue | null>(null);\n\nexport const BoardContextProvider = BoardContext.Provider;\n\nexport function useBoard(): BoardContextValue {\n const value = useContext(BoardContext);\n if (!value) {\n throw new Error(\"Fewchurs board parts must be rendered inside <FewchursBoard.Root>.\");\n }\n return value;\n}\n\nexport function makeClassName(unstyled: boolean) {\n return (...names: string[]): string | undefined =>\n unstyled ? undefined : names.filter(Boolean).join(\" \");\n}\n\nexport const FALLBACK_LABELS = DEFAULT_LABELS;\n","import type { FeatureStatus } from \"../types\";\n\nexport interface BoardLabels {\n title: string;\n tabTop: string;\n tabNew: string;\n tabRoadmap: string;\n newRequest: string;\n cancel: string;\n submit: string;\n submitting: string;\n submitted: string;\n fieldTitle: string;\n fieldTitlePlaceholder: string;\n fieldDescription: string;\n fieldDescriptionPlaceholder: string;\n fieldEmail: string;\n fieldEmailHint: string;\n fieldName: string;\n emptyTitle: string;\n emptyBody: string;\n loading: string;\n loadMore: string;\n retry: string;\n errorInvalidKeyTitle: string;\n errorInvalidKeyDetail: string;\n errorWrongAppTitle: string;\n errorWrongAppDetail: string;\n errorTitle: string;\n errorDetail: string;\n errorOfflineTitle: string;\n errorOfflineDetail: string;\n errorNotSetUpTitle: string;\n errorNotSetUpDetail: string;\n errorLoadMore: string;\n errorComments: string;\n fieldTitleTooShort: string;\n fieldEmailInvalid: string;\n comments: string;\n commentPlaceholder: string;\n postComment: string;\n noComments: string;\n follow: string;\n following: string;\n followPlaceholder: string;\n developer: string;\n poweredBy: string;\n upvote: string;\n status: Record<FeatureStatus, string>;\n}\n\nexport const DEFAULT_LABELS: BoardLabels = {\n title: \"Feature requests\",\n tabTop: \"Top\",\n tabNew: \"New\",\n tabRoadmap: \"Roadmap\",\n newRequest: \"New request\",\n cancel: \"Cancel\",\n submit: \"Submit request\",\n submitting: \"Submitting…\",\n submitted: \"Thanks — your request is in.\",\n fieldTitle: \"Title\",\n fieldTitlePlaceholder: \"Add dark mode\",\n fieldDescription: \"Details\",\n fieldDescriptionPlaceholder: \"What would this let you do?\",\n fieldEmail: \"Email\",\n fieldEmailHint: \"Only used to tell you when this ships.\",\n fieldName: \"Your name\",\n emptyTitle: \"No feature requests yet\",\n emptyBody: \"Be the first to suggest something.\",\n loading: \"Loading…\",\n loadMore: \"Load more\",\n retry: \"Try again\",\n errorInvalidKeyTitle: \"Invalid API key\",\n errorInvalidKeyDetail:\n \"Copy the key from your Fewchurs dashboard (Apps → API keys) and pass it to FewchursProvider, or set FEWCHURS_API_KEY on your server.\",\n errorWrongAppTitle: \"Invalid API key\",\n errorWrongAppDetail: \"\",\n errorTitle: \"Couldn't load requests\",\n errorDetail: \"Something went wrong. Try again.\",\n errorOfflineTitle: \"You're offline\",\n errorOfflineDetail: \"Check your connection and try again.\",\n errorNotSetUpTitle: \"Fewchurs isn't set up\",\n errorNotSetUpDetail: \"Pass apiKey to FewchursProvider, or set FEWCHURS_API_KEY on your server.\",\n errorLoadMore: \"Couldn't load more.\",\n errorComments: \"Couldn't load comments.\",\n fieldTitleTooShort: \"At least 3 characters.\",\n fieldEmailInvalid: \"Enter a valid email address.\",\n comments: \"Comments\",\n commentPlaceholder: \"Add a comment\",\n postComment: \"Post\",\n noComments: \"No comments yet.\",\n follow: \"Notify me\",\n following: \"You'll be notified\",\n followPlaceholder: \"you@example.com\",\n developer: \"Team\",\n poweredBy: \"Powered by Fewchurs\",\n upvote: \"Upvote\",\n status: {\n open: \"Open\",\n planned: \"Planned\",\n in_progress: \"In progress\",\n done: \"Done\",\n declined: \"Declined\",\n unknown: \"Open\",\n },\n};\n\nexport function mergeLabels(overrides?: Partial<BoardLabels>): BoardLabels {\n if (!overrides) return DEFAULT_LABELS;\n return {\n ...DEFAULT_LABELS,\n ...overrides,\n status: { ...DEFAULT_LABELS.status, ...overrides.status },\n };\n}\n","\"use client\";\n\nimport { useFewchursConfig } from \"../hooks/useFewchursConfig\";\nimport { useBoard } from \"./BoardContext\";\n\nexport function Branding(): React.JSX.Element | null {\n const { labels, cx } = useBoard();\n const { showBranding } = useFewchursConfig();\n if (!showBranding) return null;\n\n return (\n <p className={cx(\"fw-branding\")}>\n <a\n className={cx(\"fw-link\")}\n href=\"https://www.fewchurs.com\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n {labels.poweredBy}\n </a>\n </p>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { featureKey } from \"../store/keys\";\nimport { listStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature } from \"../types\";\n\nexport interface UseFeatureOptions {\n enabled?: boolean;\n}\n\nexport interface UseFeatureResult {\n feature: Feature | null;\n isLoading: boolean;\n error: FewchursError | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * One request by id, for a deep link into a board. The feature lands in the same store the\n * lists use, so voting, commenting and following it behave exactly as they do in a list.\n */\nexport function useFeature(\n featureId: string | undefined,\n { enabled = true }: UseFeatureOptions = {},\n): UseFeatureResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n\n const active = Boolean(featureId) && enabled;\n const list = listStateOf(state, featureKey(featureId ?? \"\"));\n\n useEffect(() => {\n if (!active || !isReady || !featureId) return;\n store.ensureFeature(featureId);\n }, [store, featureId, active, isReady]);\n\n const refresh = useCallback(\n () => (featureId ? store.refreshFeature(featureId) : Promise.resolve()),\n [store, featureId],\n );\n\n return {\n feature: list.features[0] ?? null,\n isLoading: active && (list.status === \"loading\" || list.status === \"idle\"),\n error: list.error,\n refresh,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { listKey } from \"../store/keys\";\nimport { listStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature, FeatureSort, FeatureStatus } from \"../types\";\n\nexport interface UseFeaturesOptions {\n sort?: FeatureSort;\n status?: FeatureStatus[];\n pageSize?: number;\n enabled?: boolean;\n}\n\nexport interface UseFeaturesResult {\n features: Feature[];\n isLoading: boolean;\n isLoadingMore: boolean;\n error: FewchursError | null;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n refresh: () => Promise<void>;\n}\n\nexport function useFeatures({\n sort = \"new\",\n status,\n pageSize,\n enabled = true,\n}: UseFeaturesOptions = {}): UseFeaturesResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n\n const statusKey = status?.length ? [...status].sort().join(\",\") : \"\";\n const query = useMemo(\n () => ({ sort, status: statusKey ? (statusKey.split(\",\") as FeatureStatus[]) : undefined }),\n [sort, statusKey],\n );\n const key = listKey(query);\n const list = listStateOf(state, key);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n store.ensureFeatures(query, pageSize);\n }, [store, query, pageSize, enabled, isReady]);\n\n const loadMore = useCallback(() => store.loadMore(query, pageSize), [store, query, pageSize]);\n const refresh = useCallback(() => store.refresh(query, pageSize), [store, query, pageSize]);\n\n return {\n features: list.features,\n isLoading: list.status === \"loading\" || (list.status === \"idle\" && enabled),\n isLoadingMore: list.status === \"loadingMore\",\n error: list.error,\n hasMore: list.cursor !== null,\n loadMore,\n refresh,\n };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\n\nexport interface UseFollowResult {\n isFollowing: boolean;\n isPending: boolean;\n error: FewchursError | null;\n follow: (email: string) => Promise<boolean>;\n unfollow: () => Promise<boolean>;\n}\n\nexport function useFollow(featureId: string): UseFollowResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const feature = Object.values(state.lists)\n .flatMap((list) => list.features)\n .find((candidate) => candidate.id === featureId);\n\n const run = useCallback(\n async (email: string | null) => {\n setIsPending(true);\n setError(null);\n const result = await store.setFollowing(featureId, email);\n if (!result.ok) setError(result.error);\n setIsPending(false);\n return result.ok;\n },\n [store, featureId],\n );\n\n return {\n isFollowing: feature?.isFollowing ?? false,\n isPending,\n error,\n follow: useCallback((email: string) => run(email), [run]),\n unfollow: useCallback(() => run(null), [run]),\n };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\n\nexport interface UseVoteResult {\n hasVoted: boolean;\n upvoteCount: number;\n isPending: boolean;\n error: FewchursError | null;\n toggle: () => Promise<void>;\n vote: () => Promise<void>;\n unvote: () => Promise<void>;\n}\n\nexport function useVote(featureId: string): UseVoteResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const feature = Object.values(state.lists)\n .flatMap((list) => list.features)\n .find((candidate) => candidate.id === featureId);\n\n const toggle = useCallback(async () => {\n setIsPending(true);\n setError(null);\n const result = await store.toggleVote(featureId);\n if (!result.ok) setError(result.error);\n setIsPending(false);\n }, [store, featureId]);\n\n const vote = useCallback(async () => {\n if (feature?.hasVoted) return;\n await toggle();\n }, [feature?.hasVoted, toggle]);\n\n const unvote = useCallback(async () => {\n if (!feature?.hasVoted) return;\n await toggle();\n }, [feature?.hasVoted, toggle]);\n\n return {\n hasVoted: feature?.hasVoted ?? false,\n upvoteCount: feature?.upvoteCount ?? 0,\n isPending,\n error,\n toggle,\n vote,\n unvote,\n };\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { userMessage } from \"../client/errors\";\nimport { useVote } from \"../hooks/useVote\";\nimport { useBoard } from \"./BoardContext\";\nimport { CommentList } from \"./Comments\";\nimport { FollowForm } from \"./FollowForm\";\nimport { StatusBadge } from \"./StatusBadge\";\nimport { VoteButton } from \"./VoteButton\";\nimport { formatDate } from \"./time\";\nimport type { Feature } from \"../types\";\n\nexport function FeatureCard({\n feature,\n defaultCommentsOpen = false,\n}: {\n feature: Feature;\n /** Opens the thread straight away, for a board linked to this one request. */\n defaultCommentsOpen?: boolean;\n}): React.JSX.Element {\n const { labels, allowComments, cx } = useBoard();\n const { isPending, toggle, error: voteError } = useVote(feature.id);\n const [showComments, setShowComments] = useState(defaultCommentsOpen);\n\n return (\n <li className={cx(\"fw-card\")}>\n <VoteButton feature={feature} isPending={isPending} onToggle={() => void toggle()} />\n\n <div className={cx(\"fw-card__body\")}>\n <h3 className={cx(\"fw-card__title\")}>{feature.title}</h3>\n {feature.description && <p className={cx(\"fw-card__desc\")}>{feature.description}</p>}\n\n <div className={cx(\"fw-meta\")}>\n <StatusBadge status={feature.status} />\n <span>{formatDate(feature.createdAt)}</span>\n\n {allowComments && (\n <button\n type=\"button\"\n className={cx(\"fw-link\")}\n aria-expanded={showComments}\n aria-controls={`fw-comments-${feature.id}`}\n onClick={() => setShowComments((open) => !open)}\n >\n {labels.comments} ({feature.commentCount})\n </button>\n )}\n\n <FollowForm feature={feature} />\n </div>\n\n {voteError && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(voteError)}\n </p>\n )}\n\n {allowComments && showComments && (\n <div id={`fw-comments-${feature.id}`}>\n <CommentList featureId={feature.id} />\n </div>\n )}\n </div>\n </li>\n );\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { isNotConfigured, userMessage } from \"../client/errors\";\nimport { LIMITS } from \"../client/constants\";\nimport { useComments } from \"../hooks/useComments\";\nimport { useBoard } from \"./BoardContext\";\nimport { formatDate } from \"./time\";\n\nexport function CommentList({ featureId }: { featureId: string }): React.JSX.Element {\n const { labels, cx } = useBoard();\n const { comments, isLoading, isLoadingMore, error, hasMore, loadMore, refresh } =\n useComments(featureId);\n\n return (\n <div className={cx(\"fw-comments\")}>\n {isLoading && <p className={cx(\"fw-muted\")}>{labels.loading}</p>}\n\n {error && comments.length === 0 && (\n <div className={cx(\"fw-empty\", \"fw-empty--compact\")} role=\"alert\">\n <p className={cx(\"fw-empty__title\")}>{labels.errorComments}</p>\n <p className={cx(\"fw-empty__detail\")}>\n {isNotConfigured(error) ? labels.errorNotSetUpTitle : userMessage(error)}\n </p>\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void refresh()}>\n {labels.retry}\n </button>\n </div>\n )}\n\n {error && comments.length > 0 && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n\n {!isLoading && !error && comments.length === 0 && (\n <p className={cx(\"fw-muted\")}>{labels.noComments}</p>\n )}\n\n <ul className={cx(\"fw-comment-list\")}>\n {comments.map((comment) => (\n <li key={comment.id} className={cx(\"fw-comment\")}>\n <span className={cx(\"fw-comment__author\")}>{comment.authorName}</span>\n {comment.isDeveloper && <span className={cx(\"fw-badge\")}> {labels.developer}</span>}\n <span className={cx(\"fw-muted\")}> · {formatDate(comment.createdAt)}</span>\n <p className={cx(\"fw-comment__text\")}>{comment.text}</p>\n </li>\n ))}\n </ul>\n\n {hasMore && (\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n disabled={isLoadingMore}\n onClick={() => void loadMore()}\n >\n {isLoadingMore ? labels.loading : labels.loadMore}\n </button>\n )}\n\n <CommentForm featureId={featureId} />\n </div>\n );\n}\n\nexport function CommentForm({ featureId }: { featureId: string }): React.JSX.Element {\n const { labels, cx } = useBoard();\n const { add, isSubmitting, submitError } = useComments(featureId);\n const [text, setText] = useState(\"\");\n const [authorName, setAuthorName] = useState(\"\");\n\n return (\n <form\n className={cx(\"fw-form\", \"fw-form--inline\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const posted = await add(text, authorName);\n if (posted) setText(\"\");\n }}\n >\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-comment-${featureId}`}>\n {labels.commentPlaceholder}\n </label>\n <input\n id={`fw-comment-${featureId}`}\n className={cx(\"fw-input\")}\n value={text}\n maxLength={LIMITS.commentMax}\n placeholder={labels.commentPlaceholder}\n onChange={(event) => setText(event.target.value)}\n required\n />\n </div>\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-comment-name-${featureId}`}>\n {labels.fieldName}\n </label>\n <input\n id={`fw-comment-name-${featureId}`}\n className={cx(\"fw-input\")}\n value={authorName}\n maxLength={LIMITS.authorNameMax}\n placeholder={labels.fieldName}\n onChange={(event) => setAuthorName(event.target.value)}\n />\n </div>\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isSubmitting || !text.trim()}>\n {labels.postComment}\n </button>\n {submitError && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(submitError)}\n </p>\n )}\n </form>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { commentsStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Comment } from \"../types\";\n\nexport interface UseCommentsOptions {\n enabled?: boolean;\n}\n\nexport interface UseCommentsResult {\n comments: Comment[];\n isLoading: boolean;\n isLoadingMore: boolean;\n isSubmitting: boolean;\n error: FewchursError | null;\n submitError: FewchursError | null;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n refresh: () => Promise<void>;\n add: (text: string, authorName?: string) => Promise<boolean>;\n}\n\nexport function useComments(\n featureId: string,\n { enabled = true }: UseCommentsOptions = {},\n): UseCommentsResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitError, setSubmitError] = useState<FewchursError | null>(null);\n\n const comments = commentsStateOf(state, featureId);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n store.ensureComments(featureId);\n }, [store, featureId, enabled, isReady]);\n\n const loadMore = useCallback(() => store.loadMoreComments(featureId), [store, featureId]);\n\n const refresh = useCallback(() => store.refreshComments(featureId), [store, featureId]);\n\n const add = useCallback(\n async (text: string, authorName?: string) => {\n setIsSubmitting(true);\n setSubmitError(null);\n const result = await store.addComment({ featureId, text, authorName });\n if (!result.ok) setSubmitError(result.error);\n setIsSubmitting(false);\n return result.ok;\n },\n [store, featureId],\n );\n\n return {\n comments: comments.comments,\n isLoading: comments.status === \"loading\" || (comments.status === \"idle\" && enabled),\n isLoadingMore: comments.status === \"loadingMore\",\n isSubmitting,\n error: comments.error,\n submitError,\n hasMore: comments.cursor !== null,\n loadMore,\n refresh,\n add,\n };\n}\n","/**\n * Fixed locale and time zone on purpose: a date formatted with the visitor's locale renders\n * differently on the server than in the browser, which React reports as a hydration mismatch.\n */\nconst FORMATTER = new Intl.DateTimeFormat(\"en\", {\n month: \"short\",\n day: \"numeric\",\n timeZone: \"UTC\",\n});\n\nexport function formatDate(iso: string): string {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? \"\" : FORMATTER.format(date);\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { EMAIL_PATTERN } from \"../client/constants\";\nimport { userMessage } from \"../client/errors\";\nimport { useFollow } from \"../hooks/useFollow\";\nimport { useBoard } from \"./BoardContext\";\nimport type { Feature } from \"../types\";\n\nexport function FollowForm({ feature }: { feature: Feature }): React.JSX.Element {\n const { labels, userEmail, cx } = useBoard();\n const { isFollowing, isPending, error, follow, unfollow } = useFollow(feature.id);\n const [email, setEmail] = useState(userEmail ?? \"\");\n const [isOpen, setIsOpen] = useState(false);\n\n if (isFollowing) {\n return (\n <>\n <button\n type=\"button\"\n className={cx(\"fw-link\")}\n disabled={isPending}\n onClick={() => void unfollow()}\n >\n {labels.following}\n </button>\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n </>\n );\n }\n\n if (!isOpen) {\n return (\n <button type=\"button\" className={cx(\"fw-link\")} onClick={() => setIsOpen(true)}>\n {labels.follow}\n </button>\n );\n }\n\n const isEmailValid = EMAIL_PATTERN.test(email.trim());\n\n return (\n <form\n className={cx(\"fw-form\", \"fw-form--inline\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const ok = await follow(email);\n if (ok) setIsOpen(false);\n }}\n >\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-follow-${feature.id}`}>\n {labels.fieldEmail}\n </label>\n <input\n id={`fw-follow-${feature.id}`}\n className={cx(\"fw-input\")}\n type=\"email\"\n value={email}\n placeholder={labels.followPlaceholder}\n onChange={(event) => setEmail(event.target.value)}\n required\n />\n {email !== \"\" && !isEmailValid && (\n <p className={cx(\"fw-error\")}>{labels.fieldEmailInvalid}</p>\n )}\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isPending || !isEmailValid}>\n {labels.follow}\n </button>\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n </form>\n );\n}\n","\"use client\";\n\nimport { useBoard } from \"./BoardContext\";\nimport type { FeatureStatus } from \"../types\";\n\nexport function StatusBadge({ status }: { status: FeatureStatus }): React.JSX.Element | null {\n const { labels, cx } = useBoard();\n if (status === \"open\" || status === \"unknown\") return null;\n\n return <span className={cx(\"fw-status\", `fw-status--${status}`)}>{labels.status[status]}</span>;\n}\n","\"use client\";\n\nimport { useBoard } from \"./BoardContext\";\nimport type { Feature } from \"../types\";\n\ninterface VoteButtonProps {\n feature: Feature;\n isPending: boolean;\n onToggle: () => void;\n}\n\nexport function VoteButton({ feature, isPending, onToggle }: VoteButtonProps): React.JSX.Element {\n const { labels, hideVoteCounts, cx } = useBoard();\n\n return (\n <button\n type=\"button\"\n className={cx(\"fw-vote\")}\n aria-pressed={feature.hasVoted}\n aria-label={`${labels.upvote} ${feature.title}`}\n disabled={isPending}\n onClick={onToggle}\n >\n <span className={cx(\"fw-vote__arrow\")} aria-hidden=\"true\">\n ▲\n </span>\n {!hideVoteCounts && <span className={cx(\"fw-vote__count\")}>{feature.upvoteCount}</span>}\n </button>\n );\n}\n","\"use client\";\n\nimport { ROADMAP_STATUSES } from \"../client/constants\";\nimport { useBoard } from \"./BoardContext\";\n\n/** Enough rows to fill the fold without pushing the real list down when it arrives. */\nconst ROW_COUNT = 3;\nconst ROADMAP_ROW_COUNT = 2;\n\n/**\n * Placeholder rows shaped like `FeatureCard`, so the board does not collapse to one line of\n * text and then jump when the first page lands. `labels.loading` is still announced, since\n * the bars themselves are decorative.\n */\nexport function FeatureListSkeleton({\n roadmap = false,\n rows = ROW_COUNT,\n}: {\n roadmap?: boolean;\n /** One row while a single deep-linked request loads, a full board otherwise. */\n rows?: number;\n}): React.JSX.Element {\n const { labels, cx } = useBoard();\n\n return (\n <div className={cx(\"fw-skeleton\")} role=\"status\" aria-busy=\"true\">\n <span className={cx(\"fw-sr-only\")}>{labels.loading}</span>\n\n {roadmap ? (\n <div className={cx(\"fw-roadmap\")} aria-hidden=\"true\">\n {ROADMAP_STATUSES.map((status) => (\n <div key={status} className={cx(\"fw-roadmap__column\")}>\n <Bar width=\"40%\" />\n <Rows count={ROADMAP_ROW_COUNT} />\n </div>\n ))}\n </div>\n ) : (\n <div aria-hidden=\"true\">\n <Rows count={rows} />\n </div>\n )}\n </div>\n );\n}\n\nfunction Rows({ count }: { count: number }): React.JSX.Element {\n const { cx } = useBoard();\n\n return (\n <div className={cx(\"fw-list\")}>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={cx(\"fw-card\", \"fw-skeleton__card\")}>\n <div className={cx(\"fw-skeleton__vote\")} />\n <div className={cx(\"fw-card__body\")}>\n <Bar width=\"62%\" />\n <Bar width=\"88%\" height=\"0.6rem\" />\n <Bar width=\"34%\" height=\"0.6rem\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction Bar({ width, height }: { width: string; height?: string }): React.JSX.Element {\n const { cx } = useBoard();\n return <div className={cx(\"fw-skeleton__bar\")} style={{ width, height }} />;\n}\n","\"use client\";\n\nimport { ROADMAP_STATUSES } from \"../client/constants\";\nimport { isNotConfigured, isWrongApp, userMessage, type FewchursError } from \"../client/errors\";\nimport { useFeature } from \"../hooks/useFeature\";\nimport { useFeatures } from \"../hooks/useFeatures\";\nimport { useFollow } from \"../hooks/useFollow\";\nimport { useVote } from \"../hooks/useVote\";\nimport { useBoard, type BoardTab } from \"./BoardContext\";\nimport { FeatureCard } from \"./FeatureCard\";\nimport type { BoardLabels } from \"./labels\";\nimport { FeatureListSkeleton } from \"./Skeleton\";\nimport type { Feature, FeatureSort } from \"../types\";\n\nfunction errorCopy(error: FewchursError, labels: BoardLabels): { title: string; detail: string } {\n if (isNotConfigured(error)) {\n return { title: labels.errorNotSetUpTitle, detail: labels.errorNotSetUpDetail };\n }\n if (error.code === \"network\") {\n return { title: labels.errorOfflineTitle, detail: labels.errorOfflineDetail };\n }\n if (isWrongApp(error)) {\n return {\n title: labels.errorWrongAppTitle,\n detail: labels.errorWrongAppDetail || userMessage(error),\n };\n }\n if (error.code === \"invalid_key\") {\n return { title: labels.errorInvalidKeyTitle, detail: labels.errorInvalidKeyDetail };\n }\n return {\n title: labels.errorTitle,\n detail: error.code === \"server\" ? labels.errorDetail : userMessage(error),\n };\n}\n\nexport function FeatureList(): React.JSX.Element {\n const { initialFeatureId } = useBoard();\n\n // The deep-linked request sits above the list and is dropped from it, so a board opened on\n // one request shows it first without listing it twice.\n return (\n <>\n {initialFeatureId && <PinnedFeature featureId={initialFeatureId} />}\n <Listing excludeId={initialFeatureId} />\n </>\n );\n}\n\nfunction PinnedFeature({ featureId }: { featureId: string }): React.JSX.Element | null {\n const { cx } = useBoard();\n const { feature, isLoading, error } = useFeature(featureId);\n\n if (isLoading) return <FeatureListSkeleton rows={1} />;\n if (!feature && error) {\n return (\n <p className={cx(\"fw-error\", \"fw-pinned\")} role=\"alert\">\n {userMessage(error)}\n </p>\n );\n }\n if (!feature) return null;\n\n return (\n <div className={cx(\"fw-pinned\")}>\n <ul className={cx(\"fw-list\")}>\n <FeatureCard feature={feature} defaultCommentsOpen />\n </ul>\n </div>\n );\n}\n\nfunction Listing({ excludeId }: { excludeId?: string }): React.JSX.Element {\n const { tab, showDeclined, labels, cx, renderEmpty, pageSize } = useBoard();\n const sort: FeatureSort = tab === \"roadmap\" ? \"top\" : tab;\n const isRoadmap = tab === \"roadmap\";\n\n const { features, isLoading, isLoadingMore, error, hasMore, loadMore, refresh } = useFeatures({\n sort,\n status: isRoadmap ? ROADMAP_STATUSES : undefined,\n pageSize,\n });\n\n // Also filtered here: a server that does not support ?status= yet returns everything.\n const visible = features.filter((feature) => {\n if (feature.id === excludeId) return false;\n if (isRoadmap) return ROADMAP_STATUSES.includes(feature.status);\n return showDeclined || feature.status !== \"declined\";\n });\n\n if (error && visible.length === 0) {\n const { title, detail } = errorCopy(error, labels);\n return (\n <div className={cx(\"fw-empty\")} role=\"alert\">\n <p className={cx(\"fw-empty__title\")}>{title}</p>\n <p className={cx(\"fw-empty__detail\")}>{detail}</p>\n {!isNotConfigured(error) && (\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void refresh()}>\n {labels.retry}\n </button>\n )}\n </div>\n );\n }\n\n if (isLoading && visible.length === 0) {\n return <FeatureListSkeleton roadmap={isRoadmap} />;\n }\n\n if (visible.length === 0) {\n if (renderEmpty) return <>{renderEmpty()}</>;\n return (\n <div className={cx(\"fw-empty\")}>\n <p className={cx(\"fw-empty__title\")}>{labels.emptyTitle}</p>\n <p>{labels.emptyBody}</p>\n </div>\n );\n }\n\n return (\n <>\n {isRoadmap ? <RoadmapColumns features={visible} /> : <Rows features={visible} />}\n\n {hasMore && error && (\n <div className={cx(\"fw-pagination\")} role=\"alert\">\n <span>{labels.errorLoadMore}</span>\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void loadMore()}>\n {labels.retry}\n </button>\n </div>\n )}\n\n {hasMore && !error && (\n <div className={cx(\"fw-pagination\")}>\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n disabled={isLoadingMore}\n onClick={() => void loadMore()}\n >\n {isLoadingMore ? labels.loading : labels.loadMore}\n </button>\n </div>\n )}\n </>\n );\n}\n\nfunction Rows({ features }: { features: Feature[] }): React.JSX.Element {\n const { cx } = useBoard();\n return (\n <ul className={cx(\"fw-list\")}>\n {features.map((feature) => (\n <FeatureRow key={feature.id} feature={feature} />\n ))}\n </ul>\n );\n}\n\nfunction RoadmapColumns({ features }: { features: Feature[] }): React.JSX.Element {\n const { labels, cx } = useBoard();\n\n return (\n <div className={cx(\"fw-roadmap\")}>\n {ROADMAP_STATUSES.map((status) => {\n const column = features.filter((feature) => feature.status === status);\n return (\n <section\n key={status}\n className={cx(\"fw-roadmap__column\")}\n aria-label={labels.status[status]}\n >\n <h3 className={cx(\"fw-roadmap__heading\")}>{labels.status[status]}</h3>\n {column.length === 0 ? (\n <p className={cx(\"fw-muted\")}>—</p>\n ) : (\n <ul className={cx(\"fw-list\")}>\n {column.map((feature) => (\n <FeatureRow key={feature.id} feature={feature} />\n ))}\n </ul>\n )}\n </section>\n );\n })}\n </div>\n );\n}\n\n/** Level 4: the host renders the row and drives it through the same actions the card uses. */\nfunction FeatureRow({ feature }: { feature: Feature }): React.JSX.Element {\n const { renderFeature } = useBoard();\n if (!renderFeature) return <FeatureCard feature={feature} />;\n return <FeatureSlot feature={feature} />;\n}\n\nfunction FeatureSlot({ feature }: { feature: Feature }): React.JSX.Element {\n const { renderFeature } = useBoard();\n const { toggle } = useVote(feature.id);\n const { follow, unfollow } = useFollow(feature.id);\n\n return <>{renderFeature?.(feature, { toggleVote: toggle, follow, unfollow })}</>;\n}\n\nexport { ROADMAP_STATUSES };\nexport type { BoardTab };\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { EMAIL_PATTERN, LIMITS } from \"../client/constants\";\nimport { userMessage } from \"../client/errors\";\nimport { useSubmitFeature } from \"../hooks/useSubmitFeature\";\nimport { useBoard } from \"./BoardContext\";\n\nexport function SubmitForm(): React.JSX.Element {\n const { labels, emailField, userEmail, isSubscriber, setFormOpen, setJustSubmitted, cx } =\n useBoard();\n const { submit, isPending, error } = useSubmitFeature();\n\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [email, setEmail] = useState(userEmail ?? \"\");\n\n const isTitleValid = title.trim().length >= LIMITS.titleMin;\n const isEmailInvalid = emailField !== \"off\" && email !== \"\" && !EMAIL_PATTERN.test(email.trim());\n const isEmailMissing = emailField === \"required\" && !email.trim();\n const canSubmit = isTitleValid && !isEmailInvalid && !isEmailMissing;\n\n return (\n <form\n className={cx(\"fw-form\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const created = await submit({\n title,\n description,\n ...(emailField !== \"off\" && email ? { email } : {}),\n isSubscriber,\n });\n if (!created) return;\n setTitle(\"\");\n setDescription(\"\");\n setJustSubmitted(true);\n setFormOpen(false);\n }}\n >\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-title\">\n {labels.fieldTitle}\n </label>\n <input\n id=\"fw-title\"\n className={cx(\"fw-input\")}\n value={title}\n minLength={LIMITS.titleMin}\n maxLength={LIMITS.titleMax}\n placeholder={labels.fieldTitlePlaceholder}\n onChange={(event) => setTitle(event.target.value)}\n required\n />\n <div className={cx(\"fw-field__foot\")}>\n <span className={cx(\"fw-error\")}>\n {title !== \"\" && !isTitleValid ? labels.fieldTitleTooShort : \"\"}\n </span>\n <span className={cx(\"fw-muted\")}>\n {title.length}/{LIMITS.titleMax}\n </span>\n </div>\n </div>\n\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-description\">\n {labels.fieldDescription}\n </label>\n <textarea\n id=\"fw-description\"\n className={cx(\"fw-input\", \"fw-textarea\")}\n value={description}\n maxLength={LIMITS.descriptionMax}\n placeholder={labels.fieldDescriptionPlaceholder}\n onChange={(event) => setDescription(event.target.value)}\n />\n <div className={cx(\"fw-field__foot\")}>\n <span />\n <span className={cx(\"fw-muted\")}>\n {description.length}/{LIMITS.descriptionMax}\n </span>\n </div>\n </div>\n\n {emailField !== \"off\" && (\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-email\">\n {labels.fieldEmail}\n </label>\n <input\n id=\"fw-email\"\n className={cx(\"fw-input\")}\n type=\"email\"\n value={email}\n placeholder={labels.followPlaceholder}\n aria-describedby=\"fw-email-hint\"\n onChange={(event) => setEmail(event.target.value)}\n required={emailField === \"required\"}\n />\n {isEmailInvalid ? (\n <p id=\"fw-email-hint\" className={cx(\"fw-error\")}>\n {labels.fieldEmailInvalid}\n </p>\n ) : (\n <p id=\"fw-email-hint\" className={cx(\"fw-muted\")}>\n {labels.fieldEmailHint}\n </p>\n )}\n </div>\n )}\n\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n\n <div className={cx(\"fw-form__actions\")}>\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isPending || !canSubmit}>\n {isPending ? labels.submitting : labels.submit}\n </button>\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n onClick={() => setFormOpen(false)}\n >\n {labels.cancel}\n </button>\n </div>\n </form>\n );\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature, SubmitFeatureInput } from \"../types\";\n\nexport interface UseSubmitFeatureResult {\n submit: (input: SubmitFeatureInput) => Promise<Feature | null>;\n isPending: boolean;\n error: FewchursError | null;\n reset: () => void;\n}\n\nexport function useSubmitFeature(): UseSubmitFeatureResult {\n const { store } = useFewchurs();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const submit = useCallback(\n async (input: SubmitFeatureInput) => {\n setIsPending(true);\n setError(null);\n const result = await store.submitFeature(input);\n setIsPending(false);\n if (!result.ok) {\n setError(result.error);\n return null;\n }\n return result.data;\n },\n [store],\n );\n\n const reset = useCallback(() => setError(null), []);\n\n return { submit, isPending, error, reset };\n}\n","import type { CSSProperties } from \"react\";\n\nexport interface BoardTheme {\n primary?: string;\n /** A number is read as pixels, a string is used as-is (`\"0.75rem\"`). */\n radius?: number | string;\n surface?: string;\n border?: string;\n text?: string;\n subtle?: string;\n font?: string;\n}\n\nconst VARIABLE_BY_KEY: Record<keyof BoardTheme, string> = {\n primary: \"--fw-primary\",\n radius: \"--fw-radius\",\n surface: \"--fw-surface\",\n border: \"--fw-border\",\n text: \"--fw-text\",\n subtle: \"--fw-subtle\",\n font: \"--fw-font\",\n};\n\nexport function themeToStyle(theme?: BoardTheme): CSSProperties | undefined {\n if (!theme) return undefined;\n const style: Record<string, string> = {};\n for (const [key, value] of Object.entries(theme)) {\n if (value === undefined || value === null) continue;\n const variable = VARIABLE_BY_KEY[key as keyof BoardTheme];\n style[variable] = typeof value === \"number\" ? `${value}px` : value;\n }\n return style as CSSProperties;\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { BoardRoot, type FewchursBoardProps } from \"./Board\";\n\nexport interface FewchursBoardDialogProps extends FewchursBoardProps {\n open: boolean;\n onClose: () => void;\n ariaLabel?: string;\n variant?: \"dialog\" | \"sheet\";\n}\n\nexport function FewchursBoardDialog({\n open,\n onClose,\n ariaLabel = \"Feature requests\",\n variant = \"dialog\",\n ...boardProps\n}: FewchursBoardDialogProps): React.JSX.Element | null {\n const dialogRef = useRef<HTMLDivElement>(null);\n const openerRef = useRef<Element | null>(null);\n\n useEffect(() => {\n if (!open) return;\n openerRef.current = document.activeElement;\n dialogRef.current?.focus();\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") onClose();\n }\n document.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n // Focus goes back where it came from, so a keyboard user is not dropped at the top of the page.\n (openerRef.current as HTMLElement | null)?.focus?.();\n };\n }, [open, onClose]);\n\n if (!open) return null;\n\n const isSheet = variant === \"sheet\";\n const { colorScheme } = boardProps;\n\n return (\n <div className={isSheet ? \"fw-overlay fw-overlay--sheet\" : \"fw-overlay\"} onClick={onClose}>\n <div\n ref={dialogRef}\n className={isSheet ? \"fw-dialog fw-dialog--sheet\" : \"fw-dialog\"}\n data-theme={colorScheme === \"system\" ? undefined : colorScheme}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n tabIndex={-1}\n onClick={(event) => event.stopPropagation()}\n >\n <button type=\"button\" className=\"fw-dialog__close\" aria-label=\"Close\" onClick={onClose}>\n ×\n </button>\n <BoardRoot {...boardProps} />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { FewchursBoardProps } from \"./Board\";\nimport { FewchursBoardDialog } from \"./BoardDialog\";\nimport { themeToStyle } from \"./theme\";\n\nexport interface FewchursButtonProps extends Omit<\n FewchursBoardProps,\n \"children\" | \"className\" | \"style\"\n> {\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n floating?: boolean | \"left\" | \"right\";\n}\n\nfunction launcherClasses(floating: FewchursButtonProps[\"floating\"]): string {\n if (!floating) return \"fw-launcher\";\n const side = floating === \"left\" ? \" fw-launcher--left\" : \"\";\n return `fw-launcher fw-launcher--floating${side}`;\n}\n\nexport function FewchursButton({\n children = \"Feedback\",\n className,\n style,\n ariaLabel,\n floating = false,\n ...board\n}: FewchursButtonProps): React.JSX.Element {\n const [open, setOpen] = useState(false);\n const close = useCallback(() => setOpen(false), []);\n const classes = [board.unstyled ? \"\" : launcherClasses(floating), className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <>\n <button\n type=\"button\"\n className={classes || undefined}\n style={{ ...themeToStyle(board.theme), ...style }}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen(true)}\n >\n {children}\n </button>\n {open\n ? createPortal(\n <FewchursBoardDialog\n {...board}\n variant=\"sheet\"\n ariaLabel={ariaLabel}\n open\n onClose={close}\n />,\n document.body,\n )\n : null}\n </>\n );\n}\n"],"mappings":"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","names":["failure","useEffect","useMemo","useState","useEffect","useEffect","createContext","useContext","createContext","useContext","jsx","useEffect","useEffect","useCallback","useEffect","useMemo","useMemo","useEffect","useCallback","useCallback","useState","useState","useCallback","useCallback","useState","useState","useCallback","useState","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","jsx","useState","useState","jsx","jsxs","useState","jsx","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","Fragment","jsx","jsxs","Rows","useState","useCallback","useState","useState","useCallback","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","useEffect","useMemo","useEffect","useRef","jsx","jsxs","useRef","useEffect","useCallback","useState","Fragment","jsx","jsxs","useState","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/context/provider.tsx","../src/client/version.ts","../src/client/constants.ts","../src/client/errors.ts","../src/client/normalize.ts","../src/client/validate.ts","../src/client/client.ts","../src/identity/deviceId.ts","../src/store/keys.ts","../src/store/store.ts","../src/components/Board.tsx","../src/hooks/useFewchursConfig.ts","../src/hooks/useStoreState.ts","../src/components/BoardContext.tsx","../src/components/labels.ts","../src/components/Branding.tsx","../src/hooks/useFeature.ts","../src/hooks/useFeatures.ts","../src/hooks/useFollow.ts","../src/hooks/useVote.ts","../src/components/FeatureCard.tsx","../src/components/Comments.tsx","../src/hooks/useComments.ts","../src/components/time.ts","../src/components/FollowForm.tsx","../src/components/StatusBadge.tsx","../src/components/VoteButton.tsx","../src/components/Skeleton.tsx","../src/components/FeatureList.tsx","../src/components/SubmitForm.tsx","../src/hooks/useSubmitFeature.ts","../src/components/theme.ts","../src/components/BoardDialog.tsx","../src/components/BoardButton.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createFewchursClient, type FewchursClient } from \"../client/client\";\nimport { readDeviceId, resolveDeviceId } from \"../identity/deviceId\";\nimport { createStore, type EventHandler, type Store, type StoreState } from \"../store/store\";\n\nexport interface FewchursContextValue {\n client: FewchursClient;\n store: Store;\n deviceId: string | null;\n /** False only while a direct-to-API board is still waiting for its device id. */\n isReady: boolean;\n}\n\nconst FewchursContext = createContext<FewchursContextValue | null>(null);\n\nexport interface FewchursProviderProps {\n /** Publishable key for direct API calls. Omit when `baseUrl` points at your own proxy. */\n apiKey?: string;\n baseUrl?: string;\n /** A stable per-visitor id — hash it if it comes from your auth. */\n deviceId?: string;\n language?: string;\n pageSize?: number;\n /** Server-rendered data, so the first paint has real content. Set by `@fewchurs/next`. */\n initialState?: Partial<StoreState>;\n onEvent?: EventHandler;\n client?: FewchursClient;\n children: ReactNode;\n}\n\nexport function FewchursProvider({\n apiKey,\n baseUrl,\n deviceId: deviceIdProp,\n language,\n pageSize = 20,\n initialState,\n onEvent,\n client: clientProp,\n children,\n}: FewchursProviderProps): React.JSX.Element {\n // Read during the first render, not in an effect: child hooks fetch in effects that run\n // before this component's own effect, and a request without a device id is rejected.\n const [deviceId, setDeviceId] = useState<string | null>(() => deviceIdProp ?? readDeviceId());\n const deviceIdRef = useRef(deviceId);\n deviceIdRef.current = deviceIdProp ?? deviceId;\n\n const eventRef = useRef(onEvent);\n eventRef.current = onEvent;\n\n useEffect(() => {\n if (deviceIdProp) return;\n setDeviceId(resolveDeviceId());\n }, [deviceIdProp]);\n\n const client = useMemo(\n () =>\n clientProp ??\n createFewchursClient({\n apiKey,\n baseUrl,\n language,\n deviceId: () => deviceIdRef.current,\n }),\n [clientProp, apiKey, baseUrl, language],\n );\n\n const store = useMemo(\n () =>\n createStore(client, {\n pageSize,\n initialState,\n onEvent: (event) => eventRef.current?.(event),\n }),\n // initialState is a first-paint seed; a new object identity must not wipe live state.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, pageSize],\n );\n\n const value = useMemo<FewchursContextValue>(\n () => ({\n client,\n store,\n deviceId: deviceIdProp ?? deviceId,\n isReady: Boolean(deviceIdProp ?? deviceId) || !apiKey,\n }),\n [client, store, deviceIdProp, deviceId, apiKey],\n );\n\n return <FewchursContext.Provider value={value}>{children}</FewchursContext.Provider>;\n}\n\nexport function useFewchurs(): FewchursContextValue {\n const value = useContext(FewchursContext);\n if (!value) {\n throw new Error(\n \"Fewchurs components must be rendered inside <FewchursProvider>. In Next.js, <FewchursBoard> from @fewchurs/next provides one for you.\",\n );\n }\n return value;\n}\n","// Generated by tools/stamp-version.mjs from @fewchurs/react's package.json. Do not edit by hand.\nexport const SDK_VERSION = \"1.6.0\";\n","import type { FeatureStatus } from \"../types\";\nimport { SDK_VERSION } from \"./version\";\n\nexport { SDK_VERSION };\nexport const SDK_HEADER = `react/${SDK_VERSION}`;\nexport const DEFAULT_BASE_URL = \"https://www.fewchurs.com/api/v1\";\nexport const DEFAULT_PAGE_SIZE = 20;\n\n/** Mirrors the server's zod schemas, so the UI can reject input before a round trip. */\nexport const LIMITS = {\n titleMin: 3,\n titleMax: 100,\n descriptionMax: 1000,\n commentMin: 1,\n commentMax: 1000,\n authorNameMax: 60,\n} as const;\n\n/** Deliberately loose: the server owns the real check, this only catches obvious typos. */\nexport const EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/** What the Roadmap tab asks for, and what it keeps if the server ignores the filter. */\nexport const ROADMAP_STATUSES: FeatureStatus[] = [\"planned\", \"in_progress\", \"done\"];\n","export type FewchursError =\n | { code: \"invalid_key\"; status: 401 | 403; message: string }\n | { code: \"validation_failed\"; status: 400; message: string }\n | { code: \"rate_limited\"; status: 429; message: string }\n | { code: \"not_found\"; status: 404; message: string }\n | { code: \"limit_reached\"; status: 402; message: string }\n | { code: \"server\"; status: number; message: string }\n | { code: \"network\"; message: string };\n\nexport type Result<T> = { ok: true; data: T } | { ok: false; error: FewchursError };\n\ninterface ServerErrorBody {\n error?: { code?: string; message?: string };\n}\n\nexport const NOT_CONFIGURED_MESSAGE = \"Fewchurs is not configured.\";\n\nconst USER_MESSAGES: Record<FewchursError[\"code\"], string> = {\n invalid_key: \"Invalid API key. Check the key in your Fewchurs dashboard.\",\n validation_failed: \"Invalid input.\",\n rate_limited: \"You've reached today's limit. Try again tomorrow.\",\n not_found: \"This request no longer exists.\",\n limit_reached: \"This board isn't accepting requests right now.\",\n server: \"Something went wrong. Try again.\",\n network: \"You're offline.\",\n};\n\nexport function isWrongApp(error: FewchursError): boolean {\n return error.code === \"invalid_key\" && error.status === 403;\n}\n\nexport function isNotConfigured(error: FewchursError): boolean {\n return error.code === \"server\" && error.message === NOT_CONFIGURED_MESSAGE;\n}\n\nexport function notConfiguredError(): FewchursError {\n return { code: \"server\", status: 500, message: NOT_CONFIGURED_MESSAGE };\n}\n\n/** Safe to show a visitor. Only validation and `wrong_app` use the server's own text. */\nexport function userMessage(error: FewchursError): string {\n if (error.code === \"validation_failed\" && error.message) return error.message;\n if (isWrongApp(error) && error.message) return error.message;\n return USER_MESSAGES[error.code];\n}\n\nexport function networkError(message = \"Network request failed.\"): FewchursError {\n return { code: \"network\", message };\n}\n\nexport function validationError(message: string): FewchursError {\n return { code: \"validation_failed\", status: 400, message };\n}\n\nexport function errorFromResponse(status: number, body: unknown): FewchursError {\n const code = (body as ServerErrorBody | null)?.error?.code;\n const serverMessage = (body as ServerErrorBody | null)?.error?.message;\n const message = serverMessage ?? `Request failed (${status}).`;\n\n switch (code) {\n case \"invalid_key\":\n return { code: \"invalid_key\", status: 401, message };\n case \"wrong_app\":\n return { code: \"invalid_key\", status: 403, message };\n case \"missing_device_id\":\n return { code: \"server\", status: 400, message };\n case \"validation_failed\":\n return { code: \"validation_failed\", status: 400, message: serverMessage ?? \"Invalid input.\" };\n case \"rate_limited\":\n return { code: \"rate_limited\", status: 429, message };\n case \"not_found\":\n return { code: \"not_found\", status: 404, message };\n case \"limit_reached\":\n return { code: \"limit_reached\", status: 402, message };\n default:\n return status === 401\n ? { code: \"invalid_key\", status: 401, message }\n : { code: \"server\", status, message };\n }\n}\n","import type {\n Comment,\n CommentPage,\n Feature,\n FeaturePage,\n FeatureStatus,\n FewchursConfig,\n} from \"../types\";\n\nconst KNOWN_STATUSES = new Set<string>([\"open\", \"planned\", \"in_progress\", \"done\", \"declined\"]);\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nfunction str(value: unknown, fallback = \"\"): string {\n return typeof value === \"string\" ? value : fallback;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction bool(value: unknown): boolean {\n return value === true;\n}\n\nexport function normalizeStatus(value: unknown): FeatureStatus {\n return typeof value === \"string\" && KNOWN_STATUSES.has(value)\n ? (value as FeatureStatus)\n : \"unknown\";\n}\n\n// `isMine` is the server's answer once it ships; until then the raw author device id is the\n// only signal, so it is compared here and never surfaced on the public type.\nfunction isMine(raw: Record<string, unknown>, ownerKey: string, deviceId: string | null): boolean {\n if (typeof raw.isMine === \"boolean\") return raw.isMine;\n const owner = raw[ownerKey];\n return typeof owner === \"string\" && owner.length > 0 && owner === deviceId;\n}\n\nexport function normalizeFeature(value: unknown, deviceId: string | null): Feature {\n const raw = asRecord(value);\n return {\n id: str(raw.id),\n title: str(raw.title),\n description: str(raw.description),\n status: normalizeStatus(raw.status),\n upvoteCount: num(raw.upvoteCount),\n commentCount: num(raw.commentCount),\n followerCount: num(raw.followerCount),\n hasVoted: bool(raw.hasVoted),\n isFollowing: bool(raw.isFollowing),\n isMine: isMine(raw, \"authorDeviceId\", deviceId),\n createdAt: str(raw.createdAt),\n updatedAt: str(raw.updatedAt, str(raw.createdAt)),\n };\n}\n\nexport function normalizeComment(value: unknown, deviceId: string | null): Comment {\n const raw = asRecord(value);\n return {\n id: str(raw.id),\n text: str(raw.text),\n authorName: str(raw.authorName, \"App User\"),\n isDeveloper: bool(raw.isDeveloper),\n isMine: isMine(raw, \"deviceId\", deviceId),\n createdAt: str(raw.createdAt),\n };\n}\n\nexport function normalizeFeaturePage(value: unknown, deviceId: string | null): FeaturePage {\n const raw = asRecord(value);\n const features = Array.isArray(raw.features) ? raw.features : [];\n return {\n features: features.map((feature) => normalizeFeature(feature, deviceId)),\n nextCursor: typeof raw.nextCursor === \"string\" ? raw.nextCursor : null,\n };\n}\n\nexport function normalizeCommentPage(value: unknown, deviceId: string | null): CommentPage {\n const raw = asRecord(value);\n const comments = Array.isArray(raw.comments) ? raw.comments : [];\n return {\n comments: comments.map((comment) => normalizeComment(comment, deviceId)),\n nextCursor: typeof raw.nextCursor === \"string\" ? raw.nextCursor : null,\n };\n}\n\nexport function normalizeConfig(value: unknown): FewchursConfig {\n const raw = asRecord(value);\n return {\n showBranding: raw.showBranding !== false,\n hideVoteCounts: bool(raw.hideVoteCounts),\n appName: typeof raw.appName === \"string\" && raw.appName ? raw.appName : null,\n };\n}\n\nexport function normalizeVote(value: unknown): { upvoteCount: number; hasVoted: boolean } {\n const raw = asRecord(value);\n return { upvoteCount: num(raw.upvoteCount), hasVoted: bool(raw.hasVoted) };\n}\n","import { EMAIL_PATTERN, LIMITS } from \"./constants\";\nimport { validationError, type FewchursError } from \"./errors\";\nimport type { CreateCommentInput, SubmitFeatureInput } from \"../types\";\n\nexport function validateFeatureInput(input: SubmitFeatureInput): FewchursError | null {\n const title = input.title.trim();\n if (title.length < LIMITS.titleMin || title.length > LIMITS.titleMax) {\n return validationError(`Title must be ${LIMITS.titleMin}–${LIMITS.titleMax} characters.`);\n }\n if ((input.description ?? \"\").trim().length > LIMITS.descriptionMax) {\n return validationError(`Description must be at most ${LIMITS.descriptionMax} characters.`);\n }\n if (input.email !== undefined && input.email !== \"\" && !isEmail(input.email)) {\n return validationError(\"Enter a valid email address.\");\n }\n return null;\n}\n\nexport function validateCommentInput(input: CreateCommentInput): FewchursError | null {\n const text = input.text.trim();\n if (text.length < LIMITS.commentMin || text.length > LIMITS.commentMax) {\n return validationError(`Comment must be ${LIMITS.commentMin}–${LIMITS.commentMax} characters.`);\n }\n if ((input.authorName ?? \"\").trim().length > LIMITS.authorNameMax) {\n return validationError(`Name must be at most ${LIMITS.authorNameMax} characters.`);\n }\n return null;\n}\n\nexport function validateEmail(email: string): FewchursError | null {\n return isEmail(email) ? null : validationError(\"Enter a valid email address.\");\n}\n\nfunction isEmail(email: string): boolean {\n return EMAIL_PATTERN.test(email.trim());\n}\n","import { DEFAULT_BASE_URL, DEFAULT_PAGE_SIZE, SDK_HEADER } from \"./constants\";\nimport {\n errorFromResponse,\n isNotConfigured,\n networkError,\n notConfiguredError,\n type FewchursError,\n type Result,\n} from \"./errors\";\nimport {\n normalizeComment,\n normalizeCommentPage,\n normalizeConfig,\n normalizeFeature,\n normalizeFeaturePage,\n normalizeVote,\n} from \"./normalize\";\nimport { validateCommentInput, validateEmail, validateFeatureInput } from \"./validate\";\nimport type {\n Comment,\n CommentPage,\n CreateCommentInput,\n Feature,\n FeaturePage,\n FewchursConfig,\n ListCommentsParams,\n ListFeaturesParams,\n SubmitFeatureInput,\n} from \"../types\";\n\nexport type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;\n\nexport interface FewchursClientOptions {\n /** Server-side, or in a SPA where the key is publishable. Omit when calling your own proxy. */\n apiKey?: string;\n /** `https://www.fewchurs.com/api/v1` by default, or a proxy path such as `/api/fewchurs`. */\n baseUrl?: string;\n deviceId?: string | null | (() => string | null);\n /** Sent as `Accept-Language`, so server-side copy and emails match the visitor. */\n language?: string;\n /**\n * The domain the API key is checked against, for calls made from a server. A browser reports\n * its own domain through `Origin`, which always wins, so leave this out in a SPA.\n */\n appId?: string;\n fetch?: FetchLike;\n retries?: number;\n retryDelayMs?: number;\n}\n\nexport interface FewchursClient {\n readonly baseUrl: string;\n getDeviceId(): string | null;\n getConfig(signal?: AbortSignal): Promise<Result<FewchursConfig>>;\n listFeatures(params?: ListFeaturesParams, signal?: AbortSignal): Promise<Result<FeaturePage>>;\n getFeature(featureId: string, signal?: AbortSignal): Promise<Result<Feature>>;\n submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;\n vote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n unvote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n follow(featureId: string, email: string): Promise<Result<{ following: boolean }>>;\n unfollow(featureId: string): Promise<Result<{ following: boolean }>>;\n listComments(\n featureId: string,\n params?: ListCommentsParams,\n signal?: AbortSignal,\n ): Promise<Result<CommentPage>>;\n createComment(input: CreateCommentInput): Promise<Result<Comment>>;\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: unknown;\n query?: Record<string, string | number | undefined | null>;\n signal?: AbortSignal;\n}\n\nexport function createFewchursClient(options: FewchursClientOptions = {}): FewchursClient {\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n const doFetch = options.fetch ?? globalThis.fetch?.bind(globalThis);\n const retries = options.retries ?? 1;\n const retryDelayMs = options.retryDelayMs ?? 250;\n\n if (options.apiKey && !options.apiKey.startsWith(\"fr_\")) logOnce(BAD_KEY_PREFIX);\n\n function getDeviceId(): string | null {\n return typeof options.deviceId === \"function\" ? options.deviceId() : (options.deviceId ?? null);\n }\n\n function headers(hasBody: boolean): Record<string, string> {\n const result: Record<string, string> = {\n Accept: \"application/json\",\n \"X-Fewchurs-Sdk\": SDK_HEADER,\n };\n if (hasBody) result[\"Content-Type\"] = \"application/json\";\n if (options.apiKey) result.Authorization = `Bearer ${options.apiKey}`;\n const deviceId = getDeviceId();\n if (deviceId) result[\"X-Device-Id\"] = deviceId;\n if (options.language) result[\"Accept-Language\"] = options.language;\n if (options.appId) result[\"X-Fewchurs-App-Id\"] = options.appId;\n return result;\n }\n\n function url(path: string, query?: RequestOptions[\"query\"]): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(query ?? {})) {\n if (value !== undefined && value !== null && value !== \"\") search.set(key, String(value));\n }\n const qs = search.toString();\n return `${baseUrl}${path}${qs ? `?${qs}` : \"\"}`;\n }\n\n async function request<T>(\n path: string,\n map: (body: unknown) => T,\n { method = \"GET\", body, query, signal }: RequestOptions = {},\n ): Promise<Result<T>> {\n if (!doFetch) return { ok: false, error: networkError(\"No fetch implementation available.\") };\n if (!options.apiKey && options.baseUrl === undefined) {\n const failure = notConfiguredError();\n logError(failure);\n return { ok: false, error: failure };\n }\n\n const target = url(path, query);\n const init: RequestInit = { method, headers: headers(body !== undefined) };\n if (body !== undefined) init.body = JSON.stringify(body);\n if (signal) init.signal = signal;\n\n // Only GETs are retried: a retried POST could double-submit a request or a comment.\n const attempts = method === \"GET\" ? retries + 1 : 1;\n\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n let response: Response;\n try {\n response = await doFetch(target, init);\n } catch (error) {\n if (signal?.aborted) return { ok: false, error: networkError(\"Request aborted.\") };\n if (attempt < attempts - 1) {\n await delay(retryDelayMs);\n continue;\n }\n const failure = networkError(messageOf(error));\n logError(failure);\n return { ok: false, error: failure };\n }\n\n if (response.ok) {\n const payload = await readJson(response);\n return { ok: true, data: map(payload) };\n }\n\n if (response.status >= 500 && attempt < attempts - 1) {\n await delay(retryDelayMs);\n continue;\n }\n\n const failure = errorFromResponse(response.status, await readJson(response));\n logError(failure);\n return { ok: false, error: failure };\n }\n\n return { ok: false, error: networkError() };\n }\n\n return {\n baseUrl,\n getDeviceId,\n\n getConfig: (signal) => request(\"/config\", normalizeConfig, { signal }),\n\n listFeatures: (params = {}, signal) =>\n request(\"/features\", (body) => normalizeFeaturePage(body, getDeviceId()), {\n query: {\n sort: params.sort ?? \"new\",\n limit: params.limit ?? DEFAULT_PAGE_SIZE,\n cursor: params.cursor ?? undefined,\n status: params.status?.length ? params.status.join(\",\") : undefined,\n },\n signal,\n }),\n\n getFeature: (featureId, signal) =>\n request(\n `/features/${encodeURIComponent(featureId)}`,\n (body) => normalizeFeature(body, getDeviceId()),\n { signal },\n ),\n\n submitFeature: async (input) => {\n const invalid = validateFeatureInput(input);\n if (invalid) return { ok: false, error: invalid };\n return request(\"/features\", (body) => normalizeFeature(body, getDeviceId()), {\n method: \"POST\",\n body: {\n title: input.title.trim(),\n description: (input.description ?? \"\").trim(),\n ...(input.email ? { email: input.email.trim() } : {}),\n isSubscriber: input.isSubscriber ?? false,\n },\n });\n },\n\n vote: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/vote`, normalizeVote, { method: \"POST\" }),\n\n unvote: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/vote`, normalizeVote, {\n method: \"DELETE\",\n }),\n\n follow: async (featureId, email) => {\n const invalid = validateEmail(email);\n if (invalid) return { ok: false, error: invalid };\n return request(\n `/features/${encodeURIComponent(featureId)}/follow`,\n () => ({ following: true }),\n {\n method: \"POST\",\n body: { email: email.trim() },\n },\n );\n },\n\n unfollow: (featureId) =>\n request(`/features/${encodeURIComponent(featureId)}/follow`, () => ({ following: false }), {\n method: \"DELETE\",\n }),\n\n listComments: (featureId, params = {}, signal) =>\n request(\n `/features/${encodeURIComponent(featureId)}/comments`,\n (body) => normalizeCommentPage(body, getDeviceId()),\n {\n query: { limit: params.limit ?? DEFAULT_PAGE_SIZE, cursor: params.cursor ?? undefined },\n signal,\n },\n ),\n\n // The server takes the feature id in the body here; POST /features/{id}/comments is a 405.\n createComment: async (input) => {\n const invalid = validateCommentInput(input);\n if (invalid) return { ok: false, error: invalid };\n return request(\"/comments\", (body) => normalizeComment(body, getDeviceId()), {\n method: \"POST\",\n body: {\n featureId: input.featureId,\n text: input.text.trim(),\n ...(input.authorName?.trim() ? { authorName: input.authorName.trim() } : {}),\n },\n });\n },\n };\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : \"Network request failed.\";\n}\n\n// Declared, not imported from @types/node: this is a browser package, and bundlers replace\n// `process.env.NODE_ENV` inline, so the check costs nothing in a production build.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\n\nconst INVALID_KEY_HELP =\n \"Fewchurs rejected the API key. Check the key in your dashboard (Apps → API keys).\";\n\nconst NOT_CONFIGURED_HELP =\n \"Fewchurs is not configured. Pass apiKey to FewchursProvider, or set FEWCHURS_API_KEY on your server.\";\n\nconst BAD_KEY_PREFIX = 'The Fewchurs API key should start with \"fr_\". Copy it from your dashboard.';\n\nconst loggedErrors = new Set<string>();\n\nfunction logOnce(detail: string): void {\n if (typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\") return;\n if (loggedErrors.has(detail)) return;\n loggedErrors.add(detail);\n console.warn(`[fewchurs] : ${detail}`);\n}\n\nfunction logError(error: FewchursError): void {\n if (isNotConfigured(error)) return logOnce(NOT_CONFIGURED_HELP);\n const isInvalidKey = error.code === \"invalid_key\" && error.status === 401;\n logOnce(isInvalidKey ? INVALID_KEY_HELP : error.message);\n}\n","const COOKIE_NAME = \"fewchurs_did\";\nconst STORAGE_KEY = \"fewchurs_device_id\";\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 365;\n\nexport function createDeviceId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `fw-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n}\n\nexport function readDeviceId(): string | null {\n if (typeof document === \"undefined\") return null;\n return readCookie() ?? readStorage();\n}\n\n/**\n * Cookie first, storage second: a cookie is the only copy a same-origin server can read, so\n * the board renders with the same identity on both sides and never mismatches on hydration.\n */\nexport function resolveDeviceId(): string {\n const existing = readDeviceId();\n if (existing) {\n persist(existing);\n return existing;\n }\n const created = createDeviceId();\n persist(created);\n return created;\n}\n\nfunction persist(deviceId: string): void {\n if (typeof document === \"undefined\") return;\n try {\n document.cookie = `${COOKIE_NAME}=${encodeURIComponent(deviceId)}; path=/; max-age=${COOKIE_MAX_AGE}; SameSite=Lax`;\n } catch {\n // Cookies can be blocked entirely; storage below is the fallback.\n }\n try {\n localStorage.setItem(STORAGE_KEY, deviceId);\n } catch {\n // Private-mode storage throws on write; the cookie or a fresh id per visit still works.\n }\n}\n\nfunction readCookie(): string | null {\n const match = document.cookie.match(new RegExp(`(?:^|; )${COOKIE_NAME}=([^;]*)`));\n return match?.[1] ? decodeURIComponent(match[1]) : null;\n}\n\nfunction readStorage(): string | null {\n try {\n return localStorage.getItem(STORAGE_KEY);\n } catch {\n return null;\n }\n}\n\nexport { COOKIE_NAME as DEVICE_ID_COOKIE };\n","import type { FeatureStatus, FeatureSort } from \"../types\";\n\nexport interface ListQuery {\n sort: FeatureSort;\n status?: FeatureStatus[];\n}\n\nexport function listKey({ sort, status }: ListQuery): string {\n return status?.length ? `${sort}:${[...status].sort().join(\",\")}` : sort;\n}\n\n/**\n * One feature, fetched by id, kept in `lists` beside the real lists. That way a deep-linked\n * request goes through the same vote, comment and follow updates as a row in a list.\n */\nexport function featureKey(featureId: string): string {\n return `feature:${featureId}`;\n}\n","import type { FewchursClient } from \"../client/client\";\nimport type { FewchursError, Result } from \"../client/errors\";\nimport type {\n Comment,\n CreateCommentInput,\n Feature,\n FewchursConfig,\n SubmitFeatureInput,\n} from \"../types\";\nimport { featureKey, listKey, type ListQuery } from \"./keys\";\n\nexport type LoadStatus = \"idle\" | \"loading\" | \"loadingMore\" | \"ready\" | \"error\";\n\nexport interface ListState {\n features: Feature[];\n cursor: string | null;\n status: LoadStatus;\n error: FewchursError | null;\n}\n\nexport interface CommentsState {\n comments: Comment[];\n cursor: string | null;\n status: LoadStatus;\n error: FewchursError | null;\n}\n\nexport interface StoreState {\n config: FewchursConfig | null;\n lists: Record<string, ListState>;\n comments: Record<string, CommentsState>;\n}\n\nexport type FewchursEventName =\n \"boardOpened\" | \"featureSubmitted\" | \"voted\" | \"commented\" | \"followed\" | \"error\";\n\nexport interface FewchursEvent {\n name: FewchursEventName;\n featureId?: string;\n hasVoted?: boolean;\n following?: boolean;\n error?: FewchursError;\n}\n\nexport type EventHandler = (event: FewchursEvent) => void;\n\nexport interface StoreOptions {\n pageSize?: number;\n initialState?: Partial<StoreState>;\n onEvent?: EventHandler;\n}\n\nexport interface Store {\n subscribe(listener: () => void): () => void;\n getState(): StoreState;\n ensureConfig(): void;\n ensureFeatures(query: ListQuery, pageSize?: number): void;\n ensureFeature(featureId: string): void;\n refreshFeature(featureId: string): Promise<void>;\n refresh(query: ListQuery, pageSize?: number): Promise<void>;\n loadMore(query: ListQuery, pageSize?: number): Promise<void>;\n ensureComments(featureId: string): void;\n refreshComments(featureId: string): Promise<void>;\n loadMoreComments(featureId: string): Promise<void>;\n toggleVote(featureId: string): Promise<Result<{ upvoteCount: number; hasVoted: boolean }>>;\n submitFeature(input: SubmitFeatureInput): Promise<Result<Feature>>;\n addComment(input: CreateCommentInput): Promise<Result<Comment>>;\n setFollowing(featureId: string, email: string | null): Promise<Result<{ following: boolean }>>;\n emit(event: FewchursEvent): void;\n}\n\nconst EMPTY_LIST: ListState = { features: [], cursor: null, status: \"idle\", error: null };\nconst EMPTY_COMMENTS: CommentsState = { comments: [], cursor: null, status: \"idle\", error: null };\n\n// The server filters deleted comments after paging, so a page can come back empty while a\n// cursor remains. Follow the cursor a few times before showing \"no comments yet\".\nconst MAX_EMPTY_PAGES = 5;\n\nexport function createStore(\n client: FewchursClient,\n { pageSize = 20, initialState, onEvent }: StoreOptions = {},\n): Store {\n let state: StoreState = {\n config: initialState?.config ?? null,\n lists: initialState?.lists ?? {},\n comments: initialState?.comments ?? {},\n };\n\n const listeners = new Set<() => void>();\n const inFlight = new Map<string, Promise<void>>();\n\n function setState(next: Partial<StoreState>): void {\n state = { ...state, ...next };\n for (const listener of listeners) listener();\n }\n\n function setList(key: string, patch: Partial<ListState>): void {\n const current = state.lists[key] ?? EMPTY_LIST;\n setState({ lists: { ...state.lists, [key]: { ...current, ...patch } } });\n }\n\n function setComments(featureId: string, patch: Partial<CommentsState>): void {\n const current = state.comments[featureId] ?? EMPTY_COMMENTS;\n setState({ comments: { ...state.comments, [featureId]: { ...current, ...patch } } });\n }\n\n function emit(event: FewchursEvent): void {\n onEvent?.(event);\n }\n\n function fail(error: FewchursError): void {\n emit({ name: \"error\", error });\n }\n\n /** One request per key at a time: a remounting board must not double-fetch page one. */\n function dedupe(key: string, run: () => Promise<void>): Promise<void> {\n const existing = inFlight.get(key);\n if (existing) return existing;\n const promise = run().finally(() => inFlight.delete(key));\n inFlight.set(key, promise);\n return promise;\n }\n\n function mapFeature(featureId: string, update: (feature: Feature) => Feature): void {\n const lists: Record<string, ListState> = {};\n let changed = false;\n for (const [key, list] of Object.entries(state.lists)) {\n const index = list.features.findIndex((feature) => feature.id === featureId);\n if (index === -1) {\n lists[key] = list;\n continue;\n }\n changed = true;\n const features = [...list.features];\n features[index] = update(features[index] as Feature);\n lists[key] = { ...list, features };\n }\n if (changed) setState({ lists });\n }\n\n async function fetchFeatures(query: ListQuery, append: boolean, size: number): Promise<void> {\n const key = listKey(query);\n const current = state.lists[key] ?? EMPTY_LIST;\n if (append && !current.cursor) return;\n\n setList(key, { status: append ? \"loadingMore\" : \"loading\", error: null });\n\n const result = await client.listFeatures({\n sort: query.sort,\n status: query.status,\n limit: size,\n cursor: append ? current.cursor : null,\n });\n\n if (!result.ok) {\n setList(key, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n\n const previous = append ? (state.lists[key]?.features ?? []) : [];\n setList(key, {\n features: dedupeById([...previous, ...result.data.features]),\n cursor: result.data.nextCursor,\n status: \"ready\",\n error: null,\n });\n }\n\n async function fetchFeature(featureId: string): Promise<void> {\n const key = featureKey(featureId);\n setList(key, { status: \"loading\", error: null });\n\n const result = await client.getFeature(featureId);\n if (!result.ok) {\n setList(key, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n\n setList(key, { features: [result.data], cursor: null, status: \"ready\", error: null });\n }\n\n async function fetchComments(featureId: string, append: boolean): Promise<void> {\n const current = state.comments[featureId] ?? EMPTY_COMMENTS;\n if (append && !current.cursor) return;\n\n setComments(featureId, { status: append ? \"loadingMore\" : \"loading\", error: null });\n\n let cursor = append ? current.cursor : null;\n const collected: Comment[] = [];\n\n for (let page = 0; page < MAX_EMPTY_PAGES; page += 1) {\n const result = await client.listComments(featureId, { limit: pageSize, cursor });\n if (!result.ok) {\n setComments(featureId, { status: \"error\", error: result.error });\n fail(result.error);\n return;\n }\n collected.push(...result.data.comments);\n cursor = result.data.nextCursor;\n if (collected.length > 0 || !cursor) break;\n }\n\n const previous = append ? (state.comments[featureId]?.comments ?? []) : [];\n setComments(featureId, {\n comments: dedupeById([...previous, ...collected]),\n cursor,\n status: \"ready\",\n error: null,\n });\n }\n\n return {\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n\n getState: () => state,\n\n emit,\n\n ensureConfig() {\n if (state.config) return;\n void dedupe(\"config\", async () => {\n const result = await client.getConfig();\n if (result.ok) setState({ config: result.data });\n });\n },\n\n ensureFeatures(query, size = pageSize) {\n const key = listKey(query);\n if ((state.lists[key] ?? EMPTY_LIST).status !== \"idle\") return;\n void dedupe(`features:${key}`, () => fetchFeatures(query, false, size));\n },\n\n refresh(query, size = pageSize) {\n return dedupe(`features:${listKey(query)}`, () => fetchFeatures(query, false, size));\n },\n\n loadMore(query, size = pageSize) {\n return dedupe(`features:more:${listKey(query)}`, () => fetchFeatures(query, true, size));\n },\n\n ensureFeature(featureId) {\n if ((state.lists[featureKey(featureId)] ?? EMPTY_LIST).status !== \"idle\") return;\n void dedupe(`feature:${featureId}`, () => fetchFeature(featureId));\n },\n\n refreshFeature(featureId) {\n return dedupe(`feature:${featureId}`, () => fetchFeature(featureId));\n },\n\n ensureComments(featureId) {\n if ((state.comments[featureId] ?? EMPTY_COMMENTS).status !== \"idle\") return;\n void dedupe(`comments:${featureId}`, () => fetchComments(featureId, false));\n },\n\n refreshComments(featureId) {\n return dedupe(`comments:${featureId}`, () => fetchComments(featureId, false));\n },\n\n loadMoreComments(featureId) {\n return dedupe(`comments:more:${featureId}`, () => fetchComments(featureId, true));\n },\n\n async toggleVote(featureId) {\n const before = findFeature(state, featureId);\n if (!before)\n return {\n ok: false,\n error: { code: \"not_found\", status: 404, message: \"Unknown feature.\" },\n };\n\n const nextVoted = !before.hasVoted;\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: nextVoted,\n upvoteCount: Math.max(0, feature.upvoteCount + (nextVoted ? 1 : -1)),\n }));\n\n const result = nextVoted ? await client.vote(featureId) : await client.unvote(featureId);\n\n if (!result.ok) {\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: before.hasVoted,\n upvoteCount: before.upvoteCount,\n }));\n fail(result.error);\n return result;\n }\n\n mapFeature(featureId, (feature) => ({\n ...feature,\n hasVoted: result.data.hasVoted,\n upvoteCount: result.data.upvoteCount,\n }));\n emit({ name: \"voted\", featureId, hasVoted: result.data.hasVoted });\n return result;\n },\n\n async submitFeature(input) {\n const result = await client.submitFeature(input);\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n const lists: Record<string, ListState> = {};\n for (const [key, list] of Object.entries(state.lists)) {\n // A brand-new request has no votes, so it only belongs at the top of the \"new\" list.\n lists[key] = key.startsWith(\"new\")\n ? { ...list, features: dedupeById([result.data, ...list.features]) }\n : list;\n }\n setState({ lists });\n emit({ name: \"featureSubmitted\", featureId: result.data.id });\n return result;\n },\n\n async addComment(input) {\n const result = await client.createComment(input);\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n const current = state.comments[input.featureId] ?? EMPTY_COMMENTS;\n setComments(input.featureId, { comments: [...current.comments, result.data] });\n mapFeature(input.featureId, (feature) => ({\n ...feature,\n commentCount: feature.commentCount + 1,\n }));\n emit({ name: \"commented\", featureId: input.featureId });\n return result;\n },\n\n async setFollowing(featureId, email) {\n const result = email\n ? await client.follow(featureId, email)\n : await client.unfollow(featureId);\n\n if (!result.ok) {\n fail(result.error);\n return result;\n }\n\n mapFeature(featureId, (feature) => ({\n ...feature,\n isFollowing: result.data.following,\n followerCount: Math.max(0, feature.followerCount + (result.data.following ? 1 : -1)),\n }));\n emit({ name: \"followed\", featureId, following: result.data.following });\n return result;\n },\n };\n}\n\nexport function listStateOf(state: StoreState, key: string): ListState {\n return state.lists[key] ?? EMPTY_LIST;\n}\n\nexport function commentsStateOf(state: StoreState, featureId: string): CommentsState {\n return state.comments[featureId] ?? EMPTY_COMMENTS;\n}\n\nfunction findFeature(state: StoreState, featureId: string): Feature | null {\n for (const list of Object.values(state.lists)) {\n const found = list.features.find((feature) => feature.id === featureId);\n if (found) return found;\n }\n return null;\n}\n\nfunction dedupeById<T extends { id: string }>(items: T[]): T[] {\n const seen = new Set<string>();\n const result: T[] = [];\n for (const item of items) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n result.push(item);\n }\n return result;\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useFewchursConfig } from \"../hooks/useFewchursConfig\";\nimport {\n BoardContextProvider,\n makeClassName,\n useBoard,\n type BoardContextValue,\n type BoardTab,\n type EmailFieldMode,\n type FeatureActions,\n} from \"./BoardContext\";\nimport { Branding } from \"./Branding\";\nimport { FeatureList } from \"./FeatureList\";\nimport { SubmitForm } from \"./SubmitForm\";\nimport { mergeLabels, type BoardLabels } from \"./labels\";\nimport { themeToStyle, type BoardTheme } from \"./theme\";\nimport type { Feature } from \"../types\";\n\nexport interface FewchursBoardProps {\n tabs?: BoardTab[];\n defaultTab?: BoardTab;\n /** Shows this request above the list, for a link straight to one request. */\n initialFeatureId?: string;\n showDeclined?: boolean;\n allowComments?: boolean;\n emailField?: EmailFieldMode;\n pageSize?: number;\n labels?: Partial<BoardLabels>;\n theme?: BoardTheme;\n /** Drops every class name but keeps behaviour, ARIA and keyboard handling. */\n unstyled?: boolean;\n colorScheme?: \"light\" | \"dark\" | \"system\";\n className?: string;\n style?: CSSProperties;\n /** Prefills the submit and follow forms. */\n userEmail?: string;\n isSubscriber?: boolean;\n renderHeader?: () => ReactNode;\n renderEmpty?: () => ReactNode;\n renderFeature?: (feature: Feature, actions: FeatureActions) => ReactNode;\n children?: ReactNode;\n}\n\n/** Hoisted so the default does not hand the context a new array identity every render. */\n// Top and New, like the Flutter and Laravel boards. Roadmap is opt-in: tabs={[\"top\", \"new\", \"roadmap\"]}.\nconst DEFAULT_TABS: BoardTab[] = [\"top\", \"new\"];\n\nexport function BoardRoot({\n tabs = DEFAULT_TABS,\n defaultTab,\n initialFeatureId,\n showDeclined = false,\n allowComments = true,\n emailField = \"optional\",\n pageSize,\n labels,\n theme,\n unstyled = false,\n colorScheme = \"system\",\n className,\n style,\n userEmail,\n isSubscriber = false,\n renderHeader,\n renderEmpty,\n renderFeature,\n children,\n}: FewchursBoardProps): React.JSX.Element {\n const { store } = useFewchurs();\n const { hideVoteCounts } = useFewchursConfig();\n const [tab, setTab] = useState<BoardTab>(defaultTab ?? tabs[0] ?? \"top\");\n const [isFormOpen, setFormOpen] = useState(false);\n const [justSubmitted, setJustSubmitted] = useState(false);\n\n useEffect(() => {\n store.emit({ name: \"boardOpened\" });\n }, [store]);\n\n const value = useMemo<BoardContextValue>(\n () => ({\n labels: mergeLabels(labels),\n unstyled,\n allowComments,\n emailField,\n showDeclined,\n hideVoteCounts,\n pageSize,\n userEmail,\n isSubscriber,\n tab,\n setTab,\n tabs,\n initialFeatureId,\n isFormOpen,\n setFormOpen,\n justSubmitted,\n setJustSubmitted,\n renderFeature,\n renderEmpty,\n renderHeader,\n cx: makeClassName(unstyled),\n }),\n [\n labels,\n unstyled,\n allowComments,\n emailField,\n showDeclined,\n hideVoteCounts,\n pageSize,\n userEmail,\n isSubscriber,\n tab,\n tabs,\n initialFeatureId,\n isFormOpen,\n justSubmitted,\n renderFeature,\n renderEmpty,\n renderHeader,\n ],\n );\n\n return (\n <BoardContextProvider value={value}>\n <section\n className={[unstyled ? \"\" : \"fewchurs\", className].filter(Boolean).join(\" \") || undefined}\n style={{ ...themeToStyle(theme), ...style }}\n data-theme={colorScheme === \"system\" ? undefined : colorScheme}\n >\n {children ?? <DefaultBoard />}\n </section>\n </BoardContextProvider>\n );\n}\n\nfunction DefaultBoard(): React.JSX.Element {\n const { renderHeader } = useBoard();\n\n return (\n <>\n {renderHeader ? renderHeader() : <BoardHeading />}\n <BoardPanels />\n <Branding />\n </>\n );\n}\n\nconst LEAVE_MS = 110;\nconst ENTER_MS = 300;\nconst ENTER_EASING = \"cubic-bezier(0.22, 1, 0.36, 1)\";\n\nfunction canAnimate(element: HTMLElement | null): element is HTMLElement {\n if (!element || typeof element.animate !== \"function\") return false;\n return !window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\nfunction BoardPanels(): React.JSX.Element {\n const { isFormOpen, setFormOpen, justSubmitted, setJustSubmitted, labels, unstyled, cx } =\n useBoard();\n const [showForm, setShowForm] = useState(isFormOpen);\n const panel = useRef<HTMLDivElement>(null);\n const trigger = useRef<HTMLButtonElement>(null);\n const entering = useRef<Animation | null>(null);\n const hasSwapped = useRef(false);\n\n useEffect(() => {\n if (isFormOpen === showForm) return;\n hasSwapped.current = true;\n\n const element = panel.current;\n if (unstyled || !canAnimate(element)) {\n setShowForm(isFormOpen);\n return;\n }\n\n entering.current?.cancel();\n const leaving = element.animate(\n { opacity: [1, 0], transform: [\"translateY(0)\", \"translateY(-4px)\"] },\n { duration: LEAVE_MS, easing: \"ease-in\", fill: \"forwards\" },\n );\n\n leaving.onfinish = () => {\n const from = element.offsetHeight;\n flushSync(() => setShowForm(isFormOpen));\n leaving.cancel();\n const to = element.offsetHeight;\n\n element.style.overflow = \"hidden\";\n const enter = element.animate(\n {\n opacity: [0, 1],\n transform: [\"translateY(6px)\", \"translateY(0)\"],\n height: [`${from}px`, `${to}px`],\n },\n { duration: ENTER_MS, easing: ENTER_EASING },\n );\n const finish = () => {\n element.style.overflow = \"\";\n };\n enter.onfinish = finish;\n enter.oncancel = finish;\n entering.current = enter;\n };\n\n return () => leaving.cancel();\n }, [isFormOpen, showForm, unstyled]);\n\n useEffect(() => {\n if (!hasSwapped.current) return;\n const target = showForm\n ? panel.current?.querySelector<HTMLElement>(\"#fw-title\")\n : trigger.current;\n target?.focus({ preventScroll: true });\n }, [showForm]);\n\n return (\n <div ref={panel}>\n <div hidden={showForm}>\n <div className={cx(\"fw-toolbar\")}>\n <BoardTabs />\n <button\n ref={trigger}\n type=\"button\"\n className={cx(\"fw-btn\")}\n onClick={() => {\n setJustSubmitted(false);\n setFormOpen(true);\n }}\n >\n {labels.newRequest}\n </button>\n </div>\n {justSubmitted && (\n <p className={cx(\"fw-alert\")} role=\"status\">\n {labels.submitted}\n </p>\n )}\n <FeatureList />\n </div>\n {showForm && <SubmitForm />}\n </div>\n );\n}\n\nfunction BoardHeading(): React.JSX.Element {\n const { labels, cx } = useBoard();\n return <h2 className={cx(\"fw-heading\")}>{labels.title}</h2>;\n}\n\nexport function BoardTabs(): React.JSX.Element | null {\n const { tabs, tab, setTab, labels, cx } = useBoard();\n if (tabs.length < 2) return null;\n\n const labelOf: Record<BoardTab, string> = {\n top: labels.tabTop,\n new: labels.tabNew,\n roadmap: labels.tabRoadmap,\n };\n\n return (\n <div className={cx(\"fw-tabs\")} role=\"tablist\" aria-label={labels.title}>\n {tabs.map((name) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n id={`fw-tab-${name}`}\n className={cx(\"fw-tab\")}\n aria-selected={tab === name}\n tabIndex={tab === name ? 0 : -1}\n onClick={() => setTab(name)}\n onKeyDown={(event) => {\n const step = event.key === \"ArrowRight\" ? 1 : event.key === \"ArrowLeft\" ? -1 : 0;\n if (step === 0) return;\n event.preventDefault();\n const next = tabs[(tabs.indexOf(tab) + step + tabs.length) % tabs.length];\n if (next) {\n setTab(next);\n document.getElementById(`fw-tab-${next}`)?.focus();\n }\n }}\n >\n {labelOf[name]}\n </button>\n ))}\n </div>\n );\n}\n\nexport function SubmitTrigger(): React.JSX.Element {\n const { isFormOpen, setFormOpen, setJustSubmitted, labels, cx } = useBoard();\n\n return (\n <button\n type=\"button\"\n className={cx(\"fw-btn\")}\n aria-expanded={isFormOpen}\n onClick={() => {\n if (!isFormOpen) setJustSubmitted(false);\n setFormOpen(!isFormOpen);\n }}\n >\n {isFormOpen ? labels.cancel : labels.newRequest}\n </button>\n );\n}\n\n/** Level 1 by default, level 5 when given children to compose. */\nexport const FewchursBoard = Object.assign(BoardRoot, {\n Root: BoardRoot,\n Tabs: BoardTabs,\n List: FeatureList,\n SubmitTrigger,\n SubmitForm,\n Branding,\n});\n","\"use client\";\n\nimport { useEffect } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\n\nexport interface UseFewchursConfigResult {\n showBranding: boolean;\n hideVoteCounts: boolean;\n appName: string | null;\n isLoading: boolean;\n}\n\nexport function useFewchursConfig(): UseFewchursConfigResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n\n useEffect(() => {\n store.ensureConfig();\n }, [store]);\n\n return {\n showBranding: state.config?.showBranding ?? false,\n hideVoteCounts: state.config?.hideVoteCounts ?? false,\n appName: state.config?.appName ?? null,\n isLoading: state.config === null,\n };\n}\n","\"use client\";\n\nimport { useSyncExternalStore } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport type { StoreState } from \"../store/store\";\n\nexport function useStoreState(): StoreState {\n const { store } = useFewchurs();\n // The same snapshot on the server and the first client render: the store is seeded with\n // whatever was rendered server-side, so nothing re-renders into different markup.\n return useSyncExternalStore(store.subscribe, store.getState, store.getState);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { DEFAULT_LABELS, type BoardLabels } from \"./labels\";\nimport type { Feature, FeatureSort } from \"../types\";\n\nexport type BoardTab = FeatureSort | \"roadmap\";\nexport type EmailFieldMode = \"off\" | \"optional\" | \"required\";\n\nexport interface FeatureActions {\n toggleVote: () => Promise<void>;\n follow: (email: string) => Promise<boolean>;\n unfollow: () => Promise<boolean>;\n}\n\nexport interface BoardContextValue {\n labels: BoardLabels;\n unstyled: boolean;\n allowComments: boolean;\n emailField: EmailFieldMode;\n showDeclined: boolean;\n hideVoteCounts: boolean;\n pageSize?: number;\n userEmail?: string;\n isSubscriber: boolean;\n tab: BoardTab;\n setTab: (tab: BoardTab) => void;\n tabs: BoardTab[];\n /** A request to show above the list, for a deep link into the board. */\n initialFeatureId?: string;\n isFormOpen: boolean;\n setFormOpen: (open: boolean) => void;\n /** Survives the submit form closing, so the confirmation is not unmounted with it. */\n justSubmitted: boolean;\n setJustSubmitted: (submitted: boolean) => void;\n renderFeature?: (feature: Feature, actions: FeatureActions) => React.ReactNode;\n renderEmpty?: () => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n /** Returns a class name, or undefined in unstyled mode. */\n cx: (...names: string[]) => string | undefined;\n}\n\nconst BoardContext = createContext<BoardContextValue | null>(null);\n\nexport const BoardContextProvider = BoardContext.Provider;\n\nexport function useBoard(): BoardContextValue {\n const value = useContext(BoardContext);\n if (!value) {\n throw new Error(\"Fewchurs board parts must be rendered inside <FewchursBoard.Root>.\");\n }\n return value;\n}\n\nexport function makeClassName(unstyled: boolean) {\n return (...names: string[]): string | undefined =>\n unstyled ? undefined : names.filter(Boolean).join(\" \");\n}\n\nexport const FALLBACK_LABELS = DEFAULT_LABELS;\n","import type { FeatureStatus } from \"../types\";\n\nexport interface BoardLabels {\n title: string;\n tabTop: string;\n tabNew: string;\n tabRoadmap: string;\n newRequest: string;\n cancel: string;\n submit: string;\n submitting: string;\n submitted: string;\n fieldTitle: string;\n fieldTitlePlaceholder: string;\n fieldDescription: string;\n fieldDescriptionPlaceholder: string;\n fieldEmail: string;\n fieldEmailHint: string;\n fieldName: string;\n emptyTitle: string;\n emptyBody: string;\n loading: string;\n loadMore: string;\n retry: string;\n errorInvalidKeyTitle: string;\n errorInvalidKeyDetail: string;\n errorWrongAppTitle: string;\n errorWrongAppDetail: string;\n errorTitle: string;\n errorDetail: string;\n errorOfflineTitle: string;\n errorOfflineDetail: string;\n errorNotSetUpTitle: string;\n errorNotSetUpDetail: string;\n errorLoadMore: string;\n errorComments: string;\n fieldTitleTooShort: string;\n fieldEmailInvalid: string;\n comments: string;\n commentPlaceholder: string;\n postComment: string;\n noComments: string;\n follow: string;\n following: string;\n followPlaceholder: string;\n developer: string;\n poweredBy: string;\n upvote: string;\n status: Record<FeatureStatus, string>;\n}\n\nexport const DEFAULT_LABELS: BoardLabels = {\n title: \"Feature requests\",\n tabTop: \"Top\",\n tabNew: \"New\",\n tabRoadmap: \"Roadmap\",\n newRequest: \"New request\",\n cancel: \"Cancel\",\n submit: \"Submit request\",\n submitting: \"Submitting…\",\n submitted: \"Thanks — your request is in.\",\n fieldTitle: \"Title\",\n fieldTitlePlaceholder: \"Add dark mode\",\n fieldDescription: \"Details\",\n fieldDescriptionPlaceholder: \"What would this let you do?\",\n fieldEmail: \"Email\",\n fieldEmailHint: \"Only used to tell you when this ships.\",\n fieldName: \"Your name\",\n emptyTitle: \"No feature requests yet\",\n emptyBody: \"Be the first to suggest something.\",\n loading: \"Loading…\",\n loadMore: \"Load more\",\n retry: \"Try again\",\n errorInvalidKeyTitle: \"Invalid API key\",\n errorInvalidKeyDetail:\n \"Copy the key from your Fewchurs dashboard (Apps → API keys) and pass it to FewchursProvider, or set FEWCHURS_API_KEY on your server.\",\n errorWrongAppTitle: \"Invalid API key\",\n errorWrongAppDetail: \"\",\n errorTitle: \"Couldn't load requests\",\n errorDetail: \"Something went wrong. Try again.\",\n errorOfflineTitle: \"You're offline\",\n errorOfflineDetail: \"Check your connection and try again.\",\n errorNotSetUpTitle: \"Fewchurs isn't set up\",\n errorNotSetUpDetail: \"Pass apiKey to FewchursProvider, or set FEWCHURS_API_KEY on your server.\",\n errorLoadMore: \"Couldn't load more.\",\n errorComments: \"Couldn't load comments.\",\n fieldTitleTooShort: \"At least 3 characters.\",\n fieldEmailInvalid: \"Enter a valid email address.\",\n comments: \"Comments\",\n commentPlaceholder: \"Add a comment\",\n postComment: \"Post\",\n noComments: \"No comments yet.\",\n follow: \"Notify me\",\n following: \"You'll be notified\",\n followPlaceholder: \"you@example.com\",\n developer: \"Team\",\n poweredBy: \"Powered by Fewchurs\",\n upvote: \"Upvote\",\n status: {\n open: \"Open\",\n planned: \"Planned\",\n in_progress: \"In progress\",\n done: \"Done\",\n declined: \"Declined\",\n unknown: \"Open\",\n },\n};\n\nexport function mergeLabels(overrides?: Partial<BoardLabels>): BoardLabels {\n if (!overrides) return DEFAULT_LABELS;\n return {\n ...DEFAULT_LABELS,\n ...overrides,\n status: { ...DEFAULT_LABELS.status, ...overrides.status },\n };\n}\n","\"use client\";\n\nimport { useFewchursConfig } from \"../hooks/useFewchursConfig\";\nimport { useBoard } from \"./BoardContext\";\n\nexport function Branding(): React.JSX.Element | null {\n const { labels, cx } = useBoard();\n const { showBranding } = useFewchursConfig();\n if (!showBranding) return null;\n\n return (\n <p className={cx(\"fw-branding\")}>\n <a\n className={cx(\"fw-link\")}\n href=\"https://www.fewchurs.com\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n {labels.poweredBy}\n </a>\n </p>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { featureKey } from \"../store/keys\";\nimport { listStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature } from \"../types\";\n\nexport interface UseFeatureOptions {\n enabled?: boolean;\n}\n\nexport interface UseFeatureResult {\n feature: Feature | null;\n isLoading: boolean;\n error: FewchursError | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * One request by id, for a deep link into a board. The feature lands in the same store the\n * lists use, so voting, commenting and following it behave exactly as they do in a list.\n */\nexport function useFeature(\n featureId: string | undefined,\n { enabled = true }: UseFeatureOptions = {},\n): UseFeatureResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n\n const active = Boolean(featureId) && enabled;\n const list = listStateOf(state, featureKey(featureId ?? \"\"));\n\n useEffect(() => {\n if (!active || !isReady || !featureId) return;\n store.ensureFeature(featureId);\n }, [store, featureId, active, isReady]);\n\n const refresh = useCallback(\n () => (featureId ? store.refreshFeature(featureId) : Promise.resolve()),\n [store, featureId],\n );\n\n return {\n feature: list.features[0] ?? null,\n isLoading: active && (list.status === \"loading\" || list.status === \"idle\"),\n error: list.error,\n refresh,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { listKey } from \"../store/keys\";\nimport { listStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature, FeatureSort, FeatureStatus } from \"../types\";\n\nexport interface UseFeaturesOptions {\n sort?: FeatureSort;\n status?: FeatureStatus[];\n pageSize?: number;\n enabled?: boolean;\n}\n\nexport interface UseFeaturesResult {\n features: Feature[];\n isLoading: boolean;\n isLoadingMore: boolean;\n error: FewchursError | null;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n refresh: () => Promise<void>;\n}\n\nexport function useFeatures({\n sort = \"new\",\n status,\n pageSize,\n enabled = true,\n}: UseFeaturesOptions = {}): UseFeaturesResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n\n const statusKey = status?.length ? [...status].sort().join(\",\") : \"\";\n const query = useMemo(\n () => ({ sort, status: statusKey ? (statusKey.split(\",\") as FeatureStatus[]) : undefined }),\n [sort, statusKey],\n );\n const key = listKey(query);\n const list = listStateOf(state, key);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n store.ensureFeatures(query, pageSize);\n }, [store, query, pageSize, enabled, isReady]);\n\n const loadMore = useCallback(() => store.loadMore(query, pageSize), [store, query, pageSize]);\n const refresh = useCallback(() => store.refresh(query, pageSize), [store, query, pageSize]);\n\n return {\n features: list.features,\n isLoading: list.status === \"loading\" || (list.status === \"idle\" && enabled),\n isLoadingMore: list.status === \"loadingMore\",\n error: list.error,\n hasMore: list.cursor !== null,\n loadMore,\n refresh,\n };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\n\nexport interface UseFollowResult {\n isFollowing: boolean;\n isPending: boolean;\n error: FewchursError | null;\n follow: (email: string) => Promise<boolean>;\n unfollow: () => Promise<boolean>;\n}\n\nexport function useFollow(featureId: string): UseFollowResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const feature = Object.values(state.lists)\n .flatMap((list) => list.features)\n .find((candidate) => candidate.id === featureId);\n\n const run = useCallback(\n async (email: string | null) => {\n setIsPending(true);\n setError(null);\n const result = await store.setFollowing(featureId, email);\n if (!result.ok) setError(result.error);\n setIsPending(false);\n return result.ok;\n },\n [store, featureId],\n );\n\n return {\n isFollowing: feature?.isFollowing ?? false,\n isPending,\n error,\n follow: useCallback((email: string) => run(email), [run]),\n unfollow: useCallback(() => run(null), [run]),\n };\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\n\nexport interface UseVoteResult {\n hasVoted: boolean;\n upvoteCount: number;\n isPending: boolean;\n error: FewchursError | null;\n toggle: () => Promise<void>;\n vote: () => Promise<void>;\n unvote: () => Promise<void>;\n}\n\nexport function useVote(featureId: string): UseVoteResult {\n const { store } = useFewchurs();\n const state = useStoreState();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const feature = Object.values(state.lists)\n .flatMap((list) => list.features)\n .find((candidate) => candidate.id === featureId);\n\n const toggle = useCallback(async () => {\n setIsPending(true);\n setError(null);\n const result = await store.toggleVote(featureId);\n if (!result.ok) setError(result.error);\n setIsPending(false);\n }, [store, featureId]);\n\n const vote = useCallback(async () => {\n if (feature?.hasVoted) return;\n await toggle();\n }, [feature?.hasVoted, toggle]);\n\n const unvote = useCallback(async () => {\n if (!feature?.hasVoted) return;\n await toggle();\n }, [feature?.hasVoted, toggle]);\n\n return {\n hasVoted: feature?.hasVoted ?? false,\n upvoteCount: feature?.upvoteCount ?? 0,\n isPending,\n error,\n toggle,\n vote,\n unvote,\n };\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { userMessage } from \"../client/errors\";\nimport { useVote } from \"../hooks/useVote\";\nimport { useBoard } from \"./BoardContext\";\nimport { CommentList } from \"./Comments\";\nimport { FollowForm } from \"./FollowForm\";\nimport { StatusBadge } from \"./StatusBadge\";\nimport { VoteButton } from \"./VoteButton\";\nimport { formatDate } from \"./time\";\nimport type { Feature } from \"../types\";\n\nexport function FeatureCard({\n feature,\n defaultCommentsOpen = false,\n}: {\n feature: Feature;\n /** Opens the thread straight away, for a board linked to this one request. */\n defaultCommentsOpen?: boolean;\n}): React.JSX.Element {\n const { labels, allowComments, cx } = useBoard();\n const { isPending, toggle, error: voteError } = useVote(feature.id);\n const [showComments, setShowComments] = useState(defaultCommentsOpen);\n\n return (\n <li className={cx(\"fw-card\")}>\n <VoteButton feature={feature} isPending={isPending} onToggle={() => void toggle()} />\n\n <div className={cx(\"fw-card__body\")}>\n <h3 className={cx(\"fw-card__title\")}>{feature.title}</h3>\n {feature.description && <p className={cx(\"fw-card__desc\")}>{feature.description}</p>}\n\n <div className={cx(\"fw-meta\")}>\n <StatusBadge status={feature.status} />\n <span>{formatDate(feature.createdAt)}</span>\n\n {allowComments && (\n <button\n type=\"button\"\n className={cx(\"fw-link\")}\n aria-expanded={showComments}\n aria-controls={`fw-comments-${feature.id}`}\n onClick={() => setShowComments((open) => !open)}\n >\n {labels.comments} ({feature.commentCount})\n </button>\n )}\n\n <FollowForm feature={feature} />\n </div>\n\n {voteError && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(voteError)}\n </p>\n )}\n\n {allowComments && showComments && (\n <div id={`fw-comments-${feature.id}`}>\n <CommentList featureId={feature.id} />\n </div>\n )}\n </div>\n </li>\n );\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { isNotConfigured, userMessage } from \"../client/errors\";\nimport { LIMITS } from \"../client/constants\";\nimport { useComments } from \"../hooks/useComments\";\nimport { useBoard } from \"./BoardContext\";\nimport { formatDate } from \"./time\";\n\nexport function CommentList({ featureId }: { featureId: string }): React.JSX.Element {\n const { labels, cx } = useBoard();\n const { comments, isLoading, isLoadingMore, error, hasMore, loadMore, refresh } =\n useComments(featureId);\n\n return (\n <div className={cx(\"fw-comments\")}>\n {isLoading && <p className={cx(\"fw-muted\")}>{labels.loading}</p>}\n\n {error && comments.length === 0 && (\n <div className={cx(\"fw-empty\", \"fw-empty--compact\")} role=\"alert\">\n <p className={cx(\"fw-empty__title\")}>{labels.errorComments}</p>\n <p className={cx(\"fw-empty__detail\")}>\n {isNotConfigured(error) ? labels.errorNotSetUpTitle : userMessage(error)}\n </p>\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void refresh()}>\n {labels.retry}\n </button>\n </div>\n )}\n\n {error && comments.length > 0 && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n\n {!isLoading && !error && comments.length === 0 && (\n <p className={cx(\"fw-muted\")}>{labels.noComments}</p>\n )}\n\n <ul className={cx(\"fw-comment-list\")}>\n {comments.map((comment) => (\n <li key={comment.id} className={cx(\"fw-comment\")}>\n <span className={cx(\"fw-comment__author\")}>{comment.authorName}</span>\n {comment.isDeveloper && <span className={cx(\"fw-badge\")}> {labels.developer}</span>}\n <span className={cx(\"fw-muted\")}> · {formatDate(comment.createdAt)}</span>\n <p className={cx(\"fw-comment__text\")}>{comment.text}</p>\n </li>\n ))}\n </ul>\n\n {hasMore && (\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n disabled={isLoadingMore}\n onClick={() => void loadMore()}\n >\n {isLoadingMore ? labels.loading : labels.loadMore}\n </button>\n )}\n\n <CommentForm featureId={featureId} />\n </div>\n );\n}\n\nexport function CommentForm({ featureId }: { featureId: string }): React.JSX.Element {\n const { labels, cx } = useBoard();\n const { add, isSubmitting, submitError } = useComments(featureId);\n const [text, setText] = useState(\"\");\n const [authorName, setAuthorName] = useState(\"\");\n\n return (\n <form\n className={cx(\"fw-form\", \"fw-form--inline\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const posted = await add(text, authorName);\n if (posted) setText(\"\");\n }}\n >\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-comment-${featureId}`}>\n {labels.commentPlaceholder}\n </label>\n <input\n id={`fw-comment-${featureId}`}\n className={cx(\"fw-input\")}\n value={text}\n maxLength={LIMITS.commentMax}\n placeholder={labels.commentPlaceholder}\n onChange={(event) => setText(event.target.value)}\n required\n />\n </div>\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-comment-name-${featureId}`}>\n {labels.fieldName}\n </label>\n <input\n id={`fw-comment-name-${featureId}`}\n className={cx(\"fw-input\")}\n value={authorName}\n maxLength={LIMITS.authorNameMax}\n placeholder={labels.fieldName}\n onChange={(event) => setAuthorName(event.target.value)}\n />\n </div>\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isSubmitting || !text.trim()}>\n {labels.postComment}\n </button>\n {submitError && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(submitError)}\n </p>\n )}\n </form>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport { commentsStateOf } from \"../store/store\";\nimport { useStoreState } from \"./useStoreState\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Comment } from \"../types\";\n\nexport interface UseCommentsOptions {\n enabled?: boolean;\n}\n\nexport interface UseCommentsResult {\n comments: Comment[];\n isLoading: boolean;\n isLoadingMore: boolean;\n isSubmitting: boolean;\n error: FewchursError | null;\n submitError: FewchursError | null;\n hasMore: boolean;\n loadMore: () => Promise<void>;\n refresh: () => Promise<void>;\n add: (text: string, authorName?: string) => Promise<boolean>;\n}\n\nexport function useComments(\n featureId: string,\n { enabled = true }: UseCommentsOptions = {},\n): UseCommentsResult {\n const { store, isReady } = useFewchurs();\n const state = useStoreState();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitError, setSubmitError] = useState<FewchursError | null>(null);\n\n const comments = commentsStateOf(state, featureId);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n store.ensureComments(featureId);\n }, [store, featureId, enabled, isReady]);\n\n const loadMore = useCallback(() => store.loadMoreComments(featureId), [store, featureId]);\n\n const refresh = useCallback(() => store.refreshComments(featureId), [store, featureId]);\n\n const add = useCallback(\n async (text: string, authorName?: string) => {\n setIsSubmitting(true);\n setSubmitError(null);\n const result = await store.addComment({ featureId, text, authorName });\n if (!result.ok) setSubmitError(result.error);\n setIsSubmitting(false);\n return result.ok;\n },\n [store, featureId],\n );\n\n return {\n comments: comments.comments,\n isLoading: comments.status === \"loading\" || (comments.status === \"idle\" && enabled),\n isLoadingMore: comments.status === \"loadingMore\",\n isSubmitting,\n error: comments.error,\n submitError,\n hasMore: comments.cursor !== null,\n loadMore,\n refresh,\n add,\n };\n}\n","/**\n * Fixed locale and time zone on purpose: a date formatted with the visitor's locale renders\n * differently on the server than in the browser, which React reports as a hydration mismatch.\n */\nconst FORMATTER = new Intl.DateTimeFormat(\"en\", {\n month: \"short\",\n day: \"numeric\",\n timeZone: \"UTC\",\n});\n\nexport function formatDate(iso: string): string {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? \"\" : FORMATTER.format(date);\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { EMAIL_PATTERN } from \"../client/constants\";\nimport { userMessage } from \"../client/errors\";\nimport { useFollow } from \"../hooks/useFollow\";\nimport { useBoard } from \"./BoardContext\";\nimport type { Feature } from \"../types\";\n\nexport function FollowForm({ feature }: { feature: Feature }): React.JSX.Element {\n const { labels, userEmail, cx } = useBoard();\n const { isFollowing, isPending, error, follow, unfollow } = useFollow(feature.id);\n const [email, setEmail] = useState(userEmail ?? \"\");\n const [isOpen, setIsOpen] = useState(false);\n\n if (isFollowing) {\n return (\n <>\n <button\n type=\"button\"\n className={cx(\"fw-link\")}\n disabled={isPending}\n onClick={() => void unfollow()}\n >\n {labels.following}\n </button>\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n </>\n );\n }\n\n if (!isOpen) {\n return (\n <button type=\"button\" className={cx(\"fw-link\")} onClick={() => setIsOpen(true)}>\n {labels.follow}\n </button>\n );\n }\n\n const isEmailValid = EMAIL_PATTERN.test(email.trim());\n\n return (\n <form\n className={cx(\"fw-form\", \"fw-form--inline\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const ok = await follow(email);\n if (ok) setIsOpen(false);\n }}\n >\n <label className={cx(\"fw-sr-only\")} htmlFor={`fw-follow-${feature.id}`}>\n {labels.fieldEmail}\n </label>\n <input\n id={`fw-follow-${feature.id}`}\n className={cx(\"fw-input\")}\n type=\"email\"\n value={email}\n placeholder={labels.followPlaceholder}\n onChange={(event) => setEmail(event.target.value)}\n required\n />\n {email !== \"\" && !isEmailValid && (\n <p className={cx(\"fw-error\")}>{labels.fieldEmailInvalid}</p>\n )}\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isPending || !isEmailValid}>\n {labels.follow}\n </button>\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n </form>\n );\n}\n","\"use client\";\n\nimport { useBoard } from \"./BoardContext\";\nimport type { FeatureStatus } from \"../types\";\n\nexport function StatusBadge({ status }: { status: FeatureStatus }): React.JSX.Element | null {\n const { labels, cx } = useBoard();\n if (status === \"open\" || status === \"unknown\") return null;\n\n return <span className={cx(\"fw-status\", `fw-status--${status}`)}>{labels.status[status]}</span>;\n}\n","\"use client\";\n\nimport { useBoard } from \"./BoardContext\";\nimport type { Feature } from \"../types\";\n\ninterface VoteButtonProps {\n feature: Feature;\n isPending: boolean;\n onToggle: () => void;\n}\n\nexport function VoteButton({ feature, isPending, onToggle }: VoteButtonProps): React.JSX.Element {\n const { labels, hideVoteCounts, cx } = useBoard();\n\n return (\n <button\n type=\"button\"\n className={cx(\"fw-vote\")}\n aria-pressed={feature.hasVoted}\n aria-label={`${labels.upvote} ${feature.title}`}\n disabled={isPending}\n onClick={onToggle}\n >\n <span className={cx(\"fw-vote__arrow\")} aria-hidden=\"true\">\n ▲\n </span>\n {!hideVoteCounts && <span className={cx(\"fw-vote__count\")}>{feature.upvoteCount}</span>}\n </button>\n );\n}\n","\"use client\";\n\nimport { ROADMAP_STATUSES } from \"../client/constants\";\nimport { useBoard } from \"./BoardContext\";\n\n/** Enough rows to fill the fold without pushing the real list down when it arrives. */\nconst ROW_COUNT = 3;\nconst ROADMAP_ROW_COUNT = 2;\n\n/**\n * Placeholder rows shaped like `FeatureCard`, so the board does not collapse to one line of\n * text and then jump when the first page lands. `labels.loading` is still announced, since\n * the bars themselves are decorative.\n */\nexport function FeatureListSkeleton({\n roadmap = false,\n rows = ROW_COUNT,\n}: {\n roadmap?: boolean;\n /** One row while a single deep-linked request loads, a full board otherwise. */\n rows?: number;\n}): React.JSX.Element {\n const { labels, cx } = useBoard();\n\n return (\n <div className={cx(\"fw-skeleton\")} role=\"status\" aria-busy=\"true\">\n <span className={cx(\"fw-sr-only\")}>{labels.loading}</span>\n\n {roadmap ? (\n <div className={cx(\"fw-roadmap\")} aria-hidden=\"true\">\n {ROADMAP_STATUSES.map((status) => (\n <div key={status} className={cx(\"fw-roadmap__column\")}>\n <Bar width=\"40%\" />\n <Rows count={ROADMAP_ROW_COUNT} />\n </div>\n ))}\n </div>\n ) : (\n <div aria-hidden=\"true\">\n <Rows count={rows} />\n </div>\n )}\n </div>\n );\n}\n\nfunction Rows({ count }: { count: number }): React.JSX.Element {\n const { cx } = useBoard();\n\n return (\n <div className={cx(\"fw-list\")}>\n {Array.from({ length: count }, (_, index) => (\n <div key={index} className={cx(\"fw-card\", \"fw-skeleton__card\")}>\n <div className={cx(\"fw-skeleton__vote\")} />\n <div className={cx(\"fw-card__body\")}>\n <Bar width=\"62%\" />\n <Bar width=\"88%\" height=\"0.6rem\" />\n <Bar width=\"34%\" height=\"0.6rem\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction Bar({ width, height }: { width: string; height?: string }): React.JSX.Element {\n const { cx } = useBoard();\n return <div className={cx(\"fw-skeleton__bar\")} style={{ width, height }} />;\n}\n","\"use client\";\n\nimport { ROADMAP_STATUSES } from \"../client/constants\";\nimport { isNotConfigured, isWrongApp, userMessage, type FewchursError } from \"../client/errors\";\nimport { useFeature } from \"../hooks/useFeature\";\nimport { useFeatures } from \"../hooks/useFeatures\";\nimport { useFollow } from \"../hooks/useFollow\";\nimport { useVote } from \"../hooks/useVote\";\nimport { useBoard, type BoardTab } from \"./BoardContext\";\nimport { FeatureCard } from \"./FeatureCard\";\nimport type { BoardLabels } from \"./labels\";\nimport { FeatureListSkeleton } from \"./Skeleton\";\nimport type { Feature, FeatureSort } from \"../types\";\n\nfunction errorCopy(error: FewchursError, labels: BoardLabels): { title: string; detail: string } {\n if (isNotConfigured(error)) {\n return { title: labels.errorNotSetUpTitle, detail: labels.errorNotSetUpDetail };\n }\n if (error.code === \"network\") {\n return { title: labels.errorOfflineTitle, detail: labels.errorOfflineDetail };\n }\n if (isWrongApp(error)) {\n return {\n title: labels.errorWrongAppTitle,\n detail: labels.errorWrongAppDetail || userMessage(error),\n };\n }\n if (error.code === \"invalid_key\") {\n return { title: labels.errorInvalidKeyTitle, detail: labels.errorInvalidKeyDetail };\n }\n return {\n title: labels.errorTitle,\n detail: error.code === \"server\" ? labels.errorDetail : userMessage(error),\n };\n}\n\nexport function FeatureList(): React.JSX.Element {\n const { initialFeatureId } = useBoard();\n\n // The deep-linked request sits above the list and is dropped from it, so a board opened on\n // one request shows it first without listing it twice.\n return (\n <>\n {initialFeatureId && <PinnedFeature featureId={initialFeatureId} />}\n <Listing excludeId={initialFeatureId} />\n </>\n );\n}\n\nfunction PinnedFeature({ featureId }: { featureId: string }): React.JSX.Element | null {\n const { cx } = useBoard();\n const { feature, isLoading, error } = useFeature(featureId);\n\n if (isLoading) return <FeatureListSkeleton rows={1} />;\n if (!feature && error) {\n return (\n <p className={cx(\"fw-error\", \"fw-pinned\")} role=\"alert\">\n {userMessage(error)}\n </p>\n );\n }\n if (!feature) return null;\n\n return (\n <div className={cx(\"fw-pinned\")}>\n <ul className={cx(\"fw-list\")}>\n <FeatureCard feature={feature} defaultCommentsOpen />\n </ul>\n </div>\n );\n}\n\nfunction Listing({ excludeId }: { excludeId?: string }): React.JSX.Element {\n const { tab, showDeclined, labels, cx, renderEmpty, pageSize } = useBoard();\n const sort: FeatureSort = tab === \"roadmap\" ? \"top\" : tab;\n const isRoadmap = tab === \"roadmap\";\n\n const { features, isLoading, isLoadingMore, error, hasMore, loadMore, refresh } = useFeatures({\n sort,\n status: isRoadmap ? ROADMAP_STATUSES : undefined,\n pageSize,\n });\n\n // Also filtered here: a server that does not support ?status= yet returns everything.\n const visible = features.filter((feature) => {\n if (feature.id === excludeId) return false;\n if (isRoadmap) return ROADMAP_STATUSES.includes(feature.status);\n return showDeclined || feature.status !== \"declined\";\n });\n\n if (error && visible.length === 0) {\n const { title, detail } = errorCopy(error, labels);\n return (\n <div className={cx(\"fw-empty\")} role=\"alert\">\n <p className={cx(\"fw-empty__title\")}>{title}</p>\n <p className={cx(\"fw-empty__detail\")}>{detail}</p>\n {!isNotConfigured(error) && (\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void refresh()}>\n {labels.retry}\n </button>\n )}\n </div>\n );\n }\n\n if (isLoading && visible.length === 0) {\n return <FeatureListSkeleton roadmap={isRoadmap} />;\n }\n\n if (visible.length === 0) {\n if (renderEmpty) return <>{renderEmpty()}</>;\n return (\n <div className={cx(\"fw-empty\")}>\n <p className={cx(\"fw-empty__title\")}>{labels.emptyTitle}</p>\n <p>{labels.emptyBody}</p>\n </div>\n );\n }\n\n return (\n <>\n {isRoadmap ? <RoadmapColumns features={visible} /> : <Rows features={visible} />}\n\n {hasMore && error && (\n <div className={cx(\"fw-pagination\")} role=\"alert\">\n <span>{labels.errorLoadMore}</span>\n <button type=\"button\" className={cx(\"fw-btn-text\")} onClick={() => void loadMore()}>\n {labels.retry}\n </button>\n </div>\n )}\n\n {hasMore && !error && (\n <div className={cx(\"fw-pagination\")}>\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n disabled={isLoadingMore}\n onClick={() => void loadMore()}\n >\n {isLoadingMore ? labels.loading : labels.loadMore}\n </button>\n </div>\n )}\n </>\n );\n}\n\nfunction Rows({ features }: { features: Feature[] }): React.JSX.Element {\n const { cx } = useBoard();\n return (\n <ul className={cx(\"fw-list\")}>\n {features.map((feature) => (\n <FeatureRow key={feature.id} feature={feature} />\n ))}\n </ul>\n );\n}\n\nfunction RoadmapColumns({ features }: { features: Feature[] }): React.JSX.Element {\n const { labels, cx } = useBoard();\n\n return (\n <div className={cx(\"fw-roadmap\")}>\n {ROADMAP_STATUSES.map((status) => {\n const column = features.filter((feature) => feature.status === status);\n return (\n <section\n key={status}\n className={cx(\"fw-roadmap__column\")}\n aria-label={labels.status[status]}\n >\n <h3 className={cx(\"fw-roadmap__heading\")}>{labels.status[status]}</h3>\n {column.length === 0 ? (\n <p className={cx(\"fw-muted\")}>—</p>\n ) : (\n <ul className={cx(\"fw-list\")}>\n {column.map((feature) => (\n <FeatureRow key={feature.id} feature={feature} />\n ))}\n </ul>\n )}\n </section>\n );\n })}\n </div>\n );\n}\n\n/** Level 4: the host renders the row and drives it through the same actions the card uses. */\nfunction FeatureRow({ feature }: { feature: Feature }): React.JSX.Element {\n const { renderFeature } = useBoard();\n if (!renderFeature) return <FeatureCard feature={feature} />;\n return <FeatureSlot feature={feature} />;\n}\n\nfunction FeatureSlot({ feature }: { feature: Feature }): React.JSX.Element {\n const { renderFeature } = useBoard();\n const { toggle } = useVote(feature.id);\n const { follow, unfollow } = useFollow(feature.id);\n\n return <>{renderFeature?.(feature, { toggleVote: toggle, follow, unfollow })}</>;\n}\n\nexport { ROADMAP_STATUSES };\nexport type { BoardTab };\n","\"use client\";\n\nimport { useState } from \"react\";\nimport { EMAIL_PATTERN, LIMITS } from \"../client/constants\";\nimport { userMessage } from \"../client/errors\";\nimport { useSubmitFeature } from \"../hooks/useSubmitFeature\";\nimport { useBoard } from \"./BoardContext\";\n\nexport function SubmitForm(): React.JSX.Element {\n const {\n labels,\n emailField,\n userEmail,\n isSubscriber,\n isFormOpen,\n setFormOpen,\n setJustSubmitted,\n cx,\n } = useBoard();\n const { submit, isPending, error } = useSubmitFeature();\n\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [email, setEmail] = useState(userEmail ?? \"\");\n\n const isTitleValid = title.trim().length >= LIMITS.titleMin;\n const isEmailInvalid = emailField !== \"off\" && email !== \"\" && !EMAIL_PATTERN.test(email.trim());\n const isEmailMissing = emailField === \"required\" && !email.trim();\n const canSubmit = isTitleValid && !isEmailInvalid && !isEmailMissing;\n\n return (\n <form\n className={cx(\"fw-form\")}\n onSubmit={async (event) => {\n event.preventDefault();\n const created = await submit({\n title,\n description,\n ...(emailField !== \"off\" && email ? { email } : {}),\n isSubscriber,\n });\n if (!created) return;\n if (!isFormOpen) {\n setTitle(\"\");\n setDescription(\"\");\n }\n setJustSubmitted(true);\n setFormOpen(false);\n }}\n >\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-title\">\n {labels.fieldTitle}\n </label>\n <input\n id=\"fw-title\"\n className={cx(\"fw-input\")}\n value={title}\n minLength={LIMITS.titleMin}\n maxLength={LIMITS.titleMax}\n placeholder={labels.fieldTitlePlaceholder}\n onChange={(event) => setTitle(event.target.value)}\n required\n />\n <div className={cx(\"fw-field__foot\")}>\n <span className={cx(\"fw-error\")}>\n {title !== \"\" && !isTitleValid ? labels.fieldTitleTooShort : \"\"}\n </span>\n <span className={cx(\"fw-muted\")}>\n {title.length}/{LIMITS.titleMax}\n </span>\n </div>\n </div>\n\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-description\">\n {labels.fieldDescription}\n </label>\n <textarea\n id=\"fw-description\"\n className={cx(\"fw-input\", \"fw-textarea\")}\n value={description}\n maxLength={LIMITS.descriptionMax}\n placeholder={labels.fieldDescriptionPlaceholder}\n onChange={(event) => setDescription(event.target.value)}\n />\n <div className={cx(\"fw-field__foot\")}>\n <span />\n <span className={cx(\"fw-muted\")}>\n {description.length}/{LIMITS.descriptionMax}\n </span>\n </div>\n </div>\n\n {emailField !== \"off\" && (\n <div className={cx(\"fw-field\")}>\n <label className={cx(\"fw-label\")} htmlFor=\"fw-email\">\n {labels.fieldEmail}\n </label>\n <input\n id=\"fw-email\"\n className={cx(\"fw-input\")}\n type=\"email\"\n value={email}\n placeholder={labels.followPlaceholder}\n aria-describedby=\"fw-email-hint\"\n onChange={(event) => setEmail(event.target.value)}\n required={emailField === \"required\"}\n />\n {isEmailInvalid ? (\n <p id=\"fw-email-hint\" className={cx(\"fw-error\")}>\n {labels.fieldEmailInvalid}\n </p>\n ) : (\n <p id=\"fw-email-hint\" className={cx(\"fw-muted\")}>\n {labels.fieldEmailHint}\n </p>\n )}\n </div>\n )}\n\n {error && (\n <p className={cx(\"fw-error\")} role=\"alert\">\n {userMessage(error)}\n </p>\n )}\n\n <div className={cx(\"fw-form__actions\")}>\n <button type=\"submit\" className={cx(\"fw-btn\")} disabled={isPending || !canSubmit}>\n {isPending ? labels.submitting : labels.submit}\n </button>\n <button\n type=\"button\"\n className={cx(\"fw-btn\", \"fw-btn--ghost\")}\n onClick={() => setFormOpen(false)}\n >\n {labels.cancel}\n </button>\n </div>\n </form>\n );\n}\n","\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useFewchurs } from \"../context/provider\";\nimport type { FewchursError } from \"../client/errors\";\nimport type { Feature, SubmitFeatureInput } from \"../types\";\n\nexport interface UseSubmitFeatureResult {\n submit: (input: SubmitFeatureInput) => Promise<Feature | null>;\n isPending: boolean;\n error: FewchursError | null;\n reset: () => void;\n}\n\nexport function useSubmitFeature(): UseSubmitFeatureResult {\n const { store } = useFewchurs();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<FewchursError | null>(null);\n\n const submit = useCallback(\n async (input: SubmitFeatureInput) => {\n setIsPending(true);\n setError(null);\n const result = await store.submitFeature(input);\n setIsPending(false);\n if (!result.ok) {\n setError(result.error);\n return null;\n }\n return result.data;\n },\n [store],\n );\n\n const reset = useCallback(() => setError(null), []);\n\n return { submit, isPending, error, reset };\n}\n","import type { CSSProperties } from \"react\";\n\nexport interface BoardTheme {\n primary?: string;\n /** A number is read as pixels, a string is used as-is (`\"0.75rem\"`). */\n radius?: number | string;\n surface?: string;\n border?: string;\n text?: string;\n subtle?: string;\n font?: string;\n}\n\nconst VARIABLE_BY_KEY: Record<keyof BoardTheme, string> = {\n primary: \"--fw-primary\",\n radius: \"--fw-radius\",\n surface: \"--fw-surface\",\n border: \"--fw-border\",\n text: \"--fw-text\",\n subtle: \"--fw-subtle\",\n font: \"--fw-font\",\n};\n\nexport function themeToStyle(theme?: BoardTheme): CSSProperties | undefined {\n if (!theme) return undefined;\n const style: Record<string, string> = {};\n for (const [key, value] of Object.entries(theme)) {\n if (value === undefined || value === null) continue;\n const variable = VARIABLE_BY_KEY[key as keyof BoardTheme];\n style[variable] = typeof value === \"number\" ? `${value}px` : value;\n }\n return style as CSSProperties;\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { BoardRoot, type FewchursBoardProps } from \"./Board\";\n\nexport interface FewchursBoardDialogProps extends FewchursBoardProps {\n open: boolean;\n onClose: () => void;\n ariaLabel?: string;\n variant?: \"dialog\" | \"sheet\";\n}\n\nexport function FewchursBoardDialog({\n open,\n onClose,\n ariaLabel = \"Feature requests\",\n variant = \"dialog\",\n ...boardProps\n}: FewchursBoardDialogProps): React.JSX.Element | null {\n const dialogRef = useRef<HTMLDivElement>(null);\n const openerRef = useRef<Element | null>(null);\n\n useEffect(() => {\n if (!open) return;\n openerRef.current = document.activeElement;\n dialogRef.current?.focus();\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") onClose();\n }\n document.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n // Focus goes back where it came from, so a keyboard user is not dropped at the top of the page.\n (openerRef.current as HTMLElement | null)?.focus?.();\n };\n }, [open, onClose]);\n\n if (!open) return null;\n\n const isSheet = variant === \"sheet\";\n const { colorScheme } = boardProps;\n\n return (\n <div className={isSheet ? \"fw-overlay fw-overlay--sheet\" : \"fw-overlay\"} onClick={onClose}>\n <div\n ref={dialogRef}\n className={isSheet ? \"fw-dialog fw-dialog--sheet\" : \"fw-dialog\"}\n data-theme={colorScheme === \"system\" ? undefined : colorScheme}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n tabIndex={-1}\n onClick={(event) => event.stopPropagation()}\n >\n <button type=\"button\" className=\"fw-dialog__close\" aria-label=\"Close\" onClick={onClose}>\n ×\n </button>\n <BoardRoot {...boardProps} />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { FewchursBoardProps } from \"./Board\";\nimport { FewchursBoardDialog } from \"./BoardDialog\";\nimport { themeToStyle } from \"./theme\";\n\nexport interface FewchursButtonProps extends Omit<\n FewchursBoardProps,\n \"children\" | \"className\" | \"style\"\n> {\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n ariaLabel?: string;\n floating?: boolean | \"left\" | \"right\";\n}\n\nfunction launcherClasses(floating: FewchursButtonProps[\"floating\"]): string {\n if (!floating) return \"fw-launcher\";\n const side = floating === \"left\" ? \" fw-launcher--left\" : \"\";\n return `fw-launcher fw-launcher--floating${side}`;\n}\n\nexport function FewchursButton({\n children = \"Feedback\",\n className,\n style,\n ariaLabel,\n floating = false,\n ...board\n}: FewchursButtonProps): React.JSX.Element {\n const [open, setOpen] = useState(false);\n const close = useCallback(() => setOpen(false), []);\n const classes = [board.unstyled ? \"\" : launcherClasses(floating), className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <>\n <button\n type=\"button\"\n className={classes || undefined}\n style={{ ...themeToStyle(board.theme), ...style }}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen(true)}\n >\n {children}\n </button>\n {open\n ? createPortal(\n <FewchursBoardDialog\n {...board}\n variant=\"sheet\"\n ariaLabel={ariaLabel}\n open\n onClose={close}\n />,\n document.body,\n )\n : null}\n </>\n );\n}\n"],"mappings":";;;AAEA,SAAS,eAAe,YAAY,WAAW,SAAS,QAAQ,gBAAgB;;;ACDzE,IAAM,cAAc;;;ACGpB,IAAM,aAAa,SAAS,WAAW;AACvC,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAG1B,IAAM,SAAS;AAAA,EACpB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,eAAe;AACjB;AAGO,IAAM,gBAAgB;AAGtB,IAAM,mBAAoC,CAAC,WAAW,eAAe,MAAM;;;ACP3E,IAAM,yBAAyB;AAEtC,IAAM,gBAAuD;AAAA,EAC3D,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,WAAW;AAAA,EACX,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,SAAS,WAAW,OAA+B;AACxD,SAAO,MAAM,SAAS,iBAAiB,MAAM,WAAW;AAC1D;AAEO,SAAS,gBAAgB,OAA+B;AAC7D,SAAO,MAAM,SAAS,YAAY,MAAM,YAAY;AACtD;AAEO,SAAS,qBAAoC;AAClD,SAAO,EAAE,MAAM,UAAU,QAAQ,KAAK,SAAS,uBAAuB;AACxE;AAGO,SAAS,YAAY,OAA8B;AACxD,MAAI,MAAM,SAAS,uBAAuB,MAAM,QAAS,QAAO,MAAM;AACtE,MAAI,WAAW,KAAK,KAAK,MAAM,QAAS,QAAO,MAAM;AACrD,SAAO,cAAc,MAAM,IAAI;AACjC;AAEO,SAAS,aAAa,UAAU,2BAA0C;AAC/E,SAAO,EAAE,MAAM,WAAW,QAAQ;AACpC;AAEO,SAAS,gBAAgB,SAAgC;AAC9D,SAAO,EAAE,MAAM,qBAAqB,QAAQ,KAAK,QAAQ;AAC3D;AAEO,SAAS,kBAAkB,QAAgB,MAA8B;AAC9E,QAAM,OAAQ,MAAiC,OAAO;AACtD,QAAM,gBAAiB,MAAiC,OAAO;AAC/D,QAAM,UAAU,iBAAiB,mBAAmB,MAAM;AAE1D,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,MAAM,eAAe,QAAQ,KAAK,QAAQ;AAAA,IACrD,KAAK;AACH,aAAO,EAAE,MAAM,eAAe,QAAQ,KAAK,QAAQ;AAAA,IACrD,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,QAAQ,KAAK,QAAQ;AAAA,IAChD,KAAK;AACH,aAAO,EAAE,MAAM,qBAAqB,QAAQ,KAAK,SAAS,iBAAiB,iBAAiB;AAAA,IAC9F,KAAK;AACH,aAAO,EAAE,MAAM,gBAAgB,QAAQ,KAAK,QAAQ;AAAA,IACtD,KAAK;AACH,aAAO,EAAE,MAAM,aAAa,QAAQ,KAAK,QAAQ;AAAA,IACnD,KAAK;AACH,aAAO,EAAE,MAAM,iBAAiB,QAAQ,KAAK,QAAQ;AAAA,IACvD;AACE,aAAO,WAAW,MACd,EAAE,MAAM,eAAe,QAAQ,KAAK,QAAQ,IAC5C,EAAE,MAAM,UAAU,QAAQ,QAAQ;AAAA,EAC1C;AACF;;;ACtEA,IAAM,iBAAiB,oBAAI,IAAY,CAAC,QAAQ,WAAW,eAAe,QAAQ,UAAU,CAAC;AAE7F,SAAS,SAAS,OAAyC;AACzD,SAAO,OAAO,UAAU,YAAY,UAAU,OAAQ,QAAoC,CAAC;AAC7F;AAEA,SAAS,IAAI,OAAgB,WAAW,IAAY;AAClD,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAS,IAAI,OAAwB;AACnC,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,KAAK,OAAyB;AACrC,SAAO,UAAU;AACnB;AAEO,SAAS,gBAAgB,OAA+B;AAC7D,SAAO,OAAO,UAAU,YAAY,eAAe,IAAI,KAAK,IACvD,QACD;AACN;AAIA,SAAS,OAAO,KAA8B,UAAkB,UAAkC;AAChG,MAAI,OAAO,IAAI,WAAW,UAAW,QAAO,IAAI;AAChD,QAAM,QAAQ,IAAI,QAAQ;AAC1B,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,UAAU;AACpE;AAEO,SAAS,iBAAiB,OAAgB,UAAkC;AACjF,QAAM,MAAM,SAAS,KAAK;AAC1B,SAAO;AAAA,IACL,IAAI,IAAI,IAAI,EAAE;AAAA,IACd,OAAO,IAAI,IAAI,KAAK;AAAA,IACpB,aAAa,IAAI,IAAI,WAAW;AAAA,IAChC,QAAQ,gBAAgB,IAAI,MAAM;AAAA,IAClC,aAAa,IAAI,IAAI,WAAW;AAAA,IAChC,cAAc,IAAI,IAAI,YAAY;AAAA,IAClC,eAAe,IAAI,IAAI,aAAa;AAAA,IACpC,UAAU,KAAK,IAAI,QAAQ;AAAA,IAC3B,aAAa,KAAK,IAAI,WAAW;AAAA,IACjC,QAAQ,OAAO,KAAK,kBAAkB,QAAQ;AAAA,IAC9C,WAAW,IAAI,IAAI,SAAS;AAAA,IAC5B,WAAW,IAAI,IAAI,WAAW,IAAI,IAAI,SAAS,CAAC;AAAA,EAClD;AACF;AAEO,SAAS,iBAAiB,OAAgB,UAAkC;AACjF,QAAM,MAAM,SAAS,KAAK;AAC1B,SAAO;AAAA,IACL,IAAI,IAAI,IAAI,EAAE;AAAA,IACd,MAAM,IAAI,IAAI,IAAI;AAAA,IAClB,YAAY,IAAI,IAAI,YAAY,UAAU;AAAA,IAC1C,aAAa,KAAK,IAAI,WAAW;AAAA,IACjC,QAAQ,OAAO,KAAK,YAAY,QAAQ;AAAA,IACxC,WAAW,IAAI,IAAI,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,qBAAqB,OAAgB,UAAsC;AACzF,QAAM,MAAM,SAAS,KAAK;AAC1B,QAAM,WAAW,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAC/D,SAAO;AAAA,IACL,UAAU,SAAS,IAAI,CAAC,YAAY,iBAAiB,SAAS,QAAQ,CAAC;AAAA,IACvE,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACpE;AACF;AAEO,SAAS,qBAAqB,OAAgB,UAAsC;AACzF,QAAM,MAAM,SAAS,KAAK;AAC1B,QAAM,WAAW,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAC/D,SAAO;AAAA,IACL,UAAU,SAAS,IAAI,CAAC,YAAY,iBAAiB,SAAS,QAAQ,CAAC;AAAA,IACvE,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACpE;AACF;AAEO,SAAS,gBAAgB,OAAgC;AAC9D,QAAM,MAAM,SAAS,KAAK;AAC1B,SAAO;AAAA,IACL,cAAc,IAAI,iBAAiB;AAAA,IACnC,gBAAgB,KAAK,IAAI,cAAc;AAAA,IACvC,SAAS,OAAO,IAAI,YAAY,YAAY,IAAI,UAAU,IAAI,UAAU;AAAA,EAC1E;AACF;AAEO,SAAS,cAAc,OAA4D;AACxF,QAAM,MAAM,SAAS,KAAK;AAC1B,SAAO,EAAE,aAAa,IAAI,IAAI,WAAW,GAAG,UAAU,KAAK,IAAI,QAAQ,EAAE;AAC3E;;;ACjGO,SAAS,qBAAqB,OAAiD;AACpF,QAAM,QAAQ,MAAM,MAAM,KAAK;AAC/B,MAAI,MAAM,SAAS,OAAO,YAAY,MAAM,SAAS,OAAO,UAAU;AACpE,WAAO,gBAAgB,iBAAiB,OAAO,QAAQ,SAAI,OAAO,QAAQ,cAAc;AAAA,EAC1F;AACA,OAAK,MAAM,eAAe,IAAI,KAAK,EAAE,SAAS,OAAO,gBAAgB;AACnE,WAAO,gBAAgB,+BAA+B,OAAO,cAAc,cAAc;AAAA,EAC3F;AACA,MAAI,MAAM,UAAU,UAAa,MAAM,UAAU,MAAM,CAAC,QAAQ,MAAM,KAAK,GAAG;AAC5E,WAAO,gBAAgB,8BAA8B;AAAA,EACvD;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,OAAiD;AACpF,QAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,MAAI,KAAK,SAAS,OAAO,cAAc,KAAK,SAAS,OAAO,YAAY;AACtE,WAAO,gBAAgB,mBAAmB,OAAO,UAAU,SAAI,OAAO,UAAU,cAAc;AAAA,EAChG;AACA,OAAK,MAAM,cAAc,IAAI,KAAK,EAAE,SAAS,OAAO,eAAe;AACjE,WAAO,gBAAgB,wBAAwB,OAAO,aAAa,cAAc;AAAA,EACnF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,OAAqC;AACjE,SAAO,QAAQ,KAAK,IAAI,OAAO,gBAAgB,8BAA8B;AAC/E;AAEA,SAAS,QAAQ,OAAwB;AACvC,SAAO,cAAc,KAAK,MAAM,KAAK,CAAC;AACxC;;;ACyCO,SAAS,qBAAqB,UAAiC,CAAC,GAAmB;AACxF,QAAM,WAAW,QAAQ,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACvE,QAAM,UAAU,QAAQ,SAAS,WAAW,OAAO,KAAK,UAAU;AAClE,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,eAAe,QAAQ,gBAAgB;AAE7C,MAAI,QAAQ,UAAU,CAAC,QAAQ,OAAO,WAAW,KAAK,EAAG,SAAQ,cAAc;AAE/E,WAAS,cAA6B;AACpC,WAAO,OAAO,QAAQ,aAAa,aAAa,QAAQ,SAAS,IAAK,QAAQ,YAAY;AAAA,EAC5F;AAEA,WAAS,QAAQ,SAA0C;AACzD,UAAM,SAAiC;AAAA,MACrC,QAAQ;AAAA,MACR,kBAAkB;AAAA,IACpB;AACA,QAAI,QAAS,QAAO,cAAc,IAAI;AACtC,QAAI,QAAQ,OAAQ,QAAO,gBAAgB,UAAU,QAAQ,MAAM;AACnE,UAAM,WAAW,YAAY;AAC7B,QAAI,SAAU,QAAO,aAAa,IAAI;AACtC,QAAI,QAAQ,SAAU,QAAO,iBAAiB,IAAI,QAAQ;AAC1D,QAAI,QAAQ,MAAO,QAAO,mBAAmB,IAAI,QAAQ;AACzD,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,MAAc,OAAyC;AAClE,UAAM,SAAS,IAAI,gBAAgB;AACnC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AACtD,UAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GAAI,QAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAC1F;AACA,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,EAC/C;AAEA,iBAAe,QACb,MACA,KACA,EAAE,SAAS,OAAO,MAAM,OAAO,OAAO,IAAoB,CAAC,GACvC;AACpB,QAAI,CAAC,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,aAAa,oCAAoC,EAAE;AAC5F,QAAI,CAAC,QAAQ,UAAU,QAAQ,YAAY,QAAW;AACpD,YAAM,UAAU,mBAAmB;AACnC,eAAS,OAAO;AAChB,aAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAAA,IACrC;AAEA,UAAM,SAAS,IAAI,MAAM,KAAK;AAC9B,UAAM,OAAoB,EAAE,QAAQ,SAAS,QAAQ,SAAS,MAAS,EAAE;AACzE,QAAI,SAAS,OAAW,MAAK,OAAO,KAAK,UAAU,IAAI;AACvD,QAAI,OAAQ,MAAK,SAAS;AAG1B,UAAM,WAAW,WAAW,QAAQ,UAAU,IAAI;AAElD,aAAS,UAAU,GAAG,UAAU,UAAU,WAAW,GAAG;AACtD,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,QAAQ,QAAQ,IAAI;AAAA,MACvC,SAAS,OAAO;AACd,YAAI,QAAQ,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,aAAa,kBAAkB,EAAE;AACjF,YAAI,UAAU,WAAW,GAAG;AAC1B,gBAAM,MAAM,YAAY;AACxB;AAAA,QACF;AACA,cAAMA,WAAU,aAAa,UAAU,KAAK,CAAC;AAC7C,iBAASA,QAAO;AAChB,eAAO,EAAE,IAAI,OAAO,OAAOA,SAAQ;AAAA,MACrC;AAEA,UAAI,SAAS,IAAI;AACf,cAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,eAAO,EAAE,IAAI,MAAM,MAAM,IAAI,OAAO,EAAE;AAAA,MACxC;AAEA,UAAI,SAAS,UAAU,OAAO,UAAU,WAAW,GAAG;AACpD,cAAM,MAAM,YAAY;AACxB;AAAA,MACF;AAEA,YAAM,UAAU,kBAAkB,SAAS,QAAQ,MAAM,SAAS,QAAQ,CAAC;AAC3E,eAAS,OAAO;AAChB,aAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAAA,IACrC;AAEA,WAAO,EAAE,IAAI,OAAO,OAAO,aAAa,EAAE;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IAEA,WAAW,CAAC,WAAW,QAAQ,WAAW,iBAAiB,EAAE,OAAO,CAAC;AAAA,IAErE,cAAc,CAAC,SAAS,CAAC,GAAG,WAC1B,QAAQ,aAAa,CAAC,SAAS,qBAAqB,MAAM,YAAY,CAAC,GAAG;AAAA,MACxE,OAAO;AAAA,QACL,MAAM,OAAO,QAAQ;AAAA,QACrB,OAAO,OAAO,SAAS;AAAA,QACvB,QAAQ,OAAO,UAAU;AAAA,QACzB,QAAQ,OAAO,QAAQ,SAAS,OAAO,OAAO,KAAK,GAAG,IAAI;AAAA,MAC5D;AAAA,MACA;AAAA,IACF,CAAC;AAAA,IAEH,YAAY,CAAC,WAAW,WACtB;AAAA,MACE,aAAa,mBAAmB,SAAS,CAAC;AAAA,MAC1C,CAAC,SAAS,iBAAiB,MAAM,YAAY,CAAC;AAAA,MAC9C,EAAE,OAAO;AAAA,IACX;AAAA,IAEF,eAAe,OAAO,UAAU;AAC9B,YAAM,UAAU,qBAAqB,KAAK;AAC1C,UAAI,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAChD,aAAO,QAAQ,aAAa,CAAC,SAAS,iBAAiB,MAAM,YAAY,CAAC,GAAG;AAAA,QAC3E,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,OAAO,MAAM,MAAM,KAAK;AAAA,UACxB,cAAc,MAAM,eAAe,IAAI,KAAK;AAAA,UAC5C,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,UACnD,cAAc,MAAM,gBAAgB;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,CAAC,cACL,QAAQ,aAAa,mBAAmB,SAAS,CAAC,SAAS,eAAe,EAAE,QAAQ,OAAO,CAAC;AAAA,IAE9F,QAAQ,CAAC,cACP,QAAQ,aAAa,mBAAmB,SAAS,CAAC,SAAS,eAAe;AAAA,MACxE,QAAQ;AAAA,IACV,CAAC;AAAA,IAEH,QAAQ,OAAO,WAAW,UAAU;AAClC,YAAM,UAAU,cAAc,KAAK;AACnC,UAAI,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAChD,aAAO;AAAA,QACL,aAAa,mBAAmB,SAAS,CAAC;AAAA,QAC1C,OAAO,EAAE,WAAW,KAAK;AAAA,QACzB;AAAA,UACE,QAAQ;AAAA,UACR,MAAM,EAAE,OAAO,MAAM,KAAK,EAAE;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,CAAC,cACT,QAAQ,aAAa,mBAAmB,SAAS,CAAC,WAAW,OAAO,EAAE,WAAW,MAAM,IAAI;AAAA,MACzF,QAAQ;AAAA,IACV,CAAC;AAAA,IAEH,cAAc,CAAC,WAAW,SAAS,CAAC,GAAG,WACrC;AAAA,MACE,aAAa,mBAAmB,SAAS,CAAC;AAAA,MAC1C,CAAC,SAAS,qBAAqB,MAAM,YAAY,CAAC;AAAA,MAClD;AAAA,QACE,OAAO,EAAE,OAAO,OAAO,SAAS,mBAAmB,QAAQ,OAAO,UAAU,OAAU;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,IAGF,eAAe,OAAO,UAAU;AAC9B,YAAM,UAAU,qBAAqB,KAAK;AAC1C,UAAI,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,QAAQ;AAChD,aAAO,QAAQ,aAAa,CAAC,SAAS,iBAAiB,MAAM,YAAY,CAAC,GAAG;AAAA,QAC3E,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,WAAW,MAAM;AAAA,UACjB,MAAM,MAAM,KAAK,KAAK;AAAA,UACtB,GAAI,MAAM,YAAY,KAAK,IAAI,EAAE,YAAY,MAAM,WAAW,KAAK,EAAE,IAAI,CAAC;AAAA,QAC5E;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,SAAS,UAAsC;AAC5D,MAAI;AACF,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,KAAK,IAAI,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC,IAAI,QAAQ,QAAQ;AACtF;AAEA,SAAS,UAAU,OAAwB;AACzC,SAAO,iBAAiB,QAAQ,MAAM,UAAU;AAClD;AAMA,IAAM,mBACJ;AAEF,IAAM,sBACJ;AAEF,IAAM,iBAAiB;AAEvB,IAAM,eAAe,oBAAI,IAAY;AAErC,SAAS,QAAQ,QAAsB;AACrC,MAAI,OAAO,YAAY,eAAe,QAAQ,KAAK,aAAa,aAAc;AAC9E,MAAI,aAAa,IAAI,MAAM,EAAG;AAC9B,eAAa,IAAI,MAAM;AACvB,UAAQ,KAAK,gBAAgB,MAAM,EAAE;AACvC;AAEA,SAAS,SAAS,OAA4B;AAC5C,MAAI,gBAAgB,KAAK,EAAG,QAAO,QAAQ,mBAAmB;AAC9D,QAAM,eAAe,MAAM,SAAS,iBAAiB,MAAM,WAAW;AACtE,UAAQ,eAAe,mBAAmB,MAAM,OAAO;AACzD;;;ACvSA,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,iBAAiB,KAAK,KAAK,KAAK;AAE/B,SAAS,iBAAyB;AACvC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAC5E;AAEO,SAAS,eAA8B;AAC5C,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO,WAAW,KAAK,YAAY;AACrC;AAMO,SAAS,kBAA0B;AACxC,QAAM,WAAW,aAAa;AAC9B,MAAI,UAAU;AACZ,YAAQ,QAAQ;AAChB,WAAO;AAAA,EACT;AACA,QAAM,UAAU,eAAe;AAC/B,UAAQ,OAAO;AACf,SAAO;AACT;AAEA,SAAS,QAAQ,UAAwB;AACvC,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI;AACF,aAAS,SAAS,GAAG,WAAW,IAAI,mBAAmB,QAAQ,CAAC,qBAAqB,cAAc;AAAA,EACrG,QAAQ;AAAA,EAER;AACA,MAAI;AACF,iBAAa,QAAQ,aAAa,QAAQ;AAAA,EAC5C,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,aAA4B;AACnC,QAAM,QAAQ,SAAS,OAAO,MAAM,IAAI,OAAO,WAAW,WAAW,UAAU,CAAC;AAChF,SAAO,QAAQ,CAAC,IAAI,mBAAmB,MAAM,CAAC,CAAC,IAAI;AACrD;AAEA,SAAS,cAA6B;AACpC,MAAI;AACF,WAAO,aAAa,QAAQ,WAAW;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACjDO,SAAS,QAAQ,EAAE,MAAM,OAAO,GAAsB;AAC3D,SAAO,QAAQ,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,KAAK;AACtE;AAMO,SAAS,WAAW,WAA2B;AACpD,SAAO,WAAW,SAAS;AAC7B;;;ACsDA,IAAM,aAAwB,EAAE,UAAU,CAAC,GAAG,QAAQ,MAAM,QAAQ,QAAQ,OAAO,KAAK;AACxF,IAAM,iBAAgC,EAAE,UAAU,CAAC,GAAG,QAAQ,MAAM,QAAQ,QAAQ,OAAO,KAAK;AAIhG,IAAM,kBAAkB;AAEjB,SAAS,YACd,QACA,EAAE,WAAW,IAAI,cAAc,QAAQ,IAAkB,CAAC,GACnD;AACP,MAAI,QAAoB;AAAA,IACtB,QAAQ,cAAc,UAAU;AAAA,IAChC,OAAO,cAAc,SAAS,CAAC;AAAA,IAC/B,UAAU,cAAc,YAAY,CAAC;AAAA,EACvC;AAEA,QAAM,YAAY,oBAAI,IAAgB;AACtC,QAAM,WAAW,oBAAI,IAA2B;AAEhD,WAAS,SAAS,MAAiC;AACjD,YAAQ,EAAE,GAAG,OAAO,GAAG,KAAK;AAC5B,eAAW,YAAY,UAAW,UAAS;AAAA,EAC7C;AAEA,WAAS,QAAQ,KAAa,OAAiC;AAC7D,UAAM,UAAU,MAAM,MAAM,GAAG,KAAK;AACpC,aAAS,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE,CAAC;AAAA,EACzE;AAEA,WAAS,YAAY,WAAmB,OAAqC;AAC3E,UAAM,UAAU,MAAM,SAAS,SAAS,KAAK;AAC7C,aAAS,EAAE,UAAU,EAAE,GAAG,MAAM,UAAU,CAAC,SAAS,GAAG,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE,CAAC;AAAA,EACrF;AAEA,WAAS,KAAK,OAA4B;AACxC,cAAU,KAAK;AAAA,EACjB;AAEA,WAAS,KAAK,OAA4B;AACxC,SAAK,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,EAC/B;AAGA,WAAS,OAAO,KAAa,KAAyC;AACpE,UAAM,WAAW,SAAS,IAAI,GAAG;AACjC,QAAI,SAAU,QAAO;AACrB,UAAM,UAAU,IAAI,EAAE,QAAQ,MAAM,SAAS,OAAO,GAAG,CAAC;AACxD,aAAS,IAAI,KAAK,OAAO;AACzB,WAAO;AAAA,EACT;AAEA,WAAS,WAAW,WAAmB,QAA6C;AAClF,UAAM,QAAmC,CAAC;AAC1C,QAAI,UAAU;AACd,eAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AACrD,YAAM,QAAQ,KAAK,SAAS,UAAU,CAAC,YAAY,QAAQ,OAAO,SAAS;AAC3E,UAAI,UAAU,IAAI;AAChB,cAAM,GAAG,IAAI;AACb;AAAA,MACF;AACA,gBAAU;AACV,YAAM,WAAW,CAAC,GAAG,KAAK,QAAQ;AAClC,eAAS,KAAK,IAAI,OAAO,SAAS,KAAK,CAAY;AACnD,YAAM,GAAG,IAAI,EAAE,GAAG,MAAM,SAAS;AAAA,IACnC;AACA,QAAI,QAAS,UAAS,EAAE,MAAM,CAAC;AAAA,EACjC;AAEA,iBAAe,cAAc,OAAkB,QAAiB,MAA6B;AAC3F,UAAM,MAAM,QAAQ,KAAK;AACzB,UAAM,UAAU,MAAM,MAAM,GAAG,KAAK;AACpC,QAAI,UAAU,CAAC,QAAQ,OAAQ;AAE/B,YAAQ,KAAK,EAAE,QAAQ,SAAS,gBAAgB,WAAW,OAAO,KAAK,CAAC;AAExE,UAAM,SAAS,MAAM,OAAO,aAAa;AAAA,MACvC,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,OAAO;AAAA,MACP,QAAQ,SAAS,QAAQ,SAAS;AAAA,IACpC,CAAC;AAED,QAAI,CAAC,OAAO,IAAI;AACd,cAAQ,KAAK,EAAE,QAAQ,SAAS,OAAO,OAAO,MAAM,CAAC;AACrD,WAAK,OAAO,KAAK;AACjB;AAAA,IACF;AAEA,UAAM,WAAW,SAAU,MAAM,MAAM,GAAG,GAAG,YAAY,CAAC,IAAK,CAAC;AAChE,YAAQ,KAAK;AAAA,MACX,UAAU,WAAW,CAAC,GAAG,UAAU,GAAG,OAAO,KAAK,QAAQ,CAAC;AAAA,MAC3D,QAAQ,OAAO,KAAK;AAAA,MACpB,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,iBAAe,aAAa,WAAkC;AAC5D,UAAM,MAAM,WAAW,SAAS;AAChC,YAAQ,KAAK,EAAE,QAAQ,WAAW,OAAO,KAAK,CAAC;AAE/C,UAAM,SAAS,MAAM,OAAO,WAAW,SAAS;AAChD,QAAI,CAAC,OAAO,IAAI;AACd,cAAQ,KAAK,EAAE,QAAQ,SAAS,OAAO,OAAO,MAAM,CAAC;AACrD,WAAK,OAAO,KAAK;AACjB;AAAA,IACF;AAEA,YAAQ,KAAK,EAAE,UAAU,CAAC,OAAO,IAAI,GAAG,QAAQ,MAAM,QAAQ,SAAS,OAAO,KAAK,CAAC;AAAA,EACtF;AAEA,iBAAe,cAAc,WAAmB,QAAgC;AAC9E,UAAM,UAAU,MAAM,SAAS,SAAS,KAAK;AAC7C,QAAI,UAAU,CAAC,QAAQ,OAAQ;AAE/B,gBAAY,WAAW,EAAE,QAAQ,SAAS,gBAAgB,WAAW,OAAO,KAAK,CAAC;AAElF,QAAI,SAAS,SAAS,QAAQ,SAAS;AACvC,UAAM,YAAuB,CAAC;AAE9B,aAAS,OAAO,GAAG,OAAO,iBAAiB,QAAQ,GAAG;AACpD,YAAM,SAAS,MAAM,OAAO,aAAa,WAAW,EAAE,OAAO,UAAU,OAAO,CAAC;AAC/E,UAAI,CAAC,OAAO,IAAI;AACd,oBAAY,WAAW,EAAE,QAAQ,SAAS,OAAO,OAAO,MAAM,CAAC;AAC/D,aAAK,OAAO,KAAK;AACjB;AAAA,MACF;AACA,gBAAU,KAAK,GAAG,OAAO,KAAK,QAAQ;AACtC,eAAS,OAAO,KAAK;AACrB,UAAI,UAAU,SAAS,KAAK,CAAC,OAAQ;AAAA,IACvC;AAEA,UAAM,WAAW,SAAU,MAAM,SAAS,SAAS,GAAG,YAAY,CAAC,IAAK,CAAC;AACzE,gBAAY,WAAW;AAAA,MACrB,UAAU,WAAW,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC;AAAA,MAChD;AAAA,MACA,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,UAAU,UAAU;AAClB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,IACxC;AAAA,IAEA,UAAU,MAAM;AAAA,IAEhB;AAAA,IAEA,eAAe;AACb,UAAI,MAAM,OAAQ;AAClB,WAAK,OAAO,UAAU,YAAY;AAChC,cAAM,SAAS,MAAM,OAAO,UAAU;AACtC,YAAI,OAAO,GAAI,UAAS,EAAE,QAAQ,OAAO,KAAK,CAAC;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,IAEA,eAAe,OAAO,OAAO,UAAU;AACrC,YAAM,MAAM,QAAQ,KAAK;AACzB,WAAK,MAAM,MAAM,GAAG,KAAK,YAAY,WAAW,OAAQ;AACxD,WAAK,OAAO,YAAY,GAAG,IAAI,MAAM,cAAc,OAAO,OAAO,IAAI,CAAC;AAAA,IACxE;AAAA,IAEA,QAAQ,OAAO,OAAO,UAAU;AAC9B,aAAO,OAAO,YAAY,QAAQ,KAAK,CAAC,IAAI,MAAM,cAAc,OAAO,OAAO,IAAI,CAAC;AAAA,IACrF;AAAA,IAEA,SAAS,OAAO,OAAO,UAAU;AAC/B,aAAO,OAAO,iBAAiB,QAAQ,KAAK,CAAC,IAAI,MAAM,cAAc,OAAO,MAAM,IAAI,CAAC;AAAA,IACzF;AAAA,IAEA,cAAc,WAAW;AACvB,WAAK,MAAM,MAAM,WAAW,SAAS,CAAC,KAAK,YAAY,WAAW,OAAQ;AAC1E,WAAK,OAAO,WAAW,SAAS,IAAI,MAAM,aAAa,SAAS,CAAC;AAAA,IACnE;AAAA,IAEA,eAAe,WAAW;AACxB,aAAO,OAAO,WAAW,SAAS,IAAI,MAAM,aAAa,SAAS,CAAC;AAAA,IACrE;AAAA,IAEA,eAAe,WAAW;AACxB,WAAK,MAAM,SAAS,SAAS,KAAK,gBAAgB,WAAW,OAAQ;AACrE,WAAK,OAAO,YAAY,SAAS,IAAI,MAAM,cAAc,WAAW,KAAK,CAAC;AAAA,IAC5E;AAAA,IAEA,gBAAgB,WAAW;AACzB,aAAO,OAAO,YAAY,SAAS,IAAI,MAAM,cAAc,WAAW,KAAK,CAAC;AAAA,IAC9E;AAAA,IAEA,iBAAiB,WAAW;AAC1B,aAAO,OAAO,iBAAiB,SAAS,IAAI,MAAM,cAAc,WAAW,IAAI,CAAC;AAAA,IAClF;AAAA,IAEA,MAAM,WAAW,WAAW;AAC1B,YAAM,SAAS,YAAY,OAAO,SAAS;AAC3C,UAAI,CAAC;AACH,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,OAAO,EAAE,MAAM,aAAa,QAAQ,KAAK,SAAS,mBAAmB;AAAA,QACvE;AAEF,YAAM,YAAY,CAAC,OAAO;AAC1B,iBAAW,WAAW,CAAC,aAAa;AAAA,QAClC,GAAG;AAAA,QACH,UAAU;AAAA,QACV,aAAa,KAAK,IAAI,GAAG,QAAQ,eAAe,YAAY,IAAI,GAAG;AAAA,MACrE,EAAE;AAEF,YAAM,SAAS,YAAY,MAAM,OAAO,KAAK,SAAS,IAAI,MAAM,OAAO,OAAO,SAAS;AAEvF,UAAI,CAAC,OAAO,IAAI;AACd,mBAAW,WAAW,CAAC,aAAa;AAAA,UAClC,GAAG;AAAA,UACH,UAAU,OAAO;AAAA,UACjB,aAAa,OAAO;AAAA,QACtB,EAAE;AACF,aAAK,OAAO,KAAK;AACjB,eAAO;AAAA,MACT;AAEA,iBAAW,WAAW,CAAC,aAAa;AAAA,QAClC,GAAG;AAAA,QACH,UAAU,OAAO,KAAK;AAAA,QACtB,aAAa,OAAO,KAAK;AAAA,MAC3B,EAAE;AACF,WAAK,EAAE,MAAM,SAAS,WAAW,UAAU,OAAO,KAAK,SAAS,CAAC;AACjE,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,cAAc,OAAO;AACzB,YAAM,SAAS,MAAM,OAAO,cAAc,KAAK;AAC/C,UAAI,CAAC,OAAO,IAAI;AACd,aAAK,OAAO,KAAK;AACjB,eAAO;AAAA,MACT;AAEA,YAAM,QAAmC,CAAC;AAC1C,iBAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AAErD,cAAM,GAAG,IAAI,IAAI,WAAW,KAAK,IAC7B,EAAE,GAAG,MAAM,UAAU,WAAW,CAAC,OAAO,MAAM,GAAG,KAAK,QAAQ,CAAC,EAAE,IACjE;AAAA,MACN;AACA,eAAS,EAAE,MAAM,CAAC;AAClB,WAAK,EAAE,MAAM,oBAAoB,WAAW,OAAO,KAAK,GAAG,CAAC;AAC5D,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,WAAW,OAAO;AACtB,YAAM,SAAS,MAAM,OAAO,cAAc,KAAK;AAC/C,UAAI,CAAC,OAAO,IAAI;AACd,aAAK,OAAO,KAAK;AACjB,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,MAAM,SAAS,MAAM,SAAS,KAAK;AACnD,kBAAY,MAAM,WAAW,EAAE,UAAU,CAAC,GAAG,QAAQ,UAAU,OAAO,IAAI,EAAE,CAAC;AAC7E,iBAAW,MAAM,WAAW,CAAC,aAAa;AAAA,QACxC,GAAG;AAAA,QACH,cAAc,QAAQ,eAAe;AAAA,MACvC,EAAE;AACF,WAAK,EAAE,MAAM,aAAa,WAAW,MAAM,UAAU,CAAC;AACtD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,aAAa,WAAW,OAAO;AACnC,YAAM,SAAS,QACX,MAAM,OAAO,OAAO,WAAW,KAAK,IACpC,MAAM,OAAO,SAAS,SAAS;AAEnC,UAAI,CAAC,OAAO,IAAI;AACd,aAAK,OAAO,KAAK;AACjB,eAAO;AAAA,MACT;AAEA,iBAAW,WAAW,CAAC,aAAa;AAAA,QAClC,GAAG;AAAA,QACH,aAAa,OAAO,KAAK;AAAA,QACzB,eAAe,KAAK,IAAI,GAAG,QAAQ,iBAAiB,OAAO,KAAK,YAAY,IAAI,GAAG;AAAA,MACrF,EAAE;AACF,WAAK,EAAE,MAAM,YAAY,WAAW,WAAW,OAAO,KAAK,UAAU,CAAC;AACtE,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,YAAY,OAAmB,KAAwB;AACrE,SAAO,MAAM,MAAM,GAAG,KAAK;AAC7B;AAEO,SAAS,gBAAgB,OAAmB,WAAkC;AACnF,SAAO,MAAM,SAAS,SAAS,KAAK;AACtC;AAEA,SAAS,YAAY,OAAmB,WAAmC;AACzE,aAAW,QAAQ,OAAO,OAAO,MAAM,KAAK,GAAG;AAC7C,UAAM,QAAQ,KAAK,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS;AACtE,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,WAAqC,OAAiB;AAC7D,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAc,CAAC;AACrB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,IAAI,KAAK,EAAE,EAAG;AACvB,SAAK,IAAI,KAAK,EAAE;AAChB,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;;;ATrSS;AA5ET,IAAM,kBAAkB,cAA2C,IAAI;AAiBhE,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AACF,GAA6C;AAG3C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,MAAM,gBAAgB,aAAa,CAAC;AAC5F,QAAM,cAAc,OAAO,QAAQ;AACnC,cAAY,UAAU,gBAAgB;AAEtC,QAAM,WAAW,OAAO,OAAO;AAC/B,WAAS,UAAU;AAEnB,YAAU,MAAM;AACd,QAAI,aAAc;AAClB,gBAAY,gBAAgB,CAAC;AAAA,EAC/B,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,SAAS;AAAA,IACb,MACE,cACA,qBAAqB;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,MAAM,YAAY;AAAA,IAC9B,CAAC;AAAA,IACH,CAAC,YAAY,QAAQ,SAAS,QAAQ;AAAA,EACxC;AAEA,QAAM,QAAQ;AAAA,IACZ,MACE,YAAY,QAAQ;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS,CAAC,UAAU,SAAS,UAAU,KAAK;AAAA,IAC9C,CAAC;AAAA;AAAA;AAAA,IAGH,CAAC,QAAQ,QAAQ;AAAA,EACnB;AAEA,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,UAAU,gBAAgB;AAAA,MAC1B,SAAS,QAAQ,gBAAgB,QAAQ,KAAK,CAAC;AAAA,IACjD;AAAA,IACA,CAAC,QAAQ,OAAO,cAAc,UAAU,MAAM;AAAA,EAChD;AAEA,SAAO,oBAAC,gBAAgB,UAAhB,EAAyB,OAAe,UAAS;AAC3D;AAEO,SAAS,cAAoC;AAClD,QAAM,QAAQ,WAAW,eAAe;AACxC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AUrGA,SAAS,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,kBAAgB;AAErD,SAAS,iBAAiB;;;ACF1B,SAAS,aAAAC,kBAAiB;;;ACA1B,SAAS,4BAA4B;AAI9B,SAAS,gBAA4B;AAC1C,QAAM,EAAE,MAAM,IAAI,YAAY;AAG9B,SAAO,qBAAqB,MAAM,WAAW,MAAM,UAAU,MAAM,QAAQ;AAC7E;;;ADEO,SAAS,oBAA6C;AAC3D,QAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,QAAM,QAAQ,cAAc;AAE5B,EAAAC,WAAU,MAAM;AACd,UAAM,aAAa;AAAA,EACrB,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AAAA,IACL,cAAc,MAAM,QAAQ,gBAAgB;AAAA,IAC5C,gBAAgB,MAAM,QAAQ,kBAAkB;AAAA,IAChD,SAAS,MAAM,QAAQ,WAAW;AAAA,IAClC,WAAW,MAAM,WAAW;AAAA,EAC9B;AACF;;;AEzBA,SAAS,iBAAAC,gBAAe,cAAAC,mBAAkB;;;ACiDnC,IAAM,iBAA8B;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,6BAA6B;AAAA,EAC7B,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,sBAAsB;AAAA,EACtB,uBACE;AAAA,EACF,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AACF;AAEO,SAAS,YAAY,WAA+C;AACzE,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ,EAAE,GAAG,eAAe,QAAQ,GAAG,UAAU,OAAO;AAAA,EAC1D;AACF;;;ADzEA,IAAM,eAAeC,eAAwC,IAAI;AAE1D,IAAM,uBAAuB,aAAa;AAE1C,SAAS,WAA8B;AAC5C,QAAM,QAAQC,YAAW,YAAY;AACrC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,UAAmB;AAC/C,SAAO,IAAI,UACT,WAAW,SAAY,MAAM,OAAO,OAAO,EAAE,KAAK,GAAG;AACzD;;;AE7CM,gBAAAC,YAAA;AAPC,SAAS,WAAqC;AACnD,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAChC,QAAM,EAAE,aAAa,IAAI,kBAAkB;AAC3C,MAAI,CAAC,aAAc,QAAO;AAE1B,SACE,gBAAAA,KAAC,OAAE,WAAW,GAAG,aAAa,GAC5B,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,SAAS;AAAA,MACvB,MAAK;AAAA,MACL,QAAO;AAAA,MACP,KAAI;AAAA,MAEH,iBAAO;AAAA;AAAA,EACV,GACF;AAEJ;;;ACpBA,SAAS,aAAa,aAAAC,kBAAiB;AAuBhC,SAAS,WACd,WACA,EAAE,UAAU,KAAK,IAAuB,CAAC,GACvB;AAClB,QAAM,EAAE,OAAO,QAAQ,IAAI,YAAY;AACvC,QAAM,QAAQ,cAAc;AAE5B,QAAM,SAAS,QAAQ,SAAS,KAAK;AACrC,QAAM,OAAO,YAAY,OAAO,WAAW,aAAa,EAAE,CAAC;AAE3D,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,WAAW,CAAC,UAAW;AACvC,UAAM,cAAc,SAAS;AAAA,EAC/B,GAAG,CAAC,OAAO,WAAW,QAAQ,OAAO,CAAC;AAEtC,QAAM,UAAU;AAAA,IACd,MAAO,YAAY,MAAM,eAAe,SAAS,IAAI,QAAQ,QAAQ;AAAA,IACrE,CAAC,OAAO,SAAS;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,SAAS,KAAK,SAAS,CAAC,KAAK;AAAA,IAC7B,WAAW,WAAW,KAAK,WAAW,aAAa,KAAK,WAAW;AAAA,IACnE,OAAO,KAAK;AAAA,IACZ;AAAA,EACF;AACF;;;ACjDA,SAAS,eAAAC,cAAa,aAAAC,YAAW,WAAAC,gBAAe;AAyBzC,SAAS,YAAY;AAAA,EAC1B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,UAAU;AACZ,IAAwB,CAAC,GAAsB;AAC7C,QAAM,EAAE,OAAO,QAAQ,IAAI,YAAY;AACvC,QAAM,QAAQ,cAAc;AAE5B,QAAM,YAAY,QAAQ,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;AAClE,QAAM,QAAQC;AAAA,IACZ,OAAO,EAAE,MAAM,QAAQ,YAAa,UAAU,MAAM,GAAG,IAAwB,OAAU;AAAA,IACzF,CAAC,MAAM,SAAS;AAAA,EAClB;AACA,QAAM,MAAM,QAAQ,KAAK;AACzB,QAAM,OAAO,YAAY,OAAO,GAAG;AAEnC,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,QAAS;AAC1B,UAAM,eAAe,OAAO,QAAQ;AAAA,EACtC,GAAG,CAAC,OAAO,OAAO,UAAU,SAAS,OAAO,CAAC;AAE7C,QAAM,WAAWC,aAAY,MAAM,MAAM,SAAS,OAAO,QAAQ,GAAG,CAAC,OAAO,OAAO,QAAQ,CAAC;AAC5F,QAAM,UAAUA,aAAY,MAAM,MAAM,QAAQ,OAAO,QAAQ,GAAG,CAAC,OAAO,OAAO,QAAQ,CAAC;AAE1F,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,WAAW,KAAK,WAAW,aAAc,KAAK,WAAW,UAAU;AAAA,IACnE,eAAe,KAAK,WAAW;AAAA,IAC/B,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;;;AC3DA,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAa/B,SAAS,UAAU,WAAoC;AAC5D,QAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,QAAM,QAAQ,cAAc;AAC5B,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA+B,IAAI;AAE7D,QAAM,UAAU,OAAO,OAAO,MAAM,KAAK,EACtC,QAAQ,CAAC,SAAS,KAAK,QAAQ,EAC/B,KAAK,CAAC,cAAc,UAAU,OAAO,SAAS;AAEjD,QAAM,MAAMC;AAAA,IACV,OAAO,UAAyB;AAC9B,mBAAa,IAAI;AACjB,eAAS,IAAI;AACb,YAAM,SAAS,MAAM,MAAM,aAAa,WAAW,KAAK;AACxD,UAAI,CAAC,OAAO,GAAI,UAAS,OAAO,KAAK;AACrC,mBAAa,KAAK;AAClB,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,CAAC,OAAO,SAAS;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,aAAa,SAAS,eAAe;AAAA,IACrC;AAAA,IACA;AAAA,IACA,QAAQA,aAAY,CAAC,UAAkB,IAAI,KAAK,GAAG,CAAC,GAAG,CAAC;AAAA,IACxD,UAAUA,aAAY,MAAM,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC;AAAA,EAC9C;AACF;;;AC1CA,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAe/B,SAAS,QAAQ,WAAkC;AACxD,QAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,QAAM,QAAQ,cAAc;AAC5B,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA+B,IAAI;AAE7D,QAAM,UAAU,OAAO,OAAO,MAAM,KAAK,EACtC,QAAQ,CAAC,SAAS,KAAK,QAAQ,EAC/B,KAAK,CAAC,cAAc,UAAU,OAAO,SAAS;AAEjD,QAAM,SAASC,aAAY,YAAY;AACrC,iBAAa,IAAI;AACjB,aAAS,IAAI;AACb,UAAM,SAAS,MAAM,MAAM,WAAW,SAAS;AAC/C,QAAI,CAAC,OAAO,GAAI,UAAS,OAAO,KAAK;AACrC,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,OAAO,SAAS,CAAC;AAErB,QAAM,OAAOA,aAAY,YAAY;AACnC,QAAI,SAAS,SAAU;AACvB,UAAM,OAAO;AAAA,EACf,GAAG,CAAC,SAAS,UAAU,MAAM,CAAC;AAE9B,QAAM,SAASA,aAAY,YAAY;AACrC,QAAI,CAAC,SAAS,SAAU;AACxB,UAAM,OAAO;AAAA,EACf,GAAG,CAAC,SAAS,UAAU,MAAM,CAAC;AAE9B,SAAO;AAAA,IACL,UAAU,SAAS,YAAY;AAAA,IAC/B,aAAa,SAAS,eAAe;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACpDA,SAAS,YAAAC,iBAAgB;;;ACAzB,SAAS,YAAAC,iBAAgB;;;ACAzB,SAAS,eAAAC,cAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAwB1C,SAAS,YACd,WACA,EAAE,UAAU,KAAK,IAAwB,CAAC,GACvB;AACnB,QAAM,EAAE,OAAO,QAAQ,IAAI,YAAY;AACvC,QAAM,QAAQ,cAAc;AAC5B,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAS,KAAK;AACtD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAA+B,IAAI;AAEzE,QAAM,WAAW,gBAAgB,OAAO,SAAS;AAEjD,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,QAAS;AAC1B,UAAM,eAAe,SAAS;AAAA,EAChC,GAAG,CAAC,OAAO,WAAW,SAAS,OAAO,CAAC;AAEvC,QAAM,WAAWC,aAAY,MAAM,MAAM,iBAAiB,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC;AAExF,QAAM,UAAUA,aAAY,MAAM,MAAM,gBAAgB,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC;AAEtF,QAAM,MAAMA;AAAA,IACV,OAAO,MAAc,eAAwB;AAC3C,sBAAgB,IAAI;AACpB,qBAAe,IAAI;AACnB,YAAM,SAAS,MAAM,MAAM,WAAW,EAAE,WAAW,MAAM,WAAW,CAAC;AACrE,UAAI,CAAC,OAAO,GAAI,gBAAe,OAAO,KAAK;AAC3C,sBAAgB,KAAK;AACrB,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,CAAC,OAAO,SAAS;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,UAAU,SAAS;AAAA,IACnB,WAAW,SAAS,WAAW,aAAc,SAAS,WAAW,UAAU;AAAA,IAC3E,eAAe,SAAS,WAAW;AAAA,IACnC;AAAA,IACA,OAAO,SAAS;AAAA,IAChB;AAAA,IACA,SAAS,SAAS,WAAW;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AClEA,IAAM,YAAY,IAAI,KAAK,eAAe,MAAM;AAAA,EAC9C,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AACZ,CAAC;AAEM,SAAS,WAAW,KAAqB;AAC9C,QAAM,OAAO,IAAI,KAAK,GAAG;AACzB,SAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,KAAK,UAAU,OAAO,IAAI;AAClE;;;AFGoB,gBAAAC,MAGZ,YAHY;AAPb,SAAS,YAAY,EAAE,UAAU,GAA6C;AACnF,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAChC,QAAM,EAAE,UAAU,WAAW,eAAe,OAAO,SAAS,UAAU,QAAQ,IAC5E,YAAY,SAAS;AAEvB,SACE,qBAAC,SAAI,WAAW,GAAG,aAAa,GAC7B;AAAA,iBAAa,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAI,iBAAO,SAAQ;AAAA,IAE3D,SAAS,SAAS,WAAW,KAC5B,qBAAC,SAAI,WAAW,GAAG,YAAY,mBAAmB,GAAG,MAAK,SACxD;AAAA,sBAAAA,KAAC,OAAE,WAAW,GAAG,iBAAiB,GAAI,iBAAO,eAAc;AAAA,MAC3D,gBAAAA,KAAC,OAAE,WAAW,GAAG,kBAAkB,GAChC,0BAAgB,KAAK,IAAI,OAAO,qBAAqB,YAAY,KAAK,GACzE;AAAA,MACA,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,aAAa,GAAG,SAAS,MAAM,KAAK,QAAQ,GAC7E,iBAAO,OACV;AAAA,OACF;AAAA,IAGD,SAAS,SAAS,SAAS,KAC1B,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,KAAK,GACpB;AAAA,IAGD,CAAC,aAAa,CAAC,SAAS,SAAS,WAAW,KAC3C,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAI,iBAAO,YAAW;AAAA,IAGnD,gBAAAA,KAAC,QAAG,WAAW,GAAG,iBAAiB,GAChC,mBAAS,IAAI,CAAC,YACb,qBAAC,QAAoB,WAAW,GAAG,YAAY,GAC7C;AAAA,sBAAAA,KAAC,UAAK,WAAW,GAAG,oBAAoB,GAAI,kBAAQ,YAAW;AAAA,MAC9D,QAAQ,eAAe,qBAAC,UAAK,WAAW,GAAG,UAAU,GAAG;AAAA;AAAA,QAAE,OAAO;AAAA,SAAU;AAAA,MAC5E,qBAAC,UAAK,WAAW,GAAG,UAAU,GAAG;AAAA;AAAA,QAAI,WAAW,QAAQ,SAAS;AAAA,SAAE;AAAA,MACnE,gBAAAA,KAAC,OAAE,WAAW,GAAG,kBAAkB,GAAI,kBAAQ,MAAK;AAAA,SAJ7C,QAAQ,EAKjB,CACD,GACH;AAAA,IAEC,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,GAAG,UAAU,eAAe;AAAA,QACvC,UAAU;AAAA,QACV,SAAS,MAAM,KAAK,SAAS;AAAA,QAE5B,0BAAgB,OAAO,UAAU,OAAO;AAAA;AAAA,IAC3C;AAAA,IAGF,gBAAAA,KAAC,eAAY,WAAsB;AAAA,KACrC;AAEJ;AAEO,SAAS,YAAY,EAAE,UAAU,GAA6C;AACnF,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAChC,QAAM,EAAE,KAAK,cAAc,YAAY,IAAI,YAAY,SAAS;AAChE,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,EAAE;AACnC,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,EAAE;AAE/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,WAAW,iBAAiB;AAAA,MAC1C,UAAU,OAAO,UAAU;AACzB,cAAM,eAAe;AACrB,cAAM,SAAS,MAAM,IAAI,MAAM,UAAU;AACzC,YAAI,OAAQ,SAAQ,EAAE;AAAA,MACxB;AAAA,MAEA;AAAA,6BAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAAD,KAAC,WAAM,WAAW,GAAG,YAAY,GAAG,SAAS,cAAc,SAAS,IACjE,iBAAO,oBACV;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,cAAc,SAAS;AAAA,cAC3B,WAAW,GAAG,UAAU;AAAA,cACxB,OAAO;AAAA,cACP,WAAW,OAAO;AAAA,cAClB,aAAa,OAAO;AAAA,cACpB,UAAU,CAAC,UAAU,QAAQ,MAAM,OAAO,KAAK;AAAA,cAC/C,UAAQ;AAAA;AAAA,UACV;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAAA,KAAC,WAAM,WAAW,GAAG,YAAY,GAAG,SAAS,mBAAmB,SAAS,IACtE,iBAAO,WACV;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,mBAAmB,SAAS;AAAA,cAChC,WAAW,GAAG,UAAU;AAAA,cACxB,OAAO;AAAA,cACP,WAAW,OAAO;AAAA,cAClB,aAAa,OAAO;AAAA,cACpB,UAAU,CAAC,UAAU,cAAc,MAAM,OAAO,KAAK;AAAA;AAAA,UACvD;AAAA,WACF;AAAA,QACA,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,QAAQ,GAAG,UAAU,gBAAgB,CAAC,KAAK,KAAK,GACjF,iBAAO,aACV;AAAA,QACC,eACC,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,WAAW,GAC1B;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AGrHA,SAAS,YAAAE,iBAAgB;AAenB,mBACE,OAAAC,MADF,QAAAC,aAAA;AARC,SAAS,WAAW,EAAE,QAAQ,GAA4C;AAC/E,QAAM,EAAE,QAAQ,WAAW,GAAG,IAAI,SAAS;AAC3C,QAAM,EAAE,aAAa,WAAW,OAAO,QAAQ,SAAS,IAAI,UAAU,QAAQ,EAAE;AAChF,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,aAAa,EAAE;AAClD,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,KAAK;AAE1C,MAAI,aAAa;AACf,WACE,gBAAAD,MAAA,YACE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAW,GAAG,SAAS;AAAA,UACvB,UAAU;AAAA,UACV,SAAS,MAAM,KAAK,SAAS;AAAA,UAE5B,iBAAO;AAAA;AAAA,MACV;AAAA,MACC,SACC,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,KAAK,GACpB;AAAA,OAEJ;AAAA,EAEJ;AAEA,MAAI,CAAC,QAAQ;AACX,WACE,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,SAAS,GAAG,SAAS,MAAM,UAAU,IAAI,GAC1E,iBAAO,QACV;AAAA,EAEJ;AAEA,QAAM,eAAe,cAAc,KAAK,MAAM,KAAK,CAAC;AAEpD,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,WAAW,iBAAiB;AAAA,MAC1C,UAAU,OAAO,UAAU;AACzB,cAAM,eAAe;AACrB,cAAM,KAAK,MAAM,OAAO,KAAK;AAC7B,YAAI,GAAI,WAAU,KAAK;AAAA,MACzB;AAAA,MAEA;AAAA,wBAAAD,KAAC,WAAM,WAAW,GAAG,YAAY,GAAG,SAAS,aAAa,QAAQ,EAAE,IACjE,iBAAO,YACV;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAI,aAAa,QAAQ,EAAE;AAAA,YAC3B,WAAW,GAAG,UAAU;AAAA,YACxB,MAAK;AAAA,YACL,OAAO;AAAA,YACP,aAAa,OAAO;AAAA,YACpB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,YAChD,UAAQ;AAAA;AAAA,QACV;AAAA,QACC,UAAU,MAAM,CAAC,gBAChB,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAI,iBAAO,mBAAkB;AAAA,QAE1D,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,QAAQ,GAAG,UAAU,aAAa,CAAC,cACpE,iBAAO,QACV;AAAA,QACC,SACC,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,KAAK,GACpB;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;ACtES,gBAAAG,YAAA;AAJF,SAAS,YAAY,EAAE,OAAO,GAAwD;AAC3F,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAChC,MAAI,WAAW,UAAU,WAAW,UAAW,QAAO;AAEtD,SAAO,gBAAAA,KAAC,UAAK,WAAW,GAAG,aAAa,cAAc,MAAM,EAAE,GAAI,iBAAO,OAAO,MAAM,GAAE;AAC1F;;;ACKI,SAQE,OAAAC,MARF,QAAAC,aAAA;AAJG,SAAS,WAAW,EAAE,SAAS,WAAW,SAAS,GAAuC;AAC/F,QAAM,EAAE,QAAQ,gBAAgB,GAAG,IAAI,SAAS;AAEhD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW,GAAG,SAAS;AAAA,MACvB,gBAAc,QAAQ;AAAA,MACtB,cAAY,GAAG,OAAO,MAAM,IAAI,QAAQ,KAAK;AAAA,MAC7C,UAAU;AAAA,MACV,SAAS;AAAA,MAET;AAAA,wBAAAD,KAAC,UAAK,WAAW,GAAG,gBAAgB,GAAG,eAAY,QAAO,oBAE1D;AAAA,QACC,CAAC,kBAAkB,gBAAAA,KAAC,UAAK,WAAW,GAAG,gBAAgB,GAAI,kBAAQ,aAAY;AAAA;AAAA;AAAA,EAClF;AAEJ;;;ANFM,gBAAAE,MAWM,QAAAC,aAXN;AAdC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,sBAAsB;AACxB,GAIsB;AACpB,QAAM,EAAE,QAAQ,eAAe,GAAG,IAAI,SAAS;AAC/C,QAAM,EAAE,WAAW,QAAQ,OAAO,UAAU,IAAI,QAAQ,QAAQ,EAAE;AAClE,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAS,mBAAmB;AAEpE,SACE,gBAAAD,MAAC,QAAG,WAAW,GAAG,SAAS,GACzB;AAAA,oBAAAD,KAAC,cAAW,SAAkB,WAAsB,UAAU,MAAM,KAAK,OAAO,GAAG;AAAA,IAEnF,gBAAAC,MAAC,SAAI,WAAW,GAAG,eAAe,GAChC;AAAA,sBAAAD,KAAC,QAAG,WAAW,GAAG,gBAAgB,GAAI,kBAAQ,OAAM;AAAA,MACnD,QAAQ,eAAe,gBAAAA,KAAC,OAAE,WAAW,GAAG,eAAe,GAAI,kBAAQ,aAAY;AAAA,MAEhF,gBAAAC,MAAC,SAAI,WAAW,GAAG,SAAS,GAC1B;AAAA,wBAAAD,KAAC,eAAY,QAAQ,QAAQ,QAAQ;AAAA,QACrC,gBAAAA,KAAC,UAAM,qBAAW,QAAQ,SAAS,GAAE;AAAA,QAEpC,iBACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,GAAG,SAAS;AAAA,YACvB,iBAAe;AAAA,YACf,iBAAe,eAAe,QAAQ,EAAE;AAAA,YACxC,SAAS,MAAM,gBAAgB,CAAC,SAAS,CAAC,IAAI;AAAA,YAE7C;AAAA,qBAAO;AAAA,cAAS;AAAA,cAAG,QAAQ;AAAA,cAAa;AAAA;AAAA;AAAA,QAC3C;AAAA,QAGF,gBAAAD,KAAC,cAAW,SAAkB;AAAA,SAChC;AAAA,MAEC,aACC,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,SAAS,GACxB;AAAA,MAGD,iBAAiB,gBAChB,gBAAAA,KAAC,SAAI,IAAI,eAAe,QAAQ,EAAE,IAChC,0BAAAA,KAAC,eAAY,WAAW,QAAQ,IAAI,GACtC;AAAA,OAEJ;AAAA,KACF;AAEJ;;;AOxCM,gBAAAG,MAKM,QAAAC,aALN;AApBN,IAAM,YAAY;AAClB,IAAM,oBAAoB;AAOnB,SAAS,oBAAoB;AAAA,EAClC,UAAU;AAAA,EACV,OAAO;AACT,GAIsB;AACpB,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAEhC,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,aAAa,GAAG,MAAK,UAAS,aAAU,QACzD;AAAA,oBAAAD,KAAC,UAAK,WAAW,GAAG,YAAY,GAAI,iBAAO,SAAQ;AAAA,IAElD,UACC,gBAAAA,KAAC,SAAI,WAAW,GAAG,YAAY,GAAG,eAAY,QAC3C,2BAAiB,IAAI,CAAC,WACrB,gBAAAC,MAAC,SAAiB,WAAW,GAAG,oBAAoB,GAClD;AAAA,sBAAAD,KAAC,OAAI,OAAM,OAAM;AAAA,MACjB,gBAAAA,KAAC,QAAK,OAAO,mBAAmB;AAAA,SAFxB,MAGV,CACD,GACH,IAEA,gBAAAA,KAAC,SAAI,eAAY,QACf,0BAAAA,KAAC,QAAK,OAAO,MAAM,GACrB;AAAA,KAEJ;AAEJ;AAEA,SAAS,KAAK,EAAE,MAAM,GAAyC;AAC7D,QAAM,EAAE,GAAG,IAAI,SAAS;AAExB,SACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,SAAS,GACzB,gBAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,UACjC,gBAAAC,MAAC,SAAgB,WAAW,GAAG,WAAW,mBAAmB,GAC3D;AAAA,oBAAAD,KAAC,SAAI,WAAW,GAAG,mBAAmB,GAAG;AAAA,IACzC,gBAAAC,MAAC,SAAI,WAAW,GAAG,eAAe,GAChC;AAAA,sBAAAD,KAAC,OAAI,OAAM,OAAM;AAAA,MACjB,gBAAAA,KAAC,OAAI,OAAM,OAAM,QAAO,UAAS;AAAA,MACjC,gBAAAA,KAAC,OAAI,OAAM,OAAM,QAAO,UAAS;AAAA,OACnC;AAAA,OANQ,KAOV,CACD,GACH;AAEJ;AAEA,SAAS,IAAI,EAAE,OAAO,OAAO,GAA0D;AACrF,QAAM,EAAE,GAAG,IAAI,SAAS;AACxB,SAAO,gBAAAA,KAAC,SAAI,WAAW,GAAG,kBAAkB,GAAG,OAAO,EAAE,OAAO,OAAO,GAAG;AAC3E;;;AC1BI,qBAAAE,WACuB,OAAAC,MADvB,QAAAC,aAAA;AA5BJ,SAAS,UAAU,OAAsB,QAAwD;AAC/F,MAAI,gBAAgB,KAAK,GAAG;AAC1B,WAAO,EAAE,OAAO,OAAO,oBAAoB,QAAQ,OAAO,oBAAoB;AAAA,EAChF;AACA,MAAI,MAAM,SAAS,WAAW;AAC5B,WAAO,EAAE,OAAO,OAAO,mBAAmB,QAAQ,OAAO,mBAAmB;AAAA,EAC9E;AACA,MAAI,WAAW,KAAK,GAAG;AACrB,WAAO;AAAA,MACL,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO,uBAAuB,YAAY,KAAK;AAAA,IACzD;AAAA,EACF;AACA,MAAI,MAAM,SAAS,eAAe;AAChC,WAAO,EAAE,OAAO,OAAO,sBAAsB,QAAQ,OAAO,sBAAsB;AAAA,EACpF;AACA,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,QAAQ,MAAM,SAAS,WAAW,OAAO,cAAc,YAAY,KAAK;AAAA,EAC1E;AACF;AAEO,SAAS,cAAiC;AAC/C,QAAM,EAAE,iBAAiB,IAAI,SAAS;AAItC,SACE,gBAAAA,MAAAF,WAAA,EACG;AAAA,wBAAoB,gBAAAC,KAAC,iBAAc,WAAW,kBAAkB;AAAA,IACjE,gBAAAA,KAAC,WAAQ,WAAW,kBAAkB;AAAA,KACxC;AAEJ;AAEA,SAAS,cAAc,EAAE,UAAU,GAAoD;AACrF,QAAM,EAAE,GAAG,IAAI,SAAS;AACxB,QAAM,EAAE,SAAS,WAAW,MAAM,IAAI,WAAW,SAAS;AAE1D,MAAI,UAAW,QAAO,gBAAAA,KAAC,uBAAoB,MAAM,GAAG;AACpD,MAAI,CAAC,WAAW,OAAO;AACrB,WACE,gBAAAA,KAAC,OAAE,WAAW,GAAG,YAAY,WAAW,GAAG,MAAK,SAC7C,sBAAY,KAAK,GACpB;AAAA,EAEJ;AACA,MAAI,CAAC,QAAS,QAAO;AAErB,SACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,WAAW,GAC5B,0BAAAA,KAAC,QAAG,WAAW,GAAG,SAAS,GACzB,0BAAAA,KAAC,eAAY,SAAkB,qBAAmB,MAAC,GACrD,GACF;AAEJ;AAEA,SAAS,QAAQ,EAAE,UAAU,GAA8C;AACzE,QAAM,EAAE,KAAK,cAAc,QAAQ,IAAI,aAAa,SAAS,IAAI,SAAS;AAC1E,QAAM,OAAoB,QAAQ,YAAY,QAAQ;AACtD,QAAM,YAAY,QAAQ;AAE1B,QAAM,EAAE,UAAU,WAAW,eAAe,OAAO,SAAS,UAAU,QAAQ,IAAI,YAAY;AAAA,IAC5F;AAAA,IACA,QAAQ,YAAY,mBAAmB;AAAA,IACvC;AAAA,EACF,CAAC;AAGD,QAAM,UAAU,SAAS,OAAO,CAAC,YAAY;AAC3C,QAAI,QAAQ,OAAO,UAAW,QAAO;AACrC,QAAI,UAAW,QAAO,iBAAiB,SAAS,QAAQ,MAAM;AAC9D,WAAO,gBAAgB,QAAQ,WAAW;AAAA,EAC5C,CAAC;AAED,MAAI,SAAS,QAAQ,WAAW,GAAG;AACjC,UAAM,EAAE,OAAO,OAAO,IAAI,UAAU,OAAO,MAAM;AACjD,WACE,gBAAAC,MAAC,SAAI,WAAW,GAAG,UAAU,GAAG,MAAK,SACnC;AAAA,sBAAAD,KAAC,OAAE,WAAW,GAAG,iBAAiB,GAAI,iBAAM;AAAA,MAC5C,gBAAAA,KAAC,OAAE,WAAW,GAAG,kBAAkB,GAAI,kBAAO;AAAA,MAC7C,CAAC,gBAAgB,KAAK,KACrB,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,aAAa,GAAG,SAAS,MAAM,KAAK,QAAQ,GAC7E,iBAAO,OACV;AAAA,OAEJ;AAAA,EAEJ;AAEA,MAAI,aAAa,QAAQ,WAAW,GAAG;AACrC,WAAO,gBAAAA,KAAC,uBAAoB,SAAS,WAAW;AAAA,EAClD;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,QAAI,YAAa,QAAO,gBAAAA,KAAAD,WAAA,EAAG,sBAAY,GAAE;AACzC,WACE,gBAAAE,MAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,sBAAAD,KAAC,OAAE,WAAW,GAAG,iBAAiB,GAAI,iBAAO,YAAW;AAAA,MACxD,gBAAAA,KAAC,OAAG,iBAAO,WAAU;AAAA,OACvB;AAAA,EAEJ;AAEA,SACE,gBAAAC,MAAAF,WAAA,EACG;AAAA,gBAAY,gBAAAC,KAAC,kBAAe,UAAU,SAAS,IAAK,gBAAAA,KAACE,OAAA,EAAK,UAAU,SAAS;AAAA,IAE7E,WAAW,SACV,gBAAAD,MAAC,SAAI,WAAW,GAAG,eAAe,GAAG,MAAK,SACxC;AAAA,sBAAAD,KAAC,UAAM,iBAAO,eAAc;AAAA,MAC5B,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,GAAG,aAAa,GAAG,SAAS,MAAM,KAAK,SAAS,GAC9E,iBAAO,OACV;AAAA,OACF;AAAA,IAGD,WAAW,CAAC,SACX,gBAAAA,KAAC,SAAI,WAAW,GAAG,eAAe,GAChC,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,GAAG,UAAU,eAAe;AAAA,QACvC,UAAU;AAAA,QACV,SAAS,MAAM,KAAK,SAAS;AAAA,QAE5B,0BAAgB,OAAO,UAAU,OAAO;AAAA;AAAA,IAC3C,GACF;AAAA,KAEJ;AAEJ;AAEA,SAASE,MAAK,EAAE,SAAS,GAA+C;AACtE,QAAM,EAAE,GAAG,IAAI,SAAS;AACxB,SACE,gBAAAF,KAAC,QAAG,WAAW,GAAG,SAAS,GACxB,mBAAS,IAAI,CAAC,YACb,gBAAAA,KAAC,cAA4B,WAAZ,QAAQ,EAAsB,CAChD,GACH;AAEJ;AAEA,SAAS,eAAe,EAAE,SAAS,GAA+C;AAChF,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAEhC,SACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,YAAY,GAC5B,2BAAiB,IAAI,CAAC,WAAW;AAChC,UAAM,SAAS,SAAS,OAAO,CAAC,YAAY,QAAQ,WAAW,MAAM;AACrE,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,GAAG,oBAAoB;AAAA,QAClC,cAAY,OAAO,OAAO,MAAM;AAAA,QAEhC;AAAA,0BAAAD,KAAC,QAAG,WAAW,GAAG,qBAAqB,GAAI,iBAAO,OAAO,MAAM,GAAE;AAAA,UAChE,OAAO,WAAW,IACjB,gBAAAA,KAAC,OAAE,WAAW,GAAG,UAAU,GAAG,oBAAC,IAE/B,gBAAAA,KAAC,QAAG,WAAW,GAAG,SAAS,GACxB,iBAAO,IAAI,CAAC,YACX,gBAAAA,KAAC,cAA4B,WAAZ,QAAQ,EAAsB,CAChD,GACH;AAAA;AAAA;AAAA,MAZG;AAAA,IAcP;AAAA,EAEJ,CAAC,GACH;AAEJ;AAGA,SAAS,WAAW,EAAE,QAAQ,GAA4C;AACxE,QAAM,EAAE,cAAc,IAAI,SAAS;AACnC,MAAI,CAAC,cAAe,QAAO,gBAAAA,KAAC,eAAY,SAAkB;AAC1D,SAAO,gBAAAA,KAAC,eAAY,SAAkB;AACxC;AAEA,SAAS,YAAY,EAAE,QAAQ,GAA4C;AACzE,QAAM,EAAE,cAAc,IAAI,SAAS;AACnC,QAAM,EAAE,OAAO,IAAI,QAAQ,QAAQ,EAAE;AACrC,QAAM,EAAE,QAAQ,SAAS,IAAI,UAAU,QAAQ,EAAE;AAEjD,SAAO,gBAAAA,KAAAD,WAAA,EAAG,0BAAgB,SAAS,EAAE,YAAY,QAAQ,QAAQ,SAAS,CAAC,GAAE;AAC/E;;;ACxMA,SAAS,YAAAI,iBAAgB;;;ACAzB,SAAS,eAAAC,cAAa,YAAAC,iBAAgB;AAY/B,SAAS,mBAA2C;AACzD,QAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA+B,IAAI;AAE7D,QAAM,SAASC;AAAA,IACb,OAAO,UAA8B;AACnC,mBAAa,IAAI;AACjB,eAAS,IAAI;AACb,YAAM,SAAS,MAAM,MAAM,cAAc,KAAK;AAC9C,mBAAa,KAAK;AAClB,UAAI,CAAC,OAAO,IAAI;AACd,iBAAS,OAAO,KAAK;AACrB,eAAO;AAAA,MACT;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,QAAQA,aAAY,MAAM,SAAS,IAAI,GAAG,CAAC,CAAC;AAElD,SAAO,EAAE,QAAQ,WAAW,OAAO,MAAM;AAC3C;;;ADcQ,gBAAAC,OAiBE,QAAAC,aAjBF;AA3CD,SAAS,aAAgC;AAC9C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,SAAS;AACb,QAAM,EAAE,QAAQ,WAAW,MAAM,IAAI,iBAAiB;AAEtD,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,EAAE;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,aAAa,EAAE;AAElD,QAAM,eAAe,MAAM,KAAK,EAAE,UAAU,OAAO;AACnD,QAAM,iBAAiB,eAAe,SAAS,UAAU,MAAM,CAAC,cAAc,KAAK,MAAM,KAAK,CAAC;AAC/F,QAAM,iBAAiB,eAAe,cAAc,CAAC,MAAM,KAAK;AAChE,QAAM,YAAY,gBAAgB,CAAC,kBAAkB,CAAC;AAEtD,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,SAAS;AAAA,MACvB,UAAU,OAAO,UAAU;AACzB,cAAM,eAAe;AACrB,cAAM,UAAU,MAAM,OAAO;AAAA,UAC3B;AAAA,UACA;AAAA,UACA,GAAI,eAAe,SAAS,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,UACjD;AAAA,QACF,CAAC;AACD,YAAI,CAAC,QAAS;AACd,YAAI,CAAC,YAAY;AACf,mBAAS,EAAE;AACX,yBAAe,EAAE;AAAA,QACnB;AACA,yBAAiB,IAAI;AACrB,oBAAY,KAAK;AAAA,MACnB;AAAA,MAEA;AAAA,wBAAAA,MAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAAD,MAAC,WAAM,WAAW,GAAG,UAAU,GAAG,SAAQ,YACvC,iBAAO,YACV;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,WAAW,GAAG,UAAU;AAAA,cACxB,OAAO;AAAA,cACP,WAAW,OAAO;AAAA,cAClB,WAAW,OAAO;AAAA,cAClB,aAAa,OAAO;AAAA,cACpB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,cAChD,UAAQ;AAAA;AAAA,UACV;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAW,GAAG,gBAAgB,GACjC;AAAA,4BAAAD,MAAC,UAAK,WAAW,GAAG,UAAU,GAC3B,oBAAU,MAAM,CAAC,eAAe,OAAO,qBAAqB,IAC/D;AAAA,YACA,gBAAAC,MAAC,UAAK,WAAW,GAAG,UAAU,GAC3B;AAAA,oBAAM;AAAA,cAAO;AAAA,cAAE,OAAO;AAAA,eACzB;AAAA,aACF;AAAA,WACF;AAAA,QAEA,gBAAAA,MAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAAD,MAAC,WAAM,WAAW,GAAG,UAAU,GAAG,SAAQ,kBACvC,iBAAO,kBACV;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,WAAW,GAAG,YAAY,aAAa;AAAA,cACvC,OAAO;AAAA,cACP,WAAW,OAAO;AAAA,cAClB,aAAa,OAAO;AAAA,cACpB,UAAU,CAAC,UAAU,eAAe,MAAM,OAAO,KAAK;AAAA;AAAA,UACxD;AAAA,UACA,gBAAAC,MAAC,SAAI,WAAW,GAAG,gBAAgB,GACjC;AAAA,4BAAAD,MAAC,UAAK;AAAA,YACN,gBAAAC,MAAC,UAAK,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAY;AAAA,cAAO;AAAA,cAAE,OAAO;AAAA,eAC/B;AAAA,aACF;AAAA,WACF;AAAA,QAEC,eAAe,SACd,gBAAAA,MAAC,SAAI,WAAW,GAAG,UAAU,GAC3B;AAAA,0BAAAD,MAAC,WAAM,WAAW,GAAG,UAAU,GAAG,SAAQ,YACvC,iBAAO,YACV;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,WAAW,GAAG,UAAU;AAAA,cACxB,MAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa,OAAO;AAAA,cACpB,oBAAiB;AAAA,cACjB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,cAChD,UAAU,eAAe;AAAA;AAAA,UAC3B;AAAA,UACC,iBACC,gBAAAA,MAAC,OAAE,IAAG,iBAAgB,WAAW,GAAG,UAAU,GAC3C,iBAAO,mBACV,IAEA,gBAAAA,MAAC,OAAE,IAAG,iBAAgB,WAAW,GAAG,UAAU,GAC3C,iBAAO,gBACV;AAAA,WAEJ;AAAA,QAGD,SACC,gBAAAA,MAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,SAChC,sBAAY,KAAK,GACpB;AAAA,QAGF,gBAAAC,MAAC,SAAI,WAAW,GAAG,kBAAkB,GACnC;AAAA,0BAAAD,MAAC,YAAO,MAAK,UAAS,WAAW,GAAG,QAAQ,GAAG,UAAU,aAAa,CAAC,WACpE,sBAAY,OAAO,aAAa,OAAO,QAC1C;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,GAAG,UAAU,eAAe;AAAA,cACvC,SAAS,MAAM,YAAY,KAAK;AAAA,cAE/B,iBAAO;AAAA;AAAA,UACV;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;AEhIA,IAAM,kBAAoD;AAAA,EACxD,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AACR;AAEO,SAAS,aAAa,OAA+C;AAC1E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAgC,CAAC;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,UAAM,WAAW,gBAAgB,GAAuB;AACxD,UAAM,QAAQ,IAAI,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAAA,EAC/D;AACA,SAAO;AACT;;;ArBuGqB,SAUjB,YAAAG,WAViB,OAAAC,OAUjB,QAAAC,aAViB;AArFrB,IAAM,eAA2B,CAAC,OAAO,KAAK;AAEvC,SAAS,UAAU;AAAA,EACxB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,QAAM,EAAE,eAAe,IAAI,kBAAkB;AAC7C,QAAM,CAAC,KAAK,MAAM,IAAIC,WAAmB,cAAc,KAAK,CAAC,KAAK,KAAK;AACvE,QAAM,CAAC,YAAY,WAAW,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AAExD,EAAAC,WAAU,MAAM;AACd,UAAM,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA,EACpC,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,QAAQC;AAAA,IACZ,OAAO;AAAA,MACL,QAAQ,YAAY,MAAM;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,IAAI,cAAc,QAAQ;AAAA,IAC5B;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SACE,gBAAAJ,MAAC,wBAAqB,OACpB,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,CAAC,WAAW,KAAK,YAAY,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK;AAAA,MAChF,OAAO,EAAE,GAAG,aAAa,KAAK,GAAG,GAAG,MAAM;AAAA,MAC1C,cAAY,gBAAgB,WAAW,SAAY;AAAA,MAElD,sBAAY,gBAAAA,MAAC,gBAAa;AAAA;AAAA,EAC7B,GACF;AAEJ;AAEA,SAAS,eAAkC;AACzC,QAAM,EAAE,aAAa,IAAI,SAAS;AAElC,SACE,gBAAAC,MAAAF,WAAA,EACG;AAAA,mBAAe,aAAa,IAAI,gBAAAC,MAAC,gBAAa;AAAA,IAC/C,gBAAAA,MAAC,eAAY;AAAA,IACb,gBAAAA,MAAC,YAAS;AAAA,KACZ;AAEJ;AAEA,IAAM,WAAW;AACjB,IAAM,WAAW;AACjB,IAAM,eAAe;AAErB,SAAS,WAAW,SAAqD;AACvE,MAAI,CAAC,WAAW,OAAO,QAAQ,YAAY,WAAY,QAAO;AAC9D,SAAO,CAAC,OAAO,aAAa,kCAAkC,EAAE;AAClE;AAEA,SAAS,cAAiC;AACxC,QAAM,EAAE,YAAY,aAAa,eAAe,kBAAkB,QAAQ,UAAU,GAAG,IACrF,SAAS;AACX,QAAM,CAAC,UAAU,WAAW,IAAIE,WAAS,UAAU;AACnD,QAAM,QAAQG,QAAuB,IAAI;AACzC,QAAM,UAAUA,QAA0B,IAAI;AAC9C,QAAM,WAAWA,QAAyB,IAAI;AAC9C,QAAM,aAAaA,QAAO,KAAK;AAE/B,EAAAF,WAAU,MAAM;AACd,QAAI,eAAe,SAAU;AAC7B,eAAW,UAAU;AAErB,UAAM,UAAU,MAAM;AACtB,QAAI,YAAY,CAAC,WAAW,OAAO,GAAG;AACpC,kBAAY,UAAU;AACtB;AAAA,IACF;AAEA,aAAS,SAAS,OAAO;AACzB,UAAM,UAAU,QAAQ;AAAA,MACtB,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,iBAAiB,kBAAkB,EAAE;AAAA,MACpE,EAAE,UAAU,UAAU,QAAQ,WAAW,MAAM,WAAW;AAAA,IAC5D;AAEA,YAAQ,WAAW,MAAM;AACvB,YAAM,OAAO,QAAQ;AACrB,gBAAU,MAAM,YAAY,UAAU,CAAC;AACvC,cAAQ,OAAO;AACf,YAAM,KAAK,QAAQ;AAEnB,cAAQ,MAAM,WAAW;AACzB,YAAM,QAAQ,QAAQ;AAAA,QACpB;AAAA,UACE,SAAS,CAAC,GAAG,CAAC;AAAA,UACd,WAAW,CAAC,mBAAmB,eAAe;AAAA,UAC9C,QAAQ,CAAC,GAAG,IAAI,MAAM,GAAG,EAAE,IAAI;AAAA,QACjC;AAAA,QACA,EAAE,UAAU,UAAU,QAAQ,aAAa;AAAA,MAC7C;AACA,YAAM,SAAS,MAAM;AACnB,gBAAQ,MAAM,WAAW;AAAA,MAC3B;AACA,YAAM,WAAW;AACjB,YAAM,WAAW;AACjB,eAAS,UAAU;AAAA,IACrB;AAEA,WAAO,MAAM,QAAQ,OAAO;AAAA,EAC9B,GAAG,CAAC,YAAY,UAAU,QAAQ,CAAC;AAEnC,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,QAAS;AACzB,UAAM,SAAS,WACX,MAAM,SAAS,cAA2B,WAAW,IACrD,QAAQ;AACZ,YAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAAA,EACvC,GAAG,CAAC,QAAQ,CAAC;AAEb,SACE,gBAAAF,MAAC,SAAI,KAAK,OACR;AAAA,oBAAAA,MAAC,SAAI,QAAQ,UACX;AAAA,sBAAAA,MAAC,SAAI,WAAW,GAAG,YAAY,GAC7B;AAAA,wBAAAD,MAAC,aAAU;AAAA,QACX,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAW,GAAG,QAAQ;AAAA,YACtB,SAAS,MAAM;AACb,+BAAiB,KAAK;AACtB,0BAAY,IAAI;AAAA,YAClB;AAAA,YAEC,iBAAO;AAAA;AAAA,QACV;AAAA,SACF;AAAA,MACC,iBACC,gBAAAA,MAAC,OAAE,WAAW,GAAG,UAAU,GAAG,MAAK,UAChC,iBAAO,WACV;AAAA,MAEF,gBAAAA,MAAC,eAAY;AAAA,OACf;AAAA,IACC,YAAY,gBAAAA,MAAC,cAAW;AAAA,KAC3B;AAEJ;AAEA,SAAS,eAAkC;AACzC,QAAM,EAAE,QAAQ,GAAG,IAAI,SAAS;AAChC,SAAO,gBAAAA,MAAC,QAAG,WAAW,GAAG,YAAY,GAAI,iBAAO,OAAM;AACxD;AAEO,SAAS,YAAsC;AACpD,QAAM,EAAE,MAAM,KAAK,QAAQ,QAAQ,GAAG,IAAI,SAAS;AACnD,MAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,QAAM,UAAoC;AAAA,IACxC,KAAK,OAAO;AAAA,IACZ,KAAK,OAAO;AAAA,IACZ,SAAS,OAAO;AAAA,EAClB;AAEA,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,SAAS,GAAG,MAAK,WAAU,cAAY,OAAO,OAC9D,eAAK,IAAI,CAAC,SACT,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,MAAK;AAAA,MACL,IAAI,UAAU,IAAI;AAAA,MAClB,WAAW,GAAG,QAAQ;AAAA,MACtB,iBAAe,QAAQ;AAAA,MACvB,UAAU,QAAQ,OAAO,IAAI;AAAA,MAC7B,SAAS,MAAM,OAAO,IAAI;AAAA,MAC1B,WAAW,CAAC,UAAU;AACpB,cAAM,OAAO,MAAM,QAAQ,eAAe,IAAI,MAAM,QAAQ,cAAc,KAAK;AAC/E,YAAI,SAAS,EAAG;AAChB,cAAM,eAAe;AACrB,cAAM,OAAO,MAAM,KAAK,QAAQ,GAAG,IAAI,OAAO,KAAK,UAAU,KAAK,MAAM;AACxE,YAAI,MAAM;AACR,iBAAO,IAAI;AACX,mBAAS,eAAe,UAAU,IAAI,EAAE,GAAG,MAAM;AAAA,QACnD;AAAA,MACF;AAAA,MAEC,kBAAQ,IAAI;AAAA;AAAA,IAnBR;AAAA,EAoBP,CACD,GACH;AAEJ;AAEO,SAAS,gBAAmC;AACjD,QAAM,EAAE,YAAY,aAAa,kBAAkB,QAAQ,GAAG,IAAI,SAAS;AAE3E,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW,GAAG,QAAQ;AAAA,MACtB,iBAAe;AAAA,MACf,SAAS,MAAM;AACb,YAAI,CAAC,WAAY,kBAAiB,KAAK;AACvC,oBAAY,CAAC,UAAU;AAAA,MACzB;AAAA,MAEC,uBAAa,OAAO,SAAS,OAAO;AAAA;AAAA,EACvC;AAEJ;AAGO,IAAM,gBAAgB,OAAO,OAAO,WAAW;AAAA,EACpD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;AsB/TD,SAAS,aAAAM,YAAW,UAAAC,eAAc;AA4C5B,SAUE,OAAAC,OAVF,QAAAC,aAAA;AAlCC,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,GAAG;AACL,GAAuD;AACrD,QAAM,YAAYC,QAAuB,IAAI;AAC7C,QAAM,YAAYA,QAAuB,IAAI;AAE7C,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,cAAU,UAAU,SAAS;AAC7B,cAAU,SAAS,MAAM;AAEzB,aAAS,UAAU,OAA4B;AAC7C,UAAI,MAAM,QAAQ,SAAU,SAAQ;AAAA,IACtC;AACA,aAAS,iBAAiB,WAAW,SAAS;AAE9C,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,SAAS;AAEjD,MAAC,UAAU,SAAgC,QAAQ;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAU,YAAY;AAC5B,QAAM,EAAE,YAAY,IAAI;AAExB,SACE,gBAAAH,MAAC,SAAI,WAAW,UAAU,iCAAiC,cAAc,SAAS,SAChF,0BAAAC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,UAAU,+BAA+B;AAAA,MACpD,cAAY,gBAAgB,WAAW,SAAY;AAAA,MACnD,MAAK;AAAA,MACL,cAAW;AAAA,MACX,cAAY;AAAA,MACZ,UAAU;AAAA,MACV,SAAS,CAAC,UAAU,MAAM,gBAAgB;AAAA,MAE1C;AAAA,wBAAAD,MAAC,YAAO,MAAK,UAAS,WAAU,oBAAmB,cAAW,SAAQ,SAAS,SAAS,kBAExF;AAAA,QACA,gBAAAA,MAAC,aAAW,GAAG,YAAY;AAAA;AAAA;AAAA,EAC7B,GACF;AAEJ;;;AC7DA,SAAS,eAAAI,cAAa,YAAAC,kBAAoD;AAC1E,SAAS,oBAAoB;AAqCzB,qBAAAC,WACE,OAAAC,OADF,QAAAC,cAAA;AArBJ,SAAS,gBAAgB,UAAmD;AAC1E,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,OAAO,aAAa,SAAS,uBAAuB;AAC1D,SAAO,oCAAoC,IAAI;AACjD;AAEO,SAAS,eAAe;AAAA,EAC7B,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,GAAG;AACL,GAA2C;AACzC,QAAM,CAAC,MAAM,OAAO,IAAIC,WAAS,KAAK;AACtC,QAAM,QAAQC,aAAY,MAAM,QAAQ,KAAK,GAAG,CAAC,CAAC;AAClD,QAAM,UAAU,CAAC,MAAM,WAAW,KAAK,gBAAgB,QAAQ,GAAG,SAAS,EACxE,OAAO,OAAO,EACd,KAAK,GAAG;AAEX,SACE,gBAAAF,OAAAF,WAAA,EACE;AAAA,oBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,WAAW;AAAA,QACtB,OAAO,EAAE,GAAG,aAAa,MAAM,KAAK,GAAG,GAAG,MAAM;AAAA,QAChD,iBAAc;AAAA,QACd,iBAAe;AAAA,QACf,SAAS,MAAM,QAAQ,IAAI;AAAA,QAE1B;AAAA;AAAA,IACH;AAAA,IACC,OACG;AAAA,MACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ,SAAQ;AAAA,UACR;AAAA,UACA,MAAI;AAAA,UACJ,SAAS;AAAA;AAAA,MACX;AAAA,MACA,SAAS;AAAA,IACX,IACA;AAAA,KACN;AAEJ;","names":["failure","useEffect","useMemo","useRef","useState","useEffect","useEffect","createContext","useContext","createContext","useContext","jsx","useEffect","useEffect","useCallback","useEffect","useMemo","useMemo","useEffect","useCallback","useCallback","useState","useState","useCallback","useCallback","useState","useState","useCallback","useState","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","jsx","useState","useState","jsx","jsxs","useState","jsx","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","Fragment","jsx","jsxs","Rows","useState","useCallback","useState","useState","useCallback","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","useEffect","useMemo","useRef","useEffect","useRef","jsx","jsxs","useRef","useEffect","useCallback","useState","Fragment","jsx","jsxs","useState","useCallback"]}
|