Skip to content

Instantly share code, notes, and snippets.

@OnurGvnc
Last active December 1, 2023 14:28
Show Gist options
  • Save OnurGvnc/d86525cc3c84019b8ab86bcf353813ba to your computer and use it in GitHub Desktop.
Save OnurGvnc/d86525cc3c84019b8ab86bcf353813ba to your computer and use it in GitHub Desktop.
twgroup

twgroup``

usage

import React, { useState } from 'react'
import clsx from 'clsx'
import { twgroup } from '../lib/twgroup'

export const Page(){
  return (
    <div className="p-4 max-w-[800px] mx-auto">
      <div
        className={clsx(
          'text-blue-500',
          twgroup`md:(text-red-500 text-xl)`,
          twgroup`md:hover:(font-bold font-medium)`,
        )}
      >
        Hi!
      </div>
    </div>
  )
}

setup

tailwind.config.js

const { twgroupTransform } = require('./src/lib/twgroup')

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: {
    files: ['./src/**/*.tsx'],
    transform: {
      tsx: twgroupTransform,
    },
  },
}
// https://gist.github.com/OnurGvnc/d86525cc3c84019b8ab86bcf353813ba
// https://twind.dev/handbook/grouping-syntax.html
const { expandGroups } = require('twind')
/**
* @param {TemplateStringsArray} strings
* @param {string[]} expressions
* @returns {string}
*/
function twgroup(strings, ...expressions) {
let str = strings[0]
for (let i = 0; i < expressions.length; i++) {
str += expressions[i] + strings[i + 1]
}
return expandGroups(str)
}
/**
* @param {string} content
* @returns {string}
*/
function twgroupTransform(content) {
const match = content.match(/twgroup`((.|\n|\r\n)*?)`/gm)
if (match) {
match.forEach((str, index) => {
const groupedString = str
.match(/^twgroup`((.|\n|\r\n)*)`/)[1]
.replaceAll('\n', ' ')
.trim()
const expanded = expandGroups(groupedString)
console.log({ expanded })
content = content.replace(str, '`' + expanded + '`')
})
}
return content
}
module.exports = {
twgroup,
twgroupTransform,
}
@OnurGvnc
Copy link
Author

OnurGvnc commented Dec 1, 2023

import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  let result = twMerge(clsx(inputs))
  if (result.includes(':(')) {
    result = expandGroups(result)
  }
  return result
}

// https://gist.github.com/OnurGvnc/d86525cc3c84019b8ab86bcf353813ba

// -----------------------------------------------------------------------------

function expandGroups(input: string) {
  // eslint-disable-next-line no-useless-escape
  const regex = /([\w:\[\]\-\.&]+):?\(([\w\-\:\s]+)\)/g

  const matches = [...input.matchAll(regex)].map((match) => ({
    outside: match[1], // 'md:hover' gibi
    inside: match[2], // 'font-bold font-medium' gibi
  }))

  const plainClassNames: string[] = []
  const xClassNames: string[] = []
  for (const match of matches) {
    xClassNames.push(`${match.outside}x-[${match.inside.replaceAll(' ', ',')}]`)
    match.inside.split(' ').forEach((className) => {
      plainClassNames.push(`${match.outside}${className}`)
    })
  }

  console.log('🟦 matches', plainClassNames)

  // return xClassNames.join(' ')
  return plainClassNames.join(' ')
}

export function twgroup(
  strings: TemplateStringsArray,
  ...expressions: string[]
) {
  let str = strings[0]
  for (let i = 0; i < expressions.length; i++) {
    str += expressions[i] + strings[i + 1]
  }

  const expanded = expandGroups(str)
  console.log('🟦 str', str, expanded)
  return expanded
}

export function twgroupTransform(content: string) {
  const match = content.match(/twgroup`((.|\n|\r\n)*?)`/gm)

  if (match) {
    match.forEach((str, index) => {
      const groupedString = str
        .match(/^twgroup`((.|\n|\r\n)*)`/)?.[1]
        .replaceAll('\n', ' ')
        .trim()
      const expanded = expandGroups(groupedString ?? '')
      console.log({ expanded })
      content = content.replace(str, '`' + expanded + '`')
    })
  }

  return content
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment