@measured/puck-field-contentful 0.14.0-canary.053d4c6

Sign up to get free protection for your applications and to get access to all the features.
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 @measured/puck-field-contentful
9
+ ```
10
+
11
+ ```jsx
12
+ import createFieldContentful from "@measured/puck-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 © [Measured Corporation Ltd](https://measured.co)
@@ -0,0 +1,123 @@
1
+ import { ReactElement } from 'react';
2
+ import { BaseEntry, ContentfulClientApi } from 'contentful';
3
+ export { createClient } from 'contentful';
4
+
5
+ type FieldOption = {
6
+ label: string;
7
+ value: string | number | boolean;
8
+ };
9
+ type FieldOptions = Array<FieldOption> | ReadonlyArray<FieldOption>;
10
+ type BaseField = {
11
+ label?: string;
12
+ };
13
+ type TextField = BaseField & {
14
+ type: "text";
15
+ };
16
+ type NumberField = BaseField & {
17
+ type: "number";
18
+ min?: number;
19
+ max?: number;
20
+ };
21
+ type TextareaField = BaseField & {
22
+ type: "textarea";
23
+ };
24
+ type SelectField = BaseField & {
25
+ type: "select";
26
+ options: FieldOptions;
27
+ };
28
+ type RadioField = BaseField & {
29
+ type: "radio";
30
+ options: FieldOptions;
31
+ };
32
+ type ArrayField<Props extends {
33
+ [key: string]: any;
34
+ } = {
35
+ [key: string]: any;
36
+ }> = BaseField & {
37
+ type: "array";
38
+ arrayFields: {
39
+ [SubPropName in keyof Props[0]]: Field<Props[0][SubPropName]>;
40
+ };
41
+ defaultItemProps?: Props[0];
42
+ getItemSummary?: (item: Props[0], index?: number) => string;
43
+ max?: number;
44
+ min?: number;
45
+ };
46
+ type ObjectField<Props extends {
47
+ [key: string]: any;
48
+ } = {
49
+ [key: string]: any;
50
+ }> = BaseField & {
51
+ type: "object";
52
+ objectFields: {
53
+ [SubPropName in keyof Props]: Field<Props[SubPropName]>;
54
+ };
55
+ };
56
+ type Adaptor<AdaptorParams = {}, TableShape extends Record<string, any> = {}, PropShape = TableShape> = {
57
+ name: string;
58
+ fetchList: (adaptorParams?: AdaptorParams) => Promise<TableShape[] | null>;
59
+ mapProp?: (value: TableShape) => PropShape;
60
+ };
61
+ type ExternalFieldWithAdaptor<Props extends {
62
+ [key: string]: any;
63
+ } = {
64
+ [key: string]: any;
65
+ }> = BaseField & {
66
+ type: "external";
67
+ placeholder?: string;
68
+ adaptor: Adaptor<any, any, Props>;
69
+ adaptorParams?: object;
70
+ getItemSummary: (item: Props, index?: number) => string;
71
+ };
72
+ type ExternalField<Props extends {
73
+ [key: string]: any;
74
+ } = {
75
+ [key: string]: any;
76
+ }> = BaseField & {
77
+ type: "external";
78
+ placeholder?: string;
79
+ fetchList: (params: {
80
+ query: string;
81
+ filters: Record<string, any>;
82
+ }) => Promise<any[] | null>;
83
+ mapProp?: (value: any) => Props;
84
+ mapRow?: (value: any) => Record<string, string | number>;
85
+ getItemSummary?: (item: Props, index?: number) => string;
86
+ showSearch?: boolean;
87
+ initialQuery?: string;
88
+ filterFields?: Record<string, Field>;
89
+ initialFilters?: Record<string, any>;
90
+ };
91
+ type CustomField<Props extends {
92
+ [key: string]: any;
93
+ } = {
94
+ [key: string]: any;
95
+ }> = BaseField & {
96
+ type: "custom";
97
+ render: (props: {
98
+ field: CustomField;
99
+ name: string;
100
+ value: any;
101
+ onChange: (value: Props) => void;
102
+ readOnly?: boolean;
103
+ }) => ReactElement;
104
+ };
105
+ type Field<Props extends {
106
+ [key: string]: any;
107
+ } = {
108
+ [key: string]: any;
109
+ }> = TextField | NumberField | TextareaField | SelectField | RadioField | ArrayField<Props> | ObjectField<Props> | ExternalField<Props> | ExternalFieldWithAdaptor<Props> | CustomField;
110
+
111
+ type Entry<Fields extends Record<string, any> = {}> = BaseEntry & {
112
+ fields: Fields;
113
+ };
114
+ declare function createFieldContentful<T extends Entry = Entry>(contentType: string, options?: {
115
+ client?: ContentfulClientApi<undefined>;
116
+ space?: string;
117
+ accessToken?: string;
118
+ titleField?: string;
119
+ filterFields?: ExternalField["filterFields"];
120
+ initialFilters?: ExternalField["initialFilters"];
121
+ }): ExternalField<T>;
122
+
123
+ export { 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 field_contentful_exports = {};
69
+ __export(field_contentful_exports, {
70
+ createClient: () => import_contentful.createClient,
71
+ createFieldContentful: () => createFieldContentful,
72
+ default: () => field_contentful_default
73
+ });
74
+ module.exports = __toCommonJS(field_contentful_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(this, [_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 field_contentful_default = createFieldContentful;
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ createClient,
119
+ createFieldContentful
120
+ });
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@measured/puck-field-contentful",
3
+ "version": "0.14.0-canary.053d4c6",
4
+ "author": "Measured Corporation Ltd <hello@measured.co>",
5
+ "repository": "measuredco/puck",
6
+ "bugs": "https://github.com/measuredco/puck/issues",
7
+ "homepage": "https://puckeditor.com",
8
+ "private": false,
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "license": "MIT",
12
+ "scripts": {
13
+ "lint": "eslint \"**/*.ts*\"",
14
+ "build": "rm -rf dist && tsup index.ts",
15
+ "prepare": "yarn build"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "devDependencies": {
21
+ "@measured/puck": "^0.14.0-canary.053d4c6",
22
+ "@types/react": "^18.2.0",
23
+ "@types/react-dom": "^18.2.0",
24
+ "contentful": "^10.8.6",
25
+ "eslint": "^7.32.0",
26
+ "eslint-config-custom": "*",
27
+ "tsconfig": "*",
28
+ "tsup-config": "*",
29
+ "typescript": "^4.5.2"
30
+ },
31
+ "peerDependencies": {
32
+ "@measured/puck": "^0.13.0",
33
+ "contentful": "^10.0.0",
34
+ "react": "^17.0.0 || ^18.0.0"
35
+ }
36
+ }