@measured/puck-field-contentful 0.14.0-canary.053d4c6
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 +132 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +120 -0
- package/package.json +36 -0
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)
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|