Open timoconnellaus opened 5 months ago
@pawel-commerce-studio - @r00dY said I should share this here for you. You can see docs on the repo above - and I have published the package too but it's a work in progress so don't count on it working great yet!
Hey @timoconnellaus !
I went through the code only, but this looks really exciting. I also wanted to do something similar, but more in a Sanity-like way, but this Zod-like style also looks cool. I will try to play with it soon too!
@pawel-commerce-studio - I pushed quite a big update. It's a lot better now! Includes these:
@pawel-commerce-studio @r00dY - A sneak peak of what I'm close to finishing
This is type safe top-to-bottom - it works like this:
The final result is you can build no code components in a completely type safe way - change a type on a widget, get lint errors in your styles function
Here's a simple example
const productWidget = eb.externalWidget({
zodType: z.object({ productId: z.string() }),
component: (props) => {
return <>{props.id}</>;
},
type: "shopify",
callback: async ({ externalData, externalDataId }) => {
return {
a: { type: "text", value: { productId: "asb" } },
b: { type: "text", value: { productId: "asb" } },
};
},
});
// ....
const banner = definition({
schema: schema({
size: group({
height: numberProp().defaultValue(10),
width: numberProp().defaultValue(10),
}),
product: externalCustom("product"),
}),
styles: ({ values }) => {
const { height, width, product } = values;
return {};
},
});
This is the type of the product when you hover in VSCode
import { z } from "zod";
import { eb } from "./eb";
// DEVICES
const devices = eb
// initially set to default devices
.devices({
sm: eb.device().hidden(true), // change properties
})
.mainDevice("md"); // we can set the main device
// WIDGETS
const urlWidget = eb
.inlineWidget({
zodType: z.object({ val: z.string() }),
defaultValue: { val: "" },
component: (props) => {
return <>{props.value.val}</>;
},
})
.label("URL");
const urlWidgetTwo = eb
.inlineWidget({
zodType: z.object({ two: z.string() }),
defaultValue: { two: "" },
component: (props) => {
return <>{props.value.two}</>;
},
})
.label("URL2");
const colorWidget = eb.tokenWidget({
zodType: z.string(),
defaultValue: "#000000",
component: (props) => {
return <>{props.value}</>;
},
});
const productWidget = eb.externalWidget({
zodType: z.object({ productId: z.string() }),
component: (props) => {
return <>{props.id}</>;
},
type: "shopify",
callback: async ({ externalData, externalDataId }) => {
return {
a: { type: "text", value: { productId: "asb" } },
b: { type: "text", value: { productId: "asb" } },
};
},
});
const widgets = eb.widgets({
inline: {
url: urlWidget,
urlTwo: urlWidgetTwo,
},
token: {
color: colorWidget,
},
external: {
product: productWidget,
},
});
// TOKENS
const colorTokens = eb
.colorTokens({
blue: eb.colorToken({ $res: true, xs: "#0000FF", xl: "#0000FF" }),
red: eb.colorToken("red"),
})
.default("blue");
const customToken = eb
.customTokens({
zodType: z.string(),
tokens: {
big: eb.customToken("big"),
small: eb.customToken("small"),
},
})
.default("big");
const customToken2 = eb
.customTokens({
zodType: z.number(),
tokens: {
big: eb.customToken(10),
small: eb.customToken(5),
},
})
.default("big");
const tokens = eb.tokens({
standard: {
color: colorTokens,
},
custom: {
size: customToken,
size2: customToken2,
},
});
// Base Config
// This config sets up tokens and widgets whose types need to be available when setting up easyblocks types
const { inlineType, externalType, tokenType, baseConfigWithTypes } =
eb.baseConfig({
devices: devices,
widgets,
tokens,
});
const urlType = inlineType("url").defaultValue({ val: "www.google.com" });
const colorType = tokenType("color").customValueWidget("color");
const productType = externalType(["product"]);
// Now we add the types to the base config - we now have everything we need to set up definitions
// in a type safe way
const {
definition,
schema,
stringProp,
numberProp,
inlineCustom,
tokenCustom,
externalCustom,
group,
} = baseConfigWithTypes({
inlineTypes: {
url: urlType,
},
tokenTypes: {
color: colorType,
},
externalTypes: {
product: productType,
},
});
export const s = schema({
size: group({
height: numberProp().defaultValue(10),
width: numberProp().defaultValue(10),
}),
title: stringProp().defaultValue("Banner"),
url: inlineCustom("url"),
color: tokenCustom("color"),
product: externalCustom("product"),
});
const banner = definition({
schema: schema({
size: group({
height: numberProp().defaultValue(10),
width: numberProp().defaultValue(10),
}),
title: stringProp().defaultValue("Banner"),
url: inlineCustom("url"),
color: tokenCustom("color"),
product: externalCustom("product"),
}),
styles: ({ values }) => {
const { height, width, title, url, color, product } = values;
return {};
},
});
This repo is the POC of typesafe of config / no code component definitions using zod style notiations
https://github.com/timoconnellaus/eb