@puckeditor/field-contentful 0.21.0-canary.d1c0d6a2

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 ADDED
@@ -0,0 +1,132 @@
1
+ # field-contentful
2
+
3
+ Select [entries](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/entries) from a [Contentful](https://www.contentful.com) space.
4
+
5
+ ## Quick start
6
+
7
+ ```sh
8
+ npm i @puckeditor/field-contentful
9
+ ```
10
+
11
+ ```jsx
12
+ import createFieldContentful from "@puckeditor/field-contentful";
13
+
14
+ const config = {
15
+ components: {
16
+ Example: {
17
+ fields: {
18
+ movie: createFieldContentful("movies", {
19
+ space: "my_space",
20
+ accessToken: "abcdefg123456",
21
+ }),
22
+ },
23
+ render: ({ data }) => {
24
+ return <p>{data?.fields.title || "No data selected"}</p>;
25
+ },
26
+ },
27
+ },
28
+ };
29
+ ```
30
+
31
+ ## Args
32
+
33
+ | Param | Example | Type | Status |
34
+ | ----------------------------- | -------- | ------ | -------- |
35
+ | [`contentType`](#contenttype) | `movies` | String | Required |
36
+ | [`options`](#options) | `{}` | Object | Required |
37
+
38
+ ### Required args
39
+
40
+ #### `contentType`
41
+
42
+ ID of the Contentful [Content Type](https://www.contentful.com/help/content-model-and-content-type/) to query.
43
+
44
+ #### `options`
45
+
46
+ | Param | Example | Type | Status |
47
+ | ------------------------------------------ | --------------------------------------- | --------------------------------------------------------------- | ------------------------------ |
48
+ | [`accessToken`](#optionsaccesstoken) | `"abc123"` | String | Required (unless using client) |
49
+ | [`space`](#optionsspace) | `"my-space"` | String | Required (unless using client) |
50
+ | [`client`](#optionsclient) | `createClient()` | [ContentfulClientApi](https://www.npmjs.com/package/contentful) | - |
51
+ | [`filterFields`](#optionsfilterfields) | `{ "rating[gte]": { type: "number" } }` | Object | - |
52
+ | [`initialFilters`](#optionsinitialfilters) | `{ "rating[gte]": 1 }` | Object | - |
53
+ | [`titleField`](#optionstitlefield) | `"name"` | String | - |
54
+
55
+ ##### `options.accessToken`
56
+
57
+ Your Contentful access token.
58
+
59
+ ##### `options.space`
60
+
61
+ The id for the Contentful space that contains your content.
62
+
63
+ ##### `options.client`
64
+
65
+ A Contentful client as created by the [`contentful` Node.js package](https://www.npmjs.com/package/contentful). You can use this instead of `accessToken` and `space` if you want to reuse your client, or customise it more fully.
66
+
67
+ ##### `options.filterFields`
68
+
69
+ An object describing which [`filterFields`](https://puckeditor.com/docs/api-reference/fields/external#filterfields) to render and pass the result directly to Contentful as [search parameters](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters).
70
+
71
+ ```jsx
72
+ createFieldContentful("movies", {
73
+ // ...
74
+ filterFields: {
75
+ // Filter the "rating" field by value greater than the user input
76
+ "fields.rating[gte]": {
77
+ type: "number",
78
+ },
79
+ },
80
+ });
81
+ ```
82
+
83
+ ##### `options.initialFilters`
84
+
85
+ The initial values for the filters defined in [`filterFields`](#optionsfilterfields). This data is passed directly directly to Contentful as [search parameters](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters).
86
+
87
+ ```jsx
88
+ createFieldContentful("movies", {
89
+ // ...
90
+ initialFilters: {
91
+ "fields.rating[gte]": 1,
92
+ select: "name,rating", // Can include search parameters not included in filterFields
93
+ },
94
+ });
95
+ ```
96
+
97
+ ##### `options.titleField`
98
+
99
+ The field to use as the title for the selected item. Defaults to `"title"`.
100
+
101
+ ```jsx
102
+ createFieldContentful("movies", {
103
+ // ...
104
+ titleField: "name",
105
+ });
106
+ ```
107
+
108
+ ## Returns
109
+
110
+ An [External field](https://puckeditor.com/docs/api-reference/fields/external) type that loads Contentful [entries](https://contentful.github.io/contentful.js/contentful/10.6.16/types/Entry.html).
111
+
112
+ ## TypeScript
113
+
114
+ You can use the `Entry` type for data loaded via Contentful:
115
+
116
+ ```tsx
117
+ import createFieldContentful, { Entry } from "@/field-contentful";
118
+
119
+ type MyProps = {
120
+ Example: {
121
+ movie: Entry<{ title: string; description: string; rating: number }>;
122
+ };
123
+ };
124
+
125
+ const config: Config<MyProps> = {
126
+ // ...
127
+ };
128
+ ```
129
+
130
+ ## License
131
+
132
+ MIT © [The Puck Contributors](https://github.com/puckeditor/puck/graphs/contributors)
@@ -0,0 +1,344 @@
1
+ import { ReactElement, ReactNode, CSSProperties } from 'react';
2
+ import { EditorStateSnapshot, Editor, Extensions } from '@tiptap/react';
3
+ import { BlockquoteOptions } from '@tiptap/extension-blockquote';
4
+ import { BoldOptions } from '@tiptap/extension-bold';
5
+ import { CodeOptions } from '@tiptap/extension-code';
6
+ import { CodeBlockOptions } from '@tiptap/extension-code-block';
7
+ import { HardBreakOptions } from '@tiptap/extension-hard-break';
8
+ import { HeadingOptions } from '@tiptap/extension-heading';
9
+ import { HorizontalRuleOptions } from '@tiptap/extension-horizontal-rule';
10
+ import { ItalicOptions } from '@tiptap/extension-italic';
11
+ import { LinkOptions } from '@tiptap/extension-link';
12
+ import { BulletListOptions, ListItemOptions, ListKeymapOptions, OrderedListOptions } from '@tiptap/extension-list';
13
+ import { ParagraphOptions } from '@tiptap/extension-paragraph';
14
+ import { StrikeOptions } from '@tiptap/extension-strike';
15
+ import { TextAlignOptions } from '@tiptap/extension-text-align';
16
+ import { UnderlineOptions } from '@tiptap/extension-underline';
17
+ import { BaseEntry, ContentfulClientApi } from 'contentful';
18
+ export { createClient } from 'contentful';
19
+
20
+ declare const defaultEditorState: (ctx: EditorStateSnapshot, readOnly: boolean) => {
21
+ isAlignLeft?: undefined;
22
+ canAlignLeft?: undefined;
23
+ isAlignCenter?: undefined;
24
+ canAlignCenter?: undefined;
25
+ isAlignRight?: undefined;
26
+ canAlignRight?: undefined;
27
+ isAlignJustify?: undefined;
28
+ canAlignJustify?: undefined;
29
+ isBold?: undefined;
30
+ canBold?: undefined;
31
+ isItalic?: undefined;
32
+ canItalic?: undefined;
33
+ isUnderline?: undefined;
34
+ canUnderline?: undefined;
35
+ isStrike?: undefined;
36
+ canStrike?: undefined;
37
+ isInlineCode?: undefined;
38
+ canInlineCode?: undefined;
39
+ isBulletList?: undefined;
40
+ canBulletList?: undefined;
41
+ isOrderedList?: undefined;
42
+ canOrderedList?: undefined;
43
+ isCodeBlock?: undefined;
44
+ canCodeBlock?: undefined;
45
+ isBlockquote?: undefined;
46
+ canBlockquote?: undefined;
47
+ canHorizontalRule?: undefined;
48
+ } | {
49
+ isAlignLeft: boolean;
50
+ canAlignLeft: boolean;
51
+ isAlignCenter: boolean;
52
+ canAlignCenter: boolean;
53
+ isAlignRight: boolean;
54
+ canAlignRight: boolean;
55
+ isAlignJustify: boolean;
56
+ canAlignJustify: boolean;
57
+ isBold: boolean;
58
+ canBold: boolean;
59
+ isItalic: boolean;
60
+ canItalic: boolean;
61
+ isUnderline: boolean;
62
+ canUnderline: boolean;
63
+ isStrike: boolean;
64
+ canStrike: boolean;
65
+ isInlineCode: boolean;
66
+ canInlineCode: boolean;
67
+ isBulletList: boolean;
68
+ canBulletList: boolean;
69
+ isOrderedList: boolean;
70
+ canOrderedList: boolean;
71
+ isCodeBlock: boolean;
72
+ canCodeBlock: boolean;
73
+ isBlockquote: boolean;
74
+ canBlockquote: boolean;
75
+ canHorizontalRule: boolean;
76
+ };
77
+
78
+ type RichTextSelector = (ctx: EditorStateSnapshot, readOnly: boolean) => Partial<Record<string, boolean>>;
79
+ type DefaultEditorState = ReturnType<typeof defaultEditorState>;
80
+ type EditorState<Selector extends RichTextSelector = RichTextSelector> = DefaultEditorState & ReturnType<Selector> & Record<string, boolean | undefined>;
81
+
82
+ interface PuckRichTextOptions {
83
+ /**
84
+ * If set to false, the blockquote extension will not be registered
85
+ * @example blockquote: false
86
+ */
87
+ blockquote: Partial<BlockquoteOptions> | false;
88
+ /**
89
+ * If set to false, the bold extension will not be registered
90
+ * @example bold: false
91
+ */
92
+ bold: Partial<BoldOptions> | false;
93
+ /**
94
+ * If set to false, the bulletList extension will not be registered
95
+ * @example bulletList: false
96
+ */
97
+ bulletList: Partial<BulletListOptions> | false;
98
+ /**
99
+ * If set to false, the code extension will not be registered
100
+ * @example code: false
101
+ */
102
+ code: Partial<CodeOptions> | false;
103
+ /**
104
+ * If set to false, the codeBlock extension will not be registered
105
+ * @example codeBlock: false
106
+ */
107
+ codeBlock: Partial<CodeBlockOptions> | false;
108
+ /**
109
+ * If set to false, the document extension will not be registered
110
+ * @example document: false
111
+ */
112
+ document: false;
113
+ /**
114
+ * If set to false, the hardBreak extension will not be registered
115
+ * @example hardBreak: false
116
+ */
117
+ hardBreak: Partial<HardBreakOptions> | false;
118
+ /**
119
+ * If set to false, the heading extension will not be registered
120
+ * @example heading: false
121
+ */
122
+ heading: Partial<HeadingOptions> | false;
123
+ /**
124
+ * If set to false, the horizontalRule extension will not be registered
125
+ * @example horizontalRule: false
126
+ */
127
+ horizontalRule: Partial<HorizontalRuleOptions> | false;
128
+ /**
129
+ * If set to false, the italic extension will not be registered
130
+ * @example italic: false
131
+ */
132
+ italic: Partial<ItalicOptions> | false;
133
+ /**
134
+ * If set to false, the listItem extension will not be registered
135
+ * @example listItem: false
136
+ */
137
+ listItem: Partial<ListItemOptions> | false;
138
+ /**
139
+ * If set to false, the listItemKeymap extension will not be registered
140
+ * @example listKeymap: false
141
+ */
142
+ listKeymap: Partial<ListKeymapOptions> | false;
143
+ /**
144
+ * If set to false, the link extension will not be registered
145
+ * @example link: false
146
+ */
147
+ link: Partial<LinkOptions> | false;
148
+ /**
149
+ * If set to false, the orderedList extension will not be registered
150
+ * @example orderedList: false
151
+ */
152
+ orderedList: Partial<OrderedListOptions> | false;
153
+ /**
154
+ * If set to false, the paragraph extension will not be registered
155
+ * @example paragraph: false
156
+ */
157
+ paragraph: Partial<ParagraphOptions> | false;
158
+ /**
159
+ * If set to false, the strike extension will not be registered
160
+ * @example strike: false
161
+ */
162
+ strike: Partial<StrikeOptions> | false;
163
+ /**
164
+ * If set to false, the text extension will not be registered
165
+ * @example text: false
166
+ */
167
+ text: false;
168
+ /**
169
+ * If set to false, the textAlign extension will not be registered
170
+ * @example text: false
171
+ */
172
+ textAlign: Partial<TextAlignOptions> | false;
173
+ /**
174
+ * If set to false, the underline extension will not be registered
175
+ * @example underline: false
176
+ */
177
+ underline: Partial<UnderlineOptions> | false;
178
+ }
179
+
180
+ type FieldOption = {
181
+ label: string;
182
+ value: string | number | boolean | undefined | null | object;
183
+ };
184
+ type FieldOptions = Array<FieldOption> | ReadonlyArray<FieldOption>;
185
+ interface BaseField {
186
+ label?: string;
187
+ labelIcon?: ReactElement;
188
+ metadata?: FieldMetadata;
189
+ visible?: boolean;
190
+ }
191
+ interface TextField extends BaseField {
192
+ type: "text";
193
+ placeholder?: string;
194
+ contentEditable?: boolean;
195
+ }
196
+ interface NumberField extends BaseField {
197
+ type: "number";
198
+ placeholder?: string;
199
+ min?: number;
200
+ max?: number;
201
+ step?: number;
202
+ }
203
+ interface TextareaField extends BaseField {
204
+ type: "textarea";
205
+ placeholder?: string;
206
+ contentEditable?: boolean;
207
+ }
208
+ interface SelectField extends BaseField {
209
+ type: "select";
210
+ options: FieldOptions;
211
+ }
212
+ interface RadioField extends BaseField {
213
+ type: "radio";
214
+ options: FieldOptions;
215
+ }
216
+ interface RichtextField<UserSelector extends RichTextSelector = RichTextSelector> extends BaseField {
217
+ type: "richtext";
218
+ contentEditable?: boolean;
219
+ initialHeight?: CSSProperties["height"];
220
+ options?: Partial<PuckRichTextOptions>;
221
+ renderMenu?: (props: {
222
+ children: ReactNode;
223
+ editor: Editor | null;
224
+ editorState: EditorState<UserSelector> | null;
225
+ readOnly: boolean;
226
+ }) => ReactNode;
227
+ renderInlineMenu?: (props: {
228
+ children: ReactNode;
229
+ editor: Editor | null;
230
+ editorState: EditorState<UserSelector> | null;
231
+ readOnly: boolean;
232
+ }) => ReactNode;
233
+ tiptap?: {
234
+ selector?: UserSelector;
235
+ extensions?: Extensions;
236
+ };
237
+ }
238
+ interface ArrayField<Props extends {
239
+ [key: string]: any;
240
+ }[] = {
241
+ [key: string]: any;
242
+ }[], UserField extends {} = {}> extends BaseField {
243
+ type: "array";
244
+ arrayFields: {
245
+ [SubPropName in keyof Props[0]]: UserField extends {
246
+ type: PropertyKey;
247
+ } ? Field<Props[0][SubPropName], UserField> | UserField : Field<Props[0][SubPropName], UserField>;
248
+ };
249
+ defaultItemProps?: Props[0] | ((index: number) => Props[0]);
250
+ getItemSummary?: (item: Props[0], index?: number) => ReactNode;
251
+ max?: number;
252
+ min?: number;
253
+ }
254
+ interface ObjectField<Props extends any = {
255
+ [key: string]: any;
256
+ }, UserField extends {} = {}> extends BaseField {
257
+ type: "object";
258
+ objectFields: {
259
+ [SubPropName in keyof Props]: UserField extends {
260
+ type: PropertyKey;
261
+ } ? Field<Props[SubPropName]> | UserField : Field<Props[SubPropName]>;
262
+ };
263
+ }
264
+ type Adaptor<AdaptorParams = {}, TableShape extends Record<string, any> = {}, PropShape = TableShape> = {
265
+ name: string;
266
+ fetchList: (adaptorParams?: AdaptorParams) => Promise<TableShape[] | null>;
267
+ mapProp?: (value: TableShape) => PropShape;
268
+ };
269
+ type NotUndefined<T> = T extends undefined ? never : T;
270
+ type ExternalFieldWithAdaptor<Props extends any = {
271
+ [key: string]: any;
272
+ }> = BaseField & {
273
+ type: "external";
274
+ placeholder?: string;
275
+ adaptor: Adaptor<any, any, Props>;
276
+ adaptorParams?: object;
277
+ getItemSummary: (item: NotUndefined<Props>, index?: number) => ReactNode;
278
+ };
279
+ type CacheOpts = {
280
+ enabled?: boolean;
281
+ };
282
+ interface ExternalField<Props extends any = {
283
+ [key: string]: any;
284
+ }> extends BaseField {
285
+ type: "external";
286
+ cache?: CacheOpts;
287
+ placeholder?: string;
288
+ fetchList: (params: {
289
+ query: string;
290
+ filters: Record<string, any>;
291
+ }) => Promise<any[] | null>;
292
+ mapProp?: (value: any) => Props;
293
+ mapRow?: (value: any) => Record<string, string | number | ReactElement>;
294
+ getItemSummary?: (item: NotUndefined<Props>, index?: number) => ReactNode;
295
+ showSearch?: boolean;
296
+ renderFooter?: (props: {
297
+ items: any[];
298
+ }) => ReactElement;
299
+ initialQuery?: string;
300
+ filterFields?: Record<string, Field>;
301
+ initialFilters?: Record<string, any>;
302
+ }
303
+ type CustomFieldRender<Value extends any> = (props: {
304
+ field: CustomField<Value>;
305
+ name: string;
306
+ id: string;
307
+ value: Value;
308
+ onChange: (value: Value) => void;
309
+ readOnly?: boolean;
310
+ }) => ReactElement;
311
+ interface CustomField<Value extends any> extends BaseField {
312
+ type: "custom";
313
+ render: CustomFieldRender<Value>;
314
+ contentEditable?: boolean;
315
+ key?: string;
316
+ }
317
+ interface SlotField extends BaseField {
318
+ type: "slot";
319
+ allow?: string[];
320
+ disallow?: string[];
321
+ }
322
+ type Field<ValueType = any, UserField extends {} = {}> = TextField | RichtextField | NumberField | TextareaField | SelectField | RadioField | ArrayField<ValueType extends {
323
+ [key: string]: any;
324
+ }[] ? ValueType : never, UserField> | ObjectField<ValueType, UserField> | ExternalField<ValueType> | ExternalFieldWithAdaptor<ValueType> | CustomField<ValueType> | SlotField;
325
+
326
+ type Metadata = {
327
+ [key: string]: any;
328
+ };
329
+ interface FieldMetadata extends Metadata {
330
+ }
331
+
332
+ type Entry<Fields extends Record<string, any> = {}> = BaseEntry & {
333
+ fields: Fields;
334
+ };
335
+ declare function createFieldContentful<T extends Entry = Entry>(contentType: string, options?: {
336
+ client?: ContentfulClientApi<undefined>;
337
+ space?: string;
338
+ accessToken?: string;
339
+ titleField?: string;
340
+ filterFields?: ExternalField["filterFields"];
341
+ initialFilters?: ExternalField["initialFilters"];
342
+ }): ExternalField<T>;
343
+
344
+ export { type Entry, createFieldContentful, createFieldContentful as default };
@@ -0,0 +1,344 @@
1
+ import { ReactElement, ReactNode, CSSProperties } from 'react';
2
+ import { EditorStateSnapshot, Editor, Extensions } from '@tiptap/react';
3
+ import { BlockquoteOptions } from '@tiptap/extension-blockquote';
4
+ import { BoldOptions } from '@tiptap/extension-bold';
5
+ import { CodeOptions } from '@tiptap/extension-code';
6
+ import { CodeBlockOptions } from '@tiptap/extension-code-block';
7
+ import { HardBreakOptions } from '@tiptap/extension-hard-break';
8
+ import { HeadingOptions } from '@tiptap/extension-heading';
9
+ import { HorizontalRuleOptions } from '@tiptap/extension-horizontal-rule';
10
+ import { ItalicOptions } from '@tiptap/extension-italic';
11
+ import { LinkOptions } from '@tiptap/extension-link';
12
+ import { BulletListOptions, ListItemOptions, ListKeymapOptions, OrderedListOptions } from '@tiptap/extension-list';
13
+ import { ParagraphOptions } from '@tiptap/extension-paragraph';
14
+ import { StrikeOptions } from '@tiptap/extension-strike';
15
+ import { TextAlignOptions } from '@tiptap/extension-text-align';
16
+ import { UnderlineOptions } from '@tiptap/extension-underline';
17
+ import { BaseEntry, ContentfulClientApi } from 'contentful';
18
+ export { createClient } from 'contentful';
19
+
20
+ declare const defaultEditorState: (ctx: EditorStateSnapshot, readOnly: boolean) => {
21
+ isAlignLeft?: undefined;
22
+ canAlignLeft?: undefined;
23
+ isAlignCenter?: undefined;
24
+ canAlignCenter?: undefined;
25
+ isAlignRight?: undefined;
26
+ canAlignRight?: undefined;
27
+ isAlignJustify?: undefined;
28
+ canAlignJustify?: undefined;
29
+ isBold?: undefined;
30
+ canBold?: undefined;
31
+ isItalic?: undefined;
32
+ canItalic?: undefined;
33
+ isUnderline?: undefined;
34
+ canUnderline?: undefined;
35
+ isStrike?: undefined;
36
+ canStrike?: undefined;
37
+ isInlineCode?: undefined;
38
+ canInlineCode?: undefined;
39
+ isBulletList?: undefined;
40
+ canBulletList?: undefined;
41
+ isOrderedList?: undefined;
42
+ canOrderedList?: undefined;
43
+ isCodeBlock?: undefined;
44
+ canCodeBlock?: undefined;
45
+ isBlockquote?: undefined;
46
+ canBlockquote?: undefined;
47
+ canHorizontalRule?: undefined;
48
+ } | {
49
+ isAlignLeft: boolean;
50
+ canAlignLeft: boolean;
51
+ isAlignCenter: boolean;
52
+ canAlignCenter: boolean;
53
+ isAlignRight: boolean;
54
+ canAlignRight: boolean;
55
+ isAlignJustify: boolean;
56
+ canAlignJustify: boolean;
57
+ isBold: boolean;
58
+ canBold: boolean;
59
+ isItalic: boolean;
60
+ canItalic: boolean;
61
+ isUnderline: boolean;
62
+ canUnderline: boolean;
63
+ isStrike: boolean;
64
+ canStrike: boolean;
65
+ isInlineCode: boolean;
66
+ canInlineCode: boolean;
67
+ isBulletList: boolean;
68
+ canBulletList: boolean;
69
+ isOrderedList: boolean;
70
+ canOrderedList: boolean;
71
+ isCodeBlock: boolean;
72
+ canCodeBlock: boolean;
73
+ isBlockquote: boolean;
74
+ canBlockquote: boolean;
75
+ canHorizontalRule: boolean;
76
+ };
77
+
78
+ type RichTextSelector = (ctx: EditorStateSnapshot, readOnly: boolean) => Partial<Record<string, boolean>>;
79
+ type DefaultEditorState = ReturnType<typeof defaultEditorState>;
80
+ type EditorState<Selector extends RichTextSelector = RichTextSelector> = DefaultEditorState & ReturnType<Selector> & Record<string, boolean | undefined>;
81
+
82
+ interface PuckRichTextOptions {
83
+ /**
84
+ * If set to false, the blockquote extension will not be registered
85
+ * @example blockquote: false
86
+ */
87
+ blockquote: Partial<BlockquoteOptions> | false;
88
+ /**
89
+ * If set to false, the bold extension will not be registered
90
+ * @example bold: false
91
+ */
92
+ bold: Partial<BoldOptions> | false;
93
+ /**
94
+ * If set to false, the bulletList extension will not be registered
95
+ * @example bulletList: false
96
+ */
97
+ bulletList: Partial<BulletListOptions> | false;
98
+ /**
99
+ * If set to false, the code extension will not be registered
100
+ * @example code: false
101
+ */
102
+ code: Partial<CodeOptions> | false;
103
+ /**
104
+ * If set to false, the codeBlock extension will not be registered
105
+ * @example codeBlock: false
106
+ */
107
+ codeBlock: Partial<CodeBlockOptions> | false;
108
+ /**
109
+ * If set to false, the document extension will not be registered
110
+ * @example document: false
111
+ */
112
+ document: false;
113
+ /**
114
+ * If set to false, the hardBreak extension will not be registered
115
+ * @example hardBreak: false
116
+ */
117
+ hardBreak: Partial<HardBreakOptions> | false;
118
+ /**
119
+ * If set to false, the heading extension will not be registered
120
+ * @example heading: false
121
+ */
122
+ heading: Partial<HeadingOptions> | false;
123
+ /**
124
+ * If set to false, the horizontalRule extension will not be registered
125
+ * @example horizontalRule: false
126
+ */
127
+ horizontalRule: Partial<HorizontalRuleOptions> | false;
128
+ /**
129
+ * If set to false, the italic extension will not be registered
130
+ * @example italic: false
131
+ */
132
+ italic: Partial<ItalicOptions> | false;
133
+ /**
134
+ * If set to false, the listItem extension will not be registered
135
+ * @example listItem: false
136
+ */
137
+ listItem: Partial<ListItemOptions> | false;
138
+ /**
139
+ * If set to false, the listItemKeymap extension will not be registered
140
+ * @example listKeymap: false
141
+ */
142
+ listKeymap: Partial<ListKeymapOptions> | false;
143
+ /**
144
+ * If set to false, the link extension will not be registered
145
+ * @example link: false
146
+ */
147
+ link: Partial<LinkOptions> | false;
148
+ /**
149
+ * If set to false, the orderedList extension will not be registered
150
+ * @example orderedList: false
151
+ */
152
+ orderedList: Partial<OrderedListOptions> | false;
153
+ /**
154
+ * If set to false, the paragraph extension will not be registered
155
+ * @example paragraph: false
156
+ */
157
+ paragraph: Partial<ParagraphOptions> | false;
158
+ /**
159
+ * If set to false, the strike extension will not be registered
160
+ * @example strike: false
161
+ */
162
+ strike: Partial<StrikeOptions> | false;
163
+ /**
164
+ * If set to false, the text extension will not be registered
165
+ * @example text: false
166
+ */
167
+ text: false;
168
+ /**
169
+ * If set to false, the textAlign extension will not be registered
170
+ * @example text: false
171
+ */
172
+ textAlign: Partial<TextAlignOptions> | false;
173
+ /**
174
+ * If set to false, the underline extension will not be registered
175
+ * @example underline: false
176
+ */
177
+ underline: Partial<UnderlineOptions> | false;
178
+ }
179
+
180
+ type FieldOption = {
181
+ label: string;
182
+ value: string | number | boolean | undefined | null | object;
183
+ };
184
+ type FieldOptions = Array<FieldOption> | ReadonlyArray<FieldOption>;
185
+ interface BaseField {
186
+ label?: string;
187
+ labelIcon?: ReactElement;
188
+ metadata?: FieldMetadata;
189
+ visible?: boolean;
190
+ }
191
+ interface TextField extends BaseField {
192
+ type: "text";
193
+ placeholder?: string;
194
+ contentEditable?: boolean;
195
+ }
196
+ interface NumberField extends BaseField {
197
+ type: "number";
198
+ placeholder?: string;
199
+ min?: number;
200
+ max?: number;
201
+ step?: number;
202
+ }
203
+ interface TextareaField extends BaseField {
204
+ type: "textarea";
205
+ placeholder?: string;
206
+ contentEditable?: boolean;
207
+ }
208
+ interface SelectField extends BaseField {
209
+ type: "select";
210
+ options: FieldOptions;
211
+ }
212
+ interface RadioField extends BaseField {
213
+ type: "radio";
214
+ options: FieldOptions;
215
+ }
216
+ interface RichtextField<UserSelector extends RichTextSelector = RichTextSelector> extends BaseField {
217
+ type: "richtext";
218
+ contentEditable?: boolean;
219
+ initialHeight?: CSSProperties["height"];
220
+ options?: Partial<PuckRichTextOptions>;
221
+ renderMenu?: (props: {
222
+ children: ReactNode;
223
+ editor: Editor | null;
224
+ editorState: EditorState<UserSelector> | null;
225
+ readOnly: boolean;
226
+ }) => ReactNode;
227
+ renderInlineMenu?: (props: {
228
+ children: ReactNode;
229
+ editor: Editor | null;
230
+ editorState: EditorState<UserSelector> | null;
231
+ readOnly: boolean;
232
+ }) => ReactNode;
233
+ tiptap?: {
234
+ selector?: UserSelector;
235
+ extensions?: Extensions;
236
+ };
237
+ }
238
+ interface ArrayField<Props extends {
239
+ [key: string]: any;
240
+ }[] = {
241
+ [key: string]: any;
242
+ }[], UserField extends {} = {}> extends BaseField {
243
+ type: "array";
244
+ arrayFields: {
245
+ [SubPropName in keyof Props[0]]: UserField extends {
246
+ type: PropertyKey;
247
+ } ? Field<Props[0][SubPropName], UserField> | UserField : Field<Props[0][SubPropName], UserField>;
248
+ };
249
+ defaultItemProps?: Props[0] | ((index: number) => Props[0]);
250
+ getItemSummary?: (item: Props[0], index?: number) => ReactNode;
251
+ max?: number;
252
+ min?: number;
253
+ }
254
+ interface ObjectField<Props extends any = {
255
+ [key: string]: any;
256
+ }, UserField extends {} = {}> extends BaseField {
257
+ type: "object";
258
+ objectFields: {
259
+ [SubPropName in keyof Props]: UserField extends {
260
+ type: PropertyKey;
261
+ } ? Field<Props[SubPropName]> | UserField : Field<Props[SubPropName]>;
262
+ };
263
+ }
264
+ type Adaptor<AdaptorParams = {}, TableShape extends Record<string, any> = {}, PropShape = TableShape> = {
265
+ name: string;
266
+ fetchList: (adaptorParams?: AdaptorParams) => Promise<TableShape[] | null>;
267
+ mapProp?: (value: TableShape) => PropShape;
268
+ };
269
+ type NotUndefined<T> = T extends undefined ? never : T;
270
+ type ExternalFieldWithAdaptor<Props extends any = {
271
+ [key: string]: any;
272
+ }> = BaseField & {
273
+ type: "external";
274
+ placeholder?: string;
275
+ adaptor: Adaptor<any, any, Props>;
276
+ adaptorParams?: object;
277
+ getItemSummary: (item: NotUndefined<Props>, index?: number) => ReactNode;
278
+ };
279
+ type CacheOpts = {
280
+ enabled?: boolean;
281
+ };
282
+ interface ExternalField<Props extends any = {
283
+ [key: string]: any;
284
+ }> extends BaseField {
285
+ type: "external";
286
+ cache?: CacheOpts;
287
+ placeholder?: string;
288
+ fetchList: (params: {
289
+ query: string;
290
+ filters: Record<string, any>;
291
+ }) => Promise<any[] | null>;
292
+ mapProp?: (value: any) => Props;
293
+ mapRow?: (value: any) => Record<string, string | number | ReactElement>;
294
+ getItemSummary?: (item: NotUndefined<Props>, index?: number) => ReactNode;
295
+ showSearch?: boolean;
296
+ renderFooter?: (props: {
297
+ items: any[];
298
+ }) => ReactElement;
299
+ initialQuery?: string;
300
+ filterFields?: Record<string, Field>;
301
+ initialFilters?: Record<string, any>;
302
+ }
303
+ type CustomFieldRender<Value extends any> = (props: {
304
+ field: CustomField<Value>;
305
+ name: string;
306
+ id: string;
307
+ value: Value;
308
+ onChange: (value: Value) => void;
309
+ readOnly?: boolean;
310
+ }) => ReactElement;
311
+ interface CustomField<Value extends any> extends BaseField {
312
+ type: "custom";
313
+ render: CustomFieldRender<Value>;
314
+ contentEditable?: boolean;
315
+ key?: string;
316
+ }
317
+ interface SlotField extends BaseField {
318
+ type: "slot";
319
+ allow?: string[];
320
+ disallow?: string[];
321
+ }
322
+ type Field<ValueType = any, UserField extends {} = {}> = TextField | RichtextField | NumberField | TextareaField | SelectField | RadioField | ArrayField<ValueType extends {
323
+ [key: string]: any;
324
+ }[] ? ValueType : never, UserField> | ObjectField<ValueType, UserField> | ExternalField<ValueType> | ExternalFieldWithAdaptor<ValueType> | CustomField<ValueType> | SlotField;
325
+
326
+ type Metadata = {
327
+ [key: string]: any;
328
+ };
329
+ interface FieldMetadata extends Metadata {
330
+ }
331
+
332
+ type Entry<Fields extends Record<string, any> = {}> = BaseEntry & {
333
+ fields: Fields;
334
+ };
335
+ declare function createFieldContentful<T extends Entry = Entry>(contentType: string, options?: {
336
+ client?: ContentfulClientApi<undefined>;
337
+ space?: string;
338
+ accessToken?: string;
339
+ titleField?: string;
340
+ filterFields?: ExternalField["filterFields"];
341
+ initialFilters?: ExternalField["initialFilters"];
342
+ }): ExternalField<T>;
343
+
344
+ export { type Entry, createFieldContentful, createFieldContentful as default };
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __export = (target, all) => {
26
+ for (var name in all)
27
+ __defProp(target, name, { get: all[name], enumerable: true });
28
+ };
29
+ var __copyProps = (to, from, except, desc) => {
30
+ if (from && typeof from === "object" || typeof from === "function") {
31
+ for (let key of __getOwnPropNames(from))
32
+ if (!__hasOwnProp.call(to, key) && key !== except)
33
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
+ }
35
+ return to;
36
+ };
37
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
+ // If the importer is in node compatibility mode or this is not an ESM
39
+ // file that has been converted to a CommonJS file using a Babel-
40
+ // compatible transform (i.e. "__esModule" has not been set), then set
41
+ // "default" to the CommonJS "module.exports" for node compatibility.
42
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
+ mod
44
+ ));
45
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
+ var __async = (__this, __arguments, generator) => {
47
+ return new Promise((resolve, reject) => {
48
+ var fulfilled = (value) => {
49
+ try {
50
+ step(generator.next(value));
51
+ } catch (e) {
52
+ reject(e);
53
+ }
54
+ };
55
+ var rejected = (value) => {
56
+ try {
57
+ step(generator.throw(value));
58
+ } catch (e) {
59
+ reject(e);
60
+ }
61
+ };
62
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
63
+ step((generator = generator.apply(__this, __arguments)).next());
64
+ });
65
+ };
66
+
67
+ // index.ts
68
+ var index_exports = {};
69
+ __export(index_exports, {
70
+ createClient: () => import_contentful.createClient,
71
+ createFieldContentful: () => createFieldContentful,
72
+ default: () => index_default
73
+ });
74
+ module.exports = __toCommonJS(index_exports);
75
+
76
+ // ../tsup-config/react-import.js
77
+ var import_react = __toESM(require("react"));
78
+
79
+ // index.ts
80
+ var import_contentful = require("contentful");
81
+ function createFieldContentful(contentType, options = {}) {
82
+ const {
83
+ space,
84
+ accessToken,
85
+ titleField = "title",
86
+ filterFields,
87
+ initialFilters
88
+ } = options;
89
+ if (!options.client) {
90
+ if (!space || !accessToken) {
91
+ throw new Error(
92
+ 'field-contentful: Must either specify "client", or "space" and "accessToken"'
93
+ );
94
+ }
95
+ }
96
+ const client = options.client || (0, import_contentful.createClient)({ space, accessToken });
97
+ const field = {
98
+ type: "external",
99
+ placeholder: "Select from Contentful",
100
+ showSearch: true,
101
+ fetchList: (_0) => __async(null, [_0], function* ({ query, filters = {} }) {
102
+ const entries = yield client.getEntries(__spreadProps(__spreadValues({}, filters), {
103
+ content_type: contentType,
104
+ query
105
+ }));
106
+ return entries.items;
107
+ }),
108
+ mapRow: ({ fields }) => fields,
109
+ getItemSummary: (item) => item.fields[titleField],
110
+ filterFields,
111
+ initialFilters
112
+ };
113
+ return field;
114
+ }
115
+ var index_default = createFieldContentful;
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ createClient,
119
+ createFieldContentful
120
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,85 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __async = (__this, __arguments, generator) => {
21
+ return new Promise((resolve, reject) => {
22
+ var fulfilled = (value) => {
23
+ try {
24
+ step(generator.next(value));
25
+ } catch (e) {
26
+ reject(e);
27
+ }
28
+ };
29
+ var rejected = (value) => {
30
+ try {
31
+ step(generator.throw(value));
32
+ } catch (e) {
33
+ reject(e);
34
+ }
35
+ };
36
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
+ step((generator = generator.apply(__this, __arguments)).next());
38
+ });
39
+ };
40
+
41
+ // ../tsup-config/react-import.js
42
+ import React from "react";
43
+
44
+ // index.ts
45
+ import { createClient } from "contentful";
46
+ function createFieldContentful(contentType, options = {}) {
47
+ const {
48
+ space,
49
+ accessToken,
50
+ titleField = "title",
51
+ filterFields,
52
+ initialFilters
53
+ } = options;
54
+ if (!options.client) {
55
+ if (!space || !accessToken) {
56
+ throw new Error(
57
+ 'field-contentful: Must either specify "client", or "space" and "accessToken"'
58
+ );
59
+ }
60
+ }
61
+ const client = options.client || createClient({ space, accessToken });
62
+ const field = {
63
+ type: "external",
64
+ placeholder: "Select from Contentful",
65
+ showSearch: true,
66
+ fetchList: (_0) => __async(null, [_0], function* ({ query, filters = {} }) {
67
+ const entries = yield client.getEntries(__spreadProps(__spreadValues({}, filters), {
68
+ content_type: contentType,
69
+ query
70
+ }));
71
+ return entries.items;
72
+ }),
73
+ mapRow: ({ fields }) => fields,
74
+ getItemSummary: (item) => item.fields[titleField],
75
+ filterFields,
76
+ initialFilters
77
+ };
78
+ return field;
79
+ }
80
+ var index_default = createFieldContentful;
81
+ export {
82
+ createClient,
83
+ createFieldContentful,
84
+ index_default as default
85
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@puckeditor/field-contentful",
3
+ "version": "0.21.0-canary.d1c0d6a2",
4
+ "author": "Chris Villa <chris@puckeditor.com>",
5
+ "repository": "puckeditor/puck",
6
+ "bugs": "https://github.com/puckeditor/puck/issues",
7
+ "homepage": "https://puckeditor.com",
8
+ "private": false,
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ "import": "./dist/index.mjs",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "license": "MIT",
16
+ "scripts": {
17
+ "lint": "eslint \"**/*.ts*\"",
18
+ "build": "rm -rf dist && tsup index.ts",
19
+ "prepare": "yarn build"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "devDependencies": {
25
+ "@puckeditor/core": "^0.21.0-canary.d1c0d6a2",
26
+ "@types/react": "^19.2.7",
27
+ "@types/react-dom": "^19.2.3",
28
+ "contentful": "^10.8.6",
29
+ "eslint": "^7.32.0",
30
+ "eslint-config-custom": "*",
31
+ "tsconfig": "*",
32
+ "tsup-config": "*",
33
+ "typescript": "^5.5.4"
34
+ },
35
+ "peerDependencies": {
36
+ "contentful": "^10.0.0",
37
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
38
+ }
39
+ }