diff --git a/alias.ts b/alias.ts index de7f0a7fbf..7186b28813 100644 --- a/alias.ts +++ b/alias.ts @@ -40,4 +40,5 @@ export const alias: Record = { '@unocss/vscode': r('./packages/vscode/src/'), '@unocss/postcss': r('./packages/postcss/src/'), '@unocss/webpack': r('./packages/webpack/src/'), + '@unocss/rule-utils': r('./packages/rule-utils/src/'), } diff --git a/packages/README.md b/packages/README.md index ce59dee446..2ec4de9fa6 100644 --- a/packages/README.md +++ b/packages/README.md @@ -33,4 +33,5 @@ | [@unocss/runtime](./runtime) | CSS-in-JS Runtime for UnoCSS | No | - | | [@unocss/eslint-plugin](./eslint-plugin) | ESLint plugin | No | - | | [@unocss/eslint-config](./eslint-config) | ESLint config | No | - | +| [@unocss/rule-utils](./rule-utils) | The utilities for creating rules/presets for UnoCSS | No | - | | [VS Code Extension](./vscode) | UnoCSS for VS Code | - | - | diff --git a/packages/inspector/package.json b/packages/inspector/package.json index ac13721dcd..a35db4f5f2 100644 --- a/packages/inspector/package.json +++ b/packages/inspector/package.json @@ -41,6 +41,7 @@ "update-post": "vite build" }, "dependencies": { + "@unocss/rule-utils": "workspace:*", "gzip-size": "^6.0.0", "sirv": "^2.0.3" } diff --git a/packages/preset-mini/package.json b/packages/preset-mini/package.json index 4672502593..ae02e7207d 100644 --- a/packages/preset-mini/package.json +++ b/packages/preset-mini/package.json @@ -66,6 +66,7 @@ }, "dependencies": { "@unocss/core": "workspace:*", - "@unocss/extractor-arbitrary-variants": "workspace:*" + "@unocss/extractor-arbitrary-variants": "workspace:*", + "@unocss/rule-utils": "workspace:*" } } diff --git a/packages/preset-mini/src/_rules/border.ts b/packages/preset-mini/src/_rules/border.ts index ed359d30cf..3df390b752 100644 --- a/packages/preset-mini/src/_rules/border.ts +++ b/packages/preset-mini/src/_rules/border.ts @@ -1,6 +1,7 @@ import type { CSSEntries, CSSObject, Rule, RuleContext } from '@unocss/core' +import { colorOpacityToString, colorToString } from '@unocss/rule-utils' import type { Theme } from '../theme' -import { colorOpacityToString, colorToString, cornerMap, directionMap, globalKeywords, h, hasParseableColor, parseColor } from '../utils' +import { cornerMap, directionMap, globalKeywords, h, hasParseableColor, parseColor } from '../utils' export const borderStyles = ['solid', 'dashed', 'dotted', 'double', 'hidden', 'none', 'groove', 'ridge', 'inset', 'outset', ...globalKeywords] diff --git a/packages/preset-mini/src/_utils/index.ts b/packages/preset-mini/src/_utils/index.ts index 2cb9b167ad..a8daa4db0a 100644 --- a/packages/preset-mini/src/_utils/index.ts +++ b/packages/preset-mini/src/_utils/index.ts @@ -1,4 +1,3 @@ -export * from './colors' export * from './mappings' export * from './handlers' export * from './variants' diff --git a/packages/preset-mini/src/_utils/utilities.ts b/packages/preset-mini/src/_utils/utilities.ts index 72da9f7047..490b2130b9 100644 --- a/packages/preset-mini/src/_utils/utilities.ts +++ b/packages/preset-mini/src/_utils/utilities.ts @@ -1,7 +1,7 @@ import type { CSSEntries, CSSObject, DynamicMatcher, ParsedColorValue, RuleContext, StaticRule, VariantContext } from '@unocss/core' -import { isString, toArray } from '@unocss/core' +import { toArray } from '@unocss/core' +import { colorOpacityToString, colorToString, getComponents, parseCssColor } from '@unocss/rule-utils' import type { Theme } from '../theme' -import { colorOpacityToString, colorToString, parseCssColor } from './colors' import { h } from './handlers' import { directionMap, globalKeywords } from './mappings' @@ -277,65 +277,3 @@ export function getBracket(str: string, open: string, close: string) { } } } - -export function getComponent(str: string, open: string, close: string, separators: string | string[]) { - if (str === '') - return - - if (isString(separators)) - separators = [separators] - - if (separators.length === 0) - return - - const l = str.length - let parenthesis = 0 - for (let i = 0; i < l; i++) { - switch (str[i]) { - case open: - parenthesis++ - break - - case close: - if (--parenthesis < 0) - return - break - - default: - for (const separator of separators) { - const separatorLength = separator.length - if (separatorLength && separator === str.slice(i, i + separatorLength) && parenthesis === 0) { - if (i === 0 || i === l - separatorLength) - return - return [ - str.slice(0, i), - str.slice(i + separatorLength), - ] - } - } - } - } - - return [ - str, - '', - ] -} - -export function getComponents(str: string, separators: string | string[], limit?: number) { - limit = limit ?? 10 - const components = [] - let i = 0 - while (str !== '') { - if (++i > limit) - return - const componentPair = getComponent(str, '(', ')', separators) - if (!componentPair) - return - const [component, rest] = componentPair - components.push(component) - str = rest - } - if (components.length > 0) - return components -} diff --git a/packages/preset-mini/src/_variants/negative.ts b/packages/preset-mini/src/_variants/negative.ts index 13379ef2c2..11cd478bfd 100644 --- a/packages/preset-mini/src/_variants/negative.ts +++ b/packages/preset-mini/src/_variants/negative.ts @@ -1,5 +1,6 @@ import type { Variant } from '@unocss/core' -import { CONTROL_MINI_NO_NEGATIVE, getComponent } from '../utils' +import { getComponent } from '@unocss/rule-utils' +import { CONTROL_MINI_NO_NEGATIVE } from '../utils' const numberRE = /[0-9.]+(?:[a-z]+|%)?/ diff --git a/packages/preset-uno/package.json b/packages/preset-uno/package.json index c6d58e9124..e3a4d889ce 100644 --- a/packages/preset-uno/package.json +++ b/packages/preset-uno/package.json @@ -56,6 +56,7 @@ "dependencies": { "@unocss/core": "workspace:*", "@unocss/preset-mini": "workspace:*", - "@unocss/preset-wind": "workspace:*" + "@unocss/preset-wind": "workspace:*", + "@unocss/rule-utils": "workspace:*" } } diff --git a/packages/preset-uno/src/variants/mix.ts b/packages/preset-uno/src/variants/mix.ts index e9abd0ec2e..ee72759e39 100644 --- a/packages/preset-uno/src/variants/mix.ts +++ b/packages/preset-uno/src/variants/mix.ts @@ -1,5 +1,5 @@ import type { CSSColorValue, VariantObject } from '@unocss/core' -import { colorToString, parseCssColor } from '@unocss/preset-mini/utils' +import { colorToString, parseCssColor } from '@unocss/rule-utils' function mixComponent(v1: string | number, v2: string | number, w: string | number) { return `calc(${v2} + (${v1} - ${v2}) * ${w} / 100)` diff --git a/packages/preset-wind/package.json b/packages/preset-wind/package.json index 3f59404bf4..9db6eae5e8 100644 --- a/packages/preset-wind/package.json +++ b/packages/preset-wind/package.json @@ -40,6 +40,7 @@ }, "dependencies": { "@unocss/core": "workspace:*", - "@unocss/preset-mini": "workspace:*" + "@unocss/preset-mini": "workspace:*", + "@unocss/rule-utils": "workspace:*" } } diff --git a/packages/preset-wind/src/rules/background.ts b/packages/preset-wind/src/rules/background.ts index 47bb7cdc81..93254cbe82 100644 --- a/packages/preset-wind/src/rules/background.ts +++ b/packages/preset-wind/src/rules/background.ts @@ -1,6 +1,7 @@ import type { CSSColorValue, Rule, RuleContext } from '@unocss/core' -import { colorOpacityToString, colorToString, globalKeywords, h, makeGlobalStaticRules, parseColor, positionMap } from '@unocss/preset-mini/utils' +import { globalKeywords, h, makeGlobalStaticRules, parseColor, positionMap } from '@unocss/preset-mini/utils' import type { Theme } from '@unocss/preset-mini' +import { colorOpacityToString, colorToString } from '@unocss/rule-utils' function bgGradientToValue(cssColor: CSSColorValue | undefined) { if (cssColor) diff --git a/packages/rule-utils/README.md b/packages/rule-utils/README.md new file mode 100644 index 0000000000..8420d72d23 --- /dev/null +++ b/packages/rule-utils/README.md @@ -0,0 +1,7 @@ +# @unocss/rule-utils + +The utilities for creating rules/presets for [UnoCSS](https://github.com/unocss/unocss). + +## License + +MIT License © 2021-PRESENT [Anthony Fu](https://github.com/antfu) diff --git a/packages/rule-utils/build.config.ts b/packages/rule-utils/build.config.ts new file mode 100644 index 0000000000..868e79fab0 --- /dev/null +++ b/packages/rule-utils/build.config.ts @@ -0,0 +1,12 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + 'src/index', + ], + clean: true, + declaration: true, + rollup: { + emitCJS: true, + }, +}) diff --git a/packages/rule-utils/package.json b/packages/rule-utils/package.json new file mode 100644 index 0000000000..d3c0934103 --- /dev/null +++ b/packages/rule-utils/package.json @@ -0,0 +1,42 @@ +{ + "name": "@unocss/rule-utils", + "version": "0.55.7", + "description": "Utilities for UnoCSS", + "author": "Anthony Fu ", + "license": "MIT", + "funding": "https://github.com/sponsors/antfu", + "homepage": "https://github.com/unocss/unocss/tree/main/packages/rule-utils#readme", + "repository": { + "type": "git", + "url": "https://github.com/unocss/unocss", + "directory": "packages/rule-utils" + }, + "bugs": { + "url": "https://github.com/unocss/unocss/issues" + }, + "keywords": [], + "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" + ], + "engines": { + "node": ">=14" + }, + "scripts": { + "build": "unbuild", + "stub": "unbuild --stub" + }, + "dependencies": { + "@unocss/core": "workspace:^" + } +} diff --git a/packages/preset-mini/src/_utils/colors.ts b/packages/rule-utils/src/colors.ts similarity index 100% rename from packages/preset-mini/src/_utils/colors.ts rename to packages/rule-utils/src/colors.ts diff --git a/packages/rule-utils/src/index.ts b/packages/rule-utils/src/index.ts new file mode 100644 index 0000000000..f3a9d575b9 --- /dev/null +++ b/packages/rule-utils/src/index.ts @@ -0,0 +1,2 @@ +export * from './colors' +export * from './utilities' diff --git a/packages/rule-utils/src/utilities.ts b/packages/rule-utils/src/utilities.ts new file mode 100644 index 0000000000..3c0934de3b --- /dev/null +++ b/packages/rule-utils/src/utilities.ts @@ -0,0 +1,63 @@ +import { isString } from '@unocss/core' + +export function getComponent(str: string, open: string, close: string, separators: string | string[]) { + if (str === '') + return + + if (isString(separators)) + separators = [separators] + + if (separators.length === 0) + return + + const l = str.length + let parenthesis = 0 + for (let i = 0; i < l; i++) { + switch (str[i]) { + case open: + parenthesis++ + break + + case close: + if (--parenthesis < 0) + return + break + + default: + for (const separator of separators) { + const separatorLength = separator.length + if (separatorLength && separator === str.slice(i, i + separatorLength) && parenthesis === 0) { + if (i === 0 || i === l - separatorLength) + return + return [ + str.slice(0, i), + str.slice(i + separatorLength), + ] + } + } + } + } + + return [ + str, + '', + ] +} + +export function getComponents(str: string, separators: string | string[], limit?: number) { + limit = limit ?? 10 + const components = [] + let i = 0 + while (str !== '') { + if (++i > limit) + return + const componentPair = getComponent(str, '(', ')', separators) + if (!componentPair) + return + const [component, rest] = componentPair + components.push(component) + str = rest + } + if (components.length > 0) + return components +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8741abc97d..8cea9a49e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -658,6 +658,9 @@ importers: packages/inspector: dependencies: + '@unocss/rule-utils': + specifier: workspace:* + version: link:../rule-utils gzip-size: specifier: ^6.0.0 version: 6.0.0 @@ -765,6 +768,9 @@ importers: '@unocss/extractor-arbitrary-variants': specifier: workspace:* version: link:../extractor-arbitrary-variants + '@unocss/rule-utils': + specifier: workspace:* + version: link:../rule-utils packages/preset-rem-to-px: dependencies: @@ -798,6 +804,9 @@ importers: '@unocss/preset-wind': specifier: workspace:* version: link:../preset-wind + '@unocss/rule-utils': + specifier: workspace:* + version: link:../rule-utils packages/preset-web-fonts: dependencies: @@ -816,6 +825,9 @@ importers: '@unocss/preset-mini': specifier: workspace:* version: link:../preset-mini + '@unocss/rule-utils': + specifier: workspace:* + version: link:../rule-utils packages/reset: devDependencies: @@ -826,6 +838,12 @@ importers: specifier: ^13.0.0 version: 13.0.0 + packages/rule-utils: + dependencies: + '@unocss/core': + specifier: workspace:^ + version: link:../core + packages/runtime: dependencies: '@unocss/core': diff --git a/test/color.test.ts b/test/color.test.ts index e84ccbc052..968724e376 100644 --- a/test/color.test.ts +++ b/test/color.test.ts @@ -1,6 +1,8 @@ import type { RuleContext } from '@unocss/core' import { createGenerator } from '@unocss/core' -import { colorResolver, colorToString, colorableShadows, hex2rgba, parseCssColor } from '@unocss/preset-mini/utils' +import { colorResolver, colorableShadows } from '@unocss/preset-mini/utils' +import { colorToString, hex2rgba, parseCssColor } from '@unocss/rule-utils' + import { describe, expect, it } from 'vitest' describe('color utils', () => { diff --git a/test/utils.test.ts b/test/utils.test.ts index f3e3a1408d..f83e2dae51 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,8 +1,8 @@ import { mergeDeep } from '@unocss/core' -import { getComponent } from '@unocss/preset-mini/utils' import { expect, it } from 'vitest' import { addRemToPxComment, getColorString } from '@unocss/vscode/utils' import { cartesian } from '@unocss/autocomplete' +import { getComponent } from '@unocss/rule-utils' it('mergeDeep', () => { expect(mergeDeep({ diff --git a/tsconfig.json b/tsconfig.json index 2ebbbee0df..9d61625be5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,6 +51,7 @@ "@unocss/webpack": ["./packages/webpack/src/index.ts"], "@unocss/astro": ["./packages/astro/src/index.ts"], "@unocss/postcss": ["./packages/postcss/src/index.ts"], + "@unocss/rule-utils": ["./packages/rule-utils/src/index.ts"], "unocss": ["./packages/unocss/src/index.ts"], "unocss/vite": ["./packages/unocss/src/vite.ts"] }