Hello again,
as I'm digging deeper into payload, I was wondering on how to setup custom components for
The documentation is a bit scarce on that imo, so I wanted to run the demo project but whenever I clone the repo and run npm run build
or npm run demo
I get errors.
> payload@0.4.4 build
> yarn copyfiles && yarn build:tsc && yarn build:components
yarn run v1.22.4
$ copyfiles -u 1 src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png} dist/
✨ Done in 0.58s.
yarn run v1.22.4
$ tsc --p tsconfig.admin.json && tsc --p tsconfig.server.json
src/admin/hooks/useUnmountEffect.tsx:4:78 - error TS2345: Argument of type '() => React.EffectCallback' is not assignable to parameter of type 'EffectCallback'.
Type 'EffectCallback' is not assignable to type 'void | Destructor'.
Type 'EffectCallback' is not assignable to type 'Destructor'.
Type 'void | Destructor' is not assignable to type 'void | { [UNDEFINED_VOID_ONLY]: never; }'.
Type 'Destructor' is not assignable to type 'void | { [UNDEFINED_VOID_ONLY]: never; }'.
Property '[UNDEFINED_VOID_ONLY]' is missing in type 'Destructor' but required in type '{ [UNDEFINED_VOID_ONLY]: never; }'.
4 const useUnmountEffect = (callback: React.EffectCallback): void => useEffect(() => callback, []);
~~~~~~~~~~~~~~
node_modules/@types/react/index.d.ts:58:34
58 type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
~~~~~~~~~~~~~~~~~~~~~
'[UNDEFINED_VOID_ONLY]' is declared here.
src/admin/hooks/useUnmountEffect.tsx:4:78
4 const useUnmountEffect = (callback: React.EffectCallback): void => useEffect(() => callback, []);
~~~~~~~~~~~~~~
Did you mean to call this expression?
src/admin/index.tsx:21:27 - error TS2741: Property 'xl' is missing in type '{ xs: number; s: number; m: number; l: number; }' but required in type 'Breakpoints'.
21 <WindowInfoProvider breakpoints={{
~~~~~~~~~~~
node_modules/@faceless-ui/window-info/dist/WindowInfoProvider/types.d.ts:6:5
6 xl: number;
~~
'xl' is declared here.
node_modules/@faceless-ui/window-info/dist/WindowInfoProvider/types.d.ts:9:5
9 breakpoints: Breakpoints;
~~~~~~~~~~~
The expected type comes from property 'breakpoints' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<WindowInfoProvider> & Readonly<Props> & Readonly<...>'
src/uploads/getFileByPath.ts:9:27 - error TS2339: Property 'getType' does not exist on type 'typeof import("/Users/dominik/Development/payload/node_modules/@types/mime/index")'.
9 const mimetype = mime.getType(filePath);
~~~~~~~
Found 3 errors.
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
npm ERR! code 2
npm ERR! path /Users/dominik/Development/payload
npm ERR! command failed
npm ERR! command sh -c yarn copyfiles && yarn build:tsc && yarn build:components
npm ERR! A complete log of this run can be found in:
So my question is: How are you supposed to run the demo? Does someone have a writeup?
Hi @SuddenDev,
We use the demo
in the repo as our develepment playground when building new features or troubleshooting. It could be useful for reference, but it might not provide a ton of value for building your own projects with Payload as your dependency. You're welcome to play with it though! You can use npm run dev
for live reload or demo:build
will create a dist of the demo in /dist/bin/
.
I'm not certain about the errors you shared, we use yarn build
when its time to release each new version of Payload. I am not sure how useful that would be for you.
Have you read the docs part about customizing components? https://payloadcms.com/docs/admin/components#fields
Certainly there is more we can provide when it comes to custom fields, what is it you're looking to do? I'm happy to help!
Hi @DanRibbens,
Ah, that's good to know! I thought the demo was also build-able by users, since it's referenced in the docs.
I did read through the documentation, but have a bit of a trouble to wrap my head around it. Maybe it's just me, but an written example guide would be a great addition to the (already good) docs.
Filter
and Cell
are just for the Listview in the panel and don't really need logic in my colorpicker example, since it would just render some stuff (e.g. the hex code), right?I'd highly appreacate it, if you could give like even just a short tutorial or write up!
We will have more tutorials up in the future. I'm going to add this to our list topics to cover in more depth. For now I'll do my best to answer your questions.
What I would recommend is if you have a field that you want to reuse throughout your collections or globals, export it from a single place in your app.
filename: colorField.js
// assuming these are actual components in your app somewhere
import ColorPicker from '../components/ColorPicker';
import ColorChip from '../components/ColorChip';
// let's validate colors just in case
function isHexColor(val) {
return val.match(/^#(?:[0-9a-fA-F]{3}){1,2}$/) || `${val} is not a valid hex color`;
}
const colorField = {
name: 'color',
label: 'Color',
type: 'text',
validate: (val) => isHexColor(val),
admin: {
components: {
Field: ColorPicker,
Cell: ColorChip,
},
},
};
export default colorField;
Then in your collection that uses the color:
filename: Users.js
import colorField from '../fields/colorField';
// optionally you use colorField in your fields array unmodified, this is an example of re-use with collection specific changes
const favoriteColor = {
name: 'favoriteColor',
label: 'Favorite Color',
...colorField
};
const Users = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
},
fields: [
{
name: "email",
label: "Email",
type: "email",
},
favoriteColor,
]
};
export default Users;
Nothing fancy going on here, pretty much just writing javascript. The Payload backend needs to understand the type
but other than that you can do what you want. My example hopefully gives some ideas about structuring your app and keeping it DRY if you plan to reuse a field.
You're right about Filter
and Cell
components these are presentational in the admin UI and nothing more.
Hi @DanRibbens,
thank you so much for the writeup! That makes it a lot more clear now. I somehow thought it would be more difficult, but that actually very straight forward!
Can't wait to start digging in, when I actually need a custom field component.
I mentioned Cell
is presentational only, but there are use cases where you would do something dynamic or add functionality right in the table with an action button or dropdown menu that fires an API call to modify that item.
You could have a Cell
for a status
field that shows as a dropdown that calls the API to update it on change as an example.
We published a blog post that covers how to implement custom fields. Posting here for visibility:
https://payloadcms.com/blog/building-a-custom-field
So I just tried a couple of things with the config. Replacing the Nav was easy, but I got an error when trying to replace views.dashboard. The error code says "not allowed".
My code:
import path from "path";
import React from "react";
import { buildConfig } from "payload/config";
import Pages from "./collections/Pages";
import Portfolio from "./collections/Portfolio";
import Users from "./collections/Users";
import Upload from "./collections/Upload";
export default buildConfig({
serverURL: "http://localhost:3000",
admin: {
user: Users.slug,
indexHTML: path.resolve(__dirname, "./client/index.html"),
components: {
views: {
Dashboard: () => <div>Hello</div>,
},
},
},
collections: [Pages, Portfolio, Users, Upload],
localization: {
locales: ["en", "de"],
defaultLocale: "en",
fallback: true,
},
});
My console:
[nodemon] restarting due to changes...
[nodemon] starting `node server.js`
[23:33:32] INFO (payload): Starting Payload...
[23:33:33] ERROR (payload): There were 1 errors validating your Payload config
[23:33:33] ERROR (payload): 1: "admin.components.views" is not allowed
[nodemon] app crashed - waiting for file changes before starting...
Any Ideas? Did I miss something?
Hi again,
That looks to be a bug with our validation. I'll open an issue so we can get it patched.
edit
This is now closed. #94 and I've published the change in Payload v0.4.5.
Wow, you guys are really quick. Thanks for the quick bugfix!
Cheers!
Hi there, I'm also interested in playing with the demo / sandbox but haven't had any luck starting it up - any ideas?
> payload@0.13.6 dev
> cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts nodemon
[nodemon] 2.0.15
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*.ts demo/**/*
[nodemon] watching extensions: ts,js,json
[nodemon] starting `node ./demo/index.js`
[17:20:24] INFO (payload): Starting Payload...
node:internal/modules/cjs/loader:944
throw err;
^
Error: Cannot find module '../dist/admin/components/forms/Form/context'
Require stack:
- /Users/seth/dev/payload/payload/components/forms.ts
- /Users/seth/dev/payload/payload/demo/collections/CustomComponents/components/fields/Group/Field/index.tsx
- /Users/seth/dev/payload/payload/demo/collections/CustomComponents/index.ts
- /Users/seth/dev/payload/payload/demo/payload.config.ts
- /Users/seth/dev/payload/payload/src/config/load.ts
- /Users/seth/dev/payload/payload/src/index.ts
- /Users/seth/dev/payload/payload/demo/server.ts
- /Users/seth/dev/payload/payload/demo/index.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:941:15)
at Function.Module._load (node:internal/modules/cjs/loader:774:27)
at Module.require (node:internal/modules/cjs/loader:1013:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/Users/seth/dev/payload/payload/components/forms.ts:1:2008)
at Module._compile (node:internal/modules/cjs/loader:1109:14)
at Module._compile (/Users/seth/dev/payload/payload/node_modules/pirates/lib/index.js:99:24)
at Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
at Object.newLoader [as .ts] (/Users/seth/dev/payload/payload/node_modules/pirates/lib/index.js:104:7)
at Module.load (node:internal/modules/cjs/loader:989:32) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/seth/dev/payload/payload/components/forms.ts',
'/Users/seth/dev/payload/payload/demo/collections/CustomComponents/components/fields/Group/Field/index.tsx',
'/Users/seth/dev/payload/payload/demo/collections/CustomComponents/index.ts',
'/Users/seth/dev/payload/payload/demo/payload.config.ts',
'/Users/seth/dev/payload/payload/src/config/load.ts',
'/Users/seth/dev/payload/payload/src/index.ts',
'/Users/seth/dev/payload/payload/demo/server.ts',
'/Users/seth/dev/payload/payload/demo/index.js'
]
}
[nodemon] app crashed - waiting for file changes before starting...
☝🏼 seems like there's dependency on a build for yarn dev
so I tried demo:build
first:
yarn demo:build
yarn run v1.22.17
$ cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts node dist/bin/build
node:internal/modules/cjs/loader:944
throw err;
^
Error: Cannot find module '/Users/seth/dev/payload/payload/dist/bin/build'
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:941:15)
at Function.Module._load (node:internal/modules/cjs/loader:774:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
at node:internal/main/run_main_module:17:47 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
NM I'm up and running, needed to just yarn build
first.
Hey @ssyberg — yep. Good catch! We're actually re-wiring some things so that soon, you won't need to yarn build
before running demo, but for now, that's how it works.
Will be improved shortly. Let us know if you have any questions as you poke around!
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.