Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Tailwilnd support #43

Open
timoconnellaus opened this issue May 14, 2024 · 4 comments
Open

Feature: Tailwilnd support #43

timoconnellaus opened this issue May 14, 2024 · 4 comments

Comments

@timoconnellaus
Copy link

timoconnellaus commented May 14, 2024

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:

  • using the devices to append tailwind classes with sm, lg etc. e.g sm:pt-10. This includes adhering to the tailwind convention of small being the default and then larger sizes are exceptions
  • generating a single className string bsaed on the various classes defined
  • handling arrays of components and applying classNames to the array

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
Copy link
Author

timoconnellaus commented May 14, 2024

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

  • The inbuilt components would need to be converted to support using tailwind classes instead of stitches
  • I think turning off switches when tailwind is turned on would be ideal - but I'm mindful that stitches is deeply embedded. This is a bit overwhelming tbh. I am getting my head around everything slowly but there is a lot to understand
  • it would be nice to build rendering taillwind directly into the product for simplicity - but I think this is a nice to have and keeping it separate for now (it works) is more flexible whilst working through a solution
  • we should be able to create a new EasyBlocks component that has effects as screen size reactivty is handled by the tailwind classes and not in JS
  • I'm also working on a way to test that tailwind classes being generated are correct - I will provide some examples in the PR of unit tests that check the tailwind

@timoconnellaus
Copy link
Author

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
Copy link
Author

I have submited a PR for this - #44

@r00dY
Copy link
Contributor

r00dY commented May 22, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants