@alphacifer/slidev-addon-theme 0.0.1
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 +47 -0
- package/components/core/Date.vue +31 -0
- package/components/core/QnA.vue +83 -0
- package/components/core/Quote.vue +42 -0
- package/components/core/ReflectedTitle.vue +50 -0
- package/components/core/Speaker.vue +46 -0
- package/components/shifting-heading/TransitionHeading.vue +80 -0
- package/components/thanks/ThanksContent.vue +235 -0
- package/components/thanks/ThanksOutlineSquare.vue +18 -0
- package/components/thanks/ThanksSquare.vue +18 -0
- package/layouts/core/bg-center.vue +34 -0
- package/layouts/core/table-of-contents.vue +30 -0
- package/layouts/shifting-heading/shifting-intro.vue +111 -0
- package/layouts/thanks/thanks.vue +20 -0
- package/package.json +45 -0
- package/utils/mergeUno/classifyLayout.ts +245 -0
- package/utils/mergeUno/classifySimple.ts +42 -0
- package/utils/mergeUno/classifyTypography.ts +96 -0
- package/utils/mergeUno/classifyUtility.ts +36 -0
- package/utils/mergeUno/classifyVisual.ts +249 -0
- package/utils/mergeUno/collectClassNames.ts +147 -0
- package/utils/mergeUno/index.ts +32 -0
- package/utils/mergeUno/mergeClassValues.ts +86 -0
- package/utils/mergeUno/splitVariantScope.ts +44 -0
- package/utils/mergeUno/types.ts +39 -0
- package/utils/useMergedUnoAttrs.ts +43 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { IClassifyUtilityParams, TUtilityConflictKeys } from './types';
|
|
2
|
+
|
|
3
|
+
const BORDER_STYLES = new Set([
|
|
4
|
+
'border-dashed',
|
|
5
|
+
'border-dotted',
|
|
6
|
+
'border-double',
|
|
7
|
+
'border-hidden',
|
|
8
|
+
'border-none',
|
|
9
|
+
'border-solid',
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const LENGTH_VALUE = /^(?:0|\d|px|full|screen|min|max|fit|auto|\[[-+]?\d)/;
|
|
13
|
+
|
|
14
|
+
const BORDER_SIDES: Readonly<Record<string, readonly string[]>> = {
|
|
15
|
+
'': ['top', 'right', 'bottom', 'left'],
|
|
16
|
+
b: ['bottom'],
|
|
17
|
+
e: ['inline-end'],
|
|
18
|
+
l: ['left'],
|
|
19
|
+
r: ['right'],
|
|
20
|
+
s: ['inline-start'],
|
|
21
|
+
t: ['top'],
|
|
22
|
+
x: ['left', 'right'],
|
|
23
|
+
y: ['top', 'bottom'],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const ANIMATION_KEYS = [
|
|
27
|
+
'animation-name',
|
|
28
|
+
'animation-duration',
|
|
29
|
+
'animation-delay',
|
|
30
|
+
'animation-timing-function',
|
|
31
|
+
'animation-fill-mode',
|
|
32
|
+
'animation-direction',
|
|
33
|
+
'animation-iteration-count',
|
|
34
|
+
'animation-play-state',
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
function directionKeys(property: string, direction: string): string[] {
|
|
38
|
+
return (BORDER_SIDES[direction] ?? []).map((side) => `${property}-${side}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function classifyBorder(utility: string): string[] | null {
|
|
42
|
+
if (utility === 'border-collapse' || utility === 'border-separate') {
|
|
43
|
+
return ['border-collapse'];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (utility.startsWith('border-spacing-x-')) {
|
|
47
|
+
return ['border-spacing-x'];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (utility.startsWith('border-spacing-y-')) {
|
|
51
|
+
return ['border-spacing-y'];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (utility.startsWith('border-spacing-')) {
|
|
55
|
+
return ['border-spacing-x', 'border-spacing-y'];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (BORDER_STYLES.has(utility)) {
|
|
59
|
+
return ['border-style'];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const match = utility.match(/^border(?:-([trblesxy]))?(?:-(.+))?$/);
|
|
63
|
+
|
|
64
|
+
if (!match) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const direction = match[1] ?? '';
|
|
69
|
+
const value = match[2] ?? '';
|
|
70
|
+
const kind = !value || LENGTH_VALUE.test(value) ? 'width' : 'color';
|
|
71
|
+
return directionKeys(`border-${kind}`, direction);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function classifyBackground(utility: string): string[] {
|
|
75
|
+
if (/^bg-(?:fixed|local|scroll)$/.test(utility)) {
|
|
76
|
+
return ['background-attachment'];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (/^bg-(?:clip|origin)-/.test(utility)) {
|
|
80
|
+
return [
|
|
81
|
+
utility.startsWith('bg-clip-') ? 'background-clip' : 'background-origin',
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (/^bg-(?:repeat|no-repeat)/.test(utility)) {
|
|
86
|
+
return ['background-repeat'];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (/^bg-(?:auto|cover|contain)$/.test(utility)) {
|
|
90
|
+
return ['background-size'];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
/^bg-(?:bottom|center|left|right|top)(?:-|$)/.test(utility) ||
|
|
95
|
+
utility.startsWith('bg-position-')
|
|
96
|
+
) {
|
|
97
|
+
return ['background-position'];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (/^bg-(?:gradient|image|url)-/.test(utility)) {
|
|
101
|
+
return ['background-image'];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (utility.startsWith('bg-opacity-')) {
|
|
105
|
+
return ['background-opacity'];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return ['background-color'];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function classifyAnimation(utility: string): readonly string[] {
|
|
112
|
+
if (utility.startsWith('animate-name-')) {
|
|
113
|
+
return ['animation-name'];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (utility.startsWith('animate-duration-')) {
|
|
117
|
+
return ['animation-duration'];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (utility.startsWith('animate-delay-')) {
|
|
121
|
+
return ['animation-delay'];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (utility === 'animate-ease' || utility.startsWith('animate-ease-')) {
|
|
125
|
+
return ['animation-timing-function'];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (/^animate-(?:fill-mode-|fill-|mode-)/.test(utility)) {
|
|
129
|
+
return ['animation-fill-mode'];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (utility.startsWith('animate-direction-')) {
|
|
133
|
+
return ['animation-direction'];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (/^animate-(?:iteration-count-|iteration-|count-)/.test(utility)) {
|
|
137
|
+
return ['animation-iteration-count'];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (/^animate-(?:play-state-|play-|state-)/.test(utility)) {
|
|
141
|
+
return ['animation-play-state'];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return ANIMATION_KEYS;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function classifyVisual({
|
|
148
|
+
utility,
|
|
149
|
+
}: IClassifyUtilityParams): TUtilityConflictKeys {
|
|
150
|
+
if (utility.startsWith('bg-')) {
|
|
151
|
+
return classifyBackground(utility);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (utility.startsWith('rounded')) {
|
|
155
|
+
const match = utility.match(/^rounded-?([trbles]{0,2})/)?.[1] ?? '';
|
|
156
|
+
|
|
157
|
+
return [`border-radius:${match}`];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (utility.startsWith('border')) {
|
|
161
|
+
return classifyBorder(utility) ?? [`token:${utility}`];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (utility.startsWith('divide-x-')) {
|
|
165
|
+
return ['divide-x'];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (utility.startsWith('divide-y-')) {
|
|
169
|
+
return ['divide-y'];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (utility.startsWith('ring-offset-')) {
|
|
173
|
+
return ['ring-offset'];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (utility.startsWith('ring-')) {
|
|
177
|
+
return ['ring'];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (utility.startsWith('shadow-') || utility === 'shadow') {
|
|
181
|
+
return ['shadow'];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (utility.startsWith('translate-x-')) {
|
|
185
|
+
return ['translate-x'];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (utility.startsWith('translate-y-')) {
|
|
189
|
+
return ['translate-y'];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (utility.startsWith('translate-')) {
|
|
193
|
+
return ['translate-x', 'translate-y'];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (utility.startsWith('rotate-')) {
|
|
197
|
+
return ['rotate'];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (utility.startsWith('scale-x-')) {
|
|
201
|
+
return ['scale-x'];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (utility.startsWith('scale-y-')) {
|
|
205
|
+
return ['scale-y'];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (utility.startsWith('scale-')) {
|
|
209
|
+
return ['scale-x', 'scale-y'];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (utility.startsWith('skew-x-')) {
|
|
213
|
+
return ['skew-x'];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (utility.startsWith('skew-y-')) {
|
|
217
|
+
return ['skew-y'];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (utility.startsWith('origin-')) {
|
|
221
|
+
return ['transform-origin'];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (utility.startsWith('transform-')) {
|
|
225
|
+
return ['transform'];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (utility.startsWith('transition-') || utility === 'transition') {
|
|
229
|
+
return ['transition-property'];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (utility.startsWith('duration-')) {
|
|
233
|
+
return ['transition-duration'];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (utility.startsWith('delay-')) {
|
|
237
|
+
return ['transition-delay'];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (utility.startsWith('ease-')) {
|
|
241
|
+
return ['transition-timing-function'];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (utility.startsWith('animate-')) {
|
|
245
|
+
return classifyAnimation(utility);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { TUnoClassValue } from './types';
|
|
2
|
+
|
|
3
|
+
interface ICollectClassNamesParams {
|
|
4
|
+
readonly values: readonly TUnoClassValue[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function splitClassNames(value: string): string[] {
|
|
8
|
+
const tokens: string[] = [];
|
|
9
|
+
let current = '';
|
|
10
|
+
let quote = '';
|
|
11
|
+
let escaped = false;
|
|
12
|
+
let squareDepth = 0;
|
|
13
|
+
let roundDepth = 0;
|
|
14
|
+
let curlyDepth = 0;
|
|
15
|
+
|
|
16
|
+
for (const character of value) {
|
|
17
|
+
if (escaped) {
|
|
18
|
+
current += character;
|
|
19
|
+
escaped = false;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (character === '\\') {
|
|
24
|
+
current += character;
|
|
25
|
+
escaped = true;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (quote) {
|
|
30
|
+
current += character;
|
|
31
|
+
|
|
32
|
+
if (character === quote) {
|
|
33
|
+
quote = '';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (character === '"' || character === "'") {
|
|
40
|
+
current += character;
|
|
41
|
+
quote = character;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (character === '[') {
|
|
46
|
+
squareDepth += 1;
|
|
47
|
+
} else if (character === ']') {
|
|
48
|
+
squareDepth -= 1;
|
|
49
|
+
} else if (character === '(') {
|
|
50
|
+
roundDepth += 1;
|
|
51
|
+
} else if (character === ')') {
|
|
52
|
+
roundDepth -= 1;
|
|
53
|
+
} else if (character === '{') {
|
|
54
|
+
curlyDepth += 1;
|
|
55
|
+
} else if (character === '}') {
|
|
56
|
+
curlyDepth -= 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
/\s/.test(character) &&
|
|
61
|
+
squareDepth === 0 &&
|
|
62
|
+
roundDepth === 0 &&
|
|
63
|
+
curlyDepth === 0
|
|
64
|
+
) {
|
|
65
|
+
if (current) {
|
|
66
|
+
tokens.push(current);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
current = '';
|
|
70
|
+
} else {
|
|
71
|
+
current += character;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (current) {
|
|
76
|
+
tokens.push(current);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return tokens;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function expandVariantGroup(token: string): string[] {
|
|
83
|
+
let squareDepth = 0;
|
|
84
|
+
|
|
85
|
+
for (let index = 0; index < token.length - 1; index += 1) {
|
|
86
|
+
const character = token[index];
|
|
87
|
+
|
|
88
|
+
if (character === '[') {
|
|
89
|
+
squareDepth += 1;
|
|
90
|
+
} else if (character === ']') {
|
|
91
|
+
squareDepth -= 1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
squareDepth === 0 &&
|
|
96
|
+
character === ':' &&
|
|
97
|
+
token[index + 1] === '(' &&
|
|
98
|
+
token.endsWith(')')
|
|
99
|
+
) {
|
|
100
|
+
const prefix = token.slice(0, index + 1);
|
|
101
|
+
const contents = token.slice(index + 2, -1);
|
|
102
|
+
return splitClassNames(contents).flatMap((child) =>
|
|
103
|
+
expandVariantGroup(`${prefix}${child}`),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return [token];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function collectClassName(value: TUnoClassValue, result: string[]): void {
|
|
112
|
+
if (!value) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
117
|
+
for (const token of splitClassNames(String(value))) {
|
|
118
|
+
result.push(...expandVariantGroup(token));
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (Array.isArray(value)) {
|
|
124
|
+
for (const item of value) {
|
|
125
|
+
collectClassName(item, result);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (const [className, enabled] of Object.entries(value)) {
|
|
131
|
+
if (enabled) {
|
|
132
|
+
collectClassName(className, result);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function collectClassNames({
|
|
138
|
+
values,
|
|
139
|
+
}: ICollectClassNamesParams): string[] {
|
|
140
|
+
const result: string[] = [];
|
|
141
|
+
|
|
142
|
+
for (const value of values) {
|
|
143
|
+
collectClassName(value, result);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mergeClassValues } from './mergeClassValues';
|
|
2
|
+
import type {
|
|
3
|
+
IUnoClassMergerOptions,
|
|
4
|
+
TUnoClassMerger,
|
|
5
|
+
TUnoClassValue,
|
|
6
|
+
} from './types';
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
IUnoClassDictionary,
|
|
10
|
+
IUnoClassMergerOptions,
|
|
11
|
+
IUnoConflictResolverParams,
|
|
12
|
+
TUnoClassMerger,
|
|
13
|
+
TUnoClassValue,
|
|
14
|
+
TUnoConflictResolver,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
export function createUnoClassMerger(
|
|
18
|
+
options: IUnoClassMergerOptions = {},
|
|
19
|
+
): TUnoClassMerger {
|
|
20
|
+
return (...values: TUnoClassValue[]) => {
|
|
21
|
+
return mergeClassValues({
|
|
22
|
+
values,
|
|
23
|
+
resolveConflictKeys: options.resolveConflictKeys,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function mergeUno(...values: TUnoClassValue[]): string {
|
|
29
|
+
return mergeClassValues({
|
|
30
|
+
values,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { classifyUtility } from './classifyUtility';
|
|
2
|
+
import { collectClassNames } from './collectClassNames';
|
|
3
|
+
import { splitVariantScope } from './splitVariantScope';
|
|
4
|
+
import type {
|
|
5
|
+
IClassEntry,
|
|
6
|
+
TUnoClassValue,
|
|
7
|
+
TUnoConflictResolver,
|
|
8
|
+
} from './types';
|
|
9
|
+
|
|
10
|
+
interface ICreateEntryParams {
|
|
11
|
+
readonly token: string;
|
|
12
|
+
readonly resolveConflictKeys?: TUnoConflictResolver;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IMergeClassValuesParams {
|
|
16
|
+
readonly values: readonly TUnoClassValue[];
|
|
17
|
+
readonly resolveConflictKeys?: TUnoConflictResolver;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createEntry({
|
|
21
|
+
token,
|
|
22
|
+
resolveConflictKeys,
|
|
23
|
+
}: ICreateEntryParams): IClassEntry {
|
|
24
|
+
const { base: rawBase, scope } = splitVariantScope({
|
|
25
|
+
token,
|
|
26
|
+
});
|
|
27
|
+
const important = rawBase.startsWith('!') || rawBase.endsWith('!');
|
|
28
|
+
const base = rawBase.replace(/^!/, '').replace(/!$/, '');
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
important,
|
|
32
|
+
keys:
|
|
33
|
+
resolveConflictKeys?.({
|
|
34
|
+
utility: base,
|
|
35
|
+
}) ??
|
|
36
|
+
classifyUtility({
|
|
37
|
+
rawUtility: base,
|
|
38
|
+
}),
|
|
39
|
+
scope,
|
|
40
|
+
token,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Merges common UnoCSS atomic utilities using last-class-wins semantics.
|
|
46
|
+
*
|
|
47
|
+
* Unknown utilities and compound shortcuts are preserved unless they are exact
|
|
48
|
+
* duplicates. UnoCSS permits arbitrary user-defined rules, so deleting an
|
|
49
|
+
* unknown class cannot be proven safe without the active configuration.
|
|
50
|
+
*/
|
|
51
|
+
export function mergeClassValues({
|
|
52
|
+
values,
|
|
53
|
+
resolveConflictKeys,
|
|
54
|
+
}: IMergeClassValuesParams): string {
|
|
55
|
+
const tokens = collectClassNames({
|
|
56
|
+
values,
|
|
57
|
+
});
|
|
58
|
+
const entries: Array<IClassEntry | null> = [];
|
|
59
|
+
|
|
60
|
+
for (const token of tokens) {
|
|
61
|
+
const next = createEntry({
|
|
62
|
+
token,
|
|
63
|
+
resolveConflictKeys,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
67
|
+
const previous = entries[index];
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
previous &&
|
|
71
|
+
previous.scope === next.scope &&
|
|
72
|
+
previous.important === next.important &&
|
|
73
|
+
previous.keys.every((key) => next.keys.includes(key))
|
|
74
|
+
) {
|
|
75
|
+
entries[index] = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
entries.push(next);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return entries
|
|
83
|
+
.filter((entry): entry is IClassEntry => entry !== null)
|
|
84
|
+
.map((entry) => entry.token)
|
|
85
|
+
.join(' ');
|
|
86
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
interface ISplitVariantScopeParams {
|
|
2
|
+
readonly token: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
interface IVariantScope {
|
|
6
|
+
readonly base: string;
|
|
7
|
+
readonly scope: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function splitVariantScope({
|
|
11
|
+
token,
|
|
12
|
+
}: ISplitVariantScopeParams): IVariantScope {
|
|
13
|
+
let squareDepth = 0;
|
|
14
|
+
let roundDepth = 0;
|
|
15
|
+
let lastSeparator = -1;
|
|
16
|
+
|
|
17
|
+
for (let index = 0; index < token.length; index += 1) {
|
|
18
|
+
const character = token[index];
|
|
19
|
+
|
|
20
|
+
if (character === '[') {
|
|
21
|
+
squareDepth += 1;
|
|
22
|
+
} else if (character === ']') {
|
|
23
|
+
squareDepth -= 1;
|
|
24
|
+
} else if (character === '(') {
|
|
25
|
+
roundDepth += 1;
|
|
26
|
+
} else if (character === ')') {
|
|
27
|
+
roundDepth -= 1;
|
|
28
|
+
} else if (character === ':' && squareDepth === 0 && roundDepth === 0) {
|
|
29
|
+
lastSeparator = index;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (lastSeparator < 0) {
|
|
34
|
+
return {
|
|
35
|
+
base: token,
|
|
36
|
+
scope: '',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
base: token.slice(lastSeparator + 1),
|
|
42
|
+
scope: token.slice(0, lastSeparator + 1),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type TUnoClassValue =
|
|
2
|
+
| string
|
|
3
|
+
| number
|
|
4
|
+
| false
|
|
5
|
+
| null
|
|
6
|
+
| undefined
|
|
7
|
+
| readonly TUnoClassValue[]
|
|
8
|
+
| IUnoClassDictionary;
|
|
9
|
+
|
|
10
|
+
export interface IUnoClassDictionary {
|
|
11
|
+
readonly [className: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IUnoConflictResolverParams {
|
|
15
|
+
readonly utility: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type TUnoConflictResolver = (
|
|
19
|
+
params: IUnoConflictResolverParams,
|
|
20
|
+
) => readonly string[] | null | undefined;
|
|
21
|
+
|
|
22
|
+
export type TUnoClassMerger = (...values: TUnoClassValue[]) => string;
|
|
23
|
+
|
|
24
|
+
export type TUtilityConflictKeys = readonly string[] | null;
|
|
25
|
+
|
|
26
|
+
export interface IUnoClassMergerOptions {
|
|
27
|
+
readonly resolveConflictKeys?: TUnoConflictResolver;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface IClassEntry {
|
|
31
|
+
readonly important: boolean;
|
|
32
|
+
readonly keys: readonly string[];
|
|
33
|
+
readonly scope: string;
|
|
34
|
+
readonly token: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface IClassifyUtilityParams {
|
|
38
|
+
readonly utility: string;
|
|
39
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useAttrs } from 'vue';
|
|
2
|
+
|
|
3
|
+
import { mergeUno } from './mergeUno';
|
|
4
|
+
import type { TUnoClassValue } from './mergeUno/types';
|
|
5
|
+
|
|
6
|
+
type TUnoClassSource = TUnoClassValue | (() => TUnoClassValue);
|
|
7
|
+
|
|
8
|
+
interface IUseMergedUnoAttrsResult {
|
|
9
|
+
readonly className: () => string;
|
|
10
|
+
readonly forwardedAttrs: () => Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Merges a component's default UnoCSS classes with its consumer-provided class.
|
|
15
|
+
* The original class attribute is removed from the forwarded attributes so Vue
|
|
16
|
+
* cannot append it a second time after conflict resolution.
|
|
17
|
+
*/
|
|
18
|
+
export function useMergedUnoAttrs(
|
|
19
|
+
defaultClasses: TUnoClassSource,
|
|
20
|
+
): IUseMergedUnoAttrsResult {
|
|
21
|
+
const attrs = useAttrs();
|
|
22
|
+
|
|
23
|
+
const className = (): string => {
|
|
24
|
+
const resolvedDefaults =
|
|
25
|
+
typeof defaultClasses === 'function' ? defaultClasses() : defaultClasses;
|
|
26
|
+
|
|
27
|
+
return mergeUno(resolvedDefaults, attrs.class as TUnoClassValue);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const forwardedAttrs = (): Record<string, unknown> => {
|
|
31
|
+
const result = {
|
|
32
|
+
...attrs,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
delete result.class;
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
className,
|
|
41
|
+
forwardedAttrs,
|
|
42
|
+
};
|
|
43
|
+
}
|