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

feat(preset-tagify): new preset #1010

Merged
merged 10 commits into from May 29, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions alias.ts
Expand Up @@ -13,6 +13,7 @@ export const alias: Record<string, string> = {
'@unocss/preset-attributify': r('./packages/preset-attributify/src/'),
'@unocss/preset-icons': r('./packages/preset-icons/src/'),
'@unocss/preset-mini': r('./packages/preset-mini/src/'),
'@unocss/preset-tagify': r('./packages/preset-tagify/src/'),
'@unocss/preset-typography': r('./packages/preset-typography/src/'),
'@unocss/preset-uno': r('./packages/preset-uno/src/'),
'@unocss/preset-web-fonts': r('./packages/preset-web-fonts/src/'),
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -52,6 +52,7 @@
"@unocss/preset-attributify": "workspace:*",
"@unocss/preset-icons": "workspace:*",
"@unocss/preset-mini": "workspace:*",
"@unocss/preset-tagify": "workspace:*",
"@unocss/preset-typography": "workspace:*",
"@unocss/preset-uno": "workspace:*",
"@unocss/preset-web-fonts": "workspace:*",
Expand Down
76 changes: 76 additions & 0 deletions packages/preset-tagify/README.md
@@ -0,0 +1,76 @@
# @unocss/preset-tagify

Taggify Mode for [UnoCSS](https://github.com/unocss/unocss).

## Installation

```bash
npm i -D @unocss/preset-tagify
```

```ts
import preseTagify from '@unocss/preset-tagify'

Unocss({
presets: [
presetTagify({ /* options */ }),
// ...other presets
],
})
```

## Tagify Mode

This preset can come in handy when you only need a single unocss rule to be apply on an element.

```html
<span class="text-red"> red text </span>
<div class="flex"> flexbox </div>
I'm feeling <span class="i-line-md-emoji-grin"></span> today!
```

With tagify mode, you can embed CSS styles into HTML tags:

```html
<text-red> red text </text-red>
<flex> flexbox </flex>
I'm feeling <i-line-md-emoji-grin> </i-line-md-emoji-grin> today!
```

The HTML above works exactly as you would expect.

## With Prefix

```js
presetTagify({
prefix: 'un-'
})
```

```html
<!-- this will be matched -->
<un-flex> </un-flex>
<!-- this will not be matched -->
<flex> </flex>
```

## Extra Properties

You can inject extra properties to the matched rules:

```js
presetTagify({
// adds display: inline-block to matched icons
extraProperties: matched => matched.startsWith('i-')
? { display: 'inline-block' }
: { }
})
presetTagify({
// extraProperties can also be a plain object
extraProperties: { display: 'block' }
})
```

## License

MIT License &copy; 2021-PRESENT [Anthony Fu](https://github.com/antfu)
12 changes: 12 additions & 0 deletions packages/preset-tagify/build.config.ts
@@ -0,0 +1,12 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
'src/index',
],
clean: true,
declaration: true,
rollup: {
emitCJS: true,
},
})
42 changes: 42 additions & 0 deletions packages/preset-tagify/package.json
@@ -0,0 +1,42 @@
{
"name": "@unocss/preset-tagify",
"version": "0.34.1",
"description": "Tagify preset for UnoCSS",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/antfu",
"homepage": "https://github.com/unocss/unocss/tree/main/packages/transformer-variant-group#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/unocss/unocss.git",
"directory": "packages/transformer-variant-group"
},
"bugs": {
"url": "https://github.com/unocss/unocss/issues"
},
"keywords": [
"unocss",
"unocss-preset"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"stub": "unbuild --stub"
},
"dependencies": {
"@unocss/core": "workspace:*"
}
}
16 changes: 16 additions & 0 deletions packages/preset-tagify/src/extractor.ts
@@ -0,0 +1,16 @@
import type { Extractor } from '@unocss/core'

export const MARKER = '__TAGIFY__'
export const htmlTagRE = /<([\w\d-]+)/g
zojize marked this conversation as resolved.
Show resolved Hide resolved

export const extractorTagify = (): Extractor => {
return {
name: 'tagify',
extract({ code }) {
return new Set(
Array.from(code.matchAll(htmlTagRE))
?.map(([, matched]) => `${MARKER}${matched}`),
)
},
}
}
16 changes: 16 additions & 0 deletions packages/preset-tagify/src/index.ts
@@ -0,0 +1,16 @@
import type { Preset } from '@unocss/core'
import type { TagifyOptions } from './types'
import { extractorTagify } from './extractor'
import { variantTagify } from './variant'

export * from './extractor'
export * from './types'
export * from './variant'

const preset = (options?: TagifyOptions): Preset => ({
name: '@unocss/preset-tagify',
variants: [variantTagify(options)],
extractors: [extractorTagify()],
})

export default preset
13 changes: 13 additions & 0 deletions packages/preset-tagify/src/types.ts
@@ -0,0 +1,13 @@
export interface TagifyOptions {
/**
* The prefix to use for the tagify variant.
*/
prefix?: string

/**
* Extra CSS properties to apply to matched rules
*/
extraProperties?:
| Record<string, string>
| ((matched: string) => Partial<Record<string, string>>)
}
32 changes: 32 additions & 0 deletions packages/preset-tagify/src/variant.ts
@@ -0,0 +1,32 @@
import type { VariantHandler, VariantObject } from '@unocss/core'
import type { TagifyOptions } from './types'
import { MARKER } from './extractor'

export const variantTagify = (options: TagifyOptions = {}): VariantObject => {
const prefix = `${MARKER}${options.prefix ?? ''}`

return {
name: 'tagify',
match(input) {
if (!input.startsWith(prefix))
return

const { extraProperties } = options

const handler: VariantHandler = {
matcher: input.slice(prefix.length),
selector: i => i.slice(MARKER.length + 1),
}

if (extraProperties) {
const matched = input.slice(prefix.length)
if (typeof extraProperties === 'function')
handler.body = entries => [...entries, ...Object.entries(extraProperties(matched) ?? {})]
else
handler.body = entries => [...entries, ...Object.entries(extraProperties)]
}

return handler
},
}
}