-
-
Notifications
You must be signed in to change notification settings - Fork 779
/
index.ts
186 lines (164 loc) · 4.74 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import type { UnoGenerator, UserConfig, UserConfigDefaults } from '@unocss/core'
import { createGenerator } from '@unocss/core'
import { autoPrefixer } from './utils'
export interface RuntimeOptions {
/**
* Default config of UnoCSS
*/
defaults?: UserConfigDefaults
/**
* Enable css property auto prefixer
* @default false
*/
autoPrefix?: boolean
}
export type RuntimeInspectorCallback = (element: Element) => boolean
declare global {
interface Window {
__unocss?: UserConfig & { runtime?: RuntimeOptions }
__unocss_runtime?: {
/**
* The UnoCSS instance.
*
* @type {UnoGenerator}
*/
uno: UnoGenerator
/**
* Run extractor on specified tokens
*
* @returns {Promise<void>}
*/
extract: (tokens: string | string[]) => Promise<void>
/**
* Rerun extractor on the whole <body>, regardless of paused status or inspection limitation.
*
* @returns {Promise<void>}
*/
extractAll: () => Promise<void>
/**
* Set/unset inspection callback to allow/ignore element to be extracted.
*
* @param {RuntimeInspectorCallback} [callback] - Callback to determine whether the element will be extracted.
*
* @returns {void}
*/
inspect: (callback?: RuntimeInspectorCallback) => void
/**
* Pause/resume/toggle the runtime.
*
* @param {boolean} [state] - False or True respectively pause or resume the runtime. Undefined parameter toggles the pause/resume state.
*
* @returns {void}
*/
toggleObserver: (state?: boolean) => void
/**
* The UnoCSS version.
*
* @type {string}
*/
version: string
}
}
}
export default function init(options: RuntimeOptions = {}) {
if (typeof window == 'undefined') {
console.warn('@unocss/runtime been used in non-browser environment, skipped.')
return
}
const defaultOptions = options.defaults || {}
if (options.autoPrefix) {
let postprocess = defaultOptions.postprocess
if (!postprocess)
postprocess = []
if (!Array.isArray(postprocess))
postprocess = [postprocess]
postprocess.unshift(autoPrefixer(document.createElement('div').style))
defaultOptions.postprocess = postprocess
}
Object.assign(options, window.__unocss?.runtime)
let styleElement: HTMLStyleElement | undefined
let paused = false
let inspector: RuntimeInspectorCallback | undefined
const uno = createGenerator(window.__unocss || {}, defaultOptions)
const tokens = new Set<string>()
let _timer: number | undefined
const scheduleUpdate = () => new Promise((resolve) => {
if (_timer != null)
clearTimeout(_timer)
_timer = setTimeout(() => updateStyle().then(resolve), 0) as any
})
async function updateStyle() {
const result = await uno.generate(tokens)
if (!styleElement) {
styleElement = document.createElement('style')
document.documentElement.prepend(styleElement)
}
styleElement.innerHTML = result.css
}
async function extract(str: string) {
await uno.applyExtractors(str, undefined, tokens)
await scheduleUpdate()
}
async function extractAll() {
const html = document.body && document.body.outerHTML
if (html)
await extract(html)
}
const mutationObserver = new MutationObserver((mutations) => {
if (paused)
return
mutations.forEach((mutation) => {
const target = mutation.target as Element
if (target === styleElement)
return
if (inspector && !inspector(target))
return
const attrs = Array.from(target.attributes)
.map(i => i.value ? `${i.name}="${i.value}"` : i.name)
.join(' ')
const tag = `<${target.tagName.toLowerCase()} ${attrs}>`
extract(tag)
})
})
let observing = false
function observe() {
if (!observing)
return
const target = document.documentElement || document.body
if (!target)
return
mutationObserver.observe(target, {
childList: true,
subtree: true,
attributes: true,
})
observing = true
}
function execute() {
extractAll()
observe()
}
window.__unocss_runtime = window.__unocss_runtime = {
version: uno.version,
uno,
async extract(userTokens) {
if (typeof userTokens === 'string')
return await extract(userTokens)
userTokens.forEach(t => tokens.add(t))
await updateStyle()
},
extractAll,
inspect(callback) {
inspector = callback
},
toggleObserver(set) {
if (set === undefined)
paused = !paused
else
paused = !!set
},
}
execute()
window.addEventListener('load', execute)
window.addEventListener('DOMContentLoaded', execute)
}