Comments (5)
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.
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.
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.
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 melet styleTag = getStyleTag(tw)
is not clicking - seems the getStyleTag should operate on the html var as it is the 'instance' here, no ? ie: letstyleTag = 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):
- 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>`)
- 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.
Moved to a discussion #123
from twind.
Related Issues (20)
- [Feature]: flex-shrink-* is deprecated HOT 1
- missing data HOT 1
- How to use tailwindcss plugins? HOT 3
- Is there a way to make tailwind-scrollbar plugin to work with twind? HOT 3
- [Bug]: keyframes added with injectGlobal only contain the last keyframe HOT 2
- [Bug]: Classes added with injectGlobal can't reference each other with @apply HOT 2
- [Bug]: Classes added with injectGlobal can't be used with variants HOT 2
- [Feature]: allow peer dep of typescript v5 HOT 2
- [Bug]: max-w-{number} does not work
- defineConfig / setup mixed up[Docs]:
- Template literals like className={tw`bg-green-${c}`}
- How to style host and slot elements with Lit HOT 2
- [Docs]: twind.dev is out of date and still seems active HOT 1
- [Feature]: support vars in square brackts
- [Bug]: How to extend theme in Tailwind v3.4 HOT 2
- Browser version doesn't work (non-ES module version) HOT 7
- Applying classes on Lit element CSS block HOT 1
- [Bug]: withTwind doesn't play nicely with Light DOM Lit elements
- [Bug]: Lit & Dark Mode not usable with "class" mode HOT 1
- [Bug]: Update typescript version to 5.x.x HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from twind.