convex-feedback-ui 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +115 -18
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/native/expo/ExpoFeedbackBody.d.ts +4 -0
  4. package/dist/native/expo/ExpoFeedbackBody.d.ts.map +1 -0
  5. package/dist/native/expo/ExpoFeedbackBody.js +26 -0
  6. package/dist/native/expo/ExpoFeedbackBody.js.map +1 -0
  7. package/dist/native/expo/FeedbackScreen.d.ts +3 -0
  8. package/dist/native/expo/FeedbackScreen.d.ts.map +1 -0
  9. package/dist/native/expo/FeedbackScreen.js +9 -0
  10. package/dist/native/expo/FeedbackScreen.js.map +1 -0
  11. package/dist/native/expo/FeedbackStack.d.ts +3 -0
  12. package/dist/native/expo/FeedbackStack.d.ts.map +1 -0
  13. package/dist/native/expo/FeedbackStack.js +41 -0
  14. package/dist/native/expo/FeedbackStack.js.map +1 -0
  15. package/dist/native/expo/index.d.ts +9 -0
  16. package/dist/native/expo/index.d.ts.map +1 -0
  17. package/dist/native/expo/index.js +7 -0
  18. package/dist/native/expo/index.js.map +1 -0
  19. package/dist/native/expo/types.d.ts +20 -0
  20. package/dist/native/expo/types.d.ts.map +1 -0
  21. package/dist/native/expo/types.js +2 -0
  22. package/dist/native/expo/types.js.map +1 -0
  23. package/dist/native/native/FeedbackScreen.d.ts +3 -0
  24. package/dist/native/native/FeedbackScreen.d.ts.map +1 -0
  25. package/dist/native/native/FeedbackScreen.js +9 -0
  26. package/dist/native/native/FeedbackScreen.js.map +1 -0
  27. package/dist/native/native/index.d.ts +8 -0
  28. package/dist/native/native/index.d.ts.map +1 -0
  29. package/dist/native/native/index.js +7 -0
  30. package/dist/native/native/index.js.map +1 -0
  31. package/dist/native/shared/helpers.d.ts +3 -0
  32. package/dist/native/shared/helpers.d.ts.map +1 -0
  33. package/dist/native/shared/helpers.js +4 -0
  34. package/dist/native/shared/helpers.js.map +1 -0
  35. package/dist/native/shared/ui/BodyContent.d.ts +3 -0
  36. package/dist/native/shared/ui/BodyContent.d.ts.map +1 -0
  37. package/dist/native/shared/ui/BodyContent.js +18 -0
  38. package/dist/native/shared/ui/BodyContent.js.map +1 -0
  39. package/dist/native/shared/ui/Button.d.ts +5 -0
  40. package/dist/native/shared/ui/Button.d.ts.map +1 -0
  41. package/dist/native/shared/ui/Button.js +15 -0
  42. package/dist/native/shared/ui/Button.js.map +1 -0
  43. package/dist/native/shared/ui/CommentBranch.d.ts +3 -0
  44. package/dist/native/shared/ui/CommentBranch.d.ts.map +1 -0
  45. package/dist/native/shared/ui/CommentBranch.js +35 -0
  46. package/dist/native/shared/ui/CommentBranch.js.map +1 -0
  47. package/dist/native/shared/ui/EntryCard.d.ts +3 -0
  48. package/dist/native/shared/ui/EntryCard.d.ts.map +1 -0
  49. package/dist/native/shared/ui/EntryCard.js +13 -0
  50. package/dist/native/shared/ui/EntryCard.js.map +1 -0
  51. package/dist/native/shared/ui/EntryDetail.d.ts +3 -0
  52. package/dist/native/shared/ui/EntryDetail.d.ts.map +1 -0
  53. package/dist/native/shared/ui/EntryDetail.js +37 -0
  54. package/dist/native/shared/ui/EntryDetail.js.map +1 -0
  55. package/dist/native/shared/ui/FeedbackScreenHeader.d.ts +2 -0
  56. package/dist/native/shared/ui/FeedbackScreenHeader.d.ts.map +1 -0
  57. package/dist/native/shared/ui/FeedbackScreenHeader.js +20 -0
  58. package/dist/native/shared/ui/FeedbackScreenHeader.js.map +1 -0
  59. package/dist/native/shared/ui/FeedbackScreenList.d.ts +3 -0
  60. package/dist/native/shared/ui/FeedbackScreenList.d.ts.map +1 -0
  61. package/dist/native/shared/ui/FeedbackScreenList.js +19 -0
  62. package/dist/native/shared/ui/FeedbackScreenList.js.map +1 -0
  63. package/dist/native/shared/ui/NewEntry.d.ts +5 -0
  64. package/dist/native/shared/ui/NewEntry.d.ts.map +1 -0
  65. package/dist/native/shared/ui/NewEntry.js +158 -0
  66. package/dist/native/shared/ui/NewEntry.js.map +1 -0
  67. package/dist/native/shared/ui/ReplyList.d.ts +3 -0
  68. package/dist/native/shared/ui/ReplyList.d.ts.map +1 -0
  69. package/dist/native/shared/ui/ReplyList.js +19 -0
  70. package/dist/native/shared/ui/ReplyList.js.map +1 -0
  71. package/dist/native/{primitives.d.ts → shared/ui/primitives.d.ts} +10 -12
  72. package/dist/native/shared/ui/primitives.d.ts.map +1 -0
  73. package/dist/native/{primitives.js → shared/ui/primitives.js} +19 -25
  74. package/dist/native/shared/ui/primitives.js.map +1 -0
  75. package/dist/react/{context.d.ts → css.d.ts} +2 -4
  76. package/dist/react/css.d.ts.map +1 -0
  77. package/dist/react/css.js +18 -0
  78. package/dist/react/css.js.map +1 -0
  79. package/dist/react/index.d.ts +1 -1
  80. package/dist/react/index.d.ts.map +1 -1
  81. package/dist/react/index.js +1 -1
  82. package/dist/react/index.js.map +1 -1
  83. package/dist/react/primitives.d.ts.map +1 -1
  84. package/dist/react/primitives.js +2 -1
  85. package/dist/react/primitives.js.map +1 -1
  86. package/dist/react/screen.d.ts +3 -3
  87. package/dist/react/screen.d.ts.map +1 -1
  88. package/dist/react/screen.js +25 -22
  89. package/dist/react/screen.js.map +1 -1
  90. package/dist/shared/context/FeedbackBodyProvider.d.ts +5 -0
  91. package/dist/shared/context/FeedbackBodyProvider.d.ts.map +1 -0
  92. package/dist/shared/context/FeedbackBodyProvider.js +43 -0
  93. package/dist/shared/context/FeedbackBodyProvider.js.map +1 -0
  94. package/dist/{native/context.d.ts → shared/context/FeedbackProvider.d.ts} +2 -2
  95. package/dist/shared/context/FeedbackProvider.d.ts.map +1 -0
  96. package/dist/{native/context.js → shared/context/FeedbackProvider.js} +3 -3
  97. package/dist/shared/context/FeedbackProvider.js.map +1 -0
  98. package/dist/shared/helpers.d.ts +7 -0
  99. package/dist/shared/helpers.d.ts.map +1 -0
  100. package/dist/shared/helpers.js +24 -0
  101. package/dist/shared/helpers.js.map +1 -0
  102. package/dist/shared/messages.d.ts.map +1 -1
  103. package/dist/shared/messages.js +23 -14
  104. package/dist/shared/messages.js.map +1 -1
  105. package/dist/shared/theme.d.ts.map +1 -1
  106. package/dist/shared/theme.js +1 -0
  107. package/dist/shared/theme.js.map +1 -1
  108. package/dist/shared/types/context.d.ts +4 -0
  109. package/dist/shared/types/context.d.ts.map +1 -1
  110. package/dist/shared/types/messages.d.ts +12 -1
  111. package/dist/shared/types/messages.d.ts.map +1 -1
  112. package/dist/shared/types/screen.d.ts +55 -18
  113. package/dist/shared/types/screen.d.ts.map +1 -1
  114. package/dist/shared/types/theme.d.ts +4 -0
  115. package/dist/shared/types/theme.d.ts.map +1 -1
  116. package/package.json +27 -12
  117. package/src/native/expo/ExpoFeedbackBody.tsx +48 -0
  118. package/src/native/expo/FeedbackScreen.tsx +37 -0
  119. package/src/native/expo/FeedbackStack.tsx +99 -0
  120. package/src/native/expo/README.md +17 -0
  121. package/src/native/expo/index.ts +8 -0
  122. package/src/native/expo/types.ts +23 -0
  123. package/src/native/native/FeedbackScreen.tsx +37 -0
  124. package/src/native/native/index.ts +7 -0
  125. package/src/native/shared/helpers.ts +9 -0
  126. package/src/native/shared/ui/BodyContent.tsx +43 -0
  127. package/src/native/shared/ui/Button.tsx +29 -0
  128. package/src/native/shared/ui/CommentBranch.tsx +88 -0
  129. package/src/native/shared/ui/EntryCard.tsx +37 -0
  130. package/src/native/shared/ui/EntryDetail.tsx +103 -0
  131. package/src/native/shared/ui/FeedbackScreenHeader.tsx +40 -0
  132. package/src/native/shared/ui/FeedbackScreenList.tsx +61 -0
  133. package/src/native/shared/ui/NewEntry.tsx +375 -0
  134. package/src/native/shared/ui/ReplyList.tsx +41 -0
  135. package/src/native/{primitives.tsx → shared/ui/primitives.tsx} +84 -92
  136. package/src/react/{context.tsx → css.tsx} +2 -44
  137. package/src/react/index.ts +1 -1
  138. package/src/react/primitives.tsx +2 -1
  139. package/src/react/screen.tsx +67 -123
  140. package/src/shared/context/FeedbackBodyProvider.tsx +82 -0
  141. package/src/{native/context.tsx → shared/context/FeedbackProvider.tsx} +3 -3
  142. package/src/shared/helpers.ts +33 -0
  143. package/src/shared/messages.ts +23 -22
  144. package/src/shared/theme.ts +1 -0
  145. package/src/shared/types/context.ts +5 -0
  146. package/src/shared/types/messages.ts +16 -1
  147. package/src/shared/types/screen.ts +69 -23
  148. package/src/shared/types/theme.ts +5 -0
  149. package/dist/native/context.d.ts.map +0 -1
  150. package/dist/native/context.js.map +0 -1
  151. package/dist/native/index.d.ts +0 -7
  152. package/dist/native/index.d.ts.map +0 -1
  153. package/dist/native/index.js +0 -6
  154. package/dist/native/index.js.map +0 -1
  155. package/dist/native/primitives.d.ts.map +0 -1
  156. package/dist/native/primitives.js.map +0 -1
  157. package/dist/native/screen.d.ts +0 -3
  158. package/dist/native/screen.d.ts.map +0 -1
  159. package/dist/native/screen.js +0 -284
  160. package/dist/native/screen.js.map +0 -1
  161. package/dist/react/context.d.ts.map +0 -1
  162. package/dist/react/context.js +0 -41
  163. package/dist/react/context.js.map +0 -1
  164. package/src/native/index.ts +0 -6
  165. package/src/native/screen.tsx +0 -831
  166. /package/src/native/{README.md → native/README.md} +0 -0
@@ -2,7 +2,6 @@ import type { CommentSort, EntryKind, EntrySort, FeedbackComment, FeedbackEntry
2
2
  import type { FeedbackHooks } from "convex-feedback/react";
3
3
  import type { ReactNode } from "react";
4
4
  import type { FeedbackColorProps, FeedbackProviderProps } from "./context.js";
5
- import type { Require } from "./helpers.js";
6
5
  /**
7
6
  * Presentation-only transform applied to one currently loaded comment page.
8
7
  *
@@ -17,7 +16,19 @@ export type FeedbackCommentTransform = (comments: readonly FeedbackComment[]) =>
17
16
  * owned by the host application.
18
17
  */
19
18
  export type FeedbackActorRenderer = (actorId: string) => ReactNode;
20
- export interface FeedbackScreenBaseProps extends FeedbackColorProps {
19
+ export interface FeedbackScreenTransformationProps {
20
+ /**
21
+ * Optional presentation-only transform applied to each loaded page of
22
+ * comments/replies before rendering.
23
+ */
24
+ transformComments?: FeedbackCommentTransform;
25
+ /**
26
+ * Optional host renderer for actor IDs, useful for names, avatars, or other
27
+ * host-owned profile information.
28
+ */
29
+ renderActor?: FeedbackActorRenderer;
30
+ }
31
+ export interface FeedbackScreenBaseProps {
21
32
  /** Hooks created with `createFeedbackHooks`. */
22
33
  hooks: FeedbackHooks;
23
34
  /**
@@ -52,44 +63,70 @@ export interface FeedbackScreenBaseProps extends FeedbackColorProps {
52
63
  */
53
64
  maxCommentDepth?: number;
54
65
  /**
55
- * Optional presentation-only transform applied to each loaded page of
56
- * comments/replies before rendering.
66
+ * Duration in milliseconds to wait before triggering a search.
67
+ *
68
+ * @default 300
57
69
  */
58
- transformComments?: FeedbackCommentTransform;
59
- /**
60
- * Optional host renderer for actor IDs, useful for names, avatars, or other
61
- * host-owned profile information.
70
+ debounceDuration?: number;
71
+ }
72
+ export interface FeedbackScreenRootProps extends Omit<FeedbackProviderProps, "children">, FeedbackColorProps, FeedbackScreenBaseProps, FeedbackScreenTransformationProps {
73
+ }
74
+ export interface FeedbackScreenProviderProps extends Required<FeedbackScreenBaseProps>, FeedbackScreenTransformationProps {
75
+ }
76
+ export interface FeedbackScreenBodyContextValue extends FeedbackScreenTransformationProps, FeedbackScreenProviderProps {
77
+ query: string;
78
+ debouncedQuery: string;
79
+ showForm: boolean;
80
+ isSearching: boolean;
81
+ selectedEntryId: string | null;
82
+ setQuery: React.Dispatch<React.SetStateAction<string>>;
83
+ setDebouncedQuery: React.Dispatch<React.SetStateAction<string>>;
84
+ setShowForm: React.Dispatch<React.SetStateAction<boolean>>;
85
+ setIsSearching: React.Dispatch<React.SetStateAction<boolean>>;
86
+ setSelectedEntryId: React.Dispatch<React.SetStateAction<string | null>>;
87
+ }
88
+ export type FeedbackScreenBodyProps = FeedbackColorProps;
89
+ export interface FeedbackScreenListProps {
90
+ /** Whether to show the header.
91
+ * @default true
62
92
  */
63
- renderActor?: FeedbackActorRenderer;
93
+ showHeader?: boolean;
94
+ /** Whether to hide the back button from the EntryCard.
95
+ * @default false
96
+ */
97
+ hideBackButton?: boolean;
98
+ /** Callback when the EntryCard is opened. */
99
+ onEntryOpen: (entryId: string) => void;
64
100
  }
65
- export interface FeedbackScreenRootProps extends Omit<FeedbackProviderProps, "children">, FeedbackScreenBaseProps {
101
+ export interface FeedbackScreenContentProps extends FeedbackColorProps, Partial<FeedbackScreenListProps> {
66
102
  }
67
- export type FeedbackScreenBodyProps = Require<FeedbackScreenBaseProps, "entrySort" | "commentSort" | "enabledKinds" | "maxCommentDepth">;
68
103
  export interface FeedbackScreenEntryCardProps {
69
104
  entry: FeedbackEntry;
70
105
  hooks: FeedbackHooks;
106
+ /** Callback when the EntryCard is opened. */
71
107
  onOpen: () => void;
72
108
  }
73
109
  export interface FeedbackScreenEntryModalProps {
74
- hooks: FeedbackHooks;
75
- enabledKinds: readonly EntryKind[];
110
+ /** Callback when an entry is created. */
76
111
  onCreated: (id: string) => void;
77
112
  }
78
113
  export interface FeedbackScreenEntryBaseProps {
114
+ /** The entry ID to open. */
79
115
  entryId: string;
80
- hooks: FeedbackHooks;
81
- commentSort: CommentSort;
82
- maxCommentDepth: number;
83
- transformComments?: FeedbackScreenBaseProps["transformComments"];
84
- renderActor?: FeedbackScreenBaseProps["renderActor"];
85
116
  }
86
117
  export interface FeedbackScreenEntryDetailProps extends FeedbackScreenEntryBaseProps {
118
+ /** Whether to hide the back button from the EntryCard.
119
+ * @default false
120
+ */
121
+ hideBackButton?: boolean;
122
+ /** Callback when the EntryCard is closed. */
87
123
  onBack: () => void;
88
124
  }
89
125
  export interface FeedbackScreenCommentBranchProps extends FeedbackScreenEntryBaseProps {
90
126
  comment: FeedbackComment;
91
127
  }
92
128
  export interface FeedbackScreenReplyListProps extends FeedbackScreenEntryBaseProps {
129
+ /** The parent comment ID of the reply list. */
93
130
  parentCommentId: string;
94
131
  }
95
132
  //# sourceMappingURL=screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../../src/shared/types/screen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,SAAS,EACT,eAAe,EACf,aAAa,EACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,QAAQ,EAAE,SAAS,eAAe,EAAE,KACjC,SAAS,eAAe,EAAE,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC;AAEnE,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,gDAAgD;IAChD,KAAK,EAAE,aAAa,CAAC;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAEpC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAE7C;;;OAGG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAED,MAAM,WAAW,uBACf,SAAQ,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,EAAE,uBAAuB;CAAG;AAE7E,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC3C,uBAAuB,EACvB,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,iBAAiB,CACjE,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,SAAS,SAAS,EAAE,CAAC;IACnC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;IACjE,WAAW,CAAC,EAAE,uBAAuB,CAAC,aAAa,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,8BAA+B,SAAQ,4BAA4B;IAClF,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,gCAAiC,SAAQ,4BAA4B;IACpF,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA6B,SAAQ,4BAA4B;IAChF,eAAe,EAAE,MAAM,CAAC;CACzB"}
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../../src/shared/types/screen.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@
4
4
  export interface FeedbackColors {
5
5
  /** Primary interaction and accent color. */
6
6
  primary: string;
7
+ /**
8
+ * Foreground color for primary interactions and accents.
9
+ */
10
+ primaryForeground: string;
7
11
  /** Main screen or board background color. */
8
12
  background: string;
9
13
  /** Default card and control surface color. */
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/shared/types/theme.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAEhB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IAEnB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IAErB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IAEb,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IAEf,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IAEf,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,MAAM,EAAE,cAAc,CAAC;IAEvB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IAEf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAE7C,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/shared/types/theme.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IAEnB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IAErB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IAEb,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IAEf,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IAEf,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,MAAM,EAAE,cAAc,CAAC;IAEvB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IAEf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAE7C,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convex-feedback-ui",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Customizable React and React Native UI primitives for convex-feedback.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -17,13 +17,13 @@
17
17
  "types": "./dist/react/index.d.ts",
18
18
  "default": "./dist/react/index.js"
19
19
  },
20
- "./react": {
21
- "types": "./dist/react/index.d.ts",
22
- "default": "./dist/react/index.js"
23
- },
24
20
  "./native": {
25
- "types": "./dist/native/index.d.ts",
26
- "default": "./dist/native/index.js"
21
+ "types": "./dist/native/native/index.d.ts",
22
+ "default": "./dist/native/native/index.js"
23
+ },
24
+ "./expo": {
25
+ "types": "./dist/native/expo/index.d.ts",
26
+ "default": "./dist/native/expo/index.js"
27
27
  },
28
28
  "./styles.css": "./dist/react/styles.css"
29
29
  },
@@ -37,9 +37,12 @@
37
37
  },
38
38
  "peerDependencies": {
39
39
  "convex-feedback": "^0.1.0",
40
- "react": "^18.3.1 || ^19.0.0",
41
- "react-native": "^0.83.0",
42
- "react-native-safe-area-context": "^4.5.3"
40
+ "react": ">=18.2.0",
41
+ "react-native": ">=0.83.0",
42
+ "react-native-safe-area-context": ">=5.4.0",
43
+ "react-native-screens": ">=4.23.0",
44
+ "expo": ">=55.0.0",
45
+ "expo-router": ">=55.0.0"
43
46
  },
44
47
  "peerDependenciesMeta": {
45
48
  "react-native": {
@@ -47,14 +50,26 @@
47
50
  },
48
51
  "react-native-safe-area-context": {
49
52
  "optional": true
53
+ },
54
+ "react-native-screens": {
55
+ "optional": true
56
+ },
57
+ "expo": {
58
+ "optional": true
59
+ },
60
+ "expo-router": {
61
+ "optional": true
50
62
  }
51
63
  },
52
64
  "devDependencies": {
53
65
  "@types/react": "^19.2.18",
54
- "convex-feedback": "^0.1.0",
66
+ "convex-feedback": "*",
55
67
  "react": "^19.2.0",
56
68
  "react-native": "^0.83.10",
57
- "react-native-safe-area-context": "^4.5.3"
69
+ "react-native-safe-area-context": "~5.6.2",
70
+ "react-native-screens": "^4.23.0",
71
+ "expo": "^55.0.0",
72
+ "expo-router": "^55.0.18"
58
73
  },
59
74
  "types": "./dist/react/index.d.ts",
60
75
  "module": "./dist/react/index.js"
@@ -0,0 +1,48 @@
1
+ import { useEffect, useRef } from "react";
2
+
3
+ import type { SearchBarCommands } from "react-native-screens";
4
+ import { useFeedbackBody } from "../../shared/context/FeedbackBodyProvider.js";
5
+ import { type FeedbackScreenBodyProps } from "../../shared/types/index.js";
6
+
7
+ import { FeedbackScreenContent } from "../shared/ui/BodyContent.js";
8
+ import { FeedbackStack } from "./FeedbackStack.js";
9
+ import type { FeedbackScreenStackProps } from "./types.js";
10
+
11
+ export function ExpoFeedbackBody({
12
+ useStack = true,
13
+ StackOptions,
14
+ ...props
15
+ }: FeedbackScreenBodyProps & FeedbackScreenStackProps) {
16
+ const { query, isSearching, setIsSearching, setSelectedEntryId } =
17
+ useFeedbackBody();
18
+ const searchRef = useRef<SearchBarCommands>(null);
19
+
20
+ const onEntryOpen = (entryId: string) => {
21
+ setSelectedEntryId(entryId);
22
+ if ((query || isSearching) && searchRef.current) {
23
+ searchRef.current.blur();
24
+ }
25
+ };
26
+
27
+ useEffect(() => {
28
+ const searching = query.trim().length > 0;
29
+
30
+ if (searching !== isSearching) {
31
+ setIsSearching(searching);
32
+ }
33
+ }, [query, isSearching, setIsSearching]);
34
+
35
+ if (!useStack)
36
+ return <FeedbackScreenContent onEntryOpen={onEntryOpen} {...props} />;
37
+
38
+ return (
39
+ <FeedbackStack stackOptions={StackOptions} searchRef={searchRef}>
40
+ <FeedbackScreenContent
41
+ hideBackButton
42
+ showHeader={false}
43
+ onEntryOpen={onEntryOpen}
44
+ {...props}
45
+ />
46
+ </FeedbackStack>
47
+ );
48
+ }
@@ -0,0 +1,37 @@
1
+ import { FeedbackBodyProvider } from "../../shared/context/FeedbackBodyProvider";
2
+ import { FeedbackProvider } from "../../shared/context/FeedbackProvider";
3
+ import { kinds } from "../../shared/helpers";
4
+ import { ExpoFeedbackBody } from "./ExpoFeedbackBody";
5
+ import type { ExpoFeedbackScreenProps } from "./types";
6
+
7
+ export function FeedbackScreen({
8
+ hooks,
9
+ messages,
10
+ theme,
11
+ unstyled,
12
+ entrySort = "top",
13
+ commentSort = "top",
14
+ enabledKinds = kinds,
15
+ maxCommentDepth = 5,
16
+ debounceDuration = 300,
17
+ transformComments,
18
+ renderActor,
19
+ ...props
20
+ }: ExpoFeedbackScreenProps) {
21
+ return (
22
+ <FeedbackProvider messages={messages} theme={theme} unstyled={unstyled}>
23
+ <FeedbackBodyProvider
24
+ hooks={hooks}
25
+ entrySort={entrySort}
26
+ commentSort={commentSort}
27
+ enabledKinds={enabledKinds}
28
+ maxCommentDepth={maxCommentDepth}
29
+ debounceDuration={debounceDuration}
30
+ transformComments={transformComments}
31
+ renderActor={renderActor}
32
+ >
33
+ <ExpoFeedbackBody {...props} />
34
+ </FeedbackBodyProvider>
35
+ </FeedbackProvider>
36
+ );
37
+ }
@@ -0,0 +1,99 @@
1
+ import { Stack, useRouter } from "expo-router";
2
+ import { useFeedbackBody } from "../../shared/context/FeedbackBodyProvider";
3
+ import { useFeedbackUi } from "../../shared/context/FeedbackProvider";
4
+ import type { FeedbackStackProps } from "./types";
5
+
6
+ export function FeedbackStack({
7
+ searchRef,
8
+ stackOptions,
9
+ children,
10
+ }: FeedbackStackProps) {
11
+ const {
12
+ query,
13
+ enabledKinds,
14
+ selectedEntryId,
15
+ setQuery,
16
+ setShowForm,
17
+ setIsSearching,
18
+ setSelectedEntryId,
19
+ } = useFeedbackBody();
20
+ const { messages, theme } = useFeedbackUi();
21
+ const router = useRouter();
22
+
23
+ const canGoBack = !!selectedEntryId || router.canGoBack();
24
+
25
+ const handleBackPress = () => {
26
+ if (selectedEntryId === null) {
27
+ router.back();
28
+ return;
29
+ }
30
+
31
+ if (searchRef.current && query) searchRef.current.focus();
32
+
33
+ setSelectedEntryId(null);
34
+ return true;
35
+ };
36
+
37
+ const pageTitle =
38
+ enabledKinds.length === 1
39
+ ? messages.kindsPlural[enabledKinds.at(0)!]
40
+ : messages.board.title;
41
+
42
+ return (
43
+ <>
44
+ <Stack.Screen
45
+ options={{
46
+ headerTitle: pageTitle,
47
+ headerShown: true,
48
+ headerTransparent: true,
49
+ headerShadowVisible: true,
50
+ headerBackVisible: false,
51
+ contentStyle: { backgroundColor: theme.colors.background },
52
+ ...stackOptions,
53
+ }}
54
+ />
55
+ <Stack.Toolbar placement="right">
56
+ <Stack.Toolbar.Button
57
+ icon="plus"
58
+ variant="prominent"
59
+ accessibilityLabel={messages.board.createEntry}
60
+ onPress={() => setShowForm(true)}
61
+ tintColor={theme.colors.primary}
62
+ />
63
+ </Stack.Toolbar>
64
+ <Stack.Toolbar placement="left">
65
+ <Stack.Toolbar.Button
66
+ hidden={!canGoBack}
67
+ icon="chevron.backward"
68
+ onPress={handleBackPress}
69
+ />
70
+ </Stack.Toolbar>
71
+
72
+ {children}
73
+
74
+ <Stack.SearchBar
75
+ onChangeText={(q) => {
76
+ if (selectedEntryId) setSelectedEntryId(null);
77
+ setQuery(q.nativeEvent.text);
78
+ }}
79
+ onOpen={() => console.log("opened")}
80
+ onClose={() => console.log("closed")}
81
+ onSearchButtonPress={() => console.log("search button pressed")}
82
+ onCancelButtonPress={() => console.log("cancel button pressed")}
83
+ onFocus={() => {
84
+ if (selectedEntryId) setSelectedEntryId(null);
85
+ setIsSearching(true);
86
+ }}
87
+ onBlur={() => setIsSearching(false)}
88
+ obscureBackground={false}
89
+ allowToolbarIntegration
90
+ hideNavigationBar={false}
91
+ ref={searchRef}
92
+ textColor={theme.colors.text}
93
+ />
94
+ <Stack.Toolbar placement="bottom">
95
+ <Stack.Toolbar.SearchBarSlot />
96
+ </Stack.Toolbar>
97
+ </>
98
+ );
99
+ }
@@ -0,0 +1,17 @@
1
+ # Native layer
2
+
3
+ Import this layer only from `convex-feedback-ui/expo`.
4
+
5
+ The native layer uses React Native core primitives and the shared `FeedbackMessages` / `FeedbackTheme` contracts. It intentionally does not depend on NativeWind or Expo UI.
6
+
7
+ To replace a control with Expo UI, use render-function children on an interactive leaf:
8
+
9
+ ```tsx
10
+ <Comment.Like onToggle={setLiked}>
11
+ {({ active, count, toggle }) => (
12
+ <YourExpoUiControl active={active} count={count} onPress={toggle} />
13
+ )}
14
+ </Comment.Like>
15
+ ```
16
+
17
+ Containers such as `FeedbackEntry.Content`, `FeedbackForm.Root`, and `Comment.Children` accept arbitrary children, so custom Expo UI fields/buttons can also be placed directly inside the compound layout.
@@ -0,0 +1,8 @@
1
+ export * from "../../shared/context/FeedbackBodyProvider.js";
2
+ export * from "../../shared/context/FeedbackProvider.js";
3
+ export * from "../../shared/messages.js";
4
+ export * from "../../shared/theme.js";
5
+ export type * from "../../shared/types/index.js";
6
+ export * from "../shared/ui/primitives.js";
7
+ export * from "./FeedbackScreen.js";
8
+ export type * from "./types.js";
@@ -0,0 +1,23 @@
1
+ import type { StackScreenProps } from "expo-router";
2
+ import type { SearchBarCommands } from "react-native-screens";
3
+ import type { FeedbackScreenRootProps } from "../../shared/types";
4
+
5
+ interface FeedbackScreenWithStack {
6
+ useStack?: true;
7
+ StackOptions?: StackScreenProps["options"];
8
+ }
9
+ interface FeedbackScreenWithoutStack {
10
+ useStack?: false;
11
+ StackOptions?: never;
12
+ }
13
+ export type FeedbackScreenStackProps =
14
+ FeedbackScreenWithStack | FeedbackScreenWithoutStack;
15
+
16
+ export type ExpoFeedbackScreenProps = FeedbackScreenStackProps &
17
+ FeedbackScreenRootProps;
18
+
19
+ export interface FeedbackStackProps {
20
+ searchRef: React.RefObject<SearchBarCommands | null>;
21
+ stackOptions?: StackScreenProps["options"];
22
+ children: React.ReactNode;
23
+ }
@@ -0,0 +1,37 @@
1
+ import { FeedbackBodyProvider } from "../../shared/context/FeedbackBodyProvider";
2
+ import { FeedbackProvider } from "../../shared/context/FeedbackProvider";
3
+ import { kinds } from "../../shared/helpers";
4
+ import type { FeedbackScreenRootProps } from "../../shared/types";
5
+ import { FeedbackScreenContent } from "../shared/ui/BodyContent";
6
+
7
+ export function FeedbackScreen({
8
+ hooks,
9
+ messages,
10
+ theme,
11
+ unstyled,
12
+ entrySort = "top",
13
+ commentSort = "top",
14
+ enabledKinds = kinds,
15
+ maxCommentDepth = 5,
16
+ debounceDuration = 300,
17
+ transformComments,
18
+ renderActor,
19
+ ...props
20
+ }: FeedbackScreenRootProps) {
21
+ return (
22
+ <FeedbackProvider messages={messages} theme={theme} unstyled={unstyled}>
23
+ <FeedbackBodyProvider
24
+ hooks={hooks}
25
+ entrySort={entrySort}
26
+ commentSort={commentSort}
27
+ enabledKinds={enabledKinds}
28
+ maxCommentDepth={maxCommentDepth}
29
+ debounceDuration={debounceDuration}
30
+ transformComments={transformComments}
31
+ renderActor={renderActor}
32
+ >
33
+ <FeedbackScreenContent {...props} />
34
+ </FeedbackBodyProvider>
35
+ </FeedbackProvider>
36
+ );
37
+ }
@@ -0,0 +1,7 @@
1
+ export * from "../../shared/context/FeedbackBodyProvider.js";
2
+ export * from "../../shared/context/FeedbackProvider.js";
3
+ export * from "../../shared/messages.js";
4
+ export * from "../../shared/theme.js";
5
+ export type * from "../../shared/types/index.js";
6
+ export * from "../shared/ui/primitives.js";
7
+ export * from "./FeedbackScreen.js";
@@ -0,0 +1,9 @@
1
+ import type { StyleProp } from "react-native";
2
+
3
+ export function combineStyle<T>(
4
+ enabled: boolean,
5
+ fallback: StyleProp<T>,
6
+ style: StyleProp<T>,
7
+ ): StyleProp<T> {
8
+ return enabled ? [fallback, style] : style;
9
+ }
@@ -0,0 +1,43 @@
1
+ import { useFeedbackBody } from "../../../shared/context/FeedbackBodyProvider.js";
2
+ import type { FeedbackScreenContentProps } from "../../../shared/types";
3
+ import { FeedbackScreenHeader } from "./FeedbackScreenHeader";
4
+ import { FeedbackScreenList } from "./FeedbackScreenList";
5
+ import { CreateEntryModal } from "./NewEntry";
6
+ import { FeedbackBoard } from "./primitives.js";
7
+
8
+ export function FeedbackScreenContent({
9
+ showHeader = true,
10
+ hideBackButton = false,
11
+ onEntryOpen,
12
+ ...colors
13
+ }: FeedbackScreenContentProps) {
14
+ const { showForm, setShowForm, setSelectedEntryId } = useFeedbackBody();
15
+
16
+ const handleEntryOpen = (entryId: string) => {
17
+ setSelectedEntryId(entryId);
18
+ onEntryOpen?.(entryId);
19
+ };
20
+
21
+ return (
22
+ <>
23
+ <FeedbackBoard.Root {...colors}>
24
+ {showHeader && <FeedbackScreenHeader />}
25
+
26
+ <FeedbackScreenList
27
+ hideBackButton={hideBackButton}
28
+ onEntryOpen={handleEntryOpen}
29
+ />
30
+ </FeedbackBoard.Root>
31
+
32
+ {showForm && (
33
+ <CreateEntryModal
34
+ onRequestClose={() => setShowForm(false)}
35
+ onCreated={(id) => {
36
+ setShowForm(false);
37
+ setSelectedEntryId(id);
38
+ }}
39
+ />
40
+ )}
41
+ </>
42
+ );
43
+ }
@@ -0,0 +1,29 @@
1
+ import { Pressable, Text } from "react-native";
2
+ import { useFeedbackUi } from "../../../shared/context/FeedbackProvider.js";
3
+
4
+ export function Button({
5
+ label,
6
+ onPress,
7
+ }: {
8
+ label: string;
9
+ onPress: () => void;
10
+ }) {
11
+ const { theme } = useFeedbackUi();
12
+ return (
13
+ <Pressable
14
+ onPress={onPress}
15
+ style={{
16
+ alignSelf: "flex-start",
17
+ paddingVertical: 8,
18
+ paddingHorizontal: 11,
19
+ borderRadius: 8,
20
+ borderWidth: 1,
21
+ borderColor: theme.colors.border,
22
+ }}
23
+ >
24
+ <Text style={{ color: theme.colors.text, fontWeight: "600" }}>
25
+ {label}
26
+ </Text>
27
+ </Pressable>
28
+ );
29
+ }