- prevent invalid default rule in legacy browsers (
ccc9c9a9
)
- do not replace window and document for deno bundles (
5fd4bb08
)
-
create dedicated worker and deno bundles, and downgrade module to es2019 (fixes #426) (
02ea227a
) -
add
@twind/with-react
package with support for React v18 streamed responses (fixes #409) (6521e678
)- the
@twind/with-remix
package is deprecated in favor of the@twind/with-react
package - added a Remix with React v18 and renderToPipeableStream example: examples/with-remix_react-v18 (related to #400 & #408)
- the
-
ensure that all functions from the internal context are destructurable (fixes #423) (
c832b338
)
-
automatically add
content: ''
tobefore
andafter
variant styles (closes #405, related to #414) (58c87006
) -
Add support for configuring default font-feature-settings for a font-family (
b24af095
) -
add
supports-*
variant (9254d208
)
-
add new web components integration (
c64fb457
) -
add Lit example (
e06a4830
) -
workaround webpack accessing the prototype in dev mode (
64f1ea37
)
- Fixes "warn" message doesn't respect
event.preventDefault()
(#403) (#412) 🙏🏽 @wzulfikar!
-
add @twind/preset-container-queries (
0ba8cca0
) -
respect modifier and non-alphanumeric chars in precedence (
0ba8cca0
) -
improve slotting based on at-rule width (
0ba8cca0
)
-
introduce new @twind/core package to prevent issue with existing code that imports from CDNs without a version (
4cab9d2f
) -
prevent name mangling of toplevel variables when creating a iife script (
4cab9d2f
)
-
helpful error message during dev when no active twind instance is found (
fe891f9c
) -
big documentation update (
a63ca2cb
) -
allow for
cssom
anddom
to accept a selector string to find the server rendered stylesheet (e2c17a2e
) -
BREAKING: use
install
instead ofsetup
for cdn configuration to align with other integrations (d481948b
) -
handle hex encoded ampersand (
a61e0d1d
) -
warn about invalid classes and invalid css during development (
e6acbea2
)When run in development mode, which is determined by the export condition
development
, twind notifies about invalid classes and invalid css.Further reading:
In the the browser a
warning
event is emitted on thewindow
object and, in case there is no event listener or the event listener did not callevent.preventDefault()
, a warning is logged to the console.addEventListener('warning', (event) => { // prevent default console.warn(`[<code>] <message>: <detail>`) logging event.preventDefault() const warning = event.detail // { message: '...', code: 'TWIND_INVALID_CLASS', detail: '<className>'} // { message: '...', code: 'TWIND_INVALID_CSS', detail: '<css>'} console.warn(warning) })
In Node.js a warning is emitted using
process.emitWarning
.If there is no
warning
event listener, the warning is printed tostderr
.(node:56338) [TWIND_INVALID_CLASS] Warning: ...
Alternatively, you can use the
process.on('warning', ...)
to handle warnings.import process from 'node:process' process.on('warning', (warning) => { console.warn(warning.message) // Print the warning message console.warn(warning.code) // 'TWIND_INVALID_CLASS' | 'TWIND_INVALID_CSS' console.warn(warning.detail) // '<className>' | '<css>' })
-
initial intellisense support (
2ac8e695
) -
stringify in user config always wins (
0705e419
)
-
helpful error message during dev when no active twind instance is found (fe891f9c)
-
allow for
cssom
anddom
to accept a selector string to find the server rendered stylesheet (e2c17a2e) -
BREAKING: use
install
instead ofsetup
for cdn configuration to align with other integrations (d481948b) -
warn about invalid classes and invalid css during development (e6acbea2)
When run in development mode, which is determined by the export condition
development
, twind notifies about invalid classes and invalid css.Further reading:
In the the browser a
warning
event is emitted on thewindow
object and, in case there is no event listener or the event listener did not callevent.preventDefault()
, a warning is logged to the console.addEventListener('warning', (event) => { // prevent default console.warn(`[<code>] <message>: <detail>`) logging event.preventDefault() const warning = event.detail // { message: '...', code: 'TWIND_INVALID_CLASS', detail: '<className>'} // { message: '...', code: 'TWIND_INVALID_CSS', detail: '<css>'} console.warn(warning) })
In Node.js a warning is emitted using
process.emitWarning
.If there is no
warning
event listener, the warning is printed tostderr
.(node:56338) [TWIND_INVALID_CLASS] Warning: ...
Alternatively, you can use the
process.on('warning', ...)
to handle warnings.import process from 'node:process' process.on('warning', (warning) => { console.warn(warning.message) // Print the warning message console.warn(warning.code) // 'TWIND_INVALID_CLASS' | 'TWIND_INVALID_CSS' console.warn(warning.detail) // '<className>' | '<css>' })
-
initial intellisense support (2ac8e695)
-
stringify in user config always wins (0705e419)
- configurable Dark Mode ClassName (
774e2bb4
)
- Arbitrary variants (
a3b1bcba
)
- prevent orphaned style tag when calling setup multiple times (closes #321) (
0e2aa5c4
)
injectGlobal
support for@media print (#333, #334) 🙏 @javascriptjedi! ([
9b5e3297`](https://github.com/tw-in-js/twind/commit/9b5e3297470f9d2bdbd4f540d819ee0f42e63595))
- Add
<alpha-value>
placeholder support for custom colors (closes #349) (0a63948e
)
- feat: support rgb and hsl colors opacity conversion (#336) 🙏🏽 @javascriptjedi!
- support alpha values for
theme()
function (bdc0a7a1
)
- fix missing spaces around arithmetic operators (
f74163ba
)
- fix: replace escaped quotes within class names during SSR (
b212b52f
)
- Rewrites HTML entity & when self-referenced groups are used with (p)react (
782f93df
) 🙏🏽 @rschristian!
-
feat: preserve classes created by explicit
tw
calls during SSR (fe88051d
)Previously
inline
andextract
cleared thetw
instance before parsing the html assuming that all classes are available viaclass
attributes. That led to missing styles frominjectGlobal
or explicittw
calls.This change introduces a
snaphot
method ontw
and sheet instances which allows to preserve the classes that are created by explicittw
calls.Default Mode (nothing changed here)
import { inline } from '@twind/core' function render() { return inline(renderApp()) }
Library Mode
import { tw, stringify } from '@twind/core' function render() { // remember global classes const restore = tw.snapshot() // generated html const html = renderApp() // create CSS const css = stringify(tw.target) // restore global classes restore() // inject as last element into the head return html.replace('</head>', `<style data-twind>${css}</style></head>`) }
- fix: gradients with arbitrary color stop positions (#296) (
77954405
)
- fix: workaround for replaced
'
and" when using react renderToString
(08c66ee8
)
- relax some typings where the actual generic type does not matter (
28cbaef5
)
- fix: ensure colors DEFAULT values override nested objects (
43d61076
)
- refactor: include full precendence in resume data (
80ce410a
)
- fix: move styles generated by
animation()
intocomponents
layer — this allows to override animation properties using utilities (39b45125
)
-
feat: auto dark colors (
2f8f69d2
)If enabled, automatic dark colors are generated for each light color (eg no
dark:
variant is present). This feature is opt-in and twind provides a builtin function that works with tailwind color palettes (50
,100
,200
, ...,800
,900
).import { autoDarkColor } from '@twind/core' defineConfig({ // for tailwind color palettes: 50 -> 900, 100 -> 800, ..., 800 -> 100, 900 -> 50 darkColor: autoDarkColor, // other possible implementations darkColor: (section, key, { theme }) => theme(`${section}.${key}-dark`) as ColorValue, darkColor: (section, key, { theme }) => theme(`dark.${section}.${key}`) as ColorValue, darkColor: (section, key, { theme }) => theme(`${section}.dark.${key}`) as ColorValue, darkColor: (section, key, context, lightColor) => generateDarkColor(lightColor), })
Example css for
text-gray-900
:.text-gray-900 { --tw-text-opacity: 1; color: rgba(15, 23, 42, var(--tw-text-opacity)); } @media (prefers-color-scheme: dark) { .text-gray-900 { --tw-text-opacity: 1; color: rgba(248, 250, 252, var(--tw-text-opacity)); } }
The auto-generated dark color can be overridden by the usual
dark:...
variant:text-gray-900 dark:text-gray-100
..text-gray-900 { --tw-text-opacity: 1; color: rgba(15, 23, 42, var(--tw-text-opacity)); } @media (prefers-color-scheme: dark) { .text-gray-900 { --tw-text-opacity: 1; color: rgba(248, 250, 252, var(--tw-text-opacity)); } } @media (prefers-color-scheme: dark) { .dark\\:text-gray-100 { --tw-text-opacity: 1; color: rgba(241, 245, 249, var(--tw-text-opacity)); } }
- fix: handle color function in replacement for
theme(...)
(9fc5baec
)
- fix: always use rgba color (
aaad7e44
)
- refactor: move hashing of vars (
--tw-<...>
) from preset-tailwind into core — this allows var hashing without the tailwind preset (ae979d12
)
- fix: prevent double class name hashing (
fc9b0c27
)
- fix: use
text-decoration-line
(346efc4e
)
- fix: ensure theme returns all sections (
8bbc2a42
)
- fix: use same color section detection (
8dfd105b
)
- chore: cleanup eslint rules (
009594c6
)
-
add animation helper (
b56b7282
)import { animation, keyframes } from '@twind/core' const fadeIn = animation( '1s ease-out', keyframes` 0% { opacity: 0; } 100% { opacity: 1; } `, )
- BREAKING: removed support for single line comments (
//
) — CSS comments (/* ... */
) are supported (a3191b5f
)
- adjust typings for
injectGlobal
,keyframes
, andtx
to handle.call
and.apply
correctly (b9da668c
)
- support arrays for @font-face, @import, and @apply in object notation (
a3191b5f
)
-
server side generated styles are resumed in the browser (
b223e5bb
)Server side generated styles now include resume data that allows twind in the browser to know which styles are already included in the stylesheet. This change significantly reduces the time to interactive, supports hashed classes, and prevents missing classes that have been generated by
css
orstyle
and are not yet registered.Resuming styles is enabled by default for
setup
(Shim Mode).import { setup } from '@twind/core' import config from './twind.config' // styles are resumed! setup(config)
If you want to used the
dom
sheet during development or if you currently pass a sheet as the second argument, please switch to the newgetSheet(useDOMSheet?: boolean, disableResume?: boolean)
function. This function returns aSheet
for the current environment —virtual
on server, eitherdom
orcssom
in browsers.import { setup, getSheet } from '@twind/core' import config from './twind.config' setup(config, getSheet(process.env.NODE_ENV != 'production'))
If you want to use resuming styles with Library Mode you need to adjust your code to use
getSheet
:import { twind, getSheet } from '@twind/core' import config from './twind.config' export const tw = twind(config, getSheet(process.env.NODE_ENV != 'production'))
To generate server side styles use either
inline
orextract
:import { inline, extract } from '@twind/core' // 1. using inline const html = inline(renderApp()) // 2. using extract const { html, css } = extract(renderApp()) // add the css to the head using <style data-twind>{css}</style>
The signature of
virtual(includeResumeData?: boolean)
has changed as well. This is technically a breaking change, but I doubt anybody has used the previous possiblevirtual([])
.
- expose the used config via
tw.config
(92037344
)
- fixing the strange bug now (
916e7fb9
)
- bump all packages (
57405812
)
-
mark the twind style sheet (
39001d2a
)<!-- the SSR stylesheet --> <style data-twind="ssr"></style> <!-- the client stylesheet --> <style data-twind></style>
- ensure dark class condition is always applied last (
a15d2655
)
- fix: native methods such as
bind
not working properly when used on twind's apply helper (#269) 🙏🏽 Thanks @IgnusG!
- keyframes can be use within arbitrary values
`animate-[1s_${fadeIn}_ease-out]`
(e1d3433a
)
-
merge multiple group and peer classes (
2c823293
)peer-disabled:peer-first-child:group-hover:group-focus:focus:hover:space-x-4
↓ ↓ ↓ ↓ ↓ ↓
.peer:first-child:disabled ~ .group:focus:hover .peer-disabled\\:peer-first-child\\:group-hover\\:group-focus\\:focus\\:hover\\:space-x-4:focus:hover > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); margin-right: calc(1rem * var(--tw-space-x-reverse)); }
- Fix: keyframes Proxy now passthrough Function's own properties (#270) 🙏🏽 Thanks @danielweck!
-
BREAKING: changed the definition of shortcuts within config.rules (
24b095af
)The new format should be more readable and clear about what is happening.
// defineConfig is optional but helps with type inference defineConfig({ rules: [ /* Some aliases */ // shortcut: styles are generated as defined by twind — same as if they where used alone // shortcut to multiple utilities ['card', 'py-2 px-4 font-semibold rounded-lg shadow-md'], // dynamic shortcut — `$` is everything after the match eg `btn-red` -> `red` ['card-', ({ $ }) => `bg-${$}-400 text-${$}-100 py-2 px-4 rounded-lg`], // single utility alias — need to use `~(...)` as it would be otherwise recognized as a CSS property ['red', '~(text-red-100)'], // apply: styles are generated in order they are declared // apply to multiple utilities ['btn-green', '@(bg-green-500 hover:bg-green-700 text-white)'], // dynamic apply ['btn-', ({ $ }) => `@(bg-${$}-400 text-${$}-100 py-2 px-4 rounded-lg)`], /* Some rules */ ['hidden', { display: 'none' }], // Table Layout // .table-auto { table-layout: auto } // .table-fixed { table-layout: fixed } ['table-(auto|fixed)', 'tableLayout'], // dynamic ['table-', (match, context) => /* ... */], ], })
-
allow
css()
,cx()
, andstyle()
to be used for rule definition (b7280003
)defineConfig({ rules: [ // Using css [ 'target-new-tab', css` target-name: new; target-new: tab; `, ], // dynamic [ 'target-new-(tab|window)', ({ 1: $1 }) => css` target-name: new; target-new: ${$1}; `, ], // Using cx ['highlight(-rounded)?', ({ 1: rounded }) => cx({ 'bg-yellow-200': true, rounded })], // Using style // `box?color=coral` -> `.box\\?color\\=coral{background-color:coral}` // `box?rounded` -> `.box\\?rounded{border-radius:0.25rem}` // `box?color=coral&rounded` -> `.box\\?color\\=coral\\&rounded{background-color:coral;border-radius:0.25rem}` // `box?color=purple&rounded=md` -> `.box\\?color\\=purple\\&rounded\\=md{background-color:purple;border-radius:0.375rem}` [ 'box\\?(.+)', style({ props: { color: { coral: css({ backgroundColor: 'coral', }), purple: css` background-color: purple; `, }, rounded: { '': 'rounded', md: 'rounded-md', }, }, }), ], ], })
- fix: ensure sources are included in sourcemap (
bbbbd88e
)
- add ssr marker to server render twind style (
e8eaae8b
)
- perf: remove unnecessary conditions compare (
b526c888
)
- keyframes: access global tw on usage eg lazily (
bb288434
)
- rewritten token parser to better supported nested brackets (
063b002b
)
- filter rules can be used alone and modify defaults selector to include
::before
and::after
(966fcb93
)
- ensure tw returned by observe is callable (
f1fe9a81
)
- enhance typings for config.theme (
2b91cf29
)
- cssom: the ownerNode might have already been removed (
49002cac
)
- update package badges (
4527aa91
)
- ensure dark variant is handled correctly within nested groups (
18f0caff
)
- add
keyframes
function that lazily injects the keyframes into the sheet and return a unique name (a415d389
)
- add
injectGlobal
which allows to add CSS to the base layer (1800dec7
)
- ensure each varaiant occurs only onces eg is unique (
90da3bbc
)
-
allow CSS to be used in preflight and rules (#252)
setup({ preflight: css` body { background: theme(colors.gray.100); } `, rules: [ [ // bg-red, bg-#ccc, bg-transparent 'bg-', ({ $ }) => css` background-color: ${$}; `, ], ], })
- refactor: handling of nested (shortcuts atm) groups (#252)
- add
apply
and@(...)
that uses the given order (#252)
- inline: pass html to minify function — allows to only include above-the-fold CSS (#252)
- add
tx
as convenient helper fortw(cx(...))
(877152d1
)
- BREAKING:
tw
accepts only a single string argument (usecx
for more feature) this reduces the bundle size for the shim mode by 0.25kb (#251)
- ensure that
dark
variant is always applied first (#251)
- BREAKING: move
darkMode
into twind core (#251)
inline
can accept an options object with aminify
to minify the resulting CSS before injecting it (#251)
- a custom hash function receives the default hash (
0a2daf0f
)
- BREAKING: rename
inject
toinline
(762c5153
)
- revert: remove dom sheet (
6d50cf5f
)
- fix variant cache condition (
1f578c9e
)
- add inject(html) helper to simplify extracting CSS and injecting it into the head element (#247)
- bump to same version (
ca157601
)
- BREAKING(@twind/runtime): renamed
init
tosetup
to better align with other APIs (#245)
-
use
data-twind
to locate SSR style element (#245) -
Updated dependencies [
ae9c1201
,ed21b253
,5d40cc5b
,6bdf326f
,f0715269
,13b806cd
,82de0d53
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- ensure globale
twind_core
variable points to bundled@twind/core
which allows presets to uses it (#244)
- all bundles should use the same globalName
twind
(#244)
- BREAKING(preset authors): removed
preset()
helper to simplify config merging — What needs to change? instead calling preset, return your preset (#244)
- add
comsume(html, tw)
to process static HTML (#244)
-
only update class attributes if the class names within are different (ignore order) (#244)
-
Updated dependencies [
61509050
,d45cdfd9
,6178fdc8
,01ac6b62
,599b903a
,30b374f6
,d9123489
,115a5b07
,a8a0bf49
,0614955f
,67f39048
,2093be98
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- Updated dependencies [
eb875119
]:- @twind/[email protected]
-
introduce
twind/cdn
: a bore bones Tailwind CSS replacement — no additional exports like (cx
,style
orcss
) (9bc26949
) -
Updated dependencies [
9bc26949
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- Updated dependencies [
c595b348
,dc778be0
,2ba630a3
,5848d13f
,f41e367f
,bea09c04
,123fb7f8
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
-
rename
@twind/preset-mini
to@twind/preset-ext
(d9e8c3a1
) -
Updated dependencies [
8d846cf2
,b2c7f824
,3e76ea1b
,9ac89873
,a5f112fa
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- BREAKING: a twind instance is now callable
tw('...')
instead oftw.inject('...')
(#239)
-
setup github actions for auto release (#239)
-
Updated dependencies [
56b9adef
,f618afd7
,bec4218d
,37164d82
,e284b0f4
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
-
adding stitches like style helper (
7360f15a
) -
Updated dependencies [
cc3c4fee
,7360f15a
,be5def30
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- revert to observing document.documentElement and describe a solution to prevent FOUC (
2a9f1685
)
-
re-order args for setup to simplify providing an alternative sheet like
dom()
for enhanced debugging (a7b25242
) -
Updated dependencies [
2a9f1685
,a7b25242
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- allow twind and @twind/runime package to be used outside of a DOM environment (
d8705f9d
)
-
extract runtime into own package with re-worked autoinit using MutationObserver (
aa96aef4
) -
Updated dependencies [
184d96ff
,a3d09cf4
,d8705f9d
,aa96aef4
,881e1e16
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- Updated dependencies [
d68ce341
,2c5792f9
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
-
add
apply
as known from twind v0.16 (230a57ba
) -
Updated dependencies [
af822490
,bda8c19c
,3382dd0b
,230a57ba
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
-
ensure there is config object when called from setTimeout
-
Updated dependencies []:
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- expose
tw
andapply
for twind v0.16 compatibility (79c63ef9
)
- expose setup function to configure twind (
79c63ef9
)
-
BREAKING: renamed umd bundles to global (
twind.global.js
) and there are plain IIFEs (79c63ef9
) -
Updated dependencies [
79c63ef9
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]
-
Initial publish of twind v1 preview (
179b9653
) -
Updated dependencies [
179b9653
]:- @twind/[email protected]
- @twind/[email protected]
- @twind/[email protected]