@fewchurs/react 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { ReactNode, CSSProperties } from 'react';
2
2
 
3
3
  type FewchursError = {
4
4
  code: "invalid_key";
5
- status: 401;
5
+ status: 401 | 403;
6
6
  message: string;
7
7
  } | {
8
8
  code: "validation_failed";
@@ -110,6 +110,11 @@ interface FewchursClientOptions {
110
110
  deviceId?: string | null | (() => string | null);
111
111
  /** Sent as `Accept-Language`, so server-side copy and emails match the visitor. */
112
112
  language?: string;
113
+ /**
114
+ * The domain the API key is checked against, for calls made from a server. A browser reports
115
+ * its own domain through `Origin`, which always wins, so leave this out in a SPA.
116
+ */
117
+ appId?: string;
113
118
  fetch?: FetchLike;
114
119
  retries?: number;
115
120
  retryDelayMs?: number;
@@ -308,9 +313,9 @@ declare function useBoard(): BoardContextValue;
308
313
 
309
314
  declare function Branding(): React.JSX.Element | null;
310
315
 
311
- declare const SDK_VERSION = "1.0.1";
316
+ declare const SDK_VERSION = "1.2.0";
312
317
 
313
- declare const SDK_HEADER = "react/1.0.1";
318
+ declare const SDK_HEADER = "react/1.2.0";
314
319
  declare const DEFAULT_BASE_URL = "https://www.fewchurs.com/api/v1";
315
320
  declare const DEFAULT_PAGE_SIZE = 20;
316
321
  /** Mirrors the server's zod schemas, so the UI can reject input before a round trip. */
@@ -381,8 +386,17 @@ interface FewchursBoardDialogProps extends FewchursBoardProps {
381
386
  open: boolean;
382
387
  onClose: () => void;
383
388
  ariaLabel?: string;
389
+ variant?: "dialog" | "sheet";
384
390
  }
385
- declare function FewchursBoardDialog({ open, onClose, ariaLabel, ...boardProps }: FewchursBoardDialogProps): React.JSX.Element | null;
391
+ declare function FewchursBoardDialog({ open, onClose, ariaLabel, variant, ...boardProps }: FewchursBoardDialogProps): React.JSX.Element | null;
392
+
393
+ interface FewchursButtonProps extends Omit<FewchursBoardProps, "children" | "className" | "style"> {
394
+ children?: ReactNode;
395
+ className?: string;
396
+ style?: CSSProperties;
397
+ ariaLabel?: string;
398
+ }
399
+ declare function FewchursButton({ children, className, style, ariaLabel, ...board }: FewchursButtonProps): React.JSX.Element;
386
400
 
387
401
  declare function FeatureCard({ feature, defaultCommentsOpen, }: {
388
402
  feature: Feature;
@@ -520,4 +534,4 @@ declare function validateFeatureInput(input: SubmitFeatureInput): FewchursError
520
534
  declare function validateCommentInput(input: CreateCommentInput): FewchursError | null;
521
535
  declare function validateEmail(email: string): FewchursError | null;
522
536
 
523
- export { type BoardContextValue, type BoardLabels, BoardRoot, type BoardTab, BoardTabs, type BoardTheme, Branding, type Comment, CommentForm, CommentList, type CommentPage, type CommentsState, type CreateCommentInput, DEFAULT_BASE_URL, DEFAULT_LABELS, DEFAULT_PAGE_SIZE, COOKIE_NAME as DEVICE_ID_COOKIE, type EmailFieldMode, type EventHandler, type Feature, type FeatureActions, FeatureCard, FeatureList, type FeaturePage, type FeatureSort, type FeatureStatus, type FetchLike, FewchursBoard, FewchursBoardDialog, type FewchursBoardDialogProps, type FewchursBoardProps, type FewchursClient, type FewchursClientOptions, type FewchursConfig, type FewchursContextValue, type FewchursError, type FewchursEvent, type FewchursEventName, FewchursProvider, type FewchursProviderProps, FollowForm, LIMITS, type ListCommentsParams, type ListFeaturesParams, type ListQuery, type ListState, type LoadStatus, ROADMAP_STATUSES, type Result, SDK_HEADER, SDK_VERSION, StatusBadge, type Store, type StoreOptions, type StoreState, type SubmitFeatureInput, SubmitForm, SubmitTrigger, type UseCommentsOptions, type UseCommentsResult, type UseFeatureOptions, type UseFeatureResult, type UseFeaturesOptions, type UseFeaturesResult, type UseFewchursConfigResult, type UseFollowResult, type UseSubmitFeatureResult, type UseVoteResult, VoteButton, commentsStateOf, createDeviceId, createFewchursClient, createStore, errorFromResponse, featureKey, listKey, listStateOf, mergeLabels, networkError, normalizeComment, normalizeCommentPage, normalizeConfig, normalizeFeature, normalizeFeaturePage, normalizeStatus, normalizeVote, readDeviceId, resolveDeviceId, useBoard, useComments, useFeature, useFeatures, useFewchurs, useFewchursConfig, useFollow, useSubmitFeature, useVote, userMessage, validateCommentInput, validateEmail, validateFeatureInput, validationError };
537
+ export { type BoardContextValue, type BoardLabels, BoardRoot, type BoardTab, BoardTabs, type BoardTheme, Branding, type Comment, CommentForm, CommentList, type CommentPage, type CommentsState, type CreateCommentInput, DEFAULT_BASE_URL, DEFAULT_LABELS, DEFAULT_PAGE_SIZE, COOKIE_NAME as DEVICE_ID_COOKIE, type EmailFieldMode, type EventHandler, type Feature, type FeatureActions, FeatureCard, FeatureList, type FeaturePage, type FeatureSort, type FeatureStatus, type FetchLike, FewchursBoard, FewchursBoardDialog, type FewchursBoardDialogProps, type FewchursBoardProps, FewchursButton, type FewchursButtonProps, type FewchursClient, type FewchursClientOptions, type FewchursConfig, type FewchursContextValue, type FewchursError, type FewchursEvent, type FewchursEventName, FewchursProvider, type FewchursProviderProps, FollowForm, LIMITS, type ListCommentsParams, type ListFeaturesParams, type ListQuery, type ListState, type LoadStatus, ROADMAP_STATUSES, type Result, SDK_HEADER, SDK_VERSION, StatusBadge, type Store, type StoreOptions, type StoreState, type SubmitFeatureInput, SubmitForm, SubmitTrigger, type UseCommentsOptions, type UseCommentsResult, type UseFeatureOptions, type UseFeatureResult, type UseFeaturesOptions, type UseFeaturesResult, type UseFewchursConfigResult, type UseFollowResult, type UseSubmitFeatureResult, type UseVoteResult, VoteButton, commentsStateOf, createDeviceId, createFewchursClient, createStore, errorFromResponse, featureKey, listKey, listStateOf, mergeLabels, networkError, normalizeComment, normalizeCommentPage, normalizeConfig, normalizeFeature, normalizeFeaturePage, normalizeStatus, normalizeVote, readDeviceId, resolveDeviceId, useBoard, useComments, useFeature, useFeatures, useFewchurs, useFewchursConfig, useFollow, useSubmitFeature, useVote, userMessage, validateCommentInput, validateEmail, validateFeatureInput, validationError };
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __export(src_exports, {
34
34
  FeatureList: () => FeatureList,
35
35
  FewchursBoard: () => FewchursBoard,
36
36
  FewchursBoardDialog: () => FewchursBoardDialog,
37
+ FewchursButton: () => FewchursButton,
37
38
  FewchursProvider: () => FewchursProvider,
38
39
  FollowForm: () => FollowForm,
39
40
  LIMITS: () => LIMITS,
@@ -84,7 +85,7 @@ module.exports = __toCommonJS(src_exports);
84
85
  var import_react = require("react");
85
86
 
86
87
  // src/client/version.ts
87
- var SDK_VERSION = "1.0.1";
88
+ var SDK_VERSION = "1.2.0";
88
89
 
89
90
  // src/client/constants.ts
90
91
  var SDK_HEADER = `react/${SDK_VERSION}`;
@@ -127,6 +128,8 @@ function errorFromResponse(status, body) {
127
128
  switch (code) {
128
129
  case "invalid_key":
129
130
  return { code: "invalid_key", status: 401, message };
131
+ case "wrong_app":
132
+ return { code: "invalid_key", status: 403, message };
130
133
  // missing_device_id is a client mistake the caller fixes the same way a bad field is fixed,
131
134
  // so it collapses into validation_failed rather than widening the public union.
132
135
  case "missing_device_id":
@@ -276,6 +279,7 @@ function createFewchursClient(options = {}) {
276
279
  const deviceId = getDeviceId();
277
280
  if (deviceId) result["X-Device-Id"] = deviceId;
278
281
  if (options.language) result["Accept-Language"] = options.language;
282
+ if (options.appId) result["X-Fewchurs-App-Id"] = options.appId;
279
283
  return result;
280
284
  }
281
285
  function url(path, query) {
@@ -314,7 +318,7 @@ function createFewchursClient(options = {}) {
314
318
  continue;
315
319
  }
316
320
  const failure = errorFromResponse(response.status, await readJson(response));
317
- warnAboutKey(failure.code);
321
+ warnAboutKey(failure);
318
322
  return { ok: false, error: failure };
319
323
  }
320
324
  return { ok: false, error: networkError() };
@@ -406,12 +410,12 @@ function messageOf(error) {
406
410
  return error instanceof Error ? error.message : "Network request failed.";
407
411
  }
408
412
  var warnedAboutKey = false;
409
- function warnAboutKey(code) {
410
- if (code !== "invalid_key" || warnedAboutKey) return;
413
+ function warnAboutKey(error) {
414
+ if (error.code !== "invalid_key" || warnedAboutKey) return;
411
415
  if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
412
416
  warnedAboutKey = true;
413
417
  console.error(
414
- "[fewchurs] The API key was rejected. Check FEWCHURS_API_KEY (server) or the apiKey passed to FewchursProvider, and that the key is active in your Fewchurs dashboard."
418
+ error.status === 403 ? `[fewchurs] ${error.message}` : "[fewchurs] The API key was rejected. Check FEWCHURS_API_KEY (server) or the apiKey passed to FewchursProvider, and that the key is active in your Fewchurs dashboard."
415
419
  );
416
420
  }
417
421
 
@@ -1726,6 +1730,7 @@ function FewchursBoardDialog({
1726
1730
  open,
1727
1731
  onClose,
1728
1732
  ariaLabel = "Feature requests",
1733
+ variant = "dialog",
1729
1734
  ...boardProps
1730
1735
  }) {
1731
1736
  const dialogRef = (0, import_react16.useRef)(null);
@@ -1744,11 +1749,14 @@ function FewchursBoardDialog({
1744
1749
  };
1745
1750
  }, [open, onClose]);
1746
1751
  if (!open) return null;
1747
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fw-overlay", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1752
+ const isSheet = variant === "sheet";
1753
+ const { colorScheme } = boardProps;
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: isSheet ? "fw-overlay fw-overlay--sheet" : "fw-overlay", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1748
1755
  "div",
1749
1756
  {
1750
1757
  ref: dialogRef,
1751
- className: "fw-dialog",
1758
+ className: isSheet ? "fw-dialog fw-dialog--sheet" : "fw-dialog",
1759
+ "data-theme": colorScheme === "system" ? void 0 : colorScheme,
1752
1760
  role: "dialog",
1753
1761
  "aria-modal": "true",
1754
1762
  "aria-label": ariaLabel,
@@ -1761,6 +1769,49 @@ function FewchursBoardDialog({
1761
1769
  }
1762
1770
  ) });
1763
1771
  }
1772
+
1773
+ // src/components/BoardButton.tsx
1774
+ var import_react17 = require("react");
1775
+ var import_react_dom = require("react-dom");
1776
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1777
+ function FewchursButton({
1778
+ children = "Feedback",
1779
+ className,
1780
+ style,
1781
+ ariaLabel,
1782
+ ...board
1783
+ }) {
1784
+ const [open, setOpen] = (0, import_react17.useState)(false);
1785
+ const close = (0, import_react17.useCallback)(() => setOpen(false), []);
1786
+ const classes = [board.unstyled ? "" : "fw-launcher", className].filter(Boolean).join(" ");
1787
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1788
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1789
+ "button",
1790
+ {
1791
+ type: "button",
1792
+ className: classes || void 0,
1793
+ style: { ...themeToStyle(board.theme), ...style },
1794
+ "aria-haspopup": "dialog",
1795
+ "aria-expanded": open,
1796
+ onClick: () => setOpen(true),
1797
+ children
1798
+ }
1799
+ ),
1800
+ open ? (0, import_react_dom.createPortal)(
1801
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1802
+ FewchursBoardDialog,
1803
+ {
1804
+ ...board,
1805
+ variant: "sheet",
1806
+ ariaLabel,
1807
+ open: true,
1808
+ onClose: close
1809
+ }
1810
+ ),
1811
+ document.body
1812
+ ) : null
1813
+ ] });
1814
+ }
1764
1815
  // Annotate the CommonJS export names for ESM import in node:
1765
1816
  0 && (module.exports = {
1766
1817
  BoardRoot,
@@ -1776,6 +1827,7 @@ function FewchursBoardDialog({
1776
1827
  FeatureList,
1777
1828
  FewchursBoard,
1778
1829
  FewchursBoardDialog,
1830
+ FewchursButton,
1779
1831
  FewchursProvider,
1780
1832
  FollowForm,
1781
1833
  LIMITS,