@pikacss/core 0.0.46 → 0.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/index.d.mts +3565 -1817
- package/dist/index.mjs +2541 -208
- package/package.json +11 -5
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,891 @@
|
|
|
1
|
-
//#region src/internal/
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
//#region src/internal/generated-shorthand-map.ts
|
|
2
|
+
const PROPERTY_EFFECTS = {
|
|
3
|
+
"accent-color": ["accent-color"],
|
|
4
|
+
"align-content": ["align-content"],
|
|
5
|
+
"align-items": ["align-items"],
|
|
6
|
+
"align-self": ["align-self"],
|
|
7
|
+
"align-tracks": ["align-tracks"],
|
|
8
|
+
"alignment-baseline": ["alignment-baseline"],
|
|
9
|
+
"all": ["all"],
|
|
10
|
+
"anchor-name": ["anchor-name"],
|
|
11
|
+
"anchor-scope": ["anchor-scope"],
|
|
12
|
+
"animation": [
|
|
13
|
+
"animation-delay",
|
|
14
|
+
"animation-direction",
|
|
15
|
+
"animation-duration",
|
|
16
|
+
"animation-fill-mode",
|
|
17
|
+
"animation-iteration-count",
|
|
18
|
+
"animation-name",
|
|
19
|
+
"animation-play-state",
|
|
20
|
+
"animation-timeline",
|
|
21
|
+
"animation-timing-function"
|
|
22
|
+
],
|
|
23
|
+
"animation-composition": ["animation-composition"],
|
|
24
|
+
"animation-delay": ["animation-delay"],
|
|
25
|
+
"animation-direction": ["animation-direction"],
|
|
26
|
+
"animation-duration": ["animation-duration"],
|
|
27
|
+
"animation-fill-mode": ["animation-fill-mode"],
|
|
28
|
+
"animation-iteration-count": ["animation-iteration-count"],
|
|
29
|
+
"animation-name": ["animation-name"],
|
|
30
|
+
"animation-play-state": ["animation-play-state"],
|
|
31
|
+
"animation-range": ["animation-range-end", "animation-range-start"],
|
|
32
|
+
"animation-range-end": ["animation-range-end"],
|
|
33
|
+
"animation-range-start": ["animation-range-start"],
|
|
34
|
+
"animation-timeline": ["animation-timeline"],
|
|
35
|
+
"animation-timing-function": ["animation-timing-function"],
|
|
36
|
+
"animation-trigger": ["animation-trigger"],
|
|
37
|
+
"appearance": ["appearance"],
|
|
38
|
+
"aspect-ratio": ["aspect-ratio"],
|
|
39
|
+
"backdrop-filter": ["backdrop-filter"],
|
|
40
|
+
"backface-visibility": ["backface-visibility"],
|
|
41
|
+
"background": [
|
|
42
|
+
"background-attachment",
|
|
43
|
+
"background-clip",
|
|
44
|
+
"background-color",
|
|
45
|
+
"background-image",
|
|
46
|
+
"background-origin",
|
|
47
|
+
"background-position-x",
|
|
48
|
+
"background-position-y",
|
|
49
|
+
"background-repeat",
|
|
50
|
+
"background-size"
|
|
51
|
+
],
|
|
52
|
+
"background-attachment": ["background-attachment"],
|
|
53
|
+
"background-blend-mode": ["background-blend-mode"],
|
|
54
|
+
"background-clip": ["background-clip"],
|
|
55
|
+
"background-color": ["background-color"],
|
|
56
|
+
"background-image": ["background-image"],
|
|
57
|
+
"background-origin": ["background-origin"],
|
|
58
|
+
"background-position": ["background-position-x", "background-position-y"],
|
|
59
|
+
"background-position-x": ["background-position-x"],
|
|
60
|
+
"background-position-y": ["background-position-y"],
|
|
61
|
+
"background-repeat": ["background-repeat"],
|
|
62
|
+
"background-size": ["background-size"],
|
|
63
|
+
"baseline-shift": ["baseline-shift"],
|
|
64
|
+
"baseline-source": ["baseline-source"],
|
|
65
|
+
"block-size": ["block-size"],
|
|
66
|
+
"border": [
|
|
67
|
+
"border-bottom-color",
|
|
68
|
+
"border-left-color",
|
|
69
|
+
"border-right-color",
|
|
70
|
+
"border-top-color",
|
|
71
|
+
"border-bottom-style",
|
|
72
|
+
"border-left-style",
|
|
73
|
+
"border-right-style",
|
|
74
|
+
"border-top-style",
|
|
75
|
+
"border-bottom-width",
|
|
76
|
+
"border-left-width",
|
|
77
|
+
"border-right-width",
|
|
78
|
+
"border-top-width"
|
|
79
|
+
],
|
|
80
|
+
"border-block": [
|
|
81
|
+
"border-block-end-color",
|
|
82
|
+
"border-block-start-color",
|
|
83
|
+
"border-block-end-style",
|
|
84
|
+
"border-block-start-style",
|
|
85
|
+
"border-block-end-width",
|
|
86
|
+
"border-block-start-width"
|
|
87
|
+
],
|
|
88
|
+
"border-block-color": ["border-block-end-color", "border-block-start-color"],
|
|
89
|
+
"border-block-end": [
|
|
90
|
+
"border-block-end-color",
|
|
91
|
+
"border-block-end-style",
|
|
92
|
+
"border-block-end-width"
|
|
93
|
+
],
|
|
94
|
+
"border-block-end-color": ["border-block-end-color"],
|
|
95
|
+
"border-block-end-style": ["border-block-end-style"],
|
|
96
|
+
"border-block-end-width": ["border-block-end-width"],
|
|
97
|
+
"border-block-start": [
|
|
98
|
+
"border-block-start-color",
|
|
99
|
+
"border-block-start-style",
|
|
100
|
+
"border-block-start-width"
|
|
101
|
+
],
|
|
102
|
+
"border-block-start-color": ["border-block-start-color"],
|
|
103
|
+
"border-block-start-style": ["border-block-start-style"],
|
|
104
|
+
"border-block-start-width": ["border-block-start-width"],
|
|
105
|
+
"border-block-style": ["border-block-end-style", "border-block-start-style"],
|
|
106
|
+
"border-block-width": ["border-block-end-width", "border-block-start-width"],
|
|
107
|
+
"border-bottom": [
|
|
108
|
+
"border-bottom-color",
|
|
109
|
+
"border-bottom-style",
|
|
110
|
+
"border-bottom-width"
|
|
111
|
+
],
|
|
112
|
+
"border-bottom-color": ["border-bottom-color"],
|
|
113
|
+
"border-bottom-left-radius": ["border-bottom-left-radius"],
|
|
114
|
+
"border-bottom-right-radius": ["border-bottom-right-radius"],
|
|
115
|
+
"border-bottom-style": ["border-bottom-style"],
|
|
116
|
+
"border-bottom-width": ["border-bottom-width"],
|
|
117
|
+
"border-collapse": ["border-collapse"],
|
|
118
|
+
"border-color": [
|
|
119
|
+
"border-bottom-color",
|
|
120
|
+
"border-left-color",
|
|
121
|
+
"border-right-color",
|
|
122
|
+
"border-top-color"
|
|
123
|
+
],
|
|
124
|
+
"border-end-end-radius": ["border-end-end-radius"],
|
|
125
|
+
"border-end-start-radius": ["border-end-start-radius"],
|
|
126
|
+
"border-image": [
|
|
127
|
+
"border-image-outset",
|
|
128
|
+
"border-image-repeat",
|
|
129
|
+
"border-image-slice",
|
|
130
|
+
"border-image-source",
|
|
131
|
+
"border-image-width"
|
|
132
|
+
],
|
|
133
|
+
"border-image-outset": ["border-image-outset"],
|
|
134
|
+
"border-image-repeat": ["border-image-repeat"],
|
|
135
|
+
"border-image-slice": ["border-image-slice"],
|
|
136
|
+
"border-image-source": ["border-image-source"],
|
|
137
|
+
"border-image-width": ["border-image-width"],
|
|
138
|
+
"border-inline": [
|
|
139
|
+
"border-inline-end-color",
|
|
140
|
+
"border-inline-start-color",
|
|
141
|
+
"border-inline-end-style",
|
|
142
|
+
"border-inline-start-style",
|
|
143
|
+
"border-inline-end-width",
|
|
144
|
+
"border-inline-start-width"
|
|
145
|
+
],
|
|
146
|
+
"border-inline-color": ["border-inline-end-color", "border-inline-start-color"],
|
|
147
|
+
"border-inline-end": [
|
|
148
|
+
"border-inline-end-color",
|
|
149
|
+
"border-inline-end-style",
|
|
150
|
+
"border-inline-end-width"
|
|
151
|
+
],
|
|
152
|
+
"border-inline-end-color": ["border-inline-end-color"],
|
|
153
|
+
"border-inline-end-style": ["border-inline-end-style"],
|
|
154
|
+
"border-inline-end-width": ["border-inline-end-width"],
|
|
155
|
+
"border-inline-start": [
|
|
156
|
+
"border-inline-start-color",
|
|
157
|
+
"border-inline-start-style",
|
|
158
|
+
"border-inline-start-width"
|
|
159
|
+
],
|
|
160
|
+
"border-inline-start-color": ["border-inline-start-color"],
|
|
161
|
+
"border-inline-start-style": ["border-inline-start-style"],
|
|
162
|
+
"border-inline-start-width": ["border-inline-start-width"],
|
|
163
|
+
"border-inline-style": ["border-inline-end-style", "border-inline-start-style"],
|
|
164
|
+
"border-inline-width": ["border-inline-end-width", "border-inline-start-width"],
|
|
165
|
+
"border-left": [
|
|
166
|
+
"border-left-color",
|
|
167
|
+
"border-left-style",
|
|
168
|
+
"border-left-width"
|
|
169
|
+
],
|
|
170
|
+
"border-left-color": ["border-left-color"],
|
|
171
|
+
"border-left-style": ["border-left-style"],
|
|
172
|
+
"border-left-width": ["border-left-width"],
|
|
173
|
+
"border-radius": [
|
|
174
|
+
"border-bottom-left-radius",
|
|
175
|
+
"border-bottom-right-radius",
|
|
176
|
+
"border-top-left-radius",
|
|
177
|
+
"border-top-right-radius"
|
|
178
|
+
],
|
|
179
|
+
"border-right": [
|
|
180
|
+
"border-right-color",
|
|
181
|
+
"border-right-style",
|
|
182
|
+
"border-right-width"
|
|
183
|
+
],
|
|
184
|
+
"border-right-color": ["border-right-color"],
|
|
185
|
+
"border-right-style": ["border-right-style"],
|
|
186
|
+
"border-right-width": ["border-right-width"],
|
|
187
|
+
"border-spacing": ["border-spacing"],
|
|
188
|
+
"border-start-end-radius": ["border-start-end-radius"],
|
|
189
|
+
"border-start-start-radius": ["border-start-start-radius"],
|
|
190
|
+
"border-style": [
|
|
191
|
+
"border-bottom-style",
|
|
192
|
+
"border-left-style",
|
|
193
|
+
"border-right-style",
|
|
194
|
+
"border-top-style"
|
|
195
|
+
],
|
|
196
|
+
"border-top": [
|
|
197
|
+
"border-top-color",
|
|
198
|
+
"border-top-style",
|
|
199
|
+
"border-top-width"
|
|
200
|
+
],
|
|
201
|
+
"border-top-color": ["border-top-color"],
|
|
202
|
+
"border-top-left-radius": ["border-top-left-radius"],
|
|
203
|
+
"border-top-right-radius": ["border-top-right-radius"],
|
|
204
|
+
"border-top-style": ["border-top-style"],
|
|
205
|
+
"border-top-width": ["border-top-width"],
|
|
206
|
+
"border-width": [
|
|
207
|
+
"border-bottom-width",
|
|
208
|
+
"border-left-width",
|
|
209
|
+
"border-right-width",
|
|
210
|
+
"border-top-width"
|
|
211
|
+
],
|
|
212
|
+
"bottom": ["bottom"],
|
|
213
|
+
"box-align": ["box-align"],
|
|
214
|
+
"box-decoration-break": ["box-decoration-break"],
|
|
215
|
+
"box-direction": ["box-direction"],
|
|
216
|
+
"box-flex": ["box-flex"],
|
|
217
|
+
"box-flex-group": ["box-flex-group"],
|
|
218
|
+
"box-lines": ["box-lines"],
|
|
219
|
+
"box-ordinal-group": ["box-ordinal-group"],
|
|
220
|
+
"box-orient": ["box-orient"],
|
|
221
|
+
"box-pack": ["box-pack"],
|
|
222
|
+
"box-shadow": ["box-shadow"],
|
|
223
|
+
"box-sizing": ["box-sizing"],
|
|
224
|
+
"break-after": ["break-after"],
|
|
225
|
+
"break-before": ["break-before"],
|
|
226
|
+
"break-inside": ["break-inside"],
|
|
227
|
+
"caption-side": ["caption-side"],
|
|
228
|
+
"caret": [
|
|
229
|
+
"caret-animation",
|
|
230
|
+
"caret-color",
|
|
231
|
+
"caret-shape"
|
|
232
|
+
],
|
|
233
|
+
"caret-animation": ["caret-animation"],
|
|
234
|
+
"caret-color": ["caret-color"],
|
|
235
|
+
"caret-shape": ["caret-shape"],
|
|
236
|
+
"clear": ["clear"],
|
|
237
|
+
"clip": ["clip"],
|
|
238
|
+
"clip-path": ["clip-path"],
|
|
239
|
+
"clip-rule": ["clip-rule"],
|
|
240
|
+
"color": ["color"],
|
|
241
|
+
"color-interpolation-filters": ["color-interpolation-filters"],
|
|
242
|
+
"color-scheme": ["color-scheme"],
|
|
243
|
+
"column-count": ["column-count"],
|
|
244
|
+
"column-fill": ["column-fill"],
|
|
245
|
+
"column-gap": ["column-gap"],
|
|
246
|
+
"column-height": ["column-height"],
|
|
247
|
+
"column-rule": [
|
|
248
|
+
"column-rule-color",
|
|
249
|
+
"column-rule-style",
|
|
250
|
+
"column-rule-width"
|
|
251
|
+
],
|
|
252
|
+
"column-rule-color": ["column-rule-color"],
|
|
253
|
+
"column-rule-style": ["column-rule-style"],
|
|
254
|
+
"column-rule-width": ["column-rule-width"],
|
|
255
|
+
"column-span": ["column-span"],
|
|
256
|
+
"column-width": ["column-width"],
|
|
257
|
+
"column-wrap": ["column-wrap"],
|
|
258
|
+
"columns": [
|
|
259
|
+
"column-count",
|
|
260
|
+
"column-height",
|
|
261
|
+
"column-width"
|
|
262
|
+
],
|
|
263
|
+
"contain": ["contain"],
|
|
264
|
+
"contain-intrinsic-block-size": ["contain-intrinsic-block-size"],
|
|
265
|
+
"contain-intrinsic-height": ["contain-intrinsic-height"],
|
|
266
|
+
"contain-intrinsic-inline-size": ["contain-intrinsic-inline-size"],
|
|
267
|
+
"contain-intrinsic-size": ["contain-intrinsic-height", "contain-intrinsic-width"],
|
|
268
|
+
"contain-intrinsic-width": ["contain-intrinsic-width"],
|
|
269
|
+
"container": ["container-name", "container-type"],
|
|
270
|
+
"container-name": ["container-name"],
|
|
271
|
+
"container-type": ["container-type"],
|
|
272
|
+
"content": ["content"],
|
|
273
|
+
"content-visibility": ["content-visibility"],
|
|
274
|
+
"corner-block-end-shape": ["corner-end-end-shape", "corner-end-start-shape"],
|
|
275
|
+
"corner-block-start-shape": ["corner-start-end-shape", "corner-start-start-shape"],
|
|
276
|
+
"corner-bottom-left-shape": ["corner-bottom-left-shape"],
|
|
277
|
+
"corner-bottom-right-shape": ["corner-bottom-right-shape"],
|
|
278
|
+
"corner-bottom-shape": ["corner-bottom-left-shape", "corner-bottom-right-shape"],
|
|
279
|
+
"corner-end-end-shape": ["corner-end-end-shape"],
|
|
280
|
+
"corner-end-start-shape": ["corner-end-start-shape"],
|
|
281
|
+
"corner-inline-end-shape": ["corner-end-end-shape", "corner-start-end-shape"],
|
|
282
|
+
"corner-inline-start-shape": ["corner-start-end-shape", "corner-start-start-shape"],
|
|
283
|
+
"corner-left-shape": ["corner-bottom-left-shape", "corner-top-left-shape"],
|
|
284
|
+
"corner-right-shape": ["corner-bottom-right-shape", "corner-top-right-shape"],
|
|
285
|
+
"corner-shape": [
|
|
286
|
+
"corner-bottom-left-shape",
|
|
287
|
+
"corner-bottom-right-shape",
|
|
288
|
+
"corner-top-left-shape",
|
|
289
|
+
"corner-top-right-shape"
|
|
290
|
+
],
|
|
291
|
+
"corner-start-end-shape": ["corner-start-end-shape"],
|
|
292
|
+
"corner-start-start-shape": ["corner-start-start-shape"],
|
|
293
|
+
"corner-top-left-shape": ["corner-top-left-shape"],
|
|
294
|
+
"corner-top-right-shape": ["corner-top-right-shape"],
|
|
295
|
+
"corner-top-shape": ["corner-top-left-shape", "corner-top-right-shape"],
|
|
296
|
+
"counter-increment": ["counter-increment"],
|
|
297
|
+
"counter-reset": ["counter-reset"],
|
|
298
|
+
"counter-set": ["counter-set"],
|
|
299
|
+
"cursor": ["cursor"],
|
|
300
|
+
"cx": ["cx"],
|
|
301
|
+
"cy": ["cy"],
|
|
302
|
+
"d": ["d"],
|
|
303
|
+
"direction": ["direction"],
|
|
304
|
+
"display": ["display"],
|
|
305
|
+
"dominant-baseline": ["dominant-baseline"],
|
|
306
|
+
"dynamic-range-limit": ["dynamic-range-limit"],
|
|
307
|
+
"empty-cells": ["empty-cells"],
|
|
308
|
+
"field-sizing": ["field-sizing"],
|
|
309
|
+
"fill": ["fill"],
|
|
310
|
+
"fill-opacity": ["fill-opacity"],
|
|
311
|
+
"fill-rule": ["fill-rule"],
|
|
312
|
+
"filter": ["filter"],
|
|
313
|
+
"flex": [
|
|
314
|
+
"flex-basis",
|
|
315
|
+
"flex-grow",
|
|
316
|
+
"flex-shrink"
|
|
317
|
+
],
|
|
318
|
+
"flex-basis": ["flex-basis"],
|
|
319
|
+
"flex-direction": ["flex-direction"],
|
|
320
|
+
"flex-flow": ["flex-direction", "flex-wrap"],
|
|
321
|
+
"flex-grow": ["flex-grow"],
|
|
322
|
+
"flex-shrink": ["flex-shrink"],
|
|
323
|
+
"flex-wrap": ["flex-wrap"],
|
|
324
|
+
"float": ["float"],
|
|
325
|
+
"flood-color": ["flood-color"],
|
|
326
|
+
"flood-opacity": ["flood-opacity"],
|
|
327
|
+
"font": [
|
|
328
|
+
"font-family",
|
|
329
|
+
"font-size",
|
|
330
|
+
"font-stretch",
|
|
331
|
+
"font-style",
|
|
332
|
+
"font-variant-alternates",
|
|
333
|
+
"font-variant-caps",
|
|
334
|
+
"font-variant-east-asian",
|
|
335
|
+
"font-variant-emoji",
|
|
336
|
+
"font-variant-ligatures",
|
|
337
|
+
"font-variant-numeric",
|
|
338
|
+
"font-variant-position",
|
|
339
|
+
"font-weight",
|
|
340
|
+
"line-height"
|
|
341
|
+
],
|
|
342
|
+
"font-family": ["font-family"],
|
|
343
|
+
"font-feature-settings": ["font-feature-settings"],
|
|
344
|
+
"font-kerning": ["font-kerning"],
|
|
345
|
+
"font-language-override": ["font-language-override"],
|
|
346
|
+
"font-optical-sizing": ["font-optical-sizing"],
|
|
347
|
+
"font-palette": ["font-palette"],
|
|
348
|
+
"font-size": ["font-size"],
|
|
349
|
+
"font-size-adjust": ["font-size-adjust"],
|
|
350
|
+
"font-smooth": ["font-smooth"],
|
|
351
|
+
"font-stretch": ["font-stretch"],
|
|
352
|
+
"font-style": ["font-style"],
|
|
353
|
+
"font-synthesis": [
|
|
354
|
+
"font-synthesis-position",
|
|
355
|
+
"font-synthesis-small-caps",
|
|
356
|
+
"font-synthesis-style",
|
|
357
|
+
"font-synthesis-weight"
|
|
358
|
+
],
|
|
359
|
+
"font-synthesis-position": ["font-synthesis-position"],
|
|
360
|
+
"font-synthesis-small-caps": ["font-synthesis-small-caps"],
|
|
361
|
+
"font-synthesis-style": ["font-synthesis-style"],
|
|
362
|
+
"font-synthesis-weight": ["font-synthesis-weight"],
|
|
363
|
+
"font-variant": [
|
|
364
|
+
"font-variant-alternates",
|
|
365
|
+
"font-variant-caps",
|
|
366
|
+
"font-variant-east-asian",
|
|
367
|
+
"font-variant-emoji",
|
|
368
|
+
"font-variant-ligatures",
|
|
369
|
+
"font-variant-numeric",
|
|
370
|
+
"font-variant-position"
|
|
371
|
+
],
|
|
372
|
+
"font-variant-alternates": ["font-variant-alternates"],
|
|
373
|
+
"font-variant-caps": ["font-variant-caps"],
|
|
374
|
+
"font-variant-east-asian": ["font-variant-east-asian"],
|
|
375
|
+
"font-variant-emoji": ["font-variant-emoji"],
|
|
376
|
+
"font-variant-ligatures": ["font-variant-ligatures"],
|
|
377
|
+
"font-variant-numeric": ["font-variant-numeric"],
|
|
378
|
+
"font-variant-position": ["font-variant-position"],
|
|
379
|
+
"font-variation-settings": ["font-variation-settings"],
|
|
380
|
+
"font-weight": ["font-weight"],
|
|
381
|
+
"font-width": ["font-width"],
|
|
382
|
+
"forced-color-adjust": ["forced-color-adjust"],
|
|
383
|
+
"gap": ["column-gap", "row-gap"],
|
|
384
|
+
"grid": [
|
|
385
|
+
"column-gap",
|
|
386
|
+
"grid-auto-columns",
|
|
387
|
+
"grid-auto-flow",
|
|
388
|
+
"grid-auto-rows",
|
|
389
|
+
"grid-column-gap",
|
|
390
|
+
"grid-row-gap",
|
|
391
|
+
"grid-template-areas",
|
|
392
|
+
"grid-template-columns",
|
|
393
|
+
"grid-template-rows",
|
|
394
|
+
"row-gap"
|
|
395
|
+
],
|
|
396
|
+
"grid-area": [
|
|
397
|
+
"grid-column-end",
|
|
398
|
+
"grid-column-start",
|
|
399
|
+
"grid-row-end",
|
|
400
|
+
"grid-row-start"
|
|
401
|
+
],
|
|
402
|
+
"grid-auto-columns": ["grid-auto-columns"],
|
|
403
|
+
"grid-auto-flow": ["grid-auto-flow"],
|
|
404
|
+
"grid-auto-rows": ["grid-auto-rows"],
|
|
405
|
+
"grid-column": ["grid-column-end", "grid-column-start"],
|
|
406
|
+
"grid-column-end": ["grid-column-end"],
|
|
407
|
+
"grid-column-gap": ["grid-column-gap"],
|
|
408
|
+
"grid-column-start": ["grid-column-start"],
|
|
409
|
+
"grid-gap": ["grid-column-gap", "grid-row-gap"],
|
|
410
|
+
"grid-row": ["grid-row-end", "grid-row-start"],
|
|
411
|
+
"grid-row-end": ["grid-row-end"],
|
|
412
|
+
"grid-row-gap": ["grid-row-gap"],
|
|
413
|
+
"grid-row-start": ["grid-row-start"],
|
|
414
|
+
"grid-template": [
|
|
415
|
+
"grid-template-areas",
|
|
416
|
+
"grid-template-columns",
|
|
417
|
+
"grid-template-rows"
|
|
418
|
+
],
|
|
419
|
+
"grid-template-areas": ["grid-template-areas"],
|
|
420
|
+
"grid-template-columns": ["grid-template-columns"],
|
|
421
|
+
"grid-template-rows": ["grid-template-rows"],
|
|
422
|
+
"hanging-punctuation": ["hanging-punctuation"],
|
|
423
|
+
"height": ["height"],
|
|
424
|
+
"hyphenate-character": ["hyphenate-character"],
|
|
425
|
+
"hyphenate-limit-chars": ["hyphenate-limit-chars"],
|
|
426
|
+
"hyphens": ["hyphens"],
|
|
427
|
+
"image-orientation": ["image-orientation"],
|
|
428
|
+
"image-rendering": ["image-rendering"],
|
|
429
|
+
"image-resolution": ["image-resolution"],
|
|
430
|
+
"ime-mode": ["ime-mode"],
|
|
431
|
+
"initial-letter": ["initial-letter"],
|
|
432
|
+
"initial-letter-align": ["initial-letter-align"],
|
|
433
|
+
"inline-size": ["inline-size"],
|
|
434
|
+
"inset": [
|
|
435
|
+
"bottom",
|
|
436
|
+
"left",
|
|
437
|
+
"right",
|
|
438
|
+
"top"
|
|
439
|
+
],
|
|
440
|
+
"inset-block": ["inset-block-end", "inset-block-start"],
|
|
441
|
+
"inset-block-end": ["inset-block-end"],
|
|
442
|
+
"inset-block-start": ["inset-block-start"],
|
|
443
|
+
"inset-inline": ["inset-inline-end", "inset-inline-start"],
|
|
444
|
+
"inset-inline-end": ["inset-inline-end"],
|
|
445
|
+
"inset-inline-start": ["inset-inline-start"],
|
|
446
|
+
"interactivity": ["interactivity"],
|
|
447
|
+
"interest-delay": ["interest-delay-end", "interest-delay-start"],
|
|
448
|
+
"interest-delay-end": ["interest-delay-end"],
|
|
449
|
+
"interest-delay-start": ["interest-delay-start"],
|
|
450
|
+
"interpolate-size": ["interpolate-size"],
|
|
451
|
+
"isolation": ["isolation"],
|
|
452
|
+
"justify-content": ["justify-content"],
|
|
453
|
+
"justify-items": ["justify-items"],
|
|
454
|
+
"justify-self": ["justify-self"],
|
|
455
|
+
"justify-tracks": ["justify-tracks"],
|
|
456
|
+
"left": ["left"],
|
|
457
|
+
"letter-spacing": ["letter-spacing"],
|
|
458
|
+
"lighting-color": ["lighting-color"],
|
|
459
|
+
"line-break": ["line-break"],
|
|
460
|
+
"line-clamp": ["line-clamp"],
|
|
461
|
+
"line-height": ["line-height"],
|
|
462
|
+
"line-height-step": ["line-height-step"],
|
|
463
|
+
"list-style": [
|
|
464
|
+
"list-style-image",
|
|
465
|
+
"list-style-position",
|
|
466
|
+
"list-style-type"
|
|
467
|
+
],
|
|
468
|
+
"list-style-image": ["list-style-image"],
|
|
469
|
+
"list-style-position": ["list-style-position"],
|
|
470
|
+
"list-style-type": ["list-style-type"],
|
|
471
|
+
"margin": [
|
|
472
|
+
"margin-bottom",
|
|
473
|
+
"margin-left",
|
|
474
|
+
"margin-right",
|
|
475
|
+
"margin-top"
|
|
476
|
+
],
|
|
477
|
+
"margin-block": ["margin-block-end", "margin-block-start"],
|
|
478
|
+
"margin-block-end": ["margin-block-end"],
|
|
479
|
+
"margin-block-start": ["margin-block-start"],
|
|
480
|
+
"margin-bottom": ["margin-bottom"],
|
|
481
|
+
"margin-inline": ["margin-inline-end", "margin-inline-start"],
|
|
482
|
+
"margin-inline-end": ["margin-inline-end"],
|
|
483
|
+
"margin-inline-start": ["margin-inline-start"],
|
|
484
|
+
"margin-left": ["margin-left"],
|
|
485
|
+
"margin-right": ["margin-right"],
|
|
486
|
+
"margin-top": ["margin-top"],
|
|
487
|
+
"margin-trim": ["margin-trim"],
|
|
488
|
+
"marker": [
|
|
489
|
+
"marker-end",
|
|
490
|
+
"marker-mid",
|
|
491
|
+
"marker-start"
|
|
492
|
+
],
|
|
493
|
+
"marker-end": ["marker-end"],
|
|
494
|
+
"marker-mid": ["marker-mid"],
|
|
495
|
+
"marker-start": ["marker-start"],
|
|
496
|
+
"mask": [
|
|
497
|
+
"mask-clip",
|
|
498
|
+
"mask-composite",
|
|
499
|
+
"mask-image",
|
|
500
|
+
"mask-mode",
|
|
501
|
+
"mask-origin",
|
|
502
|
+
"mask-position",
|
|
503
|
+
"mask-repeat",
|
|
504
|
+
"mask-size"
|
|
505
|
+
],
|
|
506
|
+
"mask-border": [
|
|
507
|
+
"mask-border-mode",
|
|
508
|
+
"mask-border-outset",
|
|
509
|
+
"mask-border-repeat",
|
|
510
|
+
"mask-border-slice",
|
|
511
|
+
"mask-border-source",
|
|
512
|
+
"mask-border-width"
|
|
513
|
+
],
|
|
514
|
+
"mask-border-mode": ["mask-border-mode"],
|
|
515
|
+
"mask-border-outset": ["mask-border-outset"],
|
|
516
|
+
"mask-border-repeat": ["mask-border-repeat"],
|
|
517
|
+
"mask-border-slice": ["mask-border-slice"],
|
|
518
|
+
"mask-border-source": ["mask-border-source"],
|
|
519
|
+
"mask-border-width": ["mask-border-width"],
|
|
520
|
+
"mask-clip": ["mask-clip"],
|
|
521
|
+
"mask-composite": ["mask-composite"],
|
|
522
|
+
"mask-image": ["mask-image"],
|
|
523
|
+
"mask-mode": ["mask-mode"],
|
|
524
|
+
"mask-origin": ["mask-origin"],
|
|
525
|
+
"mask-position": ["mask-position"],
|
|
526
|
+
"mask-repeat": ["mask-repeat"],
|
|
527
|
+
"mask-size": ["mask-size"],
|
|
528
|
+
"mask-type": ["mask-type"],
|
|
529
|
+
"masonry-auto-flow": ["masonry-auto-flow"],
|
|
530
|
+
"math-depth": ["math-depth"],
|
|
531
|
+
"math-shift": ["math-shift"],
|
|
532
|
+
"math-style": ["math-style"],
|
|
533
|
+
"max-block-size": ["max-block-size"],
|
|
534
|
+
"max-height": ["max-height"],
|
|
535
|
+
"max-inline-size": ["max-inline-size"],
|
|
536
|
+
"max-lines": ["max-lines"],
|
|
537
|
+
"max-width": ["max-width"],
|
|
538
|
+
"min-block-size": ["min-block-size"],
|
|
539
|
+
"min-height": ["min-height"],
|
|
540
|
+
"min-inline-size": ["min-inline-size"],
|
|
541
|
+
"min-width": ["min-width"],
|
|
542
|
+
"mix-blend-mode": ["mix-blend-mode"],
|
|
543
|
+
"object-fit": ["object-fit"],
|
|
544
|
+
"object-position": ["object-position"],
|
|
545
|
+
"object-view-box": ["object-view-box"],
|
|
546
|
+
"offset": [
|
|
547
|
+
"offset-anchor",
|
|
548
|
+
"offset-distance",
|
|
549
|
+
"offset-path",
|
|
550
|
+
"offset-position",
|
|
551
|
+
"offset-rotate"
|
|
552
|
+
],
|
|
553
|
+
"offset-anchor": ["offset-anchor"],
|
|
554
|
+
"offset-distance": ["offset-distance"],
|
|
555
|
+
"offset-path": ["offset-path"],
|
|
556
|
+
"offset-position": ["offset-position"],
|
|
557
|
+
"offset-rotate": ["offset-rotate"],
|
|
558
|
+
"opacity": ["opacity"],
|
|
559
|
+
"order": ["order"],
|
|
560
|
+
"orphans": ["orphans"],
|
|
561
|
+
"outline": [
|
|
562
|
+
"outline-color",
|
|
563
|
+
"outline-style",
|
|
564
|
+
"outline-width"
|
|
565
|
+
],
|
|
566
|
+
"outline-color": ["outline-color"],
|
|
567
|
+
"outline-offset": ["outline-offset"],
|
|
568
|
+
"outline-style": ["outline-style"],
|
|
569
|
+
"outline-width": ["outline-width"],
|
|
570
|
+
"overflow": ["overflow-x", "overflow-y"],
|
|
571
|
+
"overflow-anchor": ["overflow-anchor"],
|
|
572
|
+
"overflow-block": ["overflow-block"],
|
|
573
|
+
"overflow-clip-box": ["overflow-clip-box"],
|
|
574
|
+
"overflow-clip-margin": ["overflow-clip-margin"],
|
|
575
|
+
"overflow-inline": ["overflow-inline"],
|
|
576
|
+
"overflow-wrap": ["overflow-wrap"],
|
|
577
|
+
"overflow-x": ["overflow-x"],
|
|
578
|
+
"overflow-y": ["overflow-y"],
|
|
579
|
+
"overlay": ["overlay"],
|
|
580
|
+
"overscroll-behavior": ["overscroll-behavior-x", "overscroll-behavior-y"],
|
|
581
|
+
"overscroll-behavior-block": ["overscroll-behavior-block"],
|
|
582
|
+
"overscroll-behavior-inline": ["overscroll-behavior-inline"],
|
|
583
|
+
"overscroll-behavior-x": ["overscroll-behavior-x"],
|
|
584
|
+
"overscroll-behavior-y": ["overscroll-behavior-y"],
|
|
585
|
+
"padding": [
|
|
586
|
+
"padding-bottom",
|
|
587
|
+
"padding-left",
|
|
588
|
+
"padding-right",
|
|
589
|
+
"padding-top"
|
|
590
|
+
],
|
|
591
|
+
"padding-block": ["padding-block-end", "padding-block-start"],
|
|
592
|
+
"padding-block-end": ["padding-block-end"],
|
|
593
|
+
"padding-block-start": ["padding-block-start"],
|
|
594
|
+
"padding-bottom": ["padding-bottom"],
|
|
595
|
+
"padding-inline": ["padding-inline-end", "padding-inline-start"],
|
|
596
|
+
"padding-inline-end": ["padding-inline-end"],
|
|
597
|
+
"padding-inline-start": ["padding-inline-start"],
|
|
598
|
+
"padding-left": ["padding-left"],
|
|
599
|
+
"padding-right": ["padding-right"],
|
|
600
|
+
"padding-top": ["padding-top"],
|
|
601
|
+
"page": ["page"],
|
|
602
|
+
"page-break-after": ["page-break-after"],
|
|
603
|
+
"page-break-before": ["page-break-before"],
|
|
604
|
+
"page-break-inside": ["page-break-inside"],
|
|
605
|
+
"paint-order": ["paint-order"],
|
|
606
|
+
"perspective": ["perspective"],
|
|
607
|
+
"perspective-origin": ["perspective-origin"],
|
|
608
|
+
"place-content": ["align-content", "justify-content"],
|
|
609
|
+
"place-items": ["align-items", "justify-items"],
|
|
610
|
+
"place-self": ["align-self", "justify-self"],
|
|
611
|
+
"pointer-events": ["pointer-events"],
|
|
612
|
+
"position": ["position"],
|
|
613
|
+
"position-anchor": ["position-anchor"],
|
|
614
|
+
"position-area": ["position-area"],
|
|
615
|
+
"position-try": ["position-try-fallbacks", "position-try-order"],
|
|
616
|
+
"position-try-fallbacks": ["position-try-fallbacks"],
|
|
617
|
+
"position-try-order": ["position-try-order"],
|
|
618
|
+
"position-visibility": ["position-visibility"],
|
|
619
|
+
"print-color-adjust": ["print-color-adjust"],
|
|
620
|
+
"quotes": ["quotes"],
|
|
621
|
+
"r": ["r"],
|
|
622
|
+
"reading-flow": ["reading-flow"],
|
|
623
|
+
"reading-order": ["reading-order"],
|
|
624
|
+
"resize": ["resize"],
|
|
625
|
+
"right": ["right"],
|
|
626
|
+
"rotate": ["rotate"],
|
|
627
|
+
"row-gap": ["row-gap"],
|
|
628
|
+
"ruby-align": ["ruby-align"],
|
|
629
|
+
"ruby-merge": ["ruby-merge"],
|
|
630
|
+
"ruby-overhang": ["ruby-overhang"],
|
|
631
|
+
"ruby-position": ["ruby-position"],
|
|
632
|
+
"rx": ["rx"],
|
|
633
|
+
"ry": ["ry"],
|
|
634
|
+
"scale": ["scale"],
|
|
635
|
+
"scroll-behavior": ["scroll-behavior"],
|
|
636
|
+
"scroll-initial-target": ["scroll-initial-target"],
|
|
637
|
+
"scroll-margin": [
|
|
638
|
+
"scroll-margin-bottom",
|
|
639
|
+
"scroll-margin-left",
|
|
640
|
+
"scroll-margin-right",
|
|
641
|
+
"scroll-margin-top"
|
|
642
|
+
],
|
|
643
|
+
"scroll-margin-block": ["scroll-margin-block-end", "scroll-margin-block-start"],
|
|
644
|
+
"scroll-margin-block-end": ["scroll-margin-block-end"],
|
|
645
|
+
"scroll-margin-block-start": ["scroll-margin-block-start"],
|
|
646
|
+
"scroll-margin-bottom": ["scroll-margin-bottom"],
|
|
647
|
+
"scroll-margin-inline": ["scroll-margin-inline-end", "scroll-margin-inline-start"],
|
|
648
|
+
"scroll-margin-inline-end": ["scroll-margin-inline-end"],
|
|
649
|
+
"scroll-margin-inline-start": ["scroll-margin-inline-start"],
|
|
650
|
+
"scroll-margin-left": ["scroll-margin-left"],
|
|
651
|
+
"scroll-margin-right": ["scroll-margin-right"],
|
|
652
|
+
"scroll-margin-top": ["scroll-margin-top"],
|
|
653
|
+
"scroll-marker-group": ["scroll-marker-group"],
|
|
654
|
+
"scroll-padding": [
|
|
655
|
+
"scroll-padding-bottom",
|
|
656
|
+
"scroll-padding-left",
|
|
657
|
+
"scroll-padding-right",
|
|
658
|
+
"scroll-padding-top"
|
|
659
|
+
],
|
|
660
|
+
"scroll-padding-block": ["scroll-padding-block-end", "scroll-padding-block-start"],
|
|
661
|
+
"scroll-padding-block-end": ["scroll-padding-block-end"],
|
|
662
|
+
"scroll-padding-block-start": ["scroll-padding-block-start"],
|
|
663
|
+
"scroll-padding-bottom": ["scroll-padding-bottom"],
|
|
664
|
+
"scroll-padding-inline": ["scroll-padding-inline-end", "scroll-padding-inline-start"],
|
|
665
|
+
"scroll-padding-inline-end": ["scroll-padding-inline-end"],
|
|
666
|
+
"scroll-padding-inline-start": ["scroll-padding-inline-start"],
|
|
667
|
+
"scroll-padding-left": ["scroll-padding-left"],
|
|
668
|
+
"scroll-padding-right": ["scroll-padding-right"],
|
|
669
|
+
"scroll-padding-top": ["scroll-padding-top"],
|
|
670
|
+
"scroll-snap-align": ["scroll-snap-align"],
|
|
671
|
+
"scroll-snap-coordinate": ["scroll-snap-coordinate"],
|
|
672
|
+
"scroll-snap-destination": ["scroll-snap-destination"],
|
|
673
|
+
"scroll-snap-points-x": ["scroll-snap-points-x"],
|
|
674
|
+
"scroll-snap-points-y": ["scroll-snap-points-y"],
|
|
675
|
+
"scroll-snap-stop": ["scroll-snap-stop"],
|
|
676
|
+
"scroll-snap-type": ["scroll-snap-type"],
|
|
677
|
+
"scroll-snap-type-x": ["scroll-snap-type-x"],
|
|
678
|
+
"scroll-snap-type-y": ["scroll-snap-type-y"],
|
|
679
|
+
"scroll-target-group": ["scroll-target-group"],
|
|
680
|
+
"scroll-timeline": ["scroll-timeline-axis", "scroll-timeline-name"],
|
|
681
|
+
"scroll-timeline-axis": ["scroll-timeline-axis"],
|
|
682
|
+
"scroll-timeline-name": ["scroll-timeline-name"],
|
|
683
|
+
"scrollbar-color": ["scrollbar-color"],
|
|
684
|
+
"scrollbar-gutter": ["scrollbar-gutter"],
|
|
685
|
+
"scrollbar-width": ["scrollbar-width"],
|
|
686
|
+
"shape-image-threshold": ["shape-image-threshold"],
|
|
687
|
+
"shape-margin": ["shape-margin"],
|
|
688
|
+
"shape-outside": ["shape-outside"],
|
|
689
|
+
"shape-rendering": ["shape-rendering"],
|
|
690
|
+
"speak-as": ["speak-as"],
|
|
691
|
+
"stop-color": ["stop-color"],
|
|
692
|
+
"stop-opacity": ["stop-opacity"],
|
|
693
|
+
"stroke": [
|
|
694
|
+
"stroke-dasharray",
|
|
695
|
+
"stroke-dashoffset",
|
|
696
|
+
"stroke-linecap",
|
|
697
|
+
"stroke-linejoin",
|
|
698
|
+
"stroke-miterlimit",
|
|
699
|
+
"stroke-opacity",
|
|
700
|
+
"stroke-width"
|
|
701
|
+
],
|
|
702
|
+
"stroke-color": ["stroke-color"],
|
|
703
|
+
"stroke-dasharray": ["stroke-dasharray"],
|
|
704
|
+
"stroke-dashoffset": ["stroke-dashoffset"],
|
|
705
|
+
"stroke-linecap": ["stroke-linecap"],
|
|
706
|
+
"stroke-linejoin": ["stroke-linejoin"],
|
|
707
|
+
"stroke-miterlimit": ["stroke-miterlimit"],
|
|
708
|
+
"stroke-opacity": ["stroke-opacity"],
|
|
709
|
+
"stroke-width": ["stroke-width"],
|
|
710
|
+
"tab-size": ["tab-size"],
|
|
711
|
+
"table-layout": ["table-layout"],
|
|
712
|
+
"text-align": ["text-align"],
|
|
713
|
+
"text-align-last": ["text-align-last"],
|
|
714
|
+
"text-anchor": ["text-anchor"],
|
|
715
|
+
"text-autospace": ["text-autospace"],
|
|
716
|
+
"text-box": ["text-box-edge", "text-box-trim"],
|
|
717
|
+
"text-box-edge": ["text-box-edge"],
|
|
718
|
+
"text-box-trim": ["text-box-trim"],
|
|
719
|
+
"text-combine-upright": ["text-combine-upright"],
|
|
720
|
+
"text-decoration": [
|
|
721
|
+
"text-decoration-color",
|
|
722
|
+
"text-decoration-line",
|
|
723
|
+
"text-decoration-style",
|
|
724
|
+
"text-decoration-thickness"
|
|
725
|
+
],
|
|
726
|
+
"text-decoration-color": ["text-decoration-color"],
|
|
727
|
+
"text-decoration-inset": ["text-decoration-inset"],
|
|
728
|
+
"text-decoration-line": ["text-decoration-line"],
|
|
729
|
+
"text-decoration-skip": ["text-decoration-skip"],
|
|
730
|
+
"text-decoration-skip-ink": ["text-decoration-skip-ink"],
|
|
731
|
+
"text-decoration-style": ["text-decoration-style"],
|
|
732
|
+
"text-decoration-thickness": ["text-decoration-thickness"],
|
|
733
|
+
"text-emphasis": ["text-emphasis-color", "text-emphasis-style"],
|
|
734
|
+
"text-emphasis-color": ["text-emphasis-color"],
|
|
735
|
+
"text-emphasis-position": ["text-emphasis-position"],
|
|
736
|
+
"text-emphasis-style": ["text-emphasis-style"],
|
|
737
|
+
"text-indent": ["text-indent"],
|
|
738
|
+
"text-justify": ["text-justify"],
|
|
739
|
+
"text-orientation": ["text-orientation"],
|
|
740
|
+
"text-overflow": ["text-overflow"],
|
|
741
|
+
"text-rendering": ["text-rendering"],
|
|
742
|
+
"text-shadow": ["text-shadow"],
|
|
743
|
+
"text-size-adjust": ["text-size-adjust"],
|
|
744
|
+
"text-spacing-trim": ["text-spacing-trim"],
|
|
745
|
+
"text-transform": ["text-transform"],
|
|
746
|
+
"text-underline-offset": ["text-underline-offset"],
|
|
747
|
+
"text-underline-position": ["text-underline-position"],
|
|
748
|
+
"text-wrap": ["text-wrap-mode", "text-wrap-style"],
|
|
749
|
+
"text-wrap-mode": ["text-wrap-mode"],
|
|
750
|
+
"text-wrap-style": ["text-wrap-style"],
|
|
751
|
+
"timeline-scope": ["timeline-scope"],
|
|
752
|
+
"timeline-trigger": [
|
|
753
|
+
"timeline-trigger-exit-range-end",
|
|
754
|
+
"timeline-trigger-exit-range-start",
|
|
755
|
+
"timeline-trigger-name",
|
|
756
|
+
"timeline-trigger-range-end",
|
|
757
|
+
"timeline-trigger-range-start",
|
|
758
|
+
"timeline-trigger-source"
|
|
759
|
+
],
|
|
760
|
+
"timeline-trigger-exit-range": ["timeline-trigger-exit-range-end", "timeline-trigger-exit-range-start"],
|
|
761
|
+
"timeline-trigger-exit-range-end": ["timeline-trigger-exit-range-end"],
|
|
762
|
+
"timeline-trigger-exit-range-start": ["timeline-trigger-exit-range-start"],
|
|
763
|
+
"timeline-trigger-name": ["timeline-trigger-name"],
|
|
764
|
+
"timeline-trigger-range": ["timeline-trigger-range-end", "timeline-trigger-range-start"],
|
|
765
|
+
"timeline-trigger-range-end": ["timeline-trigger-range-end"],
|
|
766
|
+
"timeline-trigger-range-start": ["timeline-trigger-range-start"],
|
|
767
|
+
"timeline-trigger-source": ["timeline-trigger-source"],
|
|
768
|
+
"top": ["top"],
|
|
769
|
+
"touch-action": ["touch-action"],
|
|
770
|
+
"transform": ["transform"],
|
|
771
|
+
"transform-box": ["transform-box"],
|
|
772
|
+
"transform-origin": ["transform-origin"],
|
|
773
|
+
"transform-style": ["transform-style"],
|
|
774
|
+
"transition": [
|
|
775
|
+
"transition-behavior",
|
|
776
|
+
"transition-delay",
|
|
777
|
+
"transition-duration",
|
|
778
|
+
"transition-property",
|
|
779
|
+
"transition-timing-function"
|
|
780
|
+
],
|
|
781
|
+
"transition-behavior": ["transition-behavior"],
|
|
782
|
+
"transition-delay": ["transition-delay"],
|
|
783
|
+
"transition-duration": ["transition-duration"],
|
|
784
|
+
"transition-property": ["transition-property"],
|
|
785
|
+
"transition-timing-function": ["transition-timing-function"],
|
|
786
|
+
"translate": ["translate"],
|
|
787
|
+
"trigger-scope": ["trigger-scope"],
|
|
788
|
+
"unicode-bidi": ["unicode-bidi"],
|
|
789
|
+
"user-select": ["user-select"],
|
|
790
|
+
"vector-effect": ["vector-effect"],
|
|
791
|
+
"vertical-align": ["vertical-align"],
|
|
792
|
+
"view-timeline": ["view-timeline-axis", "view-timeline-name"],
|
|
793
|
+
"view-timeline-axis": ["view-timeline-axis"],
|
|
794
|
+
"view-timeline-inset": ["view-timeline-inset"],
|
|
795
|
+
"view-timeline-name": ["view-timeline-name"],
|
|
796
|
+
"view-transition-class": ["view-transition-class"],
|
|
797
|
+
"view-transition-name": ["view-transition-name"],
|
|
798
|
+
"visibility": ["visibility"],
|
|
799
|
+
"white-space": ["text-wrap-mode", "white-space-collapse"],
|
|
800
|
+
"white-space-collapse": ["white-space-collapse"],
|
|
801
|
+
"widows": ["widows"],
|
|
802
|
+
"width": ["width"],
|
|
803
|
+
"will-change": ["will-change"],
|
|
804
|
+
"word-break": ["word-break"],
|
|
805
|
+
"word-spacing": ["word-spacing"],
|
|
806
|
+
"word-wrap": ["word-wrap"],
|
|
807
|
+
"writing-mode": ["writing-mode"],
|
|
808
|
+
"x": ["x"],
|
|
809
|
+
"y": ["y"],
|
|
810
|
+
"z-index": ["z-index"],
|
|
811
|
+
"zoom": ["zoom"]
|
|
812
|
+
};
|
|
813
|
+
//#endregion
|
|
814
|
+
//#region src/internal/property-effects.ts
|
|
815
|
+
const UNIVERSAL_EFFECT = "*";
|
|
816
|
+
const propertyEffectsLookup = PROPERTY_EFFECTS;
|
|
817
|
+
function isCustomProperty(property) {
|
|
818
|
+
return property.startsWith("--");
|
|
819
|
+
}
|
|
820
|
+
function isVendorPrefixedProperty(property) {
|
|
821
|
+
return property.startsWith("-") && property.startsWith("--") === false;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Returns the list of CSS properties that a given property can affect, accounting for shorthand expansion.
|
|
825
|
+
* @internal
|
|
826
|
+
*
|
|
827
|
+
* @param property - A CSS property name in kebab-case.
|
|
828
|
+
* @returns An array of affected property names. For the `all` shorthand, returns `['*']`. For custom or vendor-prefixed properties, returns the property itself. For standard shorthands, returns the set of longhand properties they expand to.
|
|
829
|
+
*
|
|
830
|
+
* @remarks Used by the order-sensitivity detection logic to determine whether two properties in the same scope share overlapping effects (e.g. `margin` and `margin-top`). The lookup map is generated at build time from the CSS shorthand specification.
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```ts
|
|
834
|
+
* getPropertyEffects('margin') // ['margin-top', 'margin-right', 'margin-bottom', 'margin-left']
|
|
835
|
+
* getPropertyEffects('color') // ['color']
|
|
836
|
+
* getPropertyEffects('--my-var') // ['--my-var']
|
|
837
|
+
* getPropertyEffects('all') // ['*']
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
function getPropertyEffects(property) {
|
|
841
|
+
if (property === "all") return [UNIVERSAL_EFFECT];
|
|
842
|
+
if (isCustomProperty(property) || isVendorPrefixedProperty(property)) return [property];
|
|
843
|
+
return propertyEffectsLookup[property] || [property];
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Determines whether two CSS properties have overlapping effects, meaning they can interfere with each other when both are present in the same selector scope.
|
|
847
|
+
* @internal
|
|
848
|
+
*
|
|
849
|
+
* @param left - First CSS property name in kebab-case.
|
|
850
|
+
* @param right - Second CSS property name in kebab-case.
|
|
851
|
+
* @returns `true` if the two properties share at least one common affected property or if either is the universal `all` shorthand.
|
|
852
|
+
*
|
|
853
|
+
* @remarks Custom properties never overlap with other properties. Identical properties always overlap. This check drives the order-sensitivity detection in `optimizeAtomicStyleContents`, ensuring that shorthand/longhand conflicts like `margin` + `margin-top` are correctly handled.
|
|
854
|
+
*
|
|
855
|
+
* @example
|
|
856
|
+
* ```ts
|
|
857
|
+
* hasPropertyEffectOverlap('margin', 'margin-top') // true
|
|
858
|
+
* hasPropertyEffectOverlap('color', 'font-size') // false
|
|
859
|
+
* hasPropertyEffectOverlap('all', 'color') // true
|
|
860
|
+
* ```
|
|
861
|
+
*/
|
|
862
|
+
function hasPropertyEffectOverlap(left, right) {
|
|
863
|
+
if (left === right) return true;
|
|
864
|
+
if (isCustomProperty(left) || isCustomProperty(right)) return false;
|
|
865
|
+
const leftEffects = getPropertyEffects(left);
|
|
866
|
+
const rightEffects = getPropertyEffects(right);
|
|
867
|
+
if (leftEffects.includes(UNIVERSAL_EFFECT) || rightEffects.includes(UNIVERSAL_EFFECT)) return true;
|
|
868
|
+
const rightEffectSet = new Set(rightEffects);
|
|
869
|
+
return leftEffects.some((effect) => rightEffectSet.has(effect));
|
|
870
|
+
}
|
|
5
871
|
//#endregion
|
|
6
872
|
//#region src/internal/utils.ts
|
|
873
|
+
/**
|
|
874
|
+
* Creates a scoped logger with configurable log-level functions and a toggleable debug mode.
|
|
875
|
+
*
|
|
876
|
+
* @param prefix - Label prepended to every log message (e.g. `'[PikaCSS]'`).
|
|
877
|
+
* @returns A logger object with `debug`, `info`, `warn`, `error` methods and configuration setters.
|
|
878
|
+
*
|
|
879
|
+
* @remarks Debug messages are suppressed by default. Call `log.toggleDebug()` to enable them. Each log level can be replaced with a custom implementation via the `set*Fn` methods, which is useful for redirecting output in non-browser environments.
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* ```ts
|
|
883
|
+
* const log = createLogger('[MyPlugin]')
|
|
884
|
+
* log.info('initialized') // '[MyPlugin][INFO] initialized'
|
|
885
|
+
* log.toggleDebug()
|
|
886
|
+
* log.debug('verbose info') // '[MyPlugin][DEBUG] verbose info'
|
|
887
|
+
* ```
|
|
888
|
+
*/
|
|
7
889
|
function createLogger(prefix) {
|
|
8
890
|
let currentPrefix = prefix;
|
|
9
891
|
let enabledDebug = false;
|
|
@@ -45,9 +927,36 @@ function createLogger(prefix) {
|
|
|
45
927
|
}
|
|
46
928
|
};
|
|
47
929
|
}
|
|
930
|
+
/**
|
|
931
|
+
* Default logger instance used throughout the PikaCSS core engine, prefixed with `[PikaCSS]`.
|
|
932
|
+
*
|
|
933
|
+
* @remarks Shared across all internal modules. Plugins and integration code can call `log.toggleDebug()` to enable verbose output during development.
|
|
934
|
+
*
|
|
935
|
+
* @example
|
|
936
|
+
* ```ts
|
|
937
|
+
* log.info('Engine created')
|
|
938
|
+
* log.warn('Unknown layer detected')
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
48
941
|
const log = createLogger("[PikaCSS]");
|
|
49
942
|
const chars = [..."abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"];
|
|
50
943
|
const numOfChars = chars.length;
|
|
944
|
+
/**
|
|
945
|
+
* Converts a non-negative integer to a compact alphabetic string using a bijective base-52 encoding (a-z, A-Z).
|
|
946
|
+
* @internal
|
|
947
|
+
*
|
|
948
|
+
* @param num - The non-negative integer to encode.
|
|
949
|
+
* @returns A short alphabetic string unique to the given integer.
|
|
950
|
+
*
|
|
951
|
+
* @remarks Used to generate compact, human-readable atomic style class IDs. The encoding is deterministic: the same number always produces the same string.
|
|
952
|
+
*
|
|
953
|
+
* @example
|
|
954
|
+
* ```ts
|
|
955
|
+
* numberToChars(0) // 'a'
|
|
956
|
+
* numberToChars(51) // 'Z'
|
|
957
|
+
* numberToChars(52) // 'ba'
|
|
958
|
+
* ```
|
|
959
|
+
*/
|
|
51
960
|
function numberToChars(num) {
|
|
52
961
|
if (num < numOfChars) return chars[num];
|
|
53
962
|
let result = "";
|
|
@@ -59,48 +968,230 @@ function numberToChars(num) {
|
|
|
59
968
|
return result;
|
|
60
969
|
}
|
|
61
970
|
const UPPER_CASE = /[A-Z]/g;
|
|
971
|
+
/**
|
|
972
|
+
* Converts a camelCase string to kebab-case at runtime. CSS custom properties (`--*`) are returned unchanged.
|
|
973
|
+
* @internal
|
|
974
|
+
*
|
|
975
|
+
* @param str - The camelCase string to convert.
|
|
976
|
+
* @returns The kebab-case equivalent of the input string.
|
|
977
|
+
*
|
|
978
|
+
* @remarks Runtime counterpart of the `ToKebab` type utility. Used during style extraction to normalize JavaScript-style property names to CSS property names.
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```ts
|
|
982
|
+
* toKebab('backgroundColor') // 'background-color'
|
|
983
|
+
* toKebab('--my-var') // '--my-var'
|
|
984
|
+
* ```
|
|
985
|
+
*/
|
|
62
986
|
function toKebab(str) {
|
|
63
987
|
if (str.startsWith("--")) return str;
|
|
64
988
|
return str.replace(UPPER_CASE, (c) => `-${c.toLowerCase()}`);
|
|
65
989
|
}
|
|
990
|
+
/**
|
|
991
|
+
* Type-narrowing guard that returns `true` when the value is neither `null` nor `undefined`.
|
|
992
|
+
* @internal
|
|
993
|
+
*
|
|
994
|
+
* @typeParam T - The type of the input value.
|
|
995
|
+
* @param value - The value to test.
|
|
996
|
+
* @returns `true` if the value is non-nullish, narrowing the type to `NonNullable<T>`.
|
|
997
|
+
*
|
|
998
|
+
* @remarks Commonly used as a `.filter()` predicate to strip nullish entries from arrays while preserving the narrowed type.
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```ts
|
|
1002
|
+
* [1, null, 2, undefined].filter(isNotNullish) // [1, 2] typed as number[]
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
66
1005
|
function isNotNullish(value) {
|
|
67
1006
|
return value != null;
|
|
68
1007
|
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Type-narrowing guard that returns `true` when the value is not a string, narrowing the type to `Exclude<V, string>`.
|
|
1010
|
+
* @internal
|
|
1011
|
+
*
|
|
1012
|
+
* @typeParam V - The union type of the input value.
|
|
1013
|
+
* @param value - The value to test.
|
|
1014
|
+
* @returns `true` if the value is not a `string`.
|
|
1015
|
+
*
|
|
1016
|
+
* @remarks Useful for filtering processed style items to separate resolved definition objects from unresolved string references.
|
|
1017
|
+
*
|
|
1018
|
+
* @example
|
|
1019
|
+
* ```ts
|
|
1020
|
+
* const items: (string | object)[] = ['btn', { color: 'red' }]
|
|
1021
|
+
* const objects = items.filter(isNotString) // [{ color: 'red' }]
|
|
1022
|
+
* ```
|
|
1023
|
+
*/
|
|
69
1024
|
function isNotString(value) {
|
|
70
1025
|
return typeof value !== "string";
|
|
71
1026
|
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Tests whether a value conforms to the `InternalPropertyValue` shape: a string, a `[value, fallback[]]` tuple, or nullish.
|
|
1029
|
+
* @internal
|
|
1030
|
+
*
|
|
1031
|
+
* @param v - The value to inspect.
|
|
1032
|
+
* @returns `true` if the value is a valid property value.
|
|
1033
|
+
*
|
|
1034
|
+
* @remarks During extraction, the engine uses this guard to distinguish CSS property values from nested selector objects or style item arrays.
|
|
1035
|
+
*
|
|
1036
|
+
* @example
|
|
1037
|
+
* ```ts
|
|
1038
|
+
* isPropertyValue('red') // true
|
|
1039
|
+
* isPropertyValue(['red', ['blue']]) // true
|
|
1040
|
+
* isPropertyValue(null) // true
|
|
1041
|
+
* isPropertyValue({ color: 'red' }) // false
|
|
1042
|
+
* ```
|
|
1043
|
+
*/
|
|
72
1044
|
function isPropertyValue(v) {
|
|
73
1045
|
if (Array.isArray(v)) return v.length === 2 && typeof v[0] === "string" && Array.isArray(v[1]) && v[1].every((i) => typeof i === "string");
|
|
74
1046
|
if (v == null) return true;
|
|
75
1047
|
if (typeof v === "string") return true;
|
|
76
1048
|
return false;
|
|
77
1049
|
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Serializes a value to a JSON string for use as a deterministic cache key.
|
|
1052
|
+
* @internal
|
|
1053
|
+
*
|
|
1054
|
+
* @param value - The value to serialize.
|
|
1055
|
+
* @returns The JSON string representation.
|
|
1056
|
+
*
|
|
1057
|
+
* @remarks Used to produce stable keys for selector chains and property content when building deduplication maps in the optimization pipeline.
|
|
1058
|
+
*
|
|
1059
|
+
* @example
|
|
1060
|
+
* ```ts
|
|
1061
|
+
* serialize(['.pk-%', 'color']) // '[[".pk-%"],"color"]'
|
|
1062
|
+
* ```
|
|
1063
|
+
*/
|
|
78
1064
|
function serialize(value) {
|
|
79
1065
|
return JSON.stringify(value);
|
|
80
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Adds one or more values to a `Set` and returns whether the set's size increased.
|
|
1069
|
+
* @internal
|
|
1070
|
+
*
|
|
1071
|
+
* @typeParam T - The element type of the set.
|
|
1072
|
+
* @param set - The target set to append to.
|
|
1073
|
+
* @param values - Values to add.
|
|
1074
|
+
* @returns `true` if at least one new element was added (the set grew).
|
|
1075
|
+
*
|
|
1076
|
+
* @remarks The boolean return is used by `appendAutocomplete` to determine whether the autocomplete config actually changed, avoiding unnecessary notification callbacks.
|
|
1077
|
+
*
|
|
1078
|
+
* @example
|
|
1079
|
+
* ```ts
|
|
1080
|
+
* const s = new Set(['a'])
|
|
1081
|
+
* addToSet(s, 'a', 'b') // true (added 'b')
|
|
1082
|
+
* addToSet(s, 'a') // false (no change)
|
|
1083
|
+
* ```
|
|
1084
|
+
*/
|
|
81
1085
|
function addToSet(set, ...values) {
|
|
1086
|
+
const before = set.size;
|
|
82
1087
|
values.forEach((value) => set.add(value));
|
|
1088
|
+
return set.size !== before;
|
|
83
1089
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1090
|
+
/**
|
|
1091
|
+
* Flattens an `Arrayable<string>` value and adds all entries to a `Set`, returning whether the set grew.
|
|
1092
|
+
* @internal
|
|
1093
|
+
*
|
|
1094
|
+
* @param set - The target set to append to.
|
|
1095
|
+
* @param values - A single string or array of strings to add, or `undefined`/`null` to skip.
|
|
1096
|
+
* @returns `true` if at least one new entry was added; `false` if the input was nullish or all entries already existed.
|
|
1097
|
+
*
|
|
1098
|
+
* @remarks Short-circuits on nullish input for convenience, since many autocomplete contribution fields are optional.
|
|
1099
|
+
*
|
|
1100
|
+
* @example
|
|
1101
|
+
* ```ts
|
|
1102
|
+
* const s = new Set<string>()
|
|
1103
|
+
* appendAutocompleteEntries(s, 'hover') // true
|
|
1104
|
+
* appendAutocompleteEntries(s, ['hover']) // false (already present)
|
|
1105
|
+
* appendAutocompleteEntries(s, undefined) // false
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
function appendAutocompleteEntries(set, values) {
|
|
1109
|
+
if (values == null) return false;
|
|
1110
|
+
return addToSet(set, ...[values].flat());
|
|
92
1111
|
}
|
|
93
|
-
|
|
94
|
-
|
|
1112
|
+
/**
|
|
1113
|
+
* Merges a record of `Arrayable<string>` values into a `Map<string, string[]>`, returning whether any entry was added.
|
|
1114
|
+
* @internal
|
|
1115
|
+
*
|
|
1116
|
+
* @param map - The target map to append entries to.
|
|
1117
|
+
* @param entries - A record mapping keys to single or arrayed string values, or `undefined` to skip.
|
|
1118
|
+
* @returns `true` if at least one entry was added or extended; `false` if the input was nullish or empty.
|
|
1119
|
+
*
|
|
1120
|
+
* @remarks Existing map entries are extended (not replaced) with the new values, maintaining all previously registered suggestions for a given key. This accumulative behavior allows multiple plugins to contribute value suggestions for the same property.
|
|
1121
|
+
*
|
|
1122
|
+
* @example
|
|
1123
|
+
* ```ts
|
|
1124
|
+
* const map = new Map<string, string[]>()
|
|
1125
|
+
* appendAutocompleteRecordEntries(map, { color: ['red', 'blue'] }) // true
|
|
1126
|
+
* appendAutocompleteRecordEntries(map, { color: 'green' }) // true (now ['red','blue','green'])
|
|
1127
|
+
* ```
|
|
1128
|
+
*/
|
|
1129
|
+
function appendAutocompleteRecordEntries(map, entries) {
|
|
1130
|
+
if (entries == null) return false;
|
|
1131
|
+
let changed = false;
|
|
1132
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
1133
|
+
const nextValues = [value].flat();
|
|
1134
|
+
if (nextValues.length === 0) continue;
|
|
1135
|
+
const current = map.get(key) || [];
|
|
1136
|
+
map.set(key, [...current, ...nextValues]);
|
|
1137
|
+
changed = true;
|
|
1138
|
+
}
|
|
1139
|
+
return changed;
|
|
95
1140
|
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
1141
|
+
function normalizeAutocompleteRecordEntries(entries) {
|
|
1142
|
+
if (entries == null) return void 0;
|
|
1143
|
+
return Array.isArray(entries) ? Object.fromEntries(entries) : entries;
|
|
99
1144
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
1145
|
+
/**
|
|
1146
|
+
* Merges an `AutocompleteContribution` or `AutocompleteConfig` into the resolved autocomplete state, returning whether any entry changed.
|
|
1147
|
+
*
|
|
1148
|
+
* @param config - The resolved engine config (or a subset with the `autocomplete` field) to mutate.
|
|
1149
|
+
* @param contribution - The autocomplete entries to merge in.
|
|
1150
|
+
* @returns `true` if any selector, shortcut, property, CSS property, or pattern entry was added or extended.
|
|
1151
|
+
*
|
|
1152
|
+
* @remarks Called by `engine.appendAutocomplete()` and during initial config resolution. Each sub-field (selectors, shortcuts, etc.) is independently merged and the function returns `true` if any of them changed, which triggers an `autocompleteConfigUpdated` notification.
|
|
1153
|
+
*
|
|
1154
|
+
* @example
|
|
1155
|
+
* ```ts
|
|
1156
|
+
* const changed = appendAutocomplete(resolvedConfig, {
|
|
1157
|
+
* selectors: 'dark',
|
|
1158
|
+
* cssProperties: { color: 'primary' },
|
|
1159
|
+
* })
|
|
1160
|
+
* ```
|
|
1161
|
+
*/
|
|
1162
|
+
function appendAutocomplete(config, contribution) {
|
|
1163
|
+
const { patterns, properties, cssProperties, ...literals } = contribution;
|
|
1164
|
+
return [
|
|
1165
|
+
appendAutocompleteEntries(config.autocomplete.selectors, literals.selectors),
|
|
1166
|
+
appendAutocompleteEntries(config.autocomplete.shortcuts, literals.shortcuts),
|
|
1167
|
+
appendAutocompleteEntries(config.autocomplete.extraProperties, literals.extraProperties),
|
|
1168
|
+
appendAutocompleteEntries(config.autocomplete.extraCssProperties, literals.extraCssProperties),
|
|
1169
|
+
appendAutocompleteRecordEntries(config.autocomplete.properties, normalizeAutocompleteRecordEntries(properties)),
|
|
1170
|
+
appendAutocompleteRecordEntries(config.autocomplete.cssProperties, normalizeAutocompleteRecordEntries(cssProperties)),
|
|
1171
|
+
appendAutocompleteEntries(config.autocomplete.patterns.selectors, patterns?.selectors),
|
|
1172
|
+
appendAutocompleteEntries(config.autocomplete.patterns.shortcuts, patterns?.shortcuts),
|
|
1173
|
+
appendAutocompleteRecordEntries(config.autocomplete.patterns.properties, patterns?.properties),
|
|
1174
|
+
appendAutocompleteRecordEntries(config.autocomplete.patterns.cssProperties, patterns?.cssProperties)
|
|
1175
|
+
].some(Boolean);
|
|
103
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Serializes a `CSSStyleBlocks` tree into a CSS string, optionally formatted with indentation and newlines.
|
|
1179
|
+
*
|
|
1180
|
+
* @param blocks - The CSS block tree to render.
|
|
1181
|
+
* @param isFormatted - When `true`, output includes indentation and newlines for readability; when `false`, output is minified.
|
|
1182
|
+
* @param depth - Current nesting depth for indentation (defaults to `0`).
|
|
1183
|
+
* @returns The rendered CSS string.
|
|
1184
|
+
*
|
|
1185
|
+
* @remarks Recursively renders nested blocks (e.g. media queries wrapping selectors). Empty blocks (no properties and no children) are omitted from the output.
|
|
1186
|
+
*
|
|
1187
|
+
* @example
|
|
1188
|
+
* ```ts
|
|
1189
|
+
* const blocks: CSSStyleBlocks = new Map()
|
|
1190
|
+
* blocks.set('.pk-a', { properties: [{ property: 'color', value: 'red' }] })
|
|
1191
|
+
* renderCSSStyleBlocks(blocks, true)
|
|
1192
|
+
* // '.pk-a {\n color: red;\n}'
|
|
1193
|
+
* ```
|
|
1194
|
+
*/
|
|
104
1195
|
function renderCSSStyleBlocks(blocks, isFormatted, depth = 0) {
|
|
105
1196
|
const blockIndent = isFormatted ? " ".repeat(depth) : "";
|
|
106
1197
|
const blockBodyIndent = isFormatted ? " ".repeat(depth + 1) : "";
|
|
@@ -119,7 +1210,235 @@ function renderCSSStyleBlocks(blocks, isFormatted, depth = 0) {
|
|
|
119
1210
|
});
|
|
120
1211
|
return lines.join(lineEnd);
|
|
121
1212
|
}
|
|
122
|
-
|
|
1213
|
+
//#endregion
|
|
1214
|
+
//#region src/internal/atomic-style.ts
|
|
1215
|
+
/**
|
|
1216
|
+
* Creates a fresh, empty `EngineStore` with all maps initialized.
|
|
1217
|
+
* @internal
|
|
1218
|
+
*
|
|
1219
|
+
* @returns A new `EngineStore` instance with empty maps.
|
|
1220
|
+
*
|
|
1221
|
+
* @remarks Called once during engine construction. Each engine instance owns a single store.
|
|
1222
|
+
*
|
|
1223
|
+
* @example
|
|
1224
|
+
* ```ts
|
|
1225
|
+
* const store = createEngineStore()
|
|
1226
|
+
* store.atomicStyles.size // 0
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
function createEngineStore() {
|
|
1230
|
+
return {
|
|
1231
|
+
atomicStyleIds: /* @__PURE__ */ new Map(),
|
|
1232
|
+
atomicStyles: /* @__PURE__ */ new Map(),
|
|
1233
|
+
atomicStyleIdsByBaseKey: /* @__PURE__ */ new Map(),
|
|
1234
|
+
atomicStyleOrder: /* @__PURE__ */ new Map()
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Assigns or retrieves a compact atomic style ID for the given resolved style content.
|
|
1239
|
+
* @internal
|
|
1240
|
+
*
|
|
1241
|
+
* @param options - Object containing the style `content`, the engine `prefix`, and the `stored` ID map.
|
|
1242
|
+
* @param options.content - The resolved style content to hash and identify.
|
|
1243
|
+
* @param options.prefix - The class-name prefix used when constructing a new atomic style ID.
|
|
1244
|
+
* @param options.stored - The map that caches assigned IDs by serialized key.
|
|
1245
|
+
* @returns The short alphabetic ID string (e.g. `'pk-a'`, `'pk-bA'`).
|
|
1246
|
+
*
|
|
1247
|
+
* @remarks For non-order-sensitive content, returns a cached ID if one already exists for the same base key. For order-sensitive content (where `orderSensitiveTo` is set), always generates a new ID to prevent incorrect reuse across different call-site orderings.
|
|
1248
|
+
*
|
|
1249
|
+
* @example
|
|
1250
|
+
* ```ts
|
|
1251
|
+
* const id = getAtomicStyleId({ content, prefix: 'pk-', stored: store.atomicStyleIds })
|
|
1252
|
+
* // 'pk-a'
|
|
1253
|
+
* ```
|
|
1254
|
+
*/
|
|
1255
|
+
function getAtomicStyleId({ content, prefix, stored }) {
|
|
1256
|
+
const baseKey = getAtomicStyleBaseKey(content);
|
|
1257
|
+
if (isOrderSensitiveContent(content) === false) {
|
|
1258
|
+
const cached = stored.get(baseKey);
|
|
1259
|
+
if (cached != null) {
|
|
1260
|
+
log.debug(`Atomic style cached: ${cached}`);
|
|
1261
|
+
return cached;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
const num = stored.size;
|
|
1265
|
+
const id = `${prefix}${numberToChars(num)}`;
|
|
1266
|
+
const key = getAtomicStyleStoredKey({
|
|
1267
|
+
content,
|
|
1268
|
+
baseKey,
|
|
1269
|
+
num
|
|
1270
|
+
});
|
|
1271
|
+
stored.set(key, id);
|
|
1272
|
+
log.debug(`Generated new atomic style ID: ${id}`);
|
|
1273
|
+
return id;
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Resolves a `StyleContent` into an atomic style: either reusing an existing ID or creating a new `AtomicStyle` entry in the store.
|
|
1277
|
+
* @internal
|
|
1278
|
+
*
|
|
1279
|
+
* @param options - Object containing the style `content`, `prefix`, `store`, and the per-use-call `resolvedIdsByBaseKey` map for order-sensitive reuse tracking.
|
|
1280
|
+
* @param options.content - The style content to resolve into a cached or newly registered atomic style.
|
|
1281
|
+
* @param options.prefix - The atomic style ID prefix for any newly created IDs.
|
|
1282
|
+
* @param options.store - The engine store holding existing atomic styles and lookup maps.
|
|
1283
|
+
* @param options.resolvedIdsByBaseKey - Per-call memoization map for reusing order-sensitive IDs within one `engine.use()` execution.
|
|
1284
|
+
* @returns An `AtomicStyleResolution` with the assigned `id` and optionally the newly created `atomicStyle` (absent when the ID was already registered).
|
|
1285
|
+
*
|
|
1286
|
+
* @remarks First checks for reusable order-sensitive IDs within the current `engine.use()` call, then falls back to `getAtomicStyleId` for general ID assignment. When a new atomic style is created, it is registered in all store indices.
|
|
1287
|
+
*
|
|
1288
|
+
* @example
|
|
1289
|
+
* ```ts
|
|
1290
|
+
* const { id, atomicStyle } = resolveAtomicStyle({
|
|
1291
|
+
* content, prefix: 'pk-', store, resolvedIdsByBaseKey,
|
|
1292
|
+
* })
|
|
1293
|
+
* ```
|
|
1294
|
+
*/
|
|
1295
|
+
function resolveAtomicStyle({ content, prefix, store, resolvedIdsByBaseKey }) {
|
|
1296
|
+
const reusableId = findReusableOrderSensitiveAtomicStyleId({
|
|
1297
|
+
content,
|
|
1298
|
+
store,
|
|
1299
|
+
resolvedIdsByBaseKey
|
|
1300
|
+
});
|
|
1301
|
+
if (reusableId != null) {
|
|
1302
|
+
log.debug(`Order-sensitive atomic style reused: ${reusableId}`);
|
|
1303
|
+
return { id: reusableId };
|
|
1304
|
+
}
|
|
1305
|
+
const id = getAtomicStyleId({
|
|
1306
|
+
content,
|
|
1307
|
+
prefix,
|
|
1308
|
+
stored: store.atomicStyleIds
|
|
1309
|
+
});
|
|
1310
|
+
if (store.atomicStyles.has(id)) return { id };
|
|
1311
|
+
const atomicStyle = {
|
|
1312
|
+
id,
|
|
1313
|
+
content
|
|
1314
|
+
};
|
|
1315
|
+
registerAtomicStyle(store, atomicStyle);
|
|
1316
|
+
return {
|
|
1317
|
+
id,
|
|
1318
|
+
atomicStyle
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Deduplicates and optimizes a list of extracted style contents by merging duplicate selector-property pairs and detecting order-sensitive shorthand overlaps.
|
|
1323
|
+
* @internal
|
|
1324
|
+
* @param list - The raw extracted style contents to optimize.
|
|
1325
|
+
* @returns An optimized array of `StyleContent` entries with nullish-value removals applied and `orderSensitiveTo` metadata attached where needed.
|
|
1326
|
+
*
|
|
1327
|
+
* @remarks Later definitions of the same selector-property pair cancel earlier ones. When two properties in the same scope share overlapping CSS effects (e.g. `margin` and `margin-top`), the later one is marked as order-sensitive to prevent incorrect ID reuse.
|
|
1328
|
+
*
|
|
1329
|
+
* @example
|
|
1330
|
+
* ```ts
|
|
1331
|
+
* const optimized = optimizeAtomicStyleContents(extractedList)
|
|
1332
|
+
* ```
|
|
1333
|
+
*/
|
|
1334
|
+
function optimizeAtomicStyleContents(list) {
|
|
1335
|
+
const map = /* @__PURE__ */ new Map();
|
|
1336
|
+
const scopedEntries = /* @__PURE__ */ new Map();
|
|
1337
|
+
list.forEach((content) => {
|
|
1338
|
+
const scopeKey = serialize(content.selector);
|
|
1339
|
+
const key = serialize([content.selector, content.property]);
|
|
1340
|
+
const scoped = scopedEntries.get(scopeKey) || /* @__PURE__ */ new Map();
|
|
1341
|
+
scopedEntries.set(scopeKey, scoped);
|
|
1342
|
+
map.delete(key);
|
|
1343
|
+
scoped.delete(key);
|
|
1344
|
+
if (content.value == null) return;
|
|
1345
|
+
const { selector, property, value } = content;
|
|
1346
|
+
const nextContent = {
|
|
1347
|
+
selector,
|
|
1348
|
+
property,
|
|
1349
|
+
value
|
|
1350
|
+
};
|
|
1351
|
+
const dependencyKeys = getOrderSensitiveDependencyKeys(scoped, property);
|
|
1352
|
+
if (dependencyKeys.length > 0) nextContent.orderSensitiveTo = dependencyKeys;
|
|
1353
|
+
map.set(key, nextContent);
|
|
1354
|
+
scoped.set(key, nextContent);
|
|
1355
|
+
});
|
|
1356
|
+
return [...map.values()];
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Computes the base cache key for an atomic style from its selector, property, and value.
|
|
1360
|
+
* @internal
|
|
1361
|
+
*
|
|
1362
|
+
* @param content - An object with `selector`, `property`, and `value` fields.
|
|
1363
|
+
* @returns A deterministic serialized string key.
|
|
1364
|
+
*
|
|
1365
|
+
* @remarks Used for deduplication: two atomic styles with the same base key are considered equivalent (unless order-sensitive). The key is derived by serializing the triple `[selector, property, value]`.
|
|
1366
|
+
*
|
|
1367
|
+
* @example
|
|
1368
|
+
* ```ts
|
|
1369
|
+
* const key = getAtomicStyleBaseKey({ selector: ['.pk-__ID__'], property: 'color', value: ['red'] })
|
|
1370
|
+
* ```
|
|
1371
|
+
*/
|
|
1372
|
+
function getAtomicStyleBaseKey(content) {
|
|
1373
|
+
return serialize([
|
|
1374
|
+
content.selector,
|
|
1375
|
+
content.property,
|
|
1376
|
+
content.value
|
|
1377
|
+
]);
|
|
1378
|
+
}
|
|
1379
|
+
function getAtomicStyleStoredKey({ content, baseKey, num }) {
|
|
1380
|
+
return isOrderSensitiveContent(content) ? serialize([
|
|
1381
|
+
baseKey,
|
|
1382
|
+
"order-sensitive",
|
|
1383
|
+
num
|
|
1384
|
+
]) : baseKey;
|
|
1385
|
+
}
|
|
1386
|
+
function isOrderSensitiveContent(content) {
|
|
1387
|
+
return (content.orderSensitiveTo?.length ?? 0) > 0;
|
|
1388
|
+
}
|
|
1389
|
+
function registerAtomicStyle(store, atomicStyle) {
|
|
1390
|
+
const { id, content } = atomicStyle;
|
|
1391
|
+
const baseKey = getAtomicStyleBaseKey(content);
|
|
1392
|
+
store.atomicStyleOrder.set(id, store.atomicStyles.size);
|
|
1393
|
+
store.atomicStyles.set(id, atomicStyle);
|
|
1394
|
+
const ids = store.atomicStyleIdsByBaseKey.get(baseKey);
|
|
1395
|
+
if (ids == null) store.atomicStyleIdsByBaseKey.set(baseKey, [id]);
|
|
1396
|
+
else ids.push(id);
|
|
1397
|
+
}
|
|
1398
|
+
function getRequiredAtomicStyleOrder({ dependencyKeys, store, resolvedIdsByBaseKey }) {
|
|
1399
|
+
let requiredOrder = -1;
|
|
1400
|
+
for (const dependencyKey of dependencyKeys) {
|
|
1401
|
+
const dependencyId = resolvedIdsByBaseKey.get(dependencyKey) ?? store.atomicStyleIds.get(dependencyKey);
|
|
1402
|
+
if (dependencyId == null) continue;
|
|
1403
|
+
const dependencyOrder = store.atomicStyleOrder.get(dependencyId);
|
|
1404
|
+
if (dependencyOrder != null) requiredOrder = Math.max(requiredOrder, dependencyOrder);
|
|
1405
|
+
}
|
|
1406
|
+
return requiredOrder;
|
|
1407
|
+
}
|
|
1408
|
+
function findReusableOrderSensitiveAtomicStyleId({ content, store, resolvedIdsByBaseKey }) {
|
|
1409
|
+
if (isOrderSensitiveContent(content) === false) return void 0;
|
|
1410
|
+
const baseKey = getAtomicStyleBaseKey(content);
|
|
1411
|
+
const requiredOrder = getRequiredAtomicStyleOrder({
|
|
1412
|
+
dependencyKeys: content.orderSensitiveTo,
|
|
1413
|
+
store,
|
|
1414
|
+
resolvedIdsByBaseKey
|
|
1415
|
+
});
|
|
1416
|
+
return (store.atomicStyleIdsByBaseKey.get(baseKey) ?? []).find((candidateId) => {
|
|
1417
|
+
const candidateOrder = store.atomicStyleOrder.get(candidateId);
|
|
1418
|
+
return candidateOrder != null && candidateOrder > requiredOrder;
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
function getOrderSensitiveDependencyKeys(scoped, property) {
|
|
1422
|
+
const dependencyKeys = [];
|
|
1423
|
+
for (const existing of scoped.values()) if (hasPropertyEffectOverlap(existing.property, property)) dependencyKeys.push(getAtomicStyleBaseKey(existing));
|
|
1424
|
+
return dependencyKeys;
|
|
1425
|
+
}
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/internal/constants.ts
|
|
1428
|
+
/**
|
|
1429
|
+
* CSS `@layer` at-rule prefix used when constructing layer-scoped selectors
|
|
1430
|
+
* in generated stylesheet output.
|
|
1431
|
+
*
|
|
1432
|
+
* @internal
|
|
1433
|
+
*/
|
|
1434
|
+
const LAYER_SELECTOR_PREFIX = "@layer ";
|
|
1435
|
+
/**
|
|
1436
|
+
* Global regex matching all occurrences of {@link ATOMIC_STYLE_ID_PLACEHOLDER}
|
|
1437
|
+
* for batch replacement in selector templates.
|
|
1438
|
+
*
|
|
1439
|
+
* @internal
|
|
1440
|
+
*/
|
|
1441
|
+
const ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL = /%/g;
|
|
123
1442
|
//#endregion
|
|
124
1443
|
//#region src/internal/extractor.ts
|
|
125
1444
|
function replaceBySplitAndJoin(str, split, mapFn, join) {
|
|
@@ -131,9 +1450,42 @@ const RE_SPLIT = /\s*,\s*/g;
|
|
|
131
1450
|
const DEFAULT_SELECTOR_PLACEHOLDER_RE_GLOBAL = /\$/g;
|
|
132
1451
|
const ATTRIBUTE_SUFFIX_MATCH = "$=";
|
|
133
1452
|
const ATTRIBUTE_SUFFIX_MATCH_RE_GLOBAL = /\$=/g;
|
|
1453
|
+
/**
|
|
1454
|
+
* Normalizes selector strings by replacing placeholders (`$` → `defaultSelector`, `%` → atomic style ID placeholder) and splitting comma-separated selectors.
|
|
1455
|
+
* @internal
|
|
1456
|
+
*
|
|
1457
|
+
* @param options - Object containing the raw `selectors` array and the `defaultSelector` template.
|
|
1458
|
+
* @param options.selectors - The raw selector strings to normalize.
|
|
1459
|
+
* @param options.defaultSelector - The selector template that replaces `$` placeholders.
|
|
1460
|
+
* @returns An array of normalized selector strings with all placeholders resolved.
|
|
1461
|
+
*
|
|
1462
|
+
* @remarks The `$` character in a selector is replaced with the engine's `defaultSelector`. The `%` character is the atomic style ID placeholder, preserved for later substitution. Attribute suffix matches (`$=`) are protected from the `$` replacement.
|
|
1463
|
+
*
|
|
1464
|
+
* @example
|
|
1465
|
+
* ```ts
|
|
1466
|
+
* normalizeSelectors({ selectors: ['$hover $'], defaultSelector: '.%' })
|
|
1467
|
+
* // ['.%:hover .%'] (conceptually)
|
|
1468
|
+
* ```
|
|
1469
|
+
*/
|
|
134
1470
|
function normalizeSelectors({ selectors, defaultSelector }) {
|
|
135
|
-
return selectors.map((s) => replaceBySplitAndJoin(s.replace(RE_SPLIT, ","), ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, (a) => replaceBySplitAndJoin(a, ATTRIBUTE_SUFFIX_MATCH_RE_GLOBAL, (b) => replaceBySplitAndJoin(b, DEFAULT_SELECTOR_PLACEHOLDER_RE_GLOBAL, null, defaultSelector), ATTRIBUTE_SUFFIX_MATCH),
|
|
1471
|
+
return selectors.map((s) => replaceBySplitAndJoin(s.replace(RE_SPLIT, ","), ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, (a) => replaceBySplitAndJoin(a, ATTRIBUTE_SUFFIX_MATCH_RE_GLOBAL, (b) => replaceBySplitAndJoin(b, DEFAULT_SELECTOR_PLACEHOLDER_RE_GLOBAL, null, defaultSelector), ATTRIBUTE_SUFFIX_MATCH), "%"));
|
|
136
1472
|
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Normalizes a raw `InternalPropertyValue` into the extraction output format: an array of trimmed, deduplicated CSS value strings with fallbacks ordered before the primary value, or `null`/`undefined` to signal removal.
|
|
1475
|
+
* @internal
|
|
1476
|
+
*
|
|
1477
|
+
* @param value - The raw property value to normalize.
|
|
1478
|
+
* @returns An array of CSS value strings (fallbacks first, primary last), or `null`/`undefined` for removal.
|
|
1479
|
+
*
|
|
1480
|
+
* @remarks For tuple values `[primary, fallbacks]`, duplicates among fallbacks are removed and the primary value is appended last so CSS cascade uses it as the effective value while older browsers fall back to earlier entries.
|
|
1481
|
+
*
|
|
1482
|
+
* @example
|
|
1483
|
+
* ```ts
|
|
1484
|
+
* normalizeValue('red') // ['red']
|
|
1485
|
+
* normalizeValue(['red', ['blue']]) // ['blue', 'red']
|
|
1486
|
+
* normalizeValue(null) // null
|
|
1487
|
+
* ```
|
|
1488
|
+
*/
|
|
137
1489
|
function normalizeValue(value) {
|
|
138
1490
|
if (value == null) return value;
|
|
139
1491
|
if (Array.isArray(value)) {
|
|
@@ -153,13 +1505,40 @@ function normalizeValue(value) {
|
|
|
153
1505
|
}
|
|
154
1506
|
return [value.trim()];
|
|
155
1507
|
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Recursively walks a style definition tree, extracting each CSS property-value pair into a flat list of `ExtractedStyleContent` entries with their full selector chain.
|
|
1510
|
+
* @internal
|
|
1511
|
+
*
|
|
1512
|
+
* @param options - Extraction context: the `styleDefinition` to walk, current nesting `levels`, accumulated `result`, `defaultSelector`, and plugin transform hooks for selectors, style items, and style definitions.
|
|
1513
|
+
* @param options.styleDefinition - The style definition subtree currently being traversed.
|
|
1514
|
+
* @param options.levels - The accumulated nested selector levels leading to this subtree.
|
|
1515
|
+
* @param options.result - The mutable extraction result array being appended to.
|
|
1516
|
+
* @param options.defaultSelector - The selector substituted when extracted selectors omit the atomic-style placeholder.
|
|
1517
|
+
* @param options.transformSelectors - Hook that rewrites selector levels before normalization.
|
|
1518
|
+
* @param options.transformStyleItems - Hook that expands array style items before recursive extraction.
|
|
1519
|
+
* @param options.transformStyleDefinitions - Hook that rewrites style definition objects before traversal.
|
|
1520
|
+
* @returns The accumulated array of `ExtractedStyleContent` entries.
|
|
1521
|
+
*
|
|
1522
|
+
* @remarks Property values are identified using `isPropertyValue`. Array values are treated as style item lists (resolved via `transformStyleItems`). Object values are treated as nested style definitions and recursed into. The transform hooks allow plugins (shortcuts, selectors) to intercept and expand values during extraction.
|
|
1523
|
+
*
|
|
1524
|
+
* @example
|
|
1525
|
+
* ```ts
|
|
1526
|
+
* const contents = await extract({
|
|
1527
|
+
* styleDefinition: { color: 'red', '$hover': { color: 'blue' } },
|
|
1528
|
+
* defaultSelector: '.%',
|
|
1529
|
+
* transformSelectors: async s => s,
|
|
1530
|
+
* transformStyleItems: async i => i,
|
|
1531
|
+
* transformStyleDefinitions: async d => d,
|
|
1532
|
+
* })
|
|
1533
|
+
* ```
|
|
1534
|
+
*/
|
|
156
1535
|
async function extract({ styleDefinition, levels = [], result = [], defaultSelector, transformSelectors, transformStyleItems, transformStyleDefinitions }) {
|
|
157
1536
|
for (const definition of await transformStyleDefinitions([styleDefinition])) for (const [k, v] of Object.entries(definition)) if (isPropertyValue(v)) {
|
|
158
1537
|
const selector = normalizeSelectors({
|
|
159
1538
|
selectors: await transformSelectors(levels),
|
|
160
1539
|
defaultSelector
|
|
161
1540
|
});
|
|
162
|
-
if (selector.length === 0 || selector.every((s) => s.includes(
|
|
1541
|
+
if (selector.length === 0 || selector.every((s) => s.includes("%") === false)) selector.push(defaultSelector);
|
|
163
1542
|
result.push({
|
|
164
1543
|
selector,
|
|
165
1544
|
property: toKebab(k),
|
|
@@ -188,53 +1567,139 @@ async function extract({ styleDefinition, levels = [], result = [], defaultSelec
|
|
|
188
1567
|
});
|
|
189
1568
|
return result;
|
|
190
1569
|
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Creates a bound extraction function that closes over the default selector and plugin transform hooks.
|
|
1572
|
+
* @internal
|
|
1573
|
+
*
|
|
1574
|
+
* @param options - The extraction options: `defaultSelector`, `transformSelectors`, `transformStyleItems`, and `transformStyleDefinitions`.
|
|
1575
|
+
* @param options.defaultSelector - The selector used when no explicit atomic placeholder selector remains.
|
|
1576
|
+
* @param options.transformSelectors - Hook that rewrites selector arrays before normalization.
|
|
1577
|
+
* @param options.transformStyleItems - Hook that rewrites or expands style item arrays.
|
|
1578
|
+
* @param options.transformStyleDefinitions - Hook that rewrites style definition objects before extraction.
|
|
1579
|
+
* @returns An `ExtractFn` that accepts a style definition and returns extracted contents.
|
|
1580
|
+
*
|
|
1581
|
+
* @remarks Called once during engine construction. The returned function is stored as `engine.extract` and used for all subsequent `engine.use()` calls.
|
|
1582
|
+
*
|
|
1583
|
+
* @example
|
|
1584
|
+
* ```ts
|
|
1585
|
+
* const extractFn = createExtractFn({
|
|
1586
|
+
* defaultSelector: '.%',
|
|
1587
|
+
* transformSelectors: async s => s,
|
|
1588
|
+
* transformStyleItems: async i => i,
|
|
1589
|
+
* transformStyleDefinitions: async d => d,
|
|
1590
|
+
* })
|
|
1591
|
+
* ```
|
|
1592
|
+
*/
|
|
191
1593
|
function createExtractFn(options) {
|
|
192
1594
|
return (styleDefinition) => extract({
|
|
193
1595
|
styleDefinition,
|
|
194
1596
|
...options
|
|
195
1597
|
});
|
|
196
1598
|
}
|
|
197
|
-
|
|
198
1599
|
//#endregion
|
|
199
1600
|
//#region src/internal/plugin.ts
|
|
1601
|
+
function getPluginHook(plugin, hook) {
|
|
1602
|
+
const hookFn = plugin[hook];
|
|
1603
|
+
return typeof hookFn === "function" ? hookFn : null;
|
|
1604
|
+
}
|
|
1605
|
+
function applyHookPayload(current, next) {
|
|
1606
|
+
return next ?? current;
|
|
1607
|
+
}
|
|
1608
|
+
function logHookStart(kind, hook) {
|
|
1609
|
+
log.debug(`Executing ${kind.toLowerCase()} hook: ${hook}`);
|
|
1610
|
+
}
|
|
1611
|
+
function logHookEnd(kind, hook) {
|
|
1612
|
+
log.debug(`${kind} hook "${hook}" completed`);
|
|
1613
|
+
}
|
|
1614
|
+
function logPluginHookStart(plugin, hook) {
|
|
1615
|
+
log.debug(` - Plugin "${plugin.name}" executing ${hook}`);
|
|
1616
|
+
}
|
|
1617
|
+
function logPluginHookEnd(plugin, hook) {
|
|
1618
|
+
log.debug(` - Plugin "${plugin.name}" completed ${hook}`);
|
|
1619
|
+
}
|
|
1620
|
+
function logPluginHookError(plugin, hook, error) {
|
|
1621
|
+
log.error(`Plugin "${plugin.name}" failed to execute hook "${hook}": ${error instanceof Error ? error.message : error}`, error);
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Executes an async hook across all plugins in order, piping the payload through each plugin's handler.
|
|
1625
|
+
* @internal
|
|
1626
|
+
*
|
|
1627
|
+
* @typeParam P - The payload/return type flowing through the hook pipeline.
|
|
1628
|
+
* @param plugins - The ordered list of engine plugins to execute.
|
|
1629
|
+
* @param hook - The name of the async hook to invoke.
|
|
1630
|
+
* @param payload - The initial payload to pass into the first plugin.
|
|
1631
|
+
* @returns The final payload after all plugins have processed it.
|
|
1632
|
+
*
|
|
1633
|
+
* @remarks Each plugin's hook receives the current payload and may return a replacement. If a plugin's hook throws, the error is logged and the current payload is preserved for subsequent plugins.
|
|
1634
|
+
*
|
|
1635
|
+
* @example
|
|
1636
|
+
* ```ts
|
|
1637
|
+
* const config = await execAsyncHook(plugins, 'configureRawConfig', rawConfig)
|
|
1638
|
+
* ```
|
|
1639
|
+
*/
|
|
200
1640
|
async function execAsyncHook(plugins, hook, payload) {
|
|
201
|
-
|
|
1641
|
+
logHookStart("Async", hook);
|
|
202
1642
|
let current = payload;
|
|
203
1643
|
for (const plugin of plugins) {
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
1644
|
+
const hookFn = getPluginHook(plugin, hook);
|
|
1645
|
+
if (hookFn == null) continue;
|
|
206
1646
|
try {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (newPayload != null) current = newPayload;
|
|
211
|
-
log.debug(` - Plugin "${plugin.name}" completed ${hook}`);
|
|
1647
|
+
logPluginHookStart(plugin, hook);
|
|
1648
|
+
current = applyHookPayload(current, await hookFn(current));
|
|
1649
|
+
logPluginHookEnd(plugin, hook);
|
|
212
1650
|
} catch (error) {
|
|
213
|
-
|
|
1651
|
+
logPluginHookError(plugin, hook, error);
|
|
214
1652
|
}
|
|
215
1653
|
}
|
|
216
|
-
|
|
1654
|
+
logHookEnd("Async", hook);
|
|
217
1655
|
return current;
|
|
218
1656
|
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Executes a synchronous hook across all plugins in order, piping the payload through each plugin's handler.
|
|
1659
|
+
* @internal
|
|
1660
|
+
*
|
|
1661
|
+
* @typeParam P - The payload/return type flowing through the hook pipeline.
|
|
1662
|
+
* @param plugins - The ordered list of engine plugins to execute.
|
|
1663
|
+
* @param hook - The name of the sync hook to invoke.
|
|
1664
|
+
* @param payload - The initial payload to pass into the first plugin.
|
|
1665
|
+
* @returns The final payload after all plugins have processed it.
|
|
1666
|
+
*
|
|
1667
|
+
* @remarks Functions identically to `execAsyncHook` but without awaiting. Used for notification-style hooks like `preflightUpdated` or `atomicStyleAdded`.
|
|
1668
|
+
*
|
|
1669
|
+
* @example
|
|
1670
|
+
* ```ts
|
|
1671
|
+
* execSyncHook(plugins, 'atomicStyleAdded', atomicStyle)
|
|
1672
|
+
* ```
|
|
1673
|
+
*/
|
|
219
1674
|
function execSyncHook(plugins, hook, payload) {
|
|
220
|
-
|
|
1675
|
+
logHookStart("Sync", hook);
|
|
221
1676
|
let current = payload;
|
|
222
1677
|
for (const plugin of plugins) {
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
1678
|
+
const hookFn = getPluginHook(plugin, hook);
|
|
1679
|
+
if (hookFn == null) continue;
|
|
225
1680
|
try {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (newPayload != null) current = newPayload;
|
|
230
|
-
log.debug(` - Plugin "${plugin.name}" completed ${hook}`);
|
|
1681
|
+
logPluginHookStart(plugin, hook);
|
|
1682
|
+
current = applyHookPayload(current, hookFn(current));
|
|
1683
|
+
logPluginHookEnd(plugin, hook);
|
|
231
1684
|
} catch (error) {
|
|
232
|
-
|
|
1685
|
+
logPluginHookError(plugin, hook, error);
|
|
233
1686
|
}
|
|
234
1687
|
}
|
|
235
|
-
|
|
1688
|
+
logHookEnd("Sync", hook);
|
|
236
1689
|
return current;
|
|
237
1690
|
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Pre-built hook dispatcher object mapping each hook name to a function that delegates to `execAsyncHook` or `execSyncHook`.
|
|
1693
|
+
* @internal
|
|
1694
|
+
*
|
|
1695
|
+
* @remarks Provides a convenient, type-safe interface for calling any engine hook by name without manually selecting between `execAsyncHook` and `execSyncHook`. Used throughout the `Engine` class.
|
|
1696
|
+
*
|
|
1697
|
+
* @example
|
|
1698
|
+
* ```ts
|
|
1699
|
+
* const config = await hooks.configureRawConfig(plugins, rawConfig)
|
|
1700
|
+
* hooks.preflightUpdated(plugins)
|
|
1701
|
+
* ```
|
|
1702
|
+
*/
|
|
238
1703
|
const hooks = {
|
|
239
1704
|
configureRawConfig: (plugins, config) => execAsyncHook(plugins, "configureRawConfig", config),
|
|
240
1705
|
rawConfigConfigured: (plugins, config) => execSyncHook(plugins, "rawConfigConfigured", config),
|
|
@@ -252,15 +1717,45 @@ const orderMap = new Map([
|
|
|
252
1717
|
["pre", 0],
|
|
253
1718
|
["post", 2]
|
|
254
1719
|
]);
|
|
1720
|
+
/**
|
|
1721
|
+
* Sorts an array of plugins by their `order` property: `'pre'` first, default in the middle, `'post'` last.
|
|
1722
|
+
* @internal
|
|
1723
|
+
*
|
|
1724
|
+
* @param plugins - The unordered array of engine plugins.
|
|
1725
|
+
* @returns A new array sorted by execution order.
|
|
1726
|
+
*
|
|
1727
|
+
* @remarks The original array is not mutated. Plugins with the same order retain their relative insertion order (stable sort).
|
|
1728
|
+
*
|
|
1729
|
+
* @example
|
|
1730
|
+
* ```ts
|
|
1731
|
+
* const ordered = resolvePlugins([postPlugin, prePlugin, normalPlugin])
|
|
1732
|
+
* // [prePlugin, normalPlugin, postPlugin]
|
|
1733
|
+
* ```
|
|
1734
|
+
*/
|
|
255
1735
|
function resolvePlugins(plugins) {
|
|
256
1736
|
return [...plugins].sort((a, b) => orderMap.get(a.order) - orderMap.get(b.order));
|
|
257
1737
|
}
|
|
258
1738
|
/* c8 ignore start */
|
|
1739
|
+
/**
|
|
1740
|
+
* Identity helper that returns the plugin object as-is, providing TypeScript type inference for plugin definitions.
|
|
1741
|
+
*
|
|
1742
|
+
* @param plugin - The engine plugin definition.
|
|
1743
|
+
* @returns The same plugin object, unchanged.
|
|
1744
|
+
*
|
|
1745
|
+
* @remarks This is a compile-time-only helper; it has no runtime effect. Using it ensures type checking and IDE autocompletion for hook names and payloads.
|
|
1746
|
+
*
|
|
1747
|
+
* @example
|
|
1748
|
+
* ```ts
|
|
1749
|
+
* export default defineEnginePlugin({
|
|
1750
|
+
* name: 'my-plugin',
|
|
1751
|
+
* configureRawConfig: (config) => ({ ...config, important: true }),
|
|
1752
|
+
* })
|
|
1753
|
+
* ```
|
|
1754
|
+
*/
|
|
259
1755
|
function defineEnginePlugin(plugin) {
|
|
260
1756
|
return plugin;
|
|
261
1757
|
}
|
|
262
1758
|
/* c8 ignore end */
|
|
263
|
-
|
|
264
1759
|
//#endregion
|
|
265
1760
|
//#region src/internal/plugins/important.ts
|
|
266
1761
|
function appendImportant(v) {
|
|
@@ -271,6 +1766,18 @@ function modifyPropertyValue(value) {
|
|
|
271
1766
|
if (Array.isArray(value)) return [appendImportant(value[0]), value[1].map((i) => appendImportant(i))];
|
|
272
1767
|
return appendImportant(value);
|
|
273
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Built-in engine plugin that appends `!important` to generated CSS declarations.
|
|
1771
|
+
*
|
|
1772
|
+
* @returns An `EnginePlugin` that intercepts `transformStyleDefinitions` to conditionally append `!important` to every property value.
|
|
1773
|
+
*
|
|
1774
|
+
* @remarks When `EngineConfig.important.default` is `true`, all property values receive `!important` unless the style definition explicitly sets `__important: false`. Individual style definitions can also opt-in with `__important: true` regardless of the default.
|
|
1775
|
+
*
|
|
1776
|
+
* @example
|
|
1777
|
+
* ```ts
|
|
1778
|
+
* createEngine({ plugins: [important()] })
|
|
1779
|
+
* ```
|
|
1780
|
+
*/
|
|
274
1781
|
function important() {
|
|
275
1782
|
let defaultValue;
|
|
276
1783
|
return defineEnginePlugin({
|
|
@@ -279,14 +1786,15 @@ function important() {
|
|
|
279
1786
|
defaultValue = config.important?.default ?? false;
|
|
280
1787
|
},
|
|
281
1788
|
configureEngine(engine) {
|
|
282
|
-
engine.
|
|
283
|
-
|
|
1789
|
+
engine.appendAutocomplete({
|
|
1790
|
+
extraProperties: "__important",
|
|
1791
|
+
properties: { __important: "boolean" }
|
|
1792
|
+
});
|
|
284
1793
|
},
|
|
285
1794
|
transformStyleDefinitions(styleDefinitions) {
|
|
286
1795
|
return styleDefinitions.map((styleDefinition) => {
|
|
287
1796
|
const { __important, ...rest } = styleDefinition;
|
|
288
|
-
|
|
289
|
-
if ((value == null ? defaultValue : value) === false) return rest;
|
|
1797
|
+
if ((__important ?? defaultValue) === false) return rest;
|
|
290
1798
|
return Object.fromEntries(Object.entries(rest).map(([k, v]) => {
|
|
291
1799
|
if (isPropertyValue(v)) return [k, modifyPropertyValue(v)];
|
|
292
1800
|
return [k, v];
|
|
@@ -295,9 +1803,20 @@ function important() {
|
|
|
295
1803
|
}
|
|
296
1804
|
});
|
|
297
1805
|
}
|
|
298
|
-
|
|
299
1806
|
//#endregion
|
|
300
1807
|
//#region src/internal/plugins/keyframes.ts
|
|
1808
|
+
/**
|
|
1809
|
+
* Built-in engine plugin that provides CSS `@keyframes` registration, autocomplete integration, and smart pruning.
|
|
1810
|
+
*
|
|
1811
|
+
* @returns An `EnginePlugin` that registers keyframes definitions, wires up `animationName`/`animation` autocomplete entries, and emits a preflight containing only the `@keyframes` rules actually referenced by atomic styles.
|
|
1812
|
+
*
|
|
1813
|
+
* @remarks Reads `EngineConfig.keyframes` during `rawConfigConfigured` and attaches the `engine.keyframes` management interface during `configureEngine`. Unused keyframes are pruned from the output unless `pruneUnused: false` is set on the individual definition or globally.
|
|
1814
|
+
*
|
|
1815
|
+
* @example
|
|
1816
|
+
* ```ts
|
|
1817
|
+
* createEngine({ plugins: [keyframes()] })
|
|
1818
|
+
* ```
|
|
1819
|
+
*/
|
|
301
1820
|
function keyframes() {
|
|
302
1821
|
let resolveKeyframesConfig;
|
|
303
1822
|
let configList;
|
|
@@ -315,9 +1834,10 @@ function keyframes() {
|
|
|
315
1834
|
const resolved = resolveKeyframesConfig(config);
|
|
316
1835
|
const { name, frames, autocomplete: autocompleteAnimation } = resolved;
|
|
317
1836
|
if (frames != null) engine.keyframes.store.set(name, resolved);
|
|
318
|
-
engine.
|
|
319
|
-
|
|
320
|
-
|
|
1837
|
+
engine.appendAutocomplete({ cssProperties: {
|
|
1838
|
+
animationName: name,
|
|
1839
|
+
animation: autocompleteAnimation.length > 0 ? [`${name} `, ...autocompleteAnimation] : `${name} `
|
|
1840
|
+
} });
|
|
321
1841
|
});
|
|
322
1842
|
engine.notifyPreflightUpdated();
|
|
323
1843
|
}
|
|
@@ -372,17 +1892,35 @@ function createResolveConfigFn({ pruneUnused: defaultPruneUnused = true } = {})
|
|
|
372
1892
|
};
|
|
373
1893
|
};
|
|
374
1894
|
}
|
|
375
|
-
|
|
376
1895
|
//#endregion
|
|
377
1896
|
//#region src/internal/resolver.ts
|
|
378
1897
|
function stripGlobalFlag(re) {
|
|
379
1898
|
if (!re.global) return re;
|
|
380
1899
|
return new RegExp(re.source, re.flags.replace("g", ""));
|
|
381
1900
|
}
|
|
1901
|
+
/**
|
|
1902
|
+
* Base resolver class that manages static and dynamic rules and caches resolution results.
|
|
1903
|
+
* @internal
|
|
1904
|
+
*
|
|
1905
|
+
* @typeParam T - The type of resolved values.
|
|
1906
|
+
*
|
|
1907
|
+
* @remarks Subclasses override resolution behavior (e.g. `RecursiveResolver` adds recursive expansion). The base class handles rule storage, cache lookup, and the static-then-dynamic matching order. Results are cached in `_resolvedResultsMap` for subsequent lookups.
|
|
1908
|
+
*
|
|
1909
|
+
* @example
|
|
1910
|
+
* ```ts
|
|
1911
|
+
* class MyResolver extends AbstractResolver<string> { }
|
|
1912
|
+
* const r = new MyResolver()
|
|
1913
|
+
* r.addStaticRule({ key: 'x', string: 'x', resolved: 'X' })
|
|
1914
|
+
* ```
|
|
1915
|
+
*/
|
|
382
1916
|
var AbstractResolver = class {
|
|
1917
|
+
/** Cache of previously resolved input-string → result pairs. */
|
|
383
1918
|
_resolvedResultsMap = /* @__PURE__ */ new Map();
|
|
1919
|
+
/** Registry of static rules keyed by their unique key. */
|
|
384
1920
|
staticRulesMap = /* @__PURE__ */ new Map();
|
|
1921
|
+
/** Registry of dynamic rules keyed by their unique key. */
|
|
385
1922
|
dynamicRulesMap = /* @__PURE__ */ new Map();
|
|
1923
|
+
/** Callback invoked after a successful resolution, receiving the input string, rule type, and result. */
|
|
386
1924
|
onResolved = () => {};
|
|
387
1925
|
get staticRules() {
|
|
388
1926
|
return [...this.staticRulesMap.values()];
|
|
@@ -390,11 +1928,37 @@ var AbstractResolver = class {
|
|
|
390
1928
|
get dynamicRules() {
|
|
391
1929
|
return [...this.dynamicRulesMap.values()];
|
|
392
1930
|
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Registers a static rule in the resolver.
|
|
1933
|
+
*
|
|
1934
|
+
* @param rule - The static rule to register.
|
|
1935
|
+
* @returns `this` for chaining.
|
|
1936
|
+
*
|
|
1937
|
+
* @remarks Overwrites any existing static rule with the same key.
|
|
1938
|
+
*
|
|
1939
|
+
* @example
|
|
1940
|
+
* ```ts
|
|
1941
|
+
* resolver.addStaticRule({ key: 'dark', string: 'dark', resolved: ['.dark &'] })
|
|
1942
|
+
* ```
|
|
1943
|
+
*/
|
|
393
1944
|
addStaticRule(rule) {
|
|
394
1945
|
log.debug(`Adding static rule: ${rule.key}`);
|
|
395
1946
|
this.staticRulesMap.set(rule.key, rule);
|
|
396
1947
|
return this;
|
|
397
1948
|
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Removes a static rule and its cached resolution result.
|
|
1951
|
+
*
|
|
1952
|
+
* @param key - The key of the static rule to remove.
|
|
1953
|
+
* @returns `this` for chaining.
|
|
1954
|
+
*
|
|
1955
|
+
* @remarks Logs a warning if the key does not exist. Also evicts the cached result for the rule's input string.
|
|
1956
|
+
*
|
|
1957
|
+
* @example
|
|
1958
|
+
* ```ts
|
|
1959
|
+
* resolver.removeStaticRule('dark')
|
|
1960
|
+
* ```
|
|
1961
|
+
*/
|
|
398
1962
|
removeStaticRule(key) {
|
|
399
1963
|
const rule = this.staticRulesMap.get(key);
|
|
400
1964
|
if (rule == null) {
|
|
@@ -406,11 +1970,37 @@ var AbstractResolver = class {
|
|
|
406
1970
|
this._resolvedResultsMap.delete(rule.string);
|
|
407
1971
|
return this;
|
|
408
1972
|
}
|
|
1973
|
+
/**
|
|
1974
|
+
* Registers a dynamic rule in the resolver.
|
|
1975
|
+
*
|
|
1976
|
+
* @param rule - The dynamic rule to register.
|
|
1977
|
+
* @returns `this` for chaining.
|
|
1978
|
+
*
|
|
1979
|
+
* @remarks Overwrites any existing dynamic rule with the same key.
|
|
1980
|
+
*
|
|
1981
|
+
* @example
|
|
1982
|
+
* ```ts
|
|
1983
|
+
* resolver.addDynamicRule({ key: 'bp', stringPattern: /^bp-(\d+)$/, createResolved: m => [`@media (min-width: ${m[1]}px)`] })
|
|
1984
|
+
* ```
|
|
1985
|
+
*/
|
|
409
1986
|
addDynamicRule(rule) {
|
|
410
1987
|
log.debug(`Adding dynamic rule: ${rule.key}`);
|
|
411
1988
|
this.dynamicRulesMap.set(rule.key, rule);
|
|
412
1989
|
return this;
|
|
413
1990
|
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Removes a dynamic rule and evicts all cached results that its pattern matched.
|
|
1993
|
+
*
|
|
1994
|
+
* @param key - The key of the dynamic rule to remove.
|
|
1995
|
+
* @returns `this` for chaining.
|
|
1996
|
+
*
|
|
1997
|
+
* @remarks Iterates through all cached results and deletes any whose input string matches the removed rule's pattern. Logs a warning if the key does not exist.
|
|
1998
|
+
*
|
|
1999
|
+
* @example
|
|
2000
|
+
* ```ts
|
|
2001
|
+
* resolver.removeDynamicRule('bp')
|
|
2002
|
+
* ```
|
|
2003
|
+
*/
|
|
414
2004
|
removeDynamicRule(key) {
|
|
415
2005
|
const rule = this.dynamicRulesMap.get(key);
|
|
416
2006
|
if (rule == null) {
|
|
@@ -427,6 +2017,19 @@ var AbstractResolver = class {
|
|
|
427
2017
|
log.debug(` - Cleared ${matchedResolvedStringList.length} cached results`);
|
|
428
2018
|
return this;
|
|
429
2019
|
}
|
|
2020
|
+
/**
|
|
2021
|
+
* Attempts to resolve an input string by checking cached results, then static rules, then dynamic rules in order.
|
|
2022
|
+
*
|
|
2023
|
+
* @param string - The input string to resolve.
|
|
2024
|
+
* @returns The resolved result wrapper, or `null`/`undefined` if no rule matches.
|
|
2025
|
+
*
|
|
2026
|
+
* @remarks Results are cached for subsequent calls. Invokes `onResolved` after a successful match. Dynamic rule matching is async because `createResolved` may return a `Promise`.
|
|
2027
|
+
*
|
|
2028
|
+
* @example
|
|
2029
|
+
* ```ts
|
|
2030
|
+
* const result = await resolver._resolve('hover')
|
|
2031
|
+
* ```
|
|
2032
|
+
*/
|
|
430
2033
|
async _resolve(string) {
|
|
431
2034
|
const existedResult = this._resolvedResultsMap.get(string);
|
|
432
2035
|
if (existedResult != null) {
|
|
@@ -460,6 +2063,19 @@ var AbstractResolver = class {
|
|
|
460
2063
|
}
|
|
461
2064
|
log.debug(`Resolution failed for: ${string}`);
|
|
462
2065
|
}
|
|
2066
|
+
/**
|
|
2067
|
+
* Updates or creates the cached resolved result for a given input string.
|
|
2068
|
+
*
|
|
2069
|
+
* @param string - The input string whose cached result should be updated.
|
|
2070
|
+
* @param resolved - The new resolved value to store.
|
|
2071
|
+
*
|
|
2072
|
+
* @remarks If a cached `ResolvedResult` already exists for `string`, its `value` property is mutated in place. Otherwise a new entry is created. This allows `RecursiveResolver` to retroactively update partially resolved values without allocating a new wrapper.
|
|
2073
|
+
*
|
|
2074
|
+
* @example
|
|
2075
|
+
* ```ts
|
|
2076
|
+
* resolver._setResolvedResult('hover', ['&:hover'])
|
|
2077
|
+
* ```
|
|
2078
|
+
*/
|
|
463
2079
|
_setResolvedResult(string, resolved) {
|
|
464
2080
|
const resolvedResult = this._resolvedResultsMap.get(string);
|
|
465
2081
|
if (resolvedResult) {
|
|
@@ -469,7 +2085,36 @@ var AbstractResolver = class {
|
|
|
469
2085
|
this._resolvedResultsMap.set(string, { value: resolved });
|
|
470
2086
|
}
|
|
471
2087
|
};
|
|
2088
|
+
/**
|
|
2089
|
+
* Resolver subclass that recursively expands resolved values until all string references are fully resolved.
|
|
2090
|
+
* @internal
|
|
2091
|
+
*
|
|
2092
|
+
* @typeParam T - The element type of the final resolved array.
|
|
2093
|
+
*
|
|
2094
|
+
* @remarks Each resolution step may return a mix of final values and string references. The `resolve` method recurses into string values, flattening nested references while detecting circular dependencies via a visited set.
|
|
2095
|
+
*
|
|
2096
|
+
* @example
|
|
2097
|
+
* ```ts
|
|
2098
|
+
* class SelectorResolver extends RecursiveResolver<string> { }
|
|
2099
|
+
* const result = await resolver.resolve('hover-focus')
|
|
2100
|
+
* // ['&:hover', '&:focus'] after recursive expansion
|
|
2101
|
+
* ```
|
|
2102
|
+
*/
|
|
472
2103
|
var RecursiveResolver = class extends AbstractResolver {
|
|
2104
|
+
/**
|
|
2105
|
+
* Recursively resolves an input string into a flat array of final values.
|
|
2106
|
+
*
|
|
2107
|
+
* @param string - The input string to resolve.
|
|
2108
|
+
* @param _visited - Accumulator set for cycle detection; callers should omit this.
|
|
2109
|
+
* @returns A flat array of resolved values. If no rule matches, returns `[string]` cast to `T`.
|
|
2110
|
+
*
|
|
2111
|
+
* @remarks Detects circular references and short-circuits by returning the unresolved string. After full expansion, the cache is updated with the final flat result via `_setResolvedResult`.
|
|
2112
|
+
*
|
|
2113
|
+
* @example
|
|
2114
|
+
* ```ts
|
|
2115
|
+
* const selectors = await resolver.resolve('hover')
|
|
2116
|
+
* ```
|
|
2117
|
+
*/
|
|
473
2118
|
async resolve(string, _visited) {
|
|
474
2119
|
const visited = _visited ?? /* @__PURE__ */ new Set();
|
|
475
2120
|
if (visited.has(string)) {
|
|
@@ -488,6 +2133,26 @@ var RecursiveResolver = class extends AbstractResolver {
|
|
|
488
2133
|
return result;
|
|
489
2134
|
}
|
|
490
2135
|
};
|
|
2136
|
+
/**
|
|
2137
|
+
* Normalizes a user-supplied rule shorthand into a `ResolvedRuleConfig`, a plain redirect string, or `undefined`.
|
|
2138
|
+
* @internal
|
|
2139
|
+
*
|
|
2140
|
+
* @typeParam T - The element type of the rule's resolved value array.
|
|
2141
|
+
* @param config - The raw rule configuration: a string redirect, a tuple (`[string, value]` or `[RegExp, fn, autocomplete?]`), or an object with `keyName` and `value` properties.
|
|
2142
|
+
* @param keyName - The property name on an object-form config that holds the match key or pattern.
|
|
2143
|
+
* @returns A `ResolvedRuleConfig<T>` for valid static/dynamic configs, the original string for redirect configs, or `undefined` if the config shape is unrecognized.
|
|
2144
|
+
*
|
|
2145
|
+
* @remarks Handles three config shapes:
|
|
2146
|
+
* - **String**: returned as-is for the caller to treat as a redirect to another rule.
|
|
2147
|
+
* - **Tuple**: `[string, T | T[]]` for static rules, `[RegExp, fn, autocomplete?]` for dynamic rules.
|
|
2148
|
+
* - **Object**: `{ [keyName]: string | RegExp, value: T | fn, autocomplete?: string[] }`.
|
|
2149
|
+
*
|
|
2150
|
+
* @example
|
|
2151
|
+
* ```ts
|
|
2152
|
+
* resolveRuleConfig(['hover', '&:hover'], 'selector')
|
|
2153
|
+
* // { type: 'static', rule: { key: 'hover', ... }, autocomplete: ['hover'] }
|
|
2154
|
+
* ```
|
|
2155
|
+
*/
|
|
491
2156
|
function resolveRuleConfig(config, keyName) {
|
|
492
2157
|
if (typeof config === "string") return config;
|
|
493
2158
|
if (Array.isArray(config)) {
|
|
@@ -538,9 +2203,20 @@ function resolveRuleConfig(config, keyName) {
|
|
|
538
2203
|
};
|
|
539
2204
|
}
|
|
540
2205
|
}
|
|
541
|
-
|
|
542
2206
|
//#endregion
|
|
543
2207
|
//#region src/internal/plugins/selectors.ts
|
|
2208
|
+
/**
|
|
2209
|
+
* Built-in engine plugin that provides the selector resolution system.
|
|
2210
|
+
*
|
|
2211
|
+
* @returns An `EnginePlugin` that registers the `selectors` resolver on the engine and hooks into `transformSelectors` to expand selector names into resolved CSS selectors.
|
|
2212
|
+
*
|
|
2213
|
+
* @remarks Reads `EngineConfig.selectors` during `rawConfigConfigured`, attaches a `RecursiveResolver` to `engine.selectors` during `configureEngine`, and resolves all selector strings in the `transformSelectors` hook.
|
|
2214
|
+
*
|
|
2215
|
+
* @example
|
|
2216
|
+
* ```ts
|
|
2217
|
+
* createEngine({ plugins: [selectors()] })
|
|
2218
|
+
* ```
|
|
2219
|
+
*/
|
|
544
2220
|
function selectors() {
|
|
545
2221
|
let engine;
|
|
546
2222
|
let configList;
|
|
@@ -558,18 +2234,21 @@ function selectors() {
|
|
|
558
2234
|
const resolved = resolveSelectorConfig(config);
|
|
559
2235
|
if (resolved == null) return;
|
|
560
2236
|
if (typeof resolved === "string") {
|
|
561
|
-
engine.
|
|
2237
|
+
engine.appendAutocomplete({ selectors: resolved });
|
|
562
2238
|
return;
|
|
563
2239
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
2240
|
+
const addRule = {
|
|
2241
|
+
static: () => engine.selectors.resolver.addStaticRule(resolved.rule),
|
|
2242
|
+
dynamic: () => engine.selectors.resolver.addDynamicRule(resolved.rule)
|
|
2243
|
+
}[resolved.type];
|
|
2244
|
+
addRule?.();
|
|
2245
|
+
engine.appendAutocomplete({ selectors: resolved.autocomplete });
|
|
567
2246
|
});
|
|
568
2247
|
}
|
|
569
2248
|
};
|
|
570
2249
|
engine.selectors.add(...configList);
|
|
571
2250
|
engine.selectors.resolver.onResolved = (string, type) => {
|
|
572
|
-
if (type === "dynamic") engine.
|
|
2251
|
+
if (type === "dynamic") engine.appendAutocomplete({ selectors: string });
|
|
573
2252
|
};
|
|
574
2253
|
},
|
|
575
2254
|
async transformSelectors(selectors) {
|
|
@@ -580,12 +2259,36 @@ function selectors() {
|
|
|
580
2259
|
});
|
|
581
2260
|
}
|
|
582
2261
|
var SelectorResolver = class extends RecursiveResolver {};
|
|
2262
|
+
/**
|
|
2263
|
+
* Normalizes a `Selector` configuration into a `ResolvedRuleConfig`, a redirect string, or `undefined`.
|
|
2264
|
+
*
|
|
2265
|
+
* @param config - The selector rule configuration to resolve.
|
|
2266
|
+
* @returns A resolved static/dynamic rule config, a redirect string, or `undefined` if the shape is unrecognized.
|
|
2267
|
+
*
|
|
2268
|
+
* @remarks Delegates to the generic `resolveRuleConfig` with `'selector'` as the key name.
|
|
2269
|
+
*
|
|
2270
|
+
* @example
|
|
2271
|
+
* ```ts
|
|
2272
|
+
* const resolved = resolveSelectorConfig(['hover', '&:hover'])
|
|
2273
|
+
* ```
|
|
2274
|
+
*/
|
|
583
2275
|
function resolveSelectorConfig(config) {
|
|
584
2276
|
return resolveRuleConfig(config, "selector");
|
|
585
2277
|
}
|
|
586
|
-
|
|
587
2278
|
//#endregion
|
|
588
2279
|
//#region src/internal/plugins/shortcuts.ts
|
|
2280
|
+
/**
|
|
2281
|
+
* Built-in engine plugin that provides the shortcut resolution system.
|
|
2282
|
+
*
|
|
2283
|
+
* @returns An `EnginePlugin` that registers the `shortcuts` resolver on the engine and hooks into `transformStyleItems` and `transformStyleDefinitions` to expand shortcut names into style items.
|
|
2284
|
+
*
|
|
2285
|
+
* @remarks Reads `EngineConfig.shortcuts` during `rawConfigConfigured`, attaches a `RecursiveResolver` to `engine.shortcuts` during `configureEngine`, and expands shortcut references in both `transformStyleItems` (string style items) and `transformStyleDefinitions` (the `__shortcut` pseudo-property).
|
|
2286
|
+
*
|
|
2287
|
+
* @example
|
|
2288
|
+
* ```ts
|
|
2289
|
+
* createEngine({ plugins: [shortcuts()] })
|
|
2290
|
+
* ```
|
|
2291
|
+
*/
|
|
589
2292
|
function shortcuts() {
|
|
590
2293
|
let engine;
|
|
591
2294
|
let configList;
|
|
@@ -603,22 +2306,27 @@ function shortcuts() {
|
|
|
603
2306
|
const resolved = resolveShortcutConfig(config);
|
|
604
2307
|
if (resolved == null) return;
|
|
605
2308
|
if (typeof resolved === "string") {
|
|
606
|
-
engine.
|
|
2309
|
+
engine.appendAutocomplete({ shortcuts: resolved });
|
|
607
2310
|
return;
|
|
608
2311
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
2312
|
+
const addRule = {
|
|
2313
|
+
static: () => engine.shortcuts.resolver.addStaticRule(resolved.rule),
|
|
2314
|
+
dynamic: () => engine.shortcuts.resolver.addDynamicRule(resolved.rule)
|
|
2315
|
+
}[resolved.type];
|
|
2316
|
+
addRule?.();
|
|
2317
|
+
engine.appendAutocomplete({ shortcuts: resolved.autocomplete });
|
|
612
2318
|
});
|
|
613
2319
|
}
|
|
614
2320
|
};
|
|
615
2321
|
engine.shortcuts.add(...configList);
|
|
616
2322
|
engine.shortcuts.resolver.onResolved = (string, type) => {
|
|
617
|
-
if (type === "dynamic") engine.
|
|
2323
|
+
if (type === "dynamic") engine.appendAutocomplete({ shortcuts: string });
|
|
618
2324
|
};
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
2325
|
+
const unionType = ["(string & {})", "Autocomplete['Shortcut']"].join(" | ");
|
|
2326
|
+
engine.appendAutocomplete({
|
|
2327
|
+
extraProperties: "__shortcut",
|
|
2328
|
+
properties: { __shortcut: [unionType, `(${unionType})[]`] }
|
|
2329
|
+
});
|
|
622
2330
|
},
|
|
623
2331
|
async transformStyleItems(styleItems) {
|
|
624
2332
|
const result = [];
|
|
@@ -650,9 +2358,99 @@ var ShortcutResolver = class extends RecursiveResolver {};
|
|
|
650
2358
|
function resolveShortcutConfig(config) {
|
|
651
2359
|
return resolveRuleConfig(config, "shortcut");
|
|
652
2360
|
}
|
|
653
|
-
|
|
2361
|
+
//#endregion
|
|
2362
|
+
//#region src/internal/generated-property-semantics.ts
|
|
2363
|
+
const VARIABLE_SEMANTIC_FAMILY_PROPERTIES = {
|
|
2364
|
+
"angle": [],
|
|
2365
|
+
"color": [
|
|
2366
|
+
"accent-color",
|
|
2367
|
+
"background-color",
|
|
2368
|
+
"border-block-color",
|
|
2369
|
+
"border-block-end-color",
|
|
2370
|
+
"border-block-start-color",
|
|
2371
|
+
"border-bottom-color",
|
|
2372
|
+
"border-inline-color",
|
|
2373
|
+
"border-inline-end-color",
|
|
2374
|
+
"border-inline-start-color",
|
|
2375
|
+
"border-left-color",
|
|
2376
|
+
"border-right-color",
|
|
2377
|
+
"border-top-color",
|
|
2378
|
+
"caret-color",
|
|
2379
|
+
"color",
|
|
2380
|
+
"column-rule-color",
|
|
2381
|
+
"flood-color",
|
|
2382
|
+
"lighting-color",
|
|
2383
|
+
"outline-color",
|
|
2384
|
+
"stop-color",
|
|
2385
|
+
"stroke-color",
|
|
2386
|
+
"text-decoration-color",
|
|
2387
|
+
"text-emphasis-color"
|
|
2388
|
+
],
|
|
2389
|
+
"easing": ["animation-timing-function", "transition-timing-function"],
|
|
2390
|
+
"font-family": ["font-family"],
|
|
2391
|
+
"image": [],
|
|
2392
|
+
"length": [
|
|
2393
|
+
"block-size",
|
|
2394
|
+
"border-bottom-width",
|
|
2395
|
+
"border-left-width",
|
|
2396
|
+
"border-right-width",
|
|
2397
|
+
"border-spacing",
|
|
2398
|
+
"border-top-width",
|
|
2399
|
+
"bottom",
|
|
2400
|
+
"font-size",
|
|
2401
|
+
"height",
|
|
2402
|
+
"inline-size",
|
|
2403
|
+
"inset-block-end",
|
|
2404
|
+
"inset-block-start",
|
|
2405
|
+
"inset-inline-end",
|
|
2406
|
+
"inset-inline-start",
|
|
2407
|
+
"left",
|
|
2408
|
+
"letter-spacing",
|
|
2409
|
+
"max-height",
|
|
2410
|
+
"max-width",
|
|
2411
|
+
"min-height",
|
|
2412
|
+
"min-width",
|
|
2413
|
+
"outline-offset",
|
|
2414
|
+
"right",
|
|
2415
|
+
"top",
|
|
2416
|
+
"width"
|
|
2417
|
+
],
|
|
2418
|
+
"number": [
|
|
2419
|
+
"fill-opacity",
|
|
2420
|
+
"flex-grow",
|
|
2421
|
+
"flex-shrink",
|
|
2422
|
+
"flood-opacity",
|
|
2423
|
+
"opacity",
|
|
2424
|
+
"order",
|
|
2425
|
+
"orphans",
|
|
2426
|
+
"stop-opacity",
|
|
2427
|
+
"stroke-opacity",
|
|
2428
|
+
"widows"
|
|
2429
|
+
],
|
|
2430
|
+
"percentage": [],
|
|
2431
|
+
"position": [],
|
|
2432
|
+
"time": [
|
|
2433
|
+
"animation-delay",
|
|
2434
|
+
"animation-duration",
|
|
2435
|
+
"transition-delay",
|
|
2436
|
+
"transition-duration"
|
|
2437
|
+
],
|
|
2438
|
+
"url": []
|
|
2439
|
+
};
|
|
654
2440
|
//#endregion
|
|
655
2441
|
//#region src/internal/plugins/variables.ts
|
|
2442
|
+
/**
|
|
2443
|
+
* Built-in engine plugin that provides CSS custom properties (variables) with smart pruning and autocomplete integration.
|
|
2444
|
+
*
|
|
2445
|
+
* @returns An `EnginePlugin` that registers variable definitions, manages a preflight for emitting `:root` / scoped variables, and prunes unused variables from the output.
|
|
2446
|
+
*
|
|
2447
|
+
* @remarks Reads `EngineConfig.variables` during `rawConfigConfigured` and attaches the `engine.variables` management interface during `configureEngine`. A preflight is registered that collects variable references from atomic styles and other preflights, transitively expands dependencies, and emits only used (or safe-listed) variables.
|
|
2448
|
+
*
|
|
2449
|
+
* @example
|
|
2450
|
+
* ```ts
|
|
2451
|
+
* createEngine({ plugins: [variables()] })
|
|
2452
|
+
* ```
|
|
2453
|
+
*/
|
|
656
2454
|
function variables() {
|
|
657
2455
|
let resolveVariables;
|
|
658
2456
|
let rawVariables;
|
|
@@ -670,10 +2468,11 @@ function variables() {
|
|
|
670
2468
|
add: (variables) => {
|
|
671
2469
|
resolveVariables(variables).forEach((resolved) => {
|
|
672
2470
|
const { name, value, autocomplete: { asValueOf, asProperty } } = resolved;
|
|
673
|
-
asValueOf.
|
|
674
|
-
|
|
2471
|
+
const cssProperties = Object.fromEntries(asValueOf.filter((p) => p !== "-").map((p) => [p, `var(${name})`]));
|
|
2472
|
+
engine.appendAutocomplete({
|
|
2473
|
+
cssProperties,
|
|
2474
|
+
extraCssProperties: asProperty ? name : void 0
|
|
675
2475
|
});
|
|
676
|
-
if (asProperty) engine.appendAutocompleteExtraCssProperties(name);
|
|
677
2476
|
if (value != null) {
|
|
678
2477
|
const list = engine.variables.store.get(name) ?? [];
|
|
679
2478
|
list.push(resolved);
|
|
@@ -692,7 +2491,7 @@ function variables() {
|
|
|
692
2491
|
value.flatMap(extractUsedVarNames).forEach((name) => used.add(normalizeVariableName(name)));
|
|
693
2492
|
});
|
|
694
2493
|
const otherPreflights = engine.config.preflights.filter((p) => p.id !== "core:variables");
|
|
695
|
-
(await Promise.all(otherPreflights.map(({ fn }) => Promise.resolve(fn(engine, false)).catch(() => null)))).forEach((result) => {
|
|
2494
|
+
(await Promise.all(otherPreflights.map(({ fn }) => Promise.resolve().then(() => fn(engine, false)).catch(() => null)))).forEach((result) => {
|
|
696
2495
|
if (result == null) return;
|
|
697
2496
|
extractUsedVarNamesFromPreflightResult(result).forEach((name) => used.add(name));
|
|
698
2497
|
});
|
|
@@ -704,8 +2503,8 @@ function variables() {
|
|
|
704
2503
|
const entries = varMap.get(name);
|
|
705
2504
|
if (!entries) continue;
|
|
706
2505
|
for (const { value } of entries) {
|
|
707
|
-
|
|
708
|
-
for (const refName of extractUsedVarNames(
|
|
2506
|
+
const referencedValue = Array.isArray(value) ? value.join(" ") : String(value);
|
|
2507
|
+
for (const refName of extractUsedVarNames(referencedValue).map(normalizeVariableName)) if (!used.has(refName)) {
|
|
709
2508
|
used.add(refName);
|
|
710
2509
|
queue.push(refName);
|
|
711
2510
|
}
|
|
@@ -729,57 +2528,176 @@ function variables() {
|
|
|
729
2528
|
});
|
|
730
2529
|
}
|
|
731
2530
|
function createResolveVariablesFn({ pruneUnused: defaultPruneUnused = true } = {}) {
|
|
2531
|
+
function isVariableScopeObject(value) {
|
|
2532
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2533
|
+
}
|
|
732
2534
|
function _resolveVariables(variables, levels, result) {
|
|
733
2535
|
for (const [key, value] of Object.entries(variables)) if (key.startsWith("--")) {
|
|
734
|
-
const { value: varValue, autocomplete = {}, pruneUnused = defaultPruneUnused } = typeof value === "object" && value !== null && !Array.isArray(value) ? value : { value };
|
|
2536
|
+
const { value: varValue, semanticType, autocomplete = {}, pruneUnused = defaultPruneUnused } = typeof value === "object" && value !== null && !Array.isArray(value) ? value : { value };
|
|
735
2537
|
result.push({
|
|
736
2538
|
name: key,
|
|
737
2539
|
value: varValue,
|
|
738
2540
|
selector: levels.length > 0 ? levels : [":root"],
|
|
739
2541
|
autocomplete: {
|
|
740
|
-
asValueOf:
|
|
2542
|
+
asValueOf: resolveAutocompleteValueTargets({
|
|
2543
|
+
name: key,
|
|
2544
|
+
asValueOf: autocomplete.asValueOf,
|
|
2545
|
+
semanticType
|
|
2546
|
+
}),
|
|
741
2547
|
asProperty: autocomplete.asProperty ?? true
|
|
742
2548
|
},
|
|
743
2549
|
pruneUnused
|
|
744
2550
|
});
|
|
745
|
-
} else
|
|
2551
|
+
} else {
|
|
2552
|
+
if (!isVariableScopeObject(value)) {
|
|
2553
|
+
log.warn(`Invalid variables scope for selector "${key}". Expected a nested object, received ${typeof value}. Skipping.`);
|
|
2554
|
+
continue;
|
|
2555
|
+
}
|
|
2556
|
+
_resolveVariables(value, [...levels, key], result);
|
|
2557
|
+
}
|
|
746
2558
|
return result;
|
|
747
2559
|
}
|
|
748
2560
|
return function resolveVariables(variables) {
|
|
749
2561
|
return _resolveVariables(variables, [], []);
|
|
750
2562
|
};
|
|
751
2563
|
}
|
|
2564
|
+
function resolveAutocompleteValueTargets({ name, asValueOf, semanticType }) {
|
|
2565
|
+
const explicitTargets = asValueOf == null ? [] : [asValueOf].flat().map((value) => String(value));
|
|
2566
|
+
const semanticTypes = semanticType == null ? [] : [semanticType].flat().map((value) => String(value));
|
|
2567
|
+
if (explicitTargets.includes("-")) return [];
|
|
2568
|
+
const targets = /* @__PURE__ */ new Set();
|
|
2569
|
+
if (asValueOf == null && semanticTypes.length === 0) targets.add("*");
|
|
2570
|
+
explicitTargets.forEach((target) => {
|
|
2571
|
+
targets.add(target);
|
|
2572
|
+
});
|
|
2573
|
+
semanticTypes.forEach((family) => {
|
|
2574
|
+
const properties = VARIABLE_SEMANTIC_FAMILY_PROPERTIES[family];
|
|
2575
|
+
if (properties != null) {
|
|
2576
|
+
properties.forEach((property) => targets.add(property));
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
log.warn(`Unknown semanticType "${family}" for variable "${name}". Skipping semantic autocomplete expansion.`);
|
|
2580
|
+
});
|
|
2581
|
+
if (targets.has("*")) return ["*"];
|
|
2582
|
+
return [...targets];
|
|
2583
|
+
}
|
|
752
2584
|
const VAR_NAME_RE = /var\((--[\w-]+)/g;
|
|
2585
|
+
/**
|
|
2586
|
+
* Extracts all CSS variable names referenced via `var(--*)` calls in a string.
|
|
2587
|
+
*
|
|
2588
|
+
* @param input - The CSS value string to scan.
|
|
2589
|
+
* @returns An array of variable names (including the `--` prefix) found in `var()` expressions.
|
|
2590
|
+
*
|
|
2591
|
+
* @remarks Uses a global regex to find all `var(--name)` occurrences. Nested `var()` calls are matched independently.
|
|
2592
|
+
*
|
|
2593
|
+
* @example
|
|
2594
|
+
* ```ts
|
|
2595
|
+
* extractUsedVarNames('color: var(--primary)') // ['--primary']
|
|
2596
|
+
* extractUsedVarNames('var(--a) var(--b)') // ['--a', '--b']
|
|
2597
|
+
* ```
|
|
2598
|
+
*/
|
|
753
2599
|
function extractUsedVarNames(input) {
|
|
754
2600
|
return Array.from(input.matchAll(VAR_NAME_RE), (m) => m[1]);
|
|
755
2601
|
}
|
|
2602
|
+
/**
|
|
2603
|
+
* Ensures a variable name has the `--` prefix.
|
|
2604
|
+
*
|
|
2605
|
+
* @param name - The variable name, with or without the `--` prefix.
|
|
2606
|
+
* @returns The name with a guaranteed `--` prefix.
|
|
2607
|
+
*
|
|
2608
|
+
* @remarks A no-op when the name already starts with `--`.
|
|
2609
|
+
*
|
|
2610
|
+
* @example
|
|
2611
|
+
* ```ts
|
|
2612
|
+
* normalizeVariableName('color') // '--color'
|
|
2613
|
+
* normalizeVariableName('--color') // '--color'
|
|
2614
|
+
* ```
|
|
2615
|
+
*/
|
|
756
2616
|
function normalizeVariableName(name) {
|
|
757
2617
|
if (name.startsWith("--")) return name;
|
|
758
2618
|
return `--${name}`;
|
|
759
2619
|
}
|
|
760
2620
|
/**
|
|
761
|
-
* Recursively
|
|
762
|
-
*
|
|
2621
|
+
* Recursively extracts all CSS variable names referenced in a preflight result.
|
|
2622
|
+
*
|
|
2623
|
+
* @param result - A preflight output: either a raw CSS string or a nested `PreflightDefinition` object.
|
|
2624
|
+
* @returns A flat array of normalized variable names found in the result.
|
|
2625
|
+
*
|
|
2626
|
+
* @remarks For string results, scans for `var(--*)` references. For object results, recursively traverses selector scopes and string/number values. All returned names are normalized with the `--` prefix.
|
|
2627
|
+
*
|
|
2628
|
+
* @example
|
|
2629
|
+
* ```ts
|
|
2630
|
+
* extractUsedVarNamesFromPreflightResult({ ':root': { color: 'var(--primary)' } })
|
|
2631
|
+
* // ['--primary']
|
|
2632
|
+
* ```
|
|
763
2633
|
*/
|
|
764
2634
|
function extractUsedVarNamesFromPreflightResult(result) {
|
|
765
2635
|
if (typeof result === "string") return extractUsedVarNames(result).map(normalizeVariableName);
|
|
766
2636
|
const names = [];
|
|
767
2637
|
for (const value of Object.values(result)) {
|
|
768
2638
|
if (value == null) continue;
|
|
769
|
-
if (typeof value === "string" || typeof value === "number")
|
|
770
|
-
|
|
2639
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
2640
|
+
extractUsedVarNames(String(value)).forEach((n) => names.push(normalizeVariableName(n)));
|
|
2641
|
+
continue;
|
|
2642
|
+
}
|
|
2643
|
+
extractUsedVarNamesFromPreflightResult(value).forEach((n) => names.push(n));
|
|
771
2644
|
}
|
|
772
2645
|
return names;
|
|
773
2646
|
}
|
|
774
|
-
|
|
775
2647
|
//#endregion
|
|
776
2648
|
//#region src/internal/engine.ts
|
|
2649
|
+
/**
|
|
2650
|
+
* Default CSS layer name for preflight styles.
|
|
2651
|
+
* @internal
|
|
2652
|
+
*
|
|
2653
|
+
* @remarks Used as the layer name wrapping all unlayered preflight output when the layer exists in `config.layers`.
|
|
2654
|
+
*
|
|
2655
|
+
* @example
|
|
2656
|
+
* ```ts
|
|
2657
|
+
* // 'preflights'
|
|
2658
|
+
* ```
|
|
2659
|
+
*/
|
|
777
2660
|
const DEFAULT_PREFLIGHTS_LAYER = "preflights";
|
|
2661
|
+
/**
|
|
2662
|
+
* Default CSS layer name for utility (atomic) styles.
|
|
2663
|
+
* @internal
|
|
2664
|
+
*
|
|
2665
|
+
* @remarks Atomic styles without an explicit layer are placed into this layer when it exists in `config.layers`.
|
|
2666
|
+
*
|
|
2667
|
+
* @example
|
|
2668
|
+
* ```ts
|
|
2669
|
+
* // 'utilities'
|
|
2670
|
+
* ```
|
|
2671
|
+
*/
|
|
778
2672
|
const DEFAULT_UTILITIES_LAYER = "utilities";
|
|
2673
|
+
/**
|
|
2674
|
+
* Default layer ordering map: `preflights` at weight 1, `utilities` at weight 10.
|
|
2675
|
+
* @internal
|
|
2676
|
+
*
|
|
2677
|
+
* @remarks Merged with any user-supplied `config.layers` during engine config resolution. Numeric weights determine the `@layer` declaration order.
|
|
2678
|
+
*
|
|
2679
|
+
* @example
|
|
2680
|
+
* ```ts
|
|
2681
|
+
* // { preflights: 1, utilities: 10 }
|
|
2682
|
+
* ```
|
|
2683
|
+
*/
|
|
779
2684
|
const DEFAULT_LAYERS = {
|
|
780
2685
|
[DEFAULT_PREFLIGHTS_LAYER]: 1,
|
|
781
2686
|
[DEFAULT_UTILITIES_LAYER]: 10
|
|
782
2687
|
};
|
|
2688
|
+
/**
|
|
2689
|
+
* Creates and initializes a PikaCSS engine with the given configuration.
|
|
2690
|
+
*
|
|
2691
|
+
* @param config - The engine configuration, including plugins, selectors, shortcuts, variables, keyframes, preflights, and layer settings.
|
|
2692
|
+
* @returns A fully initialized `Engine` instance.
|
|
2693
|
+
*
|
|
2694
|
+
* @remarks Core plugins (`important`, `variables`, `keyframes`, `selectors`, `shortcuts`) are prepended automatically. The function resolves plugins, runs all configuration hooks in sequence, and returns the ready-to-use engine.
|
|
2695
|
+
*
|
|
2696
|
+
* @example
|
|
2697
|
+
* ```ts
|
|
2698
|
+
* const engine = await createEngine({ prefix: 'pk-', plugins: [myPlugin()] })
|
|
2699
|
+
* ```
|
|
2700
|
+
*/
|
|
783
2701
|
async function createEngine(config = {}) {
|
|
784
2702
|
log.debug("Creating engine with config:", config);
|
|
785
2703
|
const corePlugins = [
|
|
@@ -797,26 +2715,53 @@ async function createEngine(config = {}) {
|
|
|
797
2715
|
};
|
|
798
2716
|
log.debug(`Total plugins resolved: ${plugins.length}`);
|
|
799
2717
|
config = await hooks.configureRawConfig(config.plugins, config);
|
|
800
|
-
hooks.rawConfigConfigured(resolvePlugins(config.plugins
|
|
2718
|
+
hooks.rawConfigConfigured(resolvePlugins(config.plugins), config);
|
|
801
2719
|
let resolvedConfig = await resolveEngineConfig(config);
|
|
802
2720
|
log.debug("Engine config resolved with prefix:", resolvedConfig.prefix);
|
|
803
2721
|
resolvedConfig = await hooks.configureResolvedConfig(resolvedConfig.plugins, resolvedConfig);
|
|
804
2722
|
let engine = new Engine(resolvedConfig);
|
|
805
|
-
engine.
|
|
806
|
-
|
|
2723
|
+
engine.appendAutocomplete({
|
|
2724
|
+
extraProperties: "__layer",
|
|
2725
|
+
properties: { __layer: "Autocomplete['Layer']" }
|
|
2726
|
+
});
|
|
807
2727
|
log.debug("Engine instance created");
|
|
808
2728
|
engine = await hooks.configureEngine(engine.config.plugins, engine);
|
|
809
2729
|
log.debug("Engine initialized successfully");
|
|
810
2730
|
return engine;
|
|
811
2731
|
}
|
|
2732
|
+
/**
|
|
2733
|
+
* The PikaCSS engine: manages atomic style resolution, rendering, preflights, and plugin hooks.
|
|
2734
|
+
*
|
|
2735
|
+
* @remarks Constructed via `createEngine()`. Holds the resolved configuration, the atomic style store, and exposes methods for processing style items (`use`), rendering CSS output (`renderPreflights`, `renderAtomicStyles`, `renderLayerOrderDeclaration`), and managing runtime extensions (`addPreflight`, `appendAutocomplete`, `appendCssImport`).
|
|
2736
|
+
*
|
|
2737
|
+
* @example
|
|
2738
|
+
* ```ts
|
|
2739
|
+
* const engine = await createEngine({ prefix: 'pk-' })
|
|
2740
|
+
* const ids = await engine.use({ color: 'red' })
|
|
2741
|
+
* const css = await engine.renderAtomicStyles(true)
|
|
2742
|
+
* ```
|
|
2743
|
+
*/
|
|
812
2744
|
var Engine = class {
|
|
2745
|
+
/** The fully resolved engine configuration. */
|
|
813
2746
|
config;
|
|
2747
|
+
/** Reference to the plugin hook dispatcher for invoking lifecycle hooks. */
|
|
814
2748
|
pluginHooks = hooks;
|
|
2749
|
+
/** The extraction function that decomposes style definitions into atomic style contents. */
|
|
815
2750
|
extract;
|
|
816
|
-
store
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
2751
|
+
/** The engine's runtime store holding registered atomic styles and their ID mappings. */
|
|
2752
|
+
store = createEngineStore();
|
|
2753
|
+
/**
|
|
2754
|
+
* Creates an engine instance from a resolved configuration.
|
|
2755
|
+
*
|
|
2756
|
+
* @param config - The fully resolved engine configuration.
|
|
2757
|
+
*
|
|
2758
|
+
* @remarks Initializes the `extract` function by wiring it to the plugin hook pipeline for selectors, style items, and style definitions.
|
|
2759
|
+
*
|
|
2760
|
+
* @example
|
|
2761
|
+
* ```ts
|
|
2762
|
+
* const engine = new Engine(resolvedConfig)
|
|
2763
|
+
* ```
|
|
2764
|
+
*/
|
|
820
2765
|
constructor(config) {
|
|
821
2766
|
this.config = config;
|
|
822
2767
|
this.extract = createExtractFn({
|
|
@@ -826,45 +2771,113 @@ var Engine = class {
|
|
|
826
2771
|
transformStyleDefinitions: (styleDefinitions) => hooks.transformStyleDefinitions(this.config.plugins, styleDefinitions)
|
|
827
2772
|
});
|
|
828
2773
|
}
|
|
2774
|
+
/**
|
|
2775
|
+
* Fires the `preflightUpdated` hook to notify plugins that preflight content has changed.
|
|
2776
|
+
*
|
|
2777
|
+
*
|
|
2778
|
+
* @remarks Called automatically after `addPreflight` or when plugins modify preflight-contributing state (e.g. variables, keyframes).
|
|
2779
|
+
*
|
|
2780
|
+
* @example
|
|
2781
|
+
* ```ts
|
|
2782
|
+
* engine.notifyPreflightUpdated()
|
|
2783
|
+
* ```
|
|
2784
|
+
*/
|
|
829
2785
|
notifyPreflightUpdated() {
|
|
830
2786
|
hooks.preflightUpdated(this.config.plugins);
|
|
831
2787
|
}
|
|
2788
|
+
/**
|
|
2789
|
+
* Fires the `atomicStyleAdded` hook to notify plugins that a new atomic style was registered.
|
|
2790
|
+
*
|
|
2791
|
+
* @param atomicStyle - The atomic style that was just added to the store.
|
|
2792
|
+
*
|
|
2793
|
+
* @remarks Called automatically by `use()` when a previously unseen atomic style is resolved.
|
|
2794
|
+
*
|
|
2795
|
+
* @example
|
|
2796
|
+
* ```ts
|
|
2797
|
+
* engine.notifyAtomicStyleAdded(atomicStyle)
|
|
2798
|
+
* ```
|
|
2799
|
+
*/
|
|
832
2800
|
notifyAtomicStyleAdded(atomicStyle) {
|
|
833
2801
|
hooks.atomicStyleAdded(this.config.plugins, atomicStyle);
|
|
834
2802
|
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Fires the `autocompleteConfigUpdated` hook to notify plugins that autocomplete entries changed.
|
|
2805
|
+
*
|
|
2806
|
+
*
|
|
2807
|
+
* @remarks Called automatically after `appendAutocomplete` when the contribution modifies the resolved autocomplete config.
|
|
2808
|
+
*
|
|
2809
|
+
* @example
|
|
2810
|
+
* ```ts
|
|
2811
|
+
* engine.notifyAutocompleteConfigUpdated()
|
|
2812
|
+
* ```
|
|
2813
|
+
*/
|
|
835
2814
|
notifyAutocompleteConfigUpdated() {
|
|
836
2815
|
hooks.autocompleteConfigUpdated(this.config.plugins);
|
|
837
2816
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
this.notifyAutocompleteConfigUpdated();
|
|
2817
|
+
/**
|
|
2818
|
+
* Merges an autocomplete contribution into the resolved autocomplete config.
|
|
2819
|
+
*
|
|
2820
|
+
* @param contribution - The autocomplete entries to append (selectors, properties, CSS properties, etc.).
|
|
2821
|
+
*
|
|
2822
|
+
* @remarks Delegates to the `appendAutocomplete` utility and fires `autocompleteConfigUpdated` if the config was actually modified.
|
|
2823
|
+
*
|
|
2824
|
+
* @example
|
|
2825
|
+
* ```ts
|
|
2826
|
+
* engine.appendAutocomplete({ selectors: 'hover', cssProperties: { color: 'red' } })
|
|
2827
|
+
* ```
|
|
2828
|
+
*/
|
|
2829
|
+
appendAutocomplete(contribution) {
|
|
2830
|
+
if (appendAutocomplete(this.config, contribution)) this.notifyAutocompleteConfigUpdated();
|
|
853
2831
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
2832
|
+
/**
|
|
2833
|
+
* Appends a CSS `@import` statement to the preflight output.
|
|
2834
|
+
*
|
|
2835
|
+
* @param cssImport - The raw `@import` string (a trailing semicolon is appended if missing).
|
|
2836
|
+
*
|
|
2837
|
+
* @remarks Deduplicates imports. Fires `preflightUpdated` when a new import is added.
|
|
2838
|
+
*
|
|
2839
|
+
* @example
|
|
2840
|
+
* ```ts
|
|
2841
|
+
* engine.appendCssImport('@import url("https://fonts.googleapis.com/css2?family=Inter")')
|
|
2842
|
+
* ```
|
|
2843
|
+
*/
|
|
2844
|
+
appendCssImport(cssImport) {
|
|
2845
|
+
const normalized = normalizeCssImport(cssImport);
|
|
2846
|
+
if (normalized == null || this.config.cssImports.includes(normalized)) return;
|
|
2847
|
+
this.config.cssImports.push(normalized);
|
|
2848
|
+
this.notifyPreflightUpdated();
|
|
861
2849
|
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Registers a new preflight that will be rendered before atomic styles.
|
|
2852
|
+
*
|
|
2853
|
+
* @param preflight - A preflight definition: a function, a static string/object, or a wrapper with `layer`/`id` metadata.
|
|
2854
|
+
*
|
|
2855
|
+
* @remarks The preflight is resolved into a `ResolvedPreflight` (extracting optional `layer` and `id`) and appended to `config.preflights`. Fires `preflightUpdated` so plugins and the integration layer know to re-render.
|
|
2856
|
+
*
|
|
2857
|
+
* @example
|
|
2858
|
+
* ```ts
|
|
2859
|
+
* engine.addPreflight({ layer: 'base', preflight: '*, *::before { box-sizing: border-box; }' })
|
|
2860
|
+
* ```
|
|
2861
|
+
*/
|
|
862
2862
|
addPreflight(preflight) {
|
|
863
2863
|
log.debug("Adding preflight");
|
|
864
2864
|
this.config.preflights.push(resolvePreflight(preflight));
|
|
865
2865
|
log.debug(`Total preflights: ${this.config.preflights.length}`);
|
|
866
2866
|
this.notifyPreflightUpdated();
|
|
867
2867
|
}
|
|
2868
|
+
/**
|
|
2869
|
+
* Processes style items through the plugin pipeline and registers the resulting atomic styles in the store.
|
|
2870
|
+
*
|
|
2871
|
+
* @param itemList - Style items to process: string references (shortcuts) and/or style definition objects.
|
|
2872
|
+
* @returns An array of atomic style IDs (and unresolved string references) in insertion order.
|
|
2873
|
+
*
|
|
2874
|
+
* @remarks Runs `transformStyleItems` and `extractStyleDefinition` hooks, resolves each extracted content into an atomic style, deduplicates by base key, and fires `atomicStyleAdded` for new entries.
|
|
2875
|
+
*
|
|
2876
|
+
* @example
|
|
2877
|
+
* ```ts
|
|
2878
|
+
* const ids = await engine.use({ color: 'red' }, { padding: '1rem' })
|
|
2879
|
+
* ```
|
|
2880
|
+
*/
|
|
868
2881
|
async use(...itemList) {
|
|
869
2882
|
log.debug(`Processing ${itemList.length} style items`);
|
|
870
2883
|
const { unknown, contents } = await resolveStyleItemList({
|
|
@@ -873,63 +2886,89 @@ var Engine = class {
|
|
|
873
2886
|
extractStyleDefinition: (styleDefinition) => this.extract(styleDefinition)
|
|
874
2887
|
});
|
|
875
2888
|
const resolvedIds = [];
|
|
876
|
-
|
|
877
|
-
|
|
2889
|
+
const resolvedIdsByBaseKey = /* @__PURE__ */ new Map();
|
|
2890
|
+
for (const content of contents) {
|
|
2891
|
+
const { id, atomicStyle } = resolveAtomicStyle({
|
|
878
2892
|
content,
|
|
879
2893
|
prefix: this.config.prefix,
|
|
880
|
-
|
|
2894
|
+
store: this.store,
|
|
2895
|
+
resolvedIdsByBaseKey
|
|
881
2896
|
});
|
|
882
2897
|
resolvedIds.push(id);
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
id,
|
|
886
|
-
content
|
|
887
|
-
};
|
|
888
|
-
this.store.atomicStyles.set(id, atomicStyle);
|
|
2898
|
+
resolvedIdsByBaseKey.set(getAtomicStyleBaseKey(content), id);
|
|
2899
|
+
if (atomicStyle != null) {
|
|
889
2900
|
log.debug(`Atomic style added: ${id}`);
|
|
890
2901
|
this.notifyAtomicStyleAdded(atomicStyle);
|
|
891
2902
|
}
|
|
892
|
-
}
|
|
2903
|
+
}
|
|
893
2904
|
log.debug(`Resolved ${resolvedIds.length} atomic styles, ${unknown.size} unknown items`);
|
|
894
2905
|
return [...unknown, ...resolvedIds];
|
|
895
2906
|
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Renders all registered preflight definitions into a CSS string.
|
|
2909
|
+
*
|
|
2910
|
+
* @param isFormatted - Whether to produce human-readable CSS with newlines and indentation.
|
|
2911
|
+
* @returns The rendered preflight CSS, including `@import` statements, optional `@layer` wrappers, and all preflight content.
|
|
2912
|
+
*
|
|
2913
|
+
* @remarks Evaluates each preflight function, groups output by layer, wraps unlayered preflights in the default preflights layer (when present), and respects configured layer ordering.
|
|
2914
|
+
*
|
|
2915
|
+
* @example
|
|
2916
|
+
* ```ts
|
|
2917
|
+
* const css = await engine.renderPreflights(true)
|
|
2918
|
+
* ```
|
|
2919
|
+
*/
|
|
896
2920
|
async renderPreflights(isFormatted) {
|
|
897
2921
|
log.debug("Rendering preflights...");
|
|
898
2922
|
const lineEnd = isFormatted ? "\n" : "";
|
|
899
|
-
const rendered = await Promise.all(this.config.preflights.map(async ({ layer, fn }) => {
|
|
2923
|
+
const rendered = (await Promise.all(this.config.preflights.map(async ({ layer, fn }) => {
|
|
900
2924
|
const result = await fn(this, isFormatted);
|
|
901
2925
|
return {
|
|
902
2926
|
layer,
|
|
903
|
-
css: typeof result === "string" ? result : await renderPreflightDefinition({
|
|
2927
|
+
css: (typeof result === "string" ? result : await renderPreflightDefinition({
|
|
904
2928
|
engine: this,
|
|
905
2929
|
preflightDefinition: result,
|
|
906
2930
|
isFormatted
|
|
907
|
-
})
|
|
2931
|
+
})).trim()
|
|
908
2932
|
};
|
|
909
|
-
}));
|
|
2933
|
+
}))).filter((r) => r.css);
|
|
910
2934
|
log.debug(`Rendered ${rendered.length} preflights`);
|
|
911
|
-
const unlayeredParts =
|
|
912
|
-
const layerGroups = /* @__PURE__ */ new Map();
|
|
913
|
-
for (const { layer, css } of rendered) if (layer == null) unlayeredParts.push(css);
|
|
914
|
-
else {
|
|
915
|
-
if (!layerGroups.has(layer)) layerGroups.set(layer, []);
|
|
916
|
-
layerGroups.get(layer).push(css);
|
|
917
|
-
}
|
|
2935
|
+
const { unlayeredParts, layerGroups } = groupRenderedPreflightsByLayer(rendered);
|
|
918
2936
|
const outputParts = [];
|
|
2937
|
+
if (this.config.cssImports.length > 0) outputParts.push(...this.config.cssImports);
|
|
919
2938
|
if (unlayeredParts.length > 0) {
|
|
920
|
-
const unlayeredContent = unlayeredParts.join(lineEnd);
|
|
921
2939
|
const { defaultPreflightsLayer } = this.config;
|
|
922
|
-
if (defaultPreflightsLayer in this.config.layers)
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
outputParts.push(`@layer ${layerName} {${lineEnd}${content}${lineEnd}}`);
|
|
2940
|
+
if (defaultPreflightsLayer in this.config.layers) {
|
|
2941
|
+
const unlayeredContent = unlayeredParts.map((part) => part.trim().split("\n").map((line) => ` ${line}`).join(lineEnd)).join(lineEnd);
|
|
2942
|
+
outputParts.push(`@layer ${defaultPreflightsLayer} {${lineEnd}${unlayeredContent}${lineEnd}}`);
|
|
2943
|
+
} else {
|
|
2944
|
+
const unlayeredContent = unlayeredParts.join(lineEnd);
|
|
2945
|
+
outputParts.push(unlayeredContent);
|
|
2946
|
+
}
|
|
930
2947
|
}
|
|
2948
|
+
outputParts.push(...renderLayerBlocks({
|
|
2949
|
+
layerGroups,
|
|
2950
|
+
layerOrder: sortLayerNames(this.config.layers),
|
|
2951
|
+
isFormatted,
|
|
2952
|
+
render: (cssList) => cssList.join(lineEnd)
|
|
2953
|
+
}));
|
|
931
2954
|
return outputParts.join(lineEnd);
|
|
932
2955
|
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Renders atomic styles into a CSS string, optionally filtered by ID and grouped by layer.
|
|
2958
|
+
*
|
|
2959
|
+
* @param isFormatted - Whether to produce human-readable CSS with newlines and indentation.
|
|
2960
|
+
* @param options - Optional filtering: `atomicStyleIds` to render a subset, `isPreview` to use placeholder IDs.
|
|
2961
|
+
* @param options.atomicStyleIds - Specific atomic style IDs to render instead of the full store.
|
|
2962
|
+
* @param options.isPreview - Whether to keep placeholder IDs instead of substituting real class names.
|
|
2963
|
+
* @returns The rendered atomic-style CSS.
|
|
2964
|
+
*
|
|
2965
|
+
* @remarks Styles are sorted by rendering weight (selector specificity depth), grouped into configured `@layer` blocks, and rendered. When `isPreview` is true, atomic style IDs remain as placeholders for tooling previews.
|
|
2966
|
+
*
|
|
2967
|
+
* @example
|
|
2968
|
+
* ```ts
|
|
2969
|
+
* const css = await engine.renderAtomicStyles(true)
|
|
2970
|
+
* ```
|
|
2971
|
+
*/
|
|
933
2972
|
async renderAtomicStyles(isFormatted, options = {}) {
|
|
934
2973
|
log.debug("Rendering atomic styles...");
|
|
935
2974
|
const { atomicStyleIds = null, isPreview = false } = options;
|
|
@@ -944,19 +2983,141 @@ var Engine = class {
|
|
|
944
2983
|
defaultUtilitiesLayer: this.config.defaultUtilitiesLayer
|
|
945
2984
|
});
|
|
946
2985
|
}
|
|
2986
|
+
/**
|
|
2987
|
+
* Renders the CSS `@layer` order declaration for all configured layers.
|
|
2988
|
+
*
|
|
2989
|
+
* @returns A `@layer` statement listing layer names in weight order, or an empty string if no layers are configured.
|
|
2990
|
+
*
|
|
2991
|
+
* @remarks Ensures the browser applies the intended cascade priority for `preflights`, `utilities`, and any user-defined layers.
|
|
2992
|
+
*
|
|
2993
|
+
* @example
|
|
2994
|
+
* ```ts
|
|
2995
|
+
* engine.renderLayerOrderDeclaration()
|
|
2996
|
+
* // '@layer preflights, utilities;'
|
|
2997
|
+
* ```
|
|
2998
|
+
*/
|
|
947
2999
|
renderLayerOrderDeclaration() {
|
|
948
3000
|
const { layers } = this.config;
|
|
949
3001
|
if (Object.keys(layers).length === 0) return "";
|
|
950
3002
|
return `@layer ${sortLayerNames(layers).join(", ")};`;
|
|
951
3003
|
}
|
|
952
3004
|
};
|
|
3005
|
+
/**
|
|
3006
|
+
* Computes a numeric rendering weight for an atomic style based on its selector depth.
|
|
3007
|
+
* @internal
|
|
3008
|
+
*
|
|
3009
|
+
* @param style - The atomic style to weigh.
|
|
3010
|
+
* @param defaultSelector - The engine's default selector pattern.
|
|
3011
|
+
* @returns `0` for styles using only the default selector; otherwise the number of selector segments.
|
|
3012
|
+
*
|
|
3013
|
+
* @remarks Used to sort atomic styles so that simpler selectors appear before more specific ones in the CSS output, preserving deterministic cascade ordering.
|
|
3014
|
+
*
|
|
3015
|
+
* @example
|
|
3016
|
+
* ```ts
|
|
3017
|
+
* calcAtomicStyleRenderingWeight(style, '.pk-__PLACEHOLDER__')
|
|
3018
|
+
* ```
|
|
3019
|
+
*/
|
|
953
3020
|
function calcAtomicStyleRenderingWeight(style, defaultSelector) {
|
|
954
|
-
const { selector } = style.content;
|
|
3021
|
+
const { selector } = splitLayerSelector(style.content.selector);
|
|
955
3022
|
return selector.length === 1 && selector[0] === defaultSelector ? 0 : selector.length;
|
|
956
3023
|
}
|
|
3024
|
+
/**
|
|
3025
|
+
* Sorts layer names by their numeric weight, then alphabetically for ties.
|
|
3026
|
+
*
|
|
3027
|
+
* @param layers - A record mapping layer names to numeric weights.
|
|
3028
|
+
* @returns An array of layer names in ascending weight order.
|
|
3029
|
+
*
|
|
3030
|
+
* @remarks Used to produce the `@layer` declaration order and to order layer group rendering.
|
|
3031
|
+
*
|
|
3032
|
+
* @example
|
|
3033
|
+
* ```ts
|
|
3034
|
+
* sortLayerNames({ utilities: 10, preflights: 1 })
|
|
3035
|
+
* // ['preflights', 'utilities']
|
|
3036
|
+
* ```
|
|
3037
|
+
*/
|
|
957
3038
|
function sortLayerNames(layers) {
|
|
958
3039
|
return Object.entries(layers).sort((a, b) => a[1] - b[1] || a[0].localeCompare(b[0])).map(([name]) => name);
|
|
959
3040
|
}
|
|
3041
|
+
function appendLayerGroupItem(layerGroups, layer, item) {
|
|
3042
|
+
if (!layerGroups.has(layer)) layerGroups.set(layer, []);
|
|
3043
|
+
layerGroups.get(layer).push(item);
|
|
3044
|
+
}
|
|
3045
|
+
function getOrderedLayerNamesForGroups(layerGroups, layerOrder) {
|
|
3046
|
+
return [...layerOrder.filter((name) => (layerGroups.get(name)?.length ?? 0) > 0), ...[...layerGroups.keys()].filter((name) => !layerOrder.includes(name) && layerGroups.get(name).length > 0)];
|
|
3047
|
+
}
|
|
3048
|
+
function renderLayerBlocks({ layerGroups, layerOrder, isFormatted, render }) {
|
|
3049
|
+
const lineEnd = isFormatted ? "\n" : "";
|
|
3050
|
+
return getOrderedLayerNamesForGroups(layerGroups, layerOrder).map((layerName) => {
|
|
3051
|
+
const items = layerGroups.get(layerName);
|
|
3052
|
+
return `@layer ${layerName} {${lineEnd}${isFormatted ? render(items).trim().split("\n").map((line) => ` ${line}`).join("\n") : render(items)}${lineEnd}}`;
|
|
3053
|
+
});
|
|
3054
|
+
}
|
|
3055
|
+
function normalizeCssImport(cssImport) {
|
|
3056
|
+
const normalized = cssImport.trim();
|
|
3057
|
+
if (normalized.length === 0) return null;
|
|
3058
|
+
return normalized.endsWith(";") ? normalized : `${normalized};`;
|
|
3059
|
+
}
|
|
3060
|
+
function groupRenderedPreflightsByLayer(rendered) {
|
|
3061
|
+
const unlayeredParts = [];
|
|
3062
|
+
const layerGroups = /* @__PURE__ */ new Map();
|
|
3063
|
+
for (const { layer, css } of rendered) {
|
|
3064
|
+
if (layer == null) {
|
|
3065
|
+
unlayeredParts.push(css);
|
|
3066
|
+
continue;
|
|
3067
|
+
}
|
|
3068
|
+
appendLayerGroupItem(layerGroups, layer, css);
|
|
3069
|
+
}
|
|
3070
|
+
return {
|
|
3071
|
+
unlayeredParts,
|
|
3072
|
+
layerGroups
|
|
3073
|
+
};
|
|
3074
|
+
}
|
|
3075
|
+
function splitLayerSelector(selector) {
|
|
3076
|
+
const [first, ...rest] = selector;
|
|
3077
|
+
if (first == null || first.startsWith("@layer ") === false) return {
|
|
3078
|
+
layer: void 0,
|
|
3079
|
+
selector
|
|
3080
|
+
};
|
|
3081
|
+
const layer = first.slice(7).trim();
|
|
3082
|
+
if (layer.length === 0) return {
|
|
3083
|
+
layer: void 0,
|
|
3084
|
+
selector
|
|
3085
|
+
};
|
|
3086
|
+
return {
|
|
3087
|
+
layer,
|
|
3088
|
+
selector: rest
|
|
3089
|
+
};
|
|
3090
|
+
}
|
|
3091
|
+
function prependLayerSelector(selector, layer) {
|
|
3092
|
+
return [`${LAYER_SELECTOR_PREFIX}${layer}`, ...selector];
|
|
3093
|
+
}
|
|
3094
|
+
function groupAtomicStylesByLayer({ styles, layerOrder, defaultUtilitiesLayer }) {
|
|
3095
|
+
const unlayeredStyles = [];
|
|
3096
|
+
const layerGroups = new Map(layerOrder.map((name) => [name, []]));
|
|
3097
|
+
const candidateDefaultLayer = defaultUtilitiesLayer ?? layerOrder.at(-1);
|
|
3098
|
+
const defaultLayer = candidateDefaultLayer != null && layerGroups.has(candidateDefaultLayer) ? candidateDefaultLayer : layerOrder.at(-1);
|
|
3099
|
+
for (const style of styles) {
|
|
3100
|
+
const { layer } = splitLayerSelector(style.content.selector);
|
|
3101
|
+
if (layer != null && layerGroups.has(layer)) {
|
|
3102
|
+
layerGroups.get(layer).push(style);
|
|
3103
|
+
continue;
|
|
3104
|
+
}
|
|
3105
|
+
if (layer != null) {
|
|
3106
|
+
log.warn(`Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`);
|
|
3107
|
+
unlayeredStyles.push(style);
|
|
3108
|
+
continue;
|
|
3109
|
+
}
|
|
3110
|
+
if (defaultLayer != null) {
|
|
3111
|
+
layerGroups.get(defaultLayer).push(style);
|
|
3112
|
+
continue;
|
|
3113
|
+
}
|
|
3114
|
+
unlayeredStyles.push(style);
|
|
3115
|
+
}
|
|
3116
|
+
return {
|
|
3117
|
+
unlayeredStyles,
|
|
3118
|
+
layerGroups
|
|
3119
|
+
};
|
|
3120
|
+
}
|
|
960
3121
|
function isWithLayer(p) {
|
|
961
3122
|
if (typeof p !== "object" || p === null) return false;
|
|
962
3123
|
const record = p;
|
|
@@ -967,6 +3128,20 @@ function isWithId(p) {
|
|
|
967
3128
|
const record = p;
|
|
968
3129
|
return typeof record.id === "string" && record.preflight !== void 0;
|
|
969
3130
|
}
|
|
3131
|
+
/**
|
|
3132
|
+
* Normalizes a `Preflight` input into a `ResolvedPreflight` by extracting optional `layer` and `id` wrappers.
|
|
3133
|
+
* @internal
|
|
3134
|
+
*
|
|
3135
|
+
* @param preflight - A preflight value: a function, a static string/`PreflightDefinition`, or a wrapper with `layer`/`id` metadata.
|
|
3136
|
+
* @returns A `ResolvedPreflight` with separated `layer`, `id`, and `fn`.
|
|
3137
|
+
*
|
|
3138
|
+
* @remarks Handles nested wrappers: a `{ layer, preflight: { id, preflight: fn } }` shape is unwrapped in order.
|
|
3139
|
+
*
|
|
3140
|
+
* @example
|
|
3141
|
+
* ```ts
|
|
3142
|
+
* resolvePreflight({ layer: 'base', id: 'reset', preflight: '* { margin: 0 }' })
|
|
3143
|
+
* ```
|
|
3144
|
+
*/
|
|
970
3145
|
function resolvePreflight(preflight) {
|
|
971
3146
|
let layer;
|
|
972
3147
|
let id;
|
|
@@ -984,11 +3159,25 @@ function resolvePreflight(preflight) {
|
|
|
984
3159
|
fn: typeof preflight === "function" ? preflight : () => preflight
|
|
985
3160
|
};
|
|
986
3161
|
}
|
|
3162
|
+
/**
|
|
3163
|
+
* Resolves a raw `EngineConfig` into a fully normalized `ResolvedEngineConfig`.
|
|
3164
|
+
* @internal
|
|
3165
|
+
*
|
|
3166
|
+
* @param config - The raw engine configuration.
|
|
3167
|
+
* @returns A `ResolvedEngineConfig` with defaults applied, plugins sorted, preflights resolved, and autocomplete initialized.
|
|
3168
|
+
*
|
|
3169
|
+
* @remarks Merges `DEFAULT_LAYERS`, normalizes CSS imports, resolves preflight definitions, and initializes the empty autocomplete sets/maps.
|
|
3170
|
+
*
|
|
3171
|
+
* @example
|
|
3172
|
+
* ```ts
|
|
3173
|
+
* const resolved = await resolveEngineConfig({ prefix: 'pk-' })
|
|
3174
|
+
* ```
|
|
3175
|
+
*/
|
|
987
3176
|
async function resolveEngineConfig(config) {
|
|
988
|
-
const { prefix = "", defaultSelector =
|
|
3177
|
+
const { prefix = "pk-", defaultSelector = `.%`, plugins = [], cssImports = [], preflights = [] } = config;
|
|
989
3178
|
const layers = Object.assign({}, DEFAULT_LAYERS, config.layers);
|
|
990
|
-
const defaultPreflightsLayer = config.defaultPreflightsLayer ??
|
|
991
|
-
const defaultUtilitiesLayer = config.defaultUtilitiesLayer ??
|
|
3179
|
+
const defaultPreflightsLayer = config.defaultPreflightsLayer ?? "preflights";
|
|
3180
|
+
const defaultUtilitiesLayer = config.defaultUtilitiesLayer ?? "utilities";
|
|
992
3181
|
log.debug(`Resolving engine config with prefix: "${prefix}", plugins: ${plugins.length}, preflights: ${preflights.length}`);
|
|
993
3182
|
const resolvedConfig = {
|
|
994
3183
|
rawConfig: config,
|
|
@@ -996,55 +3185,31 @@ async function resolveEngineConfig(config) {
|
|
|
996
3185
|
prefix,
|
|
997
3186
|
defaultSelector,
|
|
998
3187
|
preflights: [],
|
|
3188
|
+
cssImports: [...new Set(cssImports.map(normalizeCssImport).filter(isNotNullish))],
|
|
999
3189
|
layers,
|
|
1000
3190
|
defaultPreflightsLayer,
|
|
1001
3191
|
defaultUtilitiesLayer,
|
|
1002
3192
|
autocomplete: {
|
|
1003
3193
|
selectors: /* @__PURE__ */ new Set(),
|
|
1004
|
-
|
|
3194
|
+
shortcuts: /* @__PURE__ */ new Set(),
|
|
1005
3195
|
extraProperties: /* @__PURE__ */ new Set(),
|
|
1006
3196
|
extraCssProperties: /* @__PURE__ */ new Set(),
|
|
1007
3197
|
properties: /* @__PURE__ */ new Map(),
|
|
1008
|
-
cssProperties: /* @__PURE__ */ new Map()
|
|
3198
|
+
cssProperties: /* @__PURE__ */ new Map(),
|
|
3199
|
+
patterns: {
|
|
3200
|
+
selectors: /* @__PURE__ */ new Set(),
|
|
3201
|
+
shortcuts: /* @__PURE__ */ new Set(),
|
|
3202
|
+
properties: /* @__PURE__ */ new Map(),
|
|
3203
|
+
cssProperties: /* @__PURE__ */ new Map()
|
|
3204
|
+
}
|
|
1009
3205
|
}
|
|
1010
3206
|
};
|
|
3207
|
+
appendAutocomplete(resolvedConfig, config.autocomplete ?? {});
|
|
1011
3208
|
const resolvedPreflights = preflights.map(resolvePreflight);
|
|
1012
3209
|
resolvedConfig.preflights.push(...resolvedPreflights);
|
|
1013
3210
|
log.debug(`Engine config resolved: ${resolvedPreflights.length} preflights processed`);
|
|
1014
3211
|
return resolvedConfig;
|
|
1015
3212
|
}
|
|
1016
|
-
function getAtomicStyleId({ content, prefix, stored }) {
|
|
1017
|
-
const key = serialize([
|
|
1018
|
-
content.selector,
|
|
1019
|
-
content.property,
|
|
1020
|
-
content.value,
|
|
1021
|
-
content.layer
|
|
1022
|
-
]);
|
|
1023
|
-
const cached = stored.get(key);
|
|
1024
|
-
if (cached != null) {
|
|
1025
|
-
log.debug(`Atomic style cached: ${cached}`);
|
|
1026
|
-
return cached;
|
|
1027
|
-
}
|
|
1028
|
-
const num = stored.size;
|
|
1029
|
-
const id = `${prefix}${numberToChars(num)}`;
|
|
1030
|
-
stored.set(key, id);
|
|
1031
|
-
log.debug(`Generated new atomic style ID: ${id}`);
|
|
1032
|
-
return id;
|
|
1033
|
-
}
|
|
1034
|
-
function optimizeAtomicStyleContents(list) {
|
|
1035
|
-
const map = /* @__PURE__ */ new Map();
|
|
1036
|
-
list.forEach((content) => {
|
|
1037
|
-
const key = serialize([
|
|
1038
|
-
content.selector,
|
|
1039
|
-
content.property,
|
|
1040
|
-
content.layer
|
|
1041
|
-
]);
|
|
1042
|
-
map.delete(key);
|
|
1043
|
-
if (content.value == null) return;
|
|
1044
|
-
map.set(key, { ...content });
|
|
1045
|
-
});
|
|
1046
|
-
return [...map.values()];
|
|
1047
|
-
}
|
|
1048
3213
|
function extractLayerFromStyleItem(item) {
|
|
1049
3214
|
const record = item;
|
|
1050
3215
|
const layer = typeof record.__layer === "string" ? record.__layer : void 0;
|
|
@@ -1058,6 +3223,26 @@ function extractLayerFromStyleItem(item) {
|
|
|
1058
3223
|
definition: rest
|
|
1059
3224
|
};
|
|
1060
3225
|
}
|
|
3226
|
+
/**
|
|
3227
|
+
* Transforms and extracts a list of style items into deduplicated atomic style contents.
|
|
3228
|
+
* @internal
|
|
3229
|
+
*
|
|
3230
|
+
* @param options - An object containing:
|
|
3231
|
+
* - `itemList` — the raw style items to process.
|
|
3232
|
+
* - `transformStyleItems` — the plugin hook for transforming style items.
|
|
3233
|
+
* - `extractStyleDefinition` — the function that decomposes a style definition into extracted contents.
|
|
3234
|
+
* @param options.itemList - The raw style items to process.
|
|
3235
|
+
* @param options.transformStyleItems - Hook that expands or rewrites style items before extraction.
|
|
3236
|
+
* @param options.extractStyleDefinition - Function that decomposes a style definition into extracted style contents.
|
|
3237
|
+
* @returns An object with `unknown` (unresolved string references) and `contents` (optimized extracted style contents).
|
|
3238
|
+
*
|
|
3239
|
+
* @remarks String items that survive the `transformStyleItems` hook are collected into the `unknown` set. Object items are extracted, optionally layer-prepended, and optimized for duplicate property merging.
|
|
3240
|
+
*
|
|
3241
|
+
* @example
|
|
3242
|
+
* ```ts
|
|
3243
|
+
* const { unknown, contents } = await resolveStyleItemList({ itemList, transformStyleItems, extractStyleDefinition })
|
|
3244
|
+
* ```
|
|
3245
|
+
*/
|
|
1061
3246
|
async function resolveStyleItemList({ itemList, transformStyleItems, extractStyleDefinition }) {
|
|
1062
3247
|
const unknown = /* @__PURE__ */ new Set();
|
|
1063
3248
|
const list = [];
|
|
@@ -1065,8 +3250,10 @@ async function resolveStyleItemList({ itemList, transformStyleItems, extractStyl
|
|
|
1065
3250
|
else {
|
|
1066
3251
|
const { layer, definition } = extractLayerFromStyleItem(styleItem);
|
|
1067
3252
|
const extracted = await extractStyleDefinition(definition);
|
|
1068
|
-
|
|
1069
|
-
|
|
3253
|
+
list.push(...layer == null ? extracted : extracted.map((content) => ({
|
|
3254
|
+
...content,
|
|
3255
|
+
selector: prependLayerSelector(content.selector, layer)
|
|
3256
|
+
})));
|
|
1070
3257
|
}
|
|
1071
3258
|
return {
|
|
1072
3259
|
unknown,
|
|
@@ -1078,8 +3265,9 @@ function sortAtomicStyles(styles, defaultSelector) {
|
|
|
1078
3265
|
}
|
|
1079
3266
|
function renderAtomicStylesCss({ atomicStyles, isPreview, isFormatted }) {
|
|
1080
3267
|
const blocks = /* @__PURE__ */ new Map();
|
|
1081
|
-
atomicStyles.forEach(({ id, content: { selector, property, value } }) => {
|
|
1082
|
-
|
|
3268
|
+
atomicStyles.forEach(({ id, content: { selector: rawSelector, property, value } }) => {
|
|
3269
|
+
const { selector } = splitLayerSelector(rawSelector);
|
|
3270
|
+
if (selector.some((s) => s.includes("%")) === false || value == null) return;
|
|
1083
3271
|
const renderObject = {
|
|
1084
3272
|
selector: isPreview ? selector : selector.map((s) => s.replace(ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, id)),
|
|
1085
3273
|
properties: value.map((v) => ({
|
|
@@ -1100,6 +3288,26 @@ function renderAtomicStylesCss({ atomicStyles, isPreview, isFormatted }) {
|
|
|
1100
3288
|
});
|
|
1101
3289
|
return renderCSSStyleBlocks(blocks, isFormatted);
|
|
1102
3290
|
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Standalone function that renders atomic styles into CSS with layer grouping.
|
|
3293
|
+
* @internal
|
|
3294
|
+
*
|
|
3295
|
+
* @param payload - An object containing `atomicStyles`, `isPreview`, `isFormatted`, `defaultSelector`, and optional `layers`/`defaultUtilitiesLayer`.
|
|
3296
|
+
* @param payload.atomicStyles - The atomic styles to render.
|
|
3297
|
+
* @param payload.isPreview - Whether placeholder IDs should be preserved for preview output.
|
|
3298
|
+
* @param payload.isFormatted - Whether to render with indentation and line breaks.
|
|
3299
|
+
* @param payload.defaultSelector - The engine default selector used when computing render order.
|
|
3300
|
+
* @param payload.layers - Optional configured CSS layers to group atomic styles into.
|
|
3301
|
+
* @param payload.defaultUtilitiesLayer - Optional fallback layer for unlayered utility styles.
|
|
3302
|
+
* @returns The rendered CSS string.
|
|
3303
|
+
*
|
|
3304
|
+
* @remarks Sorts styles by rendering weight, groups them into `@layer` blocks when layers are configured, and renders each group. Used by both the `Engine.renderAtomicStyles` method and external consumers.
|
|
3305
|
+
*
|
|
3306
|
+
* @example
|
|
3307
|
+
* ```ts
|
|
3308
|
+
* const css = renderAtomicStyles({ atomicStyles, isPreview: false, isFormatted: true, defaultSelector: '.pk-__ID__', layers: { utilities: 10 } })
|
|
3309
|
+
* ```
|
|
3310
|
+
*/
|
|
1103
3311
|
function renderAtomicStyles(payload) {
|
|
1104
3312
|
const { atomicStyles, isPreview, isFormatted, defaultSelector, layers, defaultUtilitiesLayer } = payload;
|
|
1105
3313
|
const sortedStyles = sortAtomicStyles(atomicStyles, defaultSelector);
|
|
@@ -1110,37 +3318,49 @@ function renderAtomicStyles(payload) {
|
|
|
1110
3318
|
});
|
|
1111
3319
|
const layerOrder = sortLayerNames(layers);
|
|
1112
3320
|
const lineEnd = isFormatted ? "\n" : "";
|
|
1113
|
-
const unlayeredStyles =
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
const layer = style.content.layer;
|
|
1119
|
-
if (layer != null && layerGroups.has(layer)) layerGroups.get(layer).push(style);
|
|
1120
|
-
else if (layer != null) {
|
|
1121
|
-
log.warn(`Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`);
|
|
1122
|
-
unlayeredStyles.push(style);
|
|
1123
|
-
} else if (defaultLayer != null) layerGroups.get(defaultLayer).push(style);
|
|
1124
|
-
else unlayeredStyles.push(style);
|
|
1125
|
-
}
|
|
3321
|
+
const { unlayeredStyles, layerGroups } = groupAtomicStylesByLayer({
|
|
3322
|
+
styles: sortedStyles,
|
|
3323
|
+
layerOrder,
|
|
3324
|
+
defaultUtilitiesLayer
|
|
3325
|
+
});
|
|
1126
3326
|
const parts = [];
|
|
1127
3327
|
if (unlayeredStyles.length > 0) parts.push(renderAtomicStylesCss({
|
|
1128
3328
|
atomicStyles: unlayeredStyles,
|
|
1129
3329
|
isPreview,
|
|
1130
3330
|
isFormatted
|
|
1131
3331
|
}));
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
3332
|
+
parts.push(...renderLayerBlocks({
|
|
3333
|
+
layerGroups,
|
|
3334
|
+
layerOrder,
|
|
3335
|
+
isFormatted,
|
|
3336
|
+
render: (styles) => renderAtomicStylesCss({
|
|
1136
3337
|
atomicStyles: styles,
|
|
1137
3338
|
isPreview,
|
|
1138
3339
|
isFormatted
|
|
1139
|
-
})
|
|
1140
|
-
|
|
1141
|
-
}
|
|
3340
|
+
})
|
|
3341
|
+
}));
|
|
1142
3342
|
return parts.join(lineEnd);
|
|
1143
3343
|
}
|
|
3344
|
+
/**
|
|
3345
|
+
* Recursively converts a `PreflightDefinition` object tree into CSS style blocks.
|
|
3346
|
+
* @internal
|
|
3347
|
+
*
|
|
3348
|
+
* @param options - An object containing:
|
|
3349
|
+
* - `engine` — the engine instance (used for selector transformation).
|
|
3350
|
+
* - `preflightDefinition` — the nested object tree of selectors and CSS properties.
|
|
3351
|
+
* - `blocks` — accumulator map for the resulting CSS blocks.
|
|
3352
|
+
* @param options.engine - The engine instance used to run selector transforms.
|
|
3353
|
+
* @param options.preflightDefinition - The nested preflight definition object to convert into CSS blocks.
|
|
3354
|
+
* @param options.blocks - Optional accumulator map reused during recursive descent.
|
|
3355
|
+
* @returns The accumulated `CSSStyleBlocks` map.
|
|
3356
|
+
*
|
|
3357
|
+
* @remarks Each key in the definition is either a CSS property (when its value is a property value) or a nested selector scope (when its value is an object). Selector keys are expanded through `hooks.transformSelectors`. The resulting blocks map is consumable by `renderCSSStyleBlocks`.
|
|
3358
|
+
*
|
|
3359
|
+
* @example
|
|
3360
|
+
* ```ts
|
|
3361
|
+
* const blocks = await _renderPreflightDefinition({ engine, preflightDefinition: { ':root': { '--color': 'red' } } })
|
|
3362
|
+
* ```
|
|
3363
|
+
*/
|
|
1144
3364
|
async function _renderPreflightDefinition({ engine, preflightDefinition, blocks = /* @__PURE__ */ new Map() }) {
|
|
1145
3365
|
for (const [selector, propertiesOrDefinition] of Object.entries(preflightDefinition)) {
|
|
1146
3366
|
if (propertiesOrDefinition == null) continue;
|
|
@@ -1179,6 +3399,23 @@ async function _renderPreflightDefinition({ engine, preflightDefinition, blocks
|
|
|
1179
3399
|
}
|
|
1180
3400
|
return blocks;
|
|
1181
3401
|
}
|
|
3402
|
+
/**
|
|
3403
|
+
* Renders a `PreflightDefinition` into a CSS string via the engine's selector pipeline.
|
|
3404
|
+
* @internal
|
|
3405
|
+
*
|
|
3406
|
+
* @param payload - An object with the `engine`, the `preflightDefinition` to render, and `isFormatted` flag.
|
|
3407
|
+
* @param payload.engine - The engine instance whose selector pipeline should be applied.
|
|
3408
|
+
* @param payload.preflightDefinition - The preflight definition tree to render.
|
|
3409
|
+
* @param payload.isFormatted - Whether the rendered CSS should include indentation and line breaks.
|
|
3410
|
+
* @returns The rendered CSS string.
|
|
3411
|
+
*
|
|
3412
|
+
* @remarks A convenience wrapper that calls `_renderPreflightDefinition` and pipes the result through `renderCSSStyleBlocks`.
|
|
3413
|
+
*
|
|
3414
|
+
* @example
|
|
3415
|
+
* ```ts
|
|
3416
|
+
* const css = await renderPreflightDefinition({ engine, preflightDefinition: { ':root': { color: 'red' } }, isFormatted: true })
|
|
3417
|
+
* ```
|
|
3418
|
+
*/
|
|
1182
3419
|
async function renderPreflightDefinition(payload) {
|
|
1183
3420
|
const { engine, preflightDefinition, isFormatted } = payload;
|
|
1184
3421
|
return renderCSSStyleBlocks(await _renderPreflightDefinition({
|
|
@@ -1186,31 +3423,127 @@ async function renderPreflightDefinition(payload) {
|
|
|
1186
3423
|
preflightDefinition
|
|
1187
3424
|
}), isFormatted);
|
|
1188
3425
|
}
|
|
1189
|
-
|
|
1190
3426
|
//#endregion
|
|
1191
3427
|
//#region src/index.ts
|
|
3428
|
+
/**
|
|
3429
|
+
* Identity helper that returns the engine configuration as-is, providing TypeScript type inference and autocompletion.
|
|
3430
|
+
*
|
|
3431
|
+
* @typeParam T - The exact literal type of the configuration object.
|
|
3432
|
+
* @param config - The engine configuration object.
|
|
3433
|
+
* @returns The same configuration object, unchanged.
|
|
3434
|
+
*
|
|
3435
|
+
* @remarks A compile-time-only helper with no runtime effect. Useful in `pika.config.ts` files for IDE support.
|
|
3436
|
+
*
|
|
3437
|
+
* @example
|
|
3438
|
+
* ```ts
|
|
3439
|
+
* export default defineEngineConfig({ prefix: 'pk-', plugins: [myPlugin()] })
|
|
3440
|
+
* ```
|
|
3441
|
+
*/
|
|
1192
3442
|
function defineEngineConfig(config) {
|
|
1193
3443
|
return config;
|
|
1194
3444
|
}
|
|
3445
|
+
/**
|
|
3446
|
+
* Identity helper that returns the style definition as-is, providing TypeScript type inference and autocompletion.
|
|
3447
|
+
*
|
|
3448
|
+
* @typeParam T - The exact literal type of the style definition.
|
|
3449
|
+
* @param styleDefinition - A style definition object.
|
|
3450
|
+
* @returns The same style definition, unchanged.
|
|
3451
|
+
*
|
|
3452
|
+
* @remarks A compile-time-only helper with no runtime effect. Useful for extracting a reusable style definition with full type safety.
|
|
3453
|
+
*
|
|
3454
|
+
* @example
|
|
3455
|
+
* ```ts
|
|
3456
|
+
* const card = defineStyleDefinition({ padding: '1rem', borderRadius: '0.5rem' })
|
|
3457
|
+
* ```
|
|
3458
|
+
*/
|
|
1195
3459
|
function defineStyleDefinition(styleDefinition) {
|
|
1196
3460
|
return styleDefinition;
|
|
1197
3461
|
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Identity helper that returns the preflight as-is, providing TypeScript type inference and autocompletion.
|
|
3464
|
+
*
|
|
3465
|
+
* @typeParam T - The exact literal type of the preflight.
|
|
3466
|
+
* @param preflight - A preflight definition: a function, a static string/object, or a wrapper with `layer`/`id` metadata.
|
|
3467
|
+
* @returns The same preflight, unchanged.
|
|
3468
|
+
*
|
|
3469
|
+
* @remarks A compile-time-only helper with no runtime effect. Useful for defining reusable preflight values with type safety.
|
|
3470
|
+
*
|
|
3471
|
+
* @example
|
|
3472
|
+
* ```ts
|
|
3473
|
+
* const reset = definePreflight('*, *::before { box-sizing: border-box; }')
|
|
3474
|
+
* ```
|
|
3475
|
+
*/
|
|
1198
3476
|
function definePreflight(preflight) {
|
|
1199
3477
|
return preflight;
|
|
1200
3478
|
}
|
|
3479
|
+
/**
|
|
3480
|
+
* Identity helper that returns the keyframes definition as-is, providing TypeScript type inference and autocompletion.
|
|
3481
|
+
*
|
|
3482
|
+
* @typeParam T - The exact literal type of the keyframes configuration.
|
|
3483
|
+
* @param keyframes - A keyframes definition: a name string, a tuple, or an object form.
|
|
3484
|
+
* @returns The same keyframes definition, unchanged.
|
|
3485
|
+
*
|
|
3486
|
+
* @remarks A compile-time-only helper with no runtime effect.
|
|
3487
|
+
*
|
|
3488
|
+
* @example
|
|
3489
|
+
* ```ts
|
|
3490
|
+
* const spin = defineKeyframes(['spin', { from: { transform: 'rotate(0deg)' }, to: { transform: 'rotate(360deg)' } }])
|
|
3491
|
+
* ```
|
|
3492
|
+
*/
|
|
1201
3493
|
function defineKeyframes(keyframes) {
|
|
1202
3494
|
return keyframes;
|
|
1203
3495
|
}
|
|
3496
|
+
/**
|
|
3497
|
+
* Identity helper that returns the selector definition as-is, providing TypeScript type inference and autocompletion.
|
|
3498
|
+
*
|
|
3499
|
+
* @typeParam T - The exact literal type of the selector configuration.
|
|
3500
|
+
* @param selector - A selector definition: a string redirect, tuple, or object form.
|
|
3501
|
+
* @returns The same selector definition, unchanged.
|
|
3502
|
+
*
|
|
3503
|
+
* @remarks A compile-time-only helper with no runtime effect.
|
|
3504
|
+
*
|
|
3505
|
+
* @example
|
|
3506
|
+
* ```ts
|
|
3507
|
+
* const hover = defineSelector(['hover', '&:hover'])
|
|
3508
|
+
* ```
|
|
3509
|
+
*/
|
|
1204
3510
|
function defineSelector(selector) {
|
|
1205
3511
|
return selector;
|
|
1206
3512
|
}
|
|
3513
|
+
/**
|
|
3514
|
+
* Identity helper that returns the shortcut definition as-is, providing TypeScript type inference and autocompletion.
|
|
3515
|
+
*
|
|
3516
|
+
* @typeParam T - The exact literal type of the shortcut configuration.
|
|
3517
|
+
* @param shortcut - A shortcut definition: a string redirect, tuple, or object form.
|
|
3518
|
+
* @returns The same shortcut definition, unchanged.
|
|
3519
|
+
*
|
|
3520
|
+
* @remarks A compile-time-only helper with no runtime effect.
|
|
3521
|
+
*
|
|
3522
|
+
* @example
|
|
3523
|
+
* ```ts
|
|
3524
|
+
* const btn = defineShortcut(['btn', { padding: '0.5rem 1rem', borderRadius: '0.25rem' }])
|
|
3525
|
+
* ```
|
|
3526
|
+
*/
|
|
1207
3527
|
function defineShortcut(shortcut) {
|
|
1208
3528
|
return shortcut;
|
|
1209
3529
|
}
|
|
3530
|
+
/**
|
|
3531
|
+
* Identity helper that returns the variables definition as-is, providing TypeScript type inference and autocompletion.
|
|
3532
|
+
*
|
|
3533
|
+
* @typeParam T - The exact literal type of the variables definition.
|
|
3534
|
+
* @param variables - A nested record of CSS custom property definitions.
|
|
3535
|
+
* @returns The same variables definition, unchanged.
|
|
3536
|
+
*
|
|
3537
|
+
* @remarks A compile-time-only helper with no runtime effect.
|
|
3538
|
+
*
|
|
3539
|
+
* @example
|
|
3540
|
+
* ```ts
|
|
3541
|
+
* const vars = defineVariables({ '--color-primary': '#3b82f6', '.dark': { '--color-primary': '#60a5fa' } })
|
|
3542
|
+
* ```
|
|
3543
|
+
*/
|
|
1210
3544
|
function defineVariables(variables) {
|
|
1211
3545
|
return variables;
|
|
1212
3546
|
}
|
|
1213
3547
|
/* c8 ignore end */
|
|
1214
|
-
|
|
1215
3548
|
//#endregion
|
|
1216
|
-
export {
|
|
3549
|
+
export { appendAutocomplete, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, log, renderCSSStyleBlocks, sortLayerNames };
|