Giter Site home page Giter Site logo

Comments (5)

sastan avatar sastan commented on August 22, 2024

I see your point. The twind module will not contain server or shim functionality. But we should definitely simplify the most common cases. We have to consider several things here:

  • we need a sheet to collect the styles
  • the sheet needs to be reseted before (or after) rendering
  • we need to adjust the class atributes in the html, which may change the html
  • provide a way to extract the generated styles

Below is my attempt for a minimal API to support these requirements.

import { tw, shim, getStyleTag } from 'twind/server' 

// 0. Start with fresh instance (sheet) - optional as getStyleTag can do that after extracting the styles
// tw.reset()

// 1. Shim the html - adjust the class attributes
let html = shim(`
  <div class="${tw`text-xl`} block px-20 text-green-100">
    can optionally use the tw function or vanilla Tailwind to sprinkle classes 
  </div>
`)

// 2. Create the style tag
let styleTag = getStyleTag(tw)

@drschwabe What do you think?

from twind.

drschwabe avatar drschwabe commented on August 22, 2024

hey that looks awesome! Super lightweight. Would look great near the top of your README :) Really the only thing to understand then is to wrap your html template with the shim function when you want to use tw`` in template literal.

that said, the one thing for me here that is slightly unintiutive is the tw object being a sort of instance unexplictly.
To me let styleTag = getStyleTag(tw) is not clicking - seems the getStyleTag should operate on the html var as it is the 'instance' here, no ? ie: let styleTag = getStyleTag(html)

that aside, this is maybe separate issue but while we're at it also would be neat if the tw function could be used without template literals as well to provide a sort of extended / alternate API.

let html = shim(`
  <div class="${tw`text-xl` tw.py(20)  tw.text('green', 80)  tw.bg( tw.randomColor() ) } block px-20">
    can optionally use the tw template literal function, tailwind imperative library functions or vanilla 
    Tailwind to sprinkle classes 
  </div>
`)

but anyway; I will conclude here as you will know best! I am still just lazily window shopping / drive by spitballing here; have yet to use twind in production but I am rather excited about using it particularly since you are giving this API TLC. Keep up the great work !

from twind.

drschwabe avatar drschwabe commented on August 22, 2024

Just to elaborate thoughts on the 'instance' ... the benefit of narrow scope imperative functions that operate on objects or 'the instance' is that your code becomes obvious when said instance is modified; easier to follow what is happening.

In your example above it looks like tw is both an instance and a functional utility; so this is potentially conflating these 2 important concepts.

In the broader sense of Taiilwind itself it seems that is in fact the 'utility', not an instance. A 'sheet' is certainly good candidate for an instance. The html string itself is also another good candidate, since the 'sheet' may ultimately end up in the same rendered result. Consider perhaps abstracting away the 'shim':

import { tw, Sheet, getStyleTag } from 'twind/server' 

let html = new Sheet() 

html(`
  <div class="${tw`text-xl`} block px-20 text-green-100">
    can optionally use the tw function or vanilla Tailwind to sprinkle classes 
  </div>
`)

let styleTag = getStyleTag(html)

let renderedResult =  `<!DOCTYPE html>
 <html lang="en">
   <head>${styleTag}</head>
   <body>${  html()  }</body>
 </html>`
//^ where html() simply returns the cached result of the original
// sheet call aka html(`some string`) which actually performs your 
// original shim function when fed a string, 
// otherwise it returns a new instance if called with new keyword. 

from twind.

sastan avatar sastan commented on August 22, 2024

Really the only thing to understand then is to wrap your html template with the shim function when you want to use tw`` in template literal.

Not quite right. The shim is needed for those classes that are not using tw:

// No need for the shim
let html = `<div class="${tw`text-xl`}">`

// Needs the shim to find class attributes which values are passed to tw
// The resulting html has those classes replaced with the result of tw
let html = shim(`<div class="text-xl">`)

The shim responsibility to find class attributes, pass them to tw, adjust the class attribute and return the new html string.

that said, the one thing for me here that is slightly unintiutive is the tw object being a sort of instance unexplictly.
To me let styleTag = getStyleTag(tw) is not clicking - seems the getStyleTag should operate on the html var as it is the 'instance' here, no ? ie: let styleTag = getStyleTag(html)

getStyleTag responsibility is to get the styles from the sheet and create a style tag. What you are proposing would add the shim step into getStyleTag which is not always wanted and in my opinion a separate task.

that aside, this is maybe separate issue but while we're at it also would be neat if the tw function could be used without template literals as well to provide a sort of extended / alternate API.

let html = shim(`
  <div class="${tw`text-xl` tw.py(20)  tw.text('green', 80)  tw.bg( tw.randomColor() ) } block px-20">
    can optionally use the tw template literal function, tailwind imperative library functions or vanilla 
    Tailwind to sprinkle classes 
  </div>
`)

That API would have huge API surface although not necessary difficult to implement and could be implemented in user-land aka I do not see this as a part of tw:

tw.py = function (size) {
  this(`py-${size}`)
}

// Or as a Proxy (not tested, not respecting variants)
twind = new Proxy(tw, {
  get(target, prop) {
   return (...args) => target([props ...args].join('-'))
  }
})
twind.text('green', 80)

I will conclude here as you will know best! I am still just lazily window shopping / drive by spitballing here;

I value this input as it allows to see the problem from a different angle. 👍

Keep up the great work !

Thank you that means a lot.

Just to elaborate thoughts on the 'instance' ... the benefit of narrow scope imperative functions that operate on objects or 'the instance' is that your code becomes obvious when said instance is modified; easier to follow what is happening.

Absolutely agree. That is what we are aiming for. But sometime we need to make tradeoffs to enhance the API usability.

In your example above it looks like tw is both an instance and a functional utility; so this is potentially conflating these 2 important concepts.

tw is not a pure function. It converts input tokens into class names and as a side effect adds their styles into a sheet (in the browser a style tag or a custom like the virtualSheet). Additionally it already has internal state, like caches.

Currently we expose this side-effect as the sheet which has to be used explicitly. What I'm proposing is hiding the sheet (as it is/may confuse beginners). It would still be used as it an integral part of the architecture.

Let take a look at how the two use case (no shim and shim):

  1. Using the tw
let html = `<div class="${tw`text-xl block px-20 text-green-100`}">...</div>`

// Read: get my the styles that tw has created
let styleTag = getStyleTag(tw)

This could be moved into a helper:

const render = (html) => {
  // Optionally we could apply the shim here
  return { html, styleTag = getStyleTag(tw) }
}

let { html, styleTag } = render(`<div class="${tw`text-xl block px-20 text-green-100`}">...</div>`)
  1. Using the shim
//  Read: apply tw on all class attributes and return the adjusted html
let html = shim(`
  <div class="text-xl block px-20 text-green-100">
    can optionally use the tw function or vanilla Tailwind to sprinkle classes 
  </div>
`)

 // Read: get my the styles that the shim has created
let styleTag = getStyleTag()

I agree that shim and getStyleTag look a bit disconnected here.

Maybe we could return an object:

let { html, styleTag } = shim(`
  <div class="text-xl block px-20 text-green-100">
    can optionally use the tw function or vanilla Tailwind to sprinkle classes 
  </div>
`)

from twind.

sastan avatar sastan commented on August 22, 2024

Moved to a discussion #123

from twind.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.