Skip to content

Commit

Permalink
feat(preset-typography): compatibility mode(#2051) (#2064)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris <1633711653@qq.com>
Co-authored-by: Jeff Yang <n2ya@duck.com>
  • Loading branch information
3 people committed Jan 20, 2023
1 parent f52ea60 commit bb321ca
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 48 deletions.
23 changes: 23 additions & 0 deletions packages/preset-typography/README.md
Expand Up @@ -99,6 +99,14 @@ export default defineConfig({
the `table` element **(NOTE: `not` utility is only usable in class since it is
only used in CSS** **selector & not scanned by UnoCSS)**.

- **Compatibility Options**

This preset used some pseudo-classes which are not widely supported, but you
can disable them.

- If you enabled `noColonNot` or `noColonWhere`, `not-prose` will be unavailable.
- If you enabled `noColonIs`, attributify mode will have a wrong behavior.

## Utilities

| Rule | Styles by this rule |
Expand Down Expand Up @@ -146,6 +154,12 @@ The CSS declarations passed to `cssExtend` will
### Type of `TypographyOptions`

```ts
export interface TypographyCompatibilityOptions {
noColonWhere?: boolean
noColonIs?: boolean
noColonNot?: boolean
}

export interface TypographyOptions {
/**
* The class name to use the typographic utilities.
Expand All @@ -164,6 +178,15 @@ export interface TypographyOptions {
* @defaultValue undefined
*/
cssExtend?: Record<string, CSSObject>

/**
* Compatibility option. Notice that it will affect some features.
* For more instructions, see
* [README](https://github.com/unocss/unocss/tree/main/packages/preset-typography)
*
* @defaultValue undefined
*/
compatibility?: TypographyCompatibilityOptions
}
```

Expand Down
30 changes: 20 additions & 10 deletions packages/preset-typography/src/index.ts
@@ -1,7 +1,8 @@
import type { CSSObject, Preset, RuleContext } from '@unocss/core'
import type { Theme } from '@unocss/preset-mini'
import { toEscapedSelector } from '@unocss/core'
import type { Theme } from '@unocss/preset-mini'
import { getPreflights } from './preflights'
import type { TypographyCompatibilityOptions } from './types/compatibilityOptions'

/**
* @public
Expand All @@ -24,6 +25,16 @@ export interface TypographyOptions {
* @defaultValue undefined
*/
cssExtend?: Record<string, CSSObject>

/**
* Compatibility option. Notice that it will affect some features.
* For more instructions, see
* [README](https://github.com/unocss/unocss/tree/main/packages/preset-typography)
*
* @defaultValue undefined
*/
compatibility?: TypographyCompatibilityOptions

/**
* @deprecated use `selectorName` instead. It will be removed in 1.0.
*/
Expand Down Expand Up @@ -52,15 +63,15 @@ export interface TypographyOptions {
export function presetTypography(options?: TypographyOptions): Preset {
if (options?.className) {
console.warn('[unocss:preset-typography] "className" is deprecated. '
+ 'Use "selectorName" instead.')
+ 'Use "selectorName" instead.')
}
let hasProseClass = false
let escapedSelector = ''
const escapedSelectors = new Set<string>()
const selectorName = options?.selectorName || options?.className || 'prose'
const selectorNameRE = new RegExp(`^${selectorName}$`)
const colorsRE = new RegExp(`^${selectorName}-([-\\w]+)$`)
const invertRE = new RegExp(`^${selectorName}-invert$`)
const cssExtend = options?.cssExtend
const compatibility = options?.compatibility

return {
name: '@unocss/preset-typography',
Expand All @@ -70,8 +81,7 @@ export function presetTypography(options?: TypographyOptions): Preset {
[
selectorNameRE,
(_, { rawSelector }) => {
hasProseClass = true
escapedSelector = toEscapedSelector(rawSelector)
escapedSelectors.add(toEscapedSelector(rawSelector))
return { 'color': 'var(--un-prose-body)', 'max-width': '65ch' }
},
{ layer: 'typography' },
Expand Down Expand Up @@ -132,10 +142,10 @@ export function presetTypography(options?: TypographyOptions): Preset {
preflights: [
{
layer: 'typography',
getCSS: () =>
hasProseClass
? getPreflights(escapedSelector, selectorName, cssExtend)
: undefined,
getCSS: () => {
if (escapedSelectors.size > 0)
return getPreflights({ escapedSelectors, selectorName, cssExtend, compatibility })
},
},
],
}
Expand Down
45 changes: 33 additions & 12 deletions packages/preset-typography/src/preflights/index.ts
@@ -1,13 +1,20 @@
import { mergeDeep } from '@unocss/core'
import type { TypographyCompatibilityOptions } from '../types/compatibilityOptions'
import { DEFAULT } from './default'

function getCSS(
escapedSelector: string,
selectorName: string,
preflights: object,
options: {
escapedSelector: string[]
selectorName: string
preflights: object
compatibility?: TypographyCompatibilityOptions
},
): string {
let css = ''

const { escapedSelector, selectorName, preflights, compatibility } = options
const disableNotUtility = compatibility?.noColonNot || compatibility?.noColonWhere

for (const selector in preflights) {
// @ts-expect-error preflights do not have definitive keys
const cssDeclarationBlock = preflights[selector]
Expand All @@ -25,7 +32,11 @@ function getCSS(
if (match) {
const matchStr = match[0]
s = s.replace(matchStr, '')
return `${escapedSelector} :where(${s})${notProseSelector}${matchStr}`
return escapedSelector.map(e =>
disableNotUtility
? `${e} ${s}${matchStr}`
: `${e} :where(${s})${notProseSelector}${matchStr}`,
).join(',')
}
return null
})
Expand All @@ -38,7 +49,11 @@ function getCSS(
}
else {
// directly from css declaration
css += `${escapedSelector} :where(${selector})${notProseSelector}`
css += escapedSelector.map(e =>
disableNotUtility
? selector.split(',').map(s => `${e} ${s}`).join(',')
: `${e} :where(${selector})${notProseSelector}`,
).join(',')
}

css += '{'
Expand All @@ -54,16 +69,22 @@ function getCSS(
}

export function getPreflights(
escapedSelector: string,
selectorName: string,
cssExtend?: object | undefined,
options: {
escapedSelectors: Set<string>
selectorName: string
cssExtend?: object | undefined
compatibility?: TypographyCompatibilityOptions
},
): string {
const { escapedSelectors, selectorName, cssExtend, compatibility } = options
let escapedSelector = Array.from(escapedSelectors)

// attribute mode -> add class selector with `:is()` pseudo-class function
if (!escapedSelector.startsWith('.'))
escapedSelector = `:is(${escapedSelector},.${selectorName})`
if (!escapedSelector[escapedSelector.length - 1].startsWith('.') && !compatibility?.noColonIs)
escapedSelector = [`:is(${escapedSelector[escapedSelector.length - 1]},.${selectorName})`]

if (cssExtend)
return getCSS(escapedSelector, selectorName, mergeDeep(DEFAULT, cssExtend))
return getCSS({ escapedSelector, selectorName, preflights: mergeDeep(DEFAULT, cssExtend), compatibility })

return getCSS(escapedSelector, selectorName, DEFAULT)
return getCSS({ escapedSelector, selectorName, preflights: DEFAULT, compatibility })
}
@@ -0,0 +1,6 @@
/** @public */
export interface TypographyCompatibilityOptions {
noColonWhere?: boolean
noColonIs?: boolean
noColonNot?: boolean
}

0 comments on commit bb321ca

Please sign in to comment.