easyblockshq / easyblocks

The open-source visual builder framework.
https://easyblocks.io
GNU Affero General Public License v3.0
344 stars 55 forks source link

Feature: Tailwilnd support #43

Open timoconnellaus opened 6 months ago

timoconnellaus commented 6 months ago

I want to start a discussion on tailwind support for easyblocks. I've been working on a POC of this. The way it works is this:

Add a special prop in the styles function tw that returns classnames for no code components

const ItemWrappers = values.DummyComponentCollection.map((c: any) => {
  return `bg-[${values.backgroundColor}]`;
});

styled: {
  Root: {}, // we still include an empty styles object - but I think this should be removed
  ItemWrappers: ItemWrappers.map((i: any) => ({})),
},
props: {
  tw: {
    Root: `bg-[${values.backgroundColor}] pt-[${values.padding}]`,
    ItemWrappers, // there is support for arrays
  },
},

We still use the no code components as usual - but now they have a className property automatically applied. For example, if we defined the backgroundColor of Root to #ffffff then the component deefined like this

<Root.type {...Root.props />

would have the className

className="bg-[#ffffff]"

And if we defined it using responsive values for lg = #000000 and xl = #ffffff the className would be

className="bg-[#000000] xl:bg-[#ffffff]"

in compileComponent.tsx we decode the $res object created in the props.tw and add it to a __className attribute on the styled object. This logic is complex and handles doing this:

In ComponentBuilder.tsx we move the __className to a prop on the react element

To handle actually rendering the tailwind css we leave that actually up to the person using the library. To make that easier, we add a subscribe callback to the editorWindowAPI that allows for receiving events that happen e.g. renderableContent

export type EditorWindowAPI = {
  editorContext: EditorContextType;
  onUpdate?: () => void; // this function will be called by parent window when data is changed, child should "subscribe" to this function

  // these callbacks are used by the useEasyblocksEditor hook
  onUpdateCallbacks?: Array<
    (eventType: EditorWindowAPICallbackEventType) => void
  >;
  subscribe: (
    callback: (eventType: EditorWindowAPICallbackEventType) => void
  ) => void;
  unsubscribe: (
    callback: (eventType: EditorWindowAPICallbackEventType) => void
  ) => void;

  meta: CompilationMetadata;
  compiled: CompiledShopstoryComponentConfig;
  externalData: ExternalData;
};

This can be used in the the project calling the EasyblocksEditor to scan editorWindowAPI.compiled to look for tailwind classes and update the CSS

In our case we have this library to generate CSS (https://github.com/mhsdesign/jit-browser-tailwindcss) and then we update the CSS in nextjs like this

<style jsx global>
  {`
    ${css}
  `}
</style>

I will submit a PR for this after we have some done more testing to make sure it is all working

We're currently converting the example components to use tailwind

The rationale of putting the logic in the styles function is that this makes moving over existing components to use tailwind. It also makes converting the logic more straightforward. We had tried using a separate tailwind function but the extensive amount of logic to get it working cause tons of issues and edge cases to deal with. Integrating into styles was more reliable by far

timoconnellaus commented 6 months ago

There are a few things I think that need worked on to make this work:

timoconnellaus commented 6 months ago

The code is a bit inprogress but you can check out what I've been working on here: https://github.com/SweenyStudio/easyblocks/tree/merged-customisations

timoconnellaus commented 6 months ago

I have submited a PR for this - #44

r00dY commented 6 months ago

Hey @timoconnellaus you're doing great work here. I know it's an overwhelming task, a lot of digging into the deep internals of Easyblocks.

We've been thinking about Tailwind for some time already and I think it could be done differently. Actually with changes that are not huge we could detach from Stitches completely and open up for any styling solution, Tailwind would be just a "module", equal to a current Stitches renderer. I can help you with that, I'll schedule a day next week to build a POC. Will update as soon as I have sth.