@portabletext/plugin-sdk-value 8.0.5 → 8.1.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/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  > Connect a Portable Text Editor with a Sanity document using the SDK
4
4
 
5
5
  Two-way synchronization between a Portable Text Editor and a field in a Sanity
6
- document, plus presence: other people's carets show up in the field, and the
7
- local user's caret shows up for them, including in the Studio.
6
+ document, plus presence and inline comments: other people's carets show up in
7
+ the field and the local user's caret shows up for them, and comment threads
8
+ anchored to text draw as highlights, all interoperating with the Studio.
8
9
 
9
10
  ## Installation
10
11
 
@@ -18,6 +19,7 @@ npm install @portabletext/plugin-sdk-value
18
19
  - **Real-time updates**: Automatically handles patches from external sources (other users, mutations, etc.)
19
20
  - **Optimistic updates**: Provides smooth user experience with immediate local updates
20
21
  - **Presence**: Reports where the local user is editing, and draws other people's carets
22
+ - **Inline comments**: Draws highlights for comment threads anchored to text, and starts new threads on the selection
21
23
 
22
24
  ## Usage
23
25
 
@@ -72,6 +74,55 @@ Pass `renderCursor={null}` to draw no carets at all while still reporting the
72
74
  local user's presence, which is what you want if you only care about keeping the
73
75
  document in sync.
74
76
 
77
+ ### Inline comments
78
+
79
+ Comment threads anchored to text in the field draw as highlights, and new
80
+ threads can be started on the current selection. The composer UI stays with the
81
+ app, the same split presence uses for carets. Comments are written in the shape
82
+ Sanity Studio stores, so threads round-trip between an SDK app and the Studio.
83
+
84
+ `useSDKCommentDecorations` returns `RangeDecoration[]` for the open threads on
85
+ the field. Pass it through `rangeDecorations`, which `SDKPortableTextEditable`
86
+ merges with the presence carets:
87
+
88
+ ```tsx
89
+ const decorations = useSDKCommentDecorations({
90
+ ...documentHandle,
91
+ path: 'content',
92
+ renderDecoration: (comment) => (props) => (
93
+ <span data-comment-id={comment.id} style={{background: '#fef3c7'}}>
94
+ {props.children}
95
+ </span>
96
+ ),
97
+ })
98
+
99
+ return (
100
+ <SDKPortableTextEditable
101
+ {...documentHandle}
102
+ path="content"
103
+ rangeDecorations={decorations}
104
+ />
105
+ )
106
+ ```
107
+
108
+ `useSDKCommentAuthoring` is the write side: `commentableSelection` is set when
109
+ the current selection can take a comment, and `createInlineComment` starts a
110
+ thread anchored to it:
111
+
112
+ ```tsx
113
+ const {commentableSelection, createInlineComment} = useSDKCommentAuthoring({
114
+ ...documentHandle,
115
+ path: 'content',
116
+ })
117
+
118
+ // Show the composer while `commentableSelection` is set, then:
119
+ await createInlineComment({message})
120
+ ```
121
+
122
+ Highlights follow the text while the user types, and a highlight whose text is
123
+ deleted or rewritten beyond recognition is dropped rather than drawn on the
124
+ wrong words. Resolved threads draw nothing, matching the Studio.
125
+
75
126
  ### Rendering the editable yourself
76
127
 
77
128
  `SDKValuePlugin` still works as a sibling component if you would rather keep
@@ -138,5 +189,5 @@ the Studio, whose field indicators compare the exact document id its form is on.
138
189
 
139
190
  This plugin requires:
140
191
 
141
- - `@sanity/sdk-react` 2.19 or newer, where the presence hooks were added
192
+ - `@sanity/sdk-react` 2.20.1 or newer, where the comment hooks were added
142
193
  - The document must exist in the Sanity dataset
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DocumentHandle, usePresenceForDocument } from "@sanity/sdk-react";
1
+ import { Comment, CommentMessage, DocumentHandle, DocumentResource, usePresenceForDocument } from "@sanity/sdk-react";
2
2
  import { EditorSelection, Patch, PortableTextBlock, PortableTextEditableProps, RangeDecoration } from "@portabletext/editor";
3
3
  import { PropsWithChildren, ReactElement } from "react";
4
4
  import "@portabletext/patches";
@@ -41,6 +41,10 @@ interface SDKRemoteCursor {
41
41
  * @public
42
42
  */
43
43
  interface SDKPresencePluginProps extends DocumentHandle {
44
+ /**
45
+ * @deprecated Use `resource` instead.
46
+ */
47
+ source?: DocumentResource;
44
48
  /**
45
49
  * The document path of the Portable Text field, for example `content`. The
46
50
  * same form `SDKValuePlugin` takes.
@@ -53,6 +57,10 @@ interface SDKPresencePluginProps extends DocumentHandle {
53
57
  * @public
54
58
  */
55
59
  interface UseSDKPresenceCursorsOptions extends DocumentHandle {
60
+ /**
61
+ * @deprecated Use `resource` instead.
62
+ */
63
+ source?: DocumentResource;
56
64
  path: string;
57
65
  renderCursor: RenderCursorFunction;
58
66
  }
@@ -86,7 +94,93 @@ declare function SDKPresencePlugin(props: SDKPresencePluginProps): null;
86
94
  * @public
87
95
  */
88
96
  declare function useSDKPresenceCursors(options: UseSDKPresenceCursorsOptions): RangeDecoration[];
97
+ /**
98
+ * Draws one comment's highlight. The plugin has no opinion about how a
99
+ * highlight looks, so it is the caller's to provide, the same way presence
100
+ * takes `renderCursor`.
101
+ *
102
+ * @public
103
+ */
104
+ type RenderCommentDecorationFunction = (comment: Comment) => (props: PropsWithChildren) => ReactElement;
105
+ /**
106
+ * Options for {@link useSDKCommentDecorations}.
107
+ *
108
+ * @public
109
+ */
110
+ interface UseSDKCommentDecorationsOptions extends DocumentHandle {
111
+ /**
112
+ * The document path of the Portable Text field, for example `content`. The
113
+ * same form `SDKValuePlugin` takes.
114
+ */
115
+ path: string;
116
+ renderDecoration: RenderCommentDecorationFunction;
117
+ }
118
+ /**
119
+ * Inline comment highlights for a Portable Text field, as range decorations.
120
+ *
121
+ * Pass the result to `<PortableTextEditable rangeDecorations={...} />`. Each
122
+ * thread's first comment that carries a text anchor on this field gets one
123
+ * decoration. Highlights stay put while the local user types, and a highlight
124
+ * whose text has been deleted or rewritten beyond recognition is dropped
125
+ * rather than drawn on the wrong words.
126
+ *
127
+ * Suspends while the document's comments load, like every SDK read hook.
128
+ *
129
+ * Resolved threads draw nothing: this mirrors the Studio, where resolving a
130
+ * thread removes its highlight from the text.
131
+ *
132
+ * @public
133
+ */
134
+ declare function useSDKCommentDecorations(options: UseSDKCommentDecorationsOptions): RangeDecoration[];
135
+ /**
136
+ * Options for {@link useSDKCommentAuthoring}.
137
+ *
138
+ * @public
139
+ */
140
+ interface UseSDKCommentAuthoringOptions extends DocumentHandle {
141
+ /**
142
+ * The document path of the Portable Text field, for example `content`.
143
+ */
144
+ path: string;
145
+ }
146
+ /**
147
+ * What {@link useSDKCommentAuthoring} returns.
148
+ *
149
+ * @public
150
+ */
151
+ interface SDKCommentAuthoring {
152
+ /**
153
+ * The current selection when it can take a comment, `null` otherwise. Show
154
+ * the comment affordance when this is set, and position it off the
155
+ * selection. A selection can take a comment when it is expanded, contains
156
+ * text, and stays within one array of blocks.
157
+ */
158
+ commentableSelection: EditorSelection;
159
+ /**
160
+ * Starts a comment thread anchored to the text selected right now.
161
+ *
162
+ * The anchor is captured from the live selection at call time, so call this
163
+ * from the affordance while the selection still stands. Rejects when nothing
164
+ * commentable is selected.
165
+ */
166
+ createInlineComment: (options: {
167
+ message: CommentMessage;
168
+ /** Reuse the id of a failed comment to retry it. */
169
+ commentId?: string;
170
+ }) => Promise<Comment>;
171
+ }
172
+ /**
173
+ * Lets the app author inline comments on a Portable Text field.
174
+ *
175
+ * The plugin captures the selection and writes the comment; the composer UI is
176
+ * the app's, the same split the Studio and Canvas use. Comments are written in
177
+ * the shape the Studio stores, so a thread started here shows up there.
178
+ *
179
+ * @public
180
+ */
181
+ declare function useSDKCommentAuthoring(options: UseSDKCommentAuthoringOptions): SDKCommentAuthoring;
89
182
  interface SDKValuePluginProps extends DocumentHandle {
183
+ source?: DocumentResource;
90
184
  path: string;
91
185
  }
92
186
  /**
@@ -132,6 +226,10 @@ declare function ValueSyncPlugin(props: ValueSyncConfig): null;
132
226
  * @public
133
227
  */
134
228
  interface SDKPortableTextEditableProps extends DocumentHandle, Omit<PortableTextEditableProps, keyof DocumentHandle> {
229
+ /**
230
+ * @deprecated Use `resource` instead.
231
+ */
232
+ source?: DocumentResource;
135
233
  /**
136
234
  * The document path of the Portable Text field, for example `content`.
137
235
  */
@@ -170,5 +268,5 @@ interface SDKPortableTextEditableProps extends DocumentHandle, Omit<PortableText
170
268
  * @public
171
269
  */
172
270
  declare function SDKPortableTextEditable(props: SDKPortableTextEditableProps): import("react").JSX.Element;
173
- export { type RenderCursorFunction, SDKPortableTextEditable, type SDKPortableTextEditableProps, SDKPresencePlugin, type SDKPresencePluginProps, type SDKRemoteCursor, SDKValuePlugin, type UseSDKPresenceCursorsOptions, ValueSyncPlugin, useSDKPresenceCursors };
271
+ export { type RenderCommentDecorationFunction, type RenderCursorFunction, type SDKCommentAuthoring, SDKPortableTextEditable, type SDKPortableTextEditableProps, SDKPresencePlugin, type SDKPresencePluginProps, type SDKRemoteCursor, SDKValuePlugin, type UseSDKCommentAuthoringOptions, type UseSDKCommentDecorationsOptions, type UseSDKPresenceCursorsOptions, ValueSyncPlugin, useSDKCommentAuthoring, useSDKCommentDecorations, useSDKPresenceCursors };
174
272
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/plugin.sdk-presence.tsx","../src/plugin.sdk-value.tsx","../src/sdk-editable.tsx"],"mappings":";;;;;;;;;KAeK,mBAAmB,kBACf;;;;;;;KASG,wBACV,QAAQ,qBACJ,OAAO,sBAAsB;;;;;;;;;UAUlB;;;;;EAKf;;;;EAIA,WAAW;EACX,MAAM;;;;;;;UAQS,+BAA+B;;;;;EAK9C;;;;;;;UAQe,qCAAqC;EACpD;EACA,cAAc;;;;;;;;;;;;;;;;iBAiBA,kBAAkB,OAAO;;;;;;;;;;;;;;;iBAwBzB,sBACd,SAAS,+BACR;UC48BO,4BAA4B;EACpC;;;;;iBAqCc,eAAe,OAAO,sCAAmB,IAAA;;;;KAiFpD;EACH,sBAAsB;EACtB,YAAY,OAAO;EACnB,sBAAsB;;;;;;;;EAQtB,mBACE,WAAW,SAAS;;;;;;EAOtB,eAAe,SAAS;;;;;;;;;;;;iBAaV,gBAAgB,OAAO;;;;;;UChsCtB,qCAEb,gBAGA,KAAK,iCAAiC;;;;EAIxC;;;;;;EAMA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CD,wBAAwB,OAAO,+CAA4B,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/plugin.sdk-presence.tsx","../src/plugin.sdk-comments.tsx","../src/plugin.sdk-value.tsx","../src/sdk-editable.tsx"],"mappings":";;;;;;;;;KAiBK,mBAAmB,kBACf;;;;;;;KASG,wBACV,QAAQ,qBACJ,OAAO,sBAAsB;;;;;;;;;UAUlB;;;;;EAKf;;;;EAIA,WAAW;EACX,MAAM;;;;;;;UAQS,+BAA+B;;;;EAI9C,SAAS;;;;;EAKT;;;;;;;UAQe,qCAAqC;;;;EAIpD,SAAS;EACT;EACA,cAAc;;;;;;;;;;;;;;;;iBAiBA,kBAAkB,OAAO;;;;;;;;;;;;;;;iBAwBzB,sBACd,SAAS,+BACR;;;;;;;;KCnCS,mCACV,SAAS,aACL,OAAO,sBAAsB;;;;;;UAOlB,wCAAwC;;;;;EAKvD;EACA,kBAAkB;;;;;;;;;;;;;;;;;;iBAmBJ,yBACd,SAAS,kCACR;;;;;;UAgGc,sCAAsC;;;;EAIrD;;;;;;;UAQe;;;;;;;EAOf,sBAAsB;;;;;;;;EAQtB,sBAAsB;IACpB,SAAS;;IAET;QACI,QAAQ;;;;;;;;;;;iBAwBA,uBACd,SAAS,gCACR;UC0yBO,4BAA4B;EACpC,SAAS;EACT;;;;;iBAqCc,eAAe,OAAO,sCAAmB,IAAA;;;;KAkFpD;EACH,sBAAsB;EACtB,YAAY,OAAO;EACnB,sBAAsB;;;;;;;;EAQtB,mBACE,WAAW,SAAS;;;;;;EAOtB,eAAe,SAAS;;;;;;;;;;;;iBAaV,gBAAgB,OAAO;;;;;;UCnsCtB,qCAEb,gBAGA,KAAK,iCAAiC;;;;EAIxC,SAAS;;;;EAIT;;;;;;EAMA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CD,wBAAwB,OAAO,+CAA4B,IAAA"}