@udixio/tailwind 1.7.3 → 2.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@udixio/tailwind",
3
- "version": "1.7.3",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/node.js",
6
6
  "module": "./dist/node.js",
@@ -26,11 +26,12 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
+ "text-case": "^1.2.9",
29
30
  "tailwindcss": "^4.1.12",
30
31
  "chalk": "^5.6.0",
31
32
  "pathe": "^2.0.3",
32
33
  "tslib": "^2.3.0",
33
- "@udixio/theme": "1.3.1"
34
+ "@udixio/theme": "2.0.0"
34
35
  },
35
36
  "repository": {
36
37
  "type": "git",
@@ -1,5 +1,9 @@
1
1
  import { FontPlugin, PluginAbstract, PluginImplAbstract } from '@udixio/theme';
2
- import { argbFromHex, Hct, hexFromArgb } from '@material/material-color-utilities';
2
+ import {
3
+ argbFromHex,
4
+ Hct,
5
+ hexFromArgb,
6
+ } from '@material/material-color-utilities';
3
7
 
4
8
  export interface TailwindPluginOptions {
5
9
  darkMode?: 'class' | 'media';
@@ -158,12 +162,12 @@ export class TailwindImplPluginBrowser extends PluginImplAbstract<TailwindPlugin
158
162
  })}
159
163
  }`;
160
164
 
161
- const sourceColor = this.api.themes.sourceColorHex;
165
+ const sourceColor = this.api.context.sourceColor;
162
166
  for (const [key, value] of Object.entries(this.options.subThemes ?? {})) {
163
167
  const newHue = Hct.fromInt(argbFromHex(value)).hue;
164
168
  const newColor = Hct.from(newHue, sourceColor.chroma, sourceColor.tone);
165
169
 
166
- this.api.themes.update({ sourceColorHex: hexFromArgb(newColor.toInt()) });
170
+ this.api.context.sourceColor = hexFromArgb(newColor.toInt());
167
171
  const colors = this.getColors();
168
172
  this.outputCss += `
169
173
  @layer theme {
@@ -190,35 +194,30 @@ export class TailwindImplPluginBrowser extends PluginImplAbstract<TailwindPlugin
190
194
  }
191
195
 
192
196
  getColors() {
193
- const colors: Record<
194
- string,
195
- {
196
- light: string;
197
- dark: string;
198
- }
199
- > = {};
200
- for (const isDark of [false, true]) {
201
- this.api.themes.update({ isDark: isDark });
202
- for (const [key, value] of this.api.colors.getColors().entries()) {
203
- const newKey = key
204
- .replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2')
205
- .toLowerCase();
206
- colors[newKey] ??= { light: '', dark: '' };
197
+ const colors: Record<string, { light: string; dark: string }> = {};
198
+ const regex = /([a-z0-9]|(?=[A-Z]))([A-Z])/g;
199
+ [false, true].forEach((isDark) => {
200
+ this.api.context.darkMode = isDark;
201
+ this.api.colors.getAll().forEach((value, key) => {
202
+ const newKey = key.replace(regex, '$1-$2').toLowerCase();
203
+ if (!colors[newKey]) {
204
+ colors[newKey] = { light: '', dark: '' };
205
+ }
207
206
  colors[newKey][isDark ? 'dark' : 'light'] = value.getHex();
208
- }
209
- }
210
-
207
+ });
208
+ });
211
209
  return colors;
212
210
  }
213
211
 
214
212
  async onLoad() {
215
213
  this.getColors();
216
214
 
217
- if (typeof window !== 'undefined') {
218
- const { tailwindBrowserInit } = await import('./tailwind-browser');
215
+ // if (typeof window !== 'undefined') {
216
+ // const { tailwindBrowserInit } = await import('./tailwind-browser');
217
+ //
218
+ // this.outputCss = await tailwindBrowserInit(this.outputCss);
219
+ // }
219
220
 
220
- this.outputCss = await tailwindBrowserInit(this.outputCss);
221
- }
222
221
  this.loadColor({ isDynamic: true });
223
222
  }
224
223
  }
package/src/main.ts CHANGED
@@ -1,10 +1,7 @@
1
1
  import plugin, { PluginAPI } from 'tailwindcss/plugin';
2
- import {
3
- font,
4
- FontPluginOptions,
5
- state,
6
- StateOptions,
7
- } from './plugins-tailwind';
2
+ import { animation } from './plugins-tailwind/animation';
3
+ import { font, FontPluginOptions } from './plugins-tailwind/font';
4
+ import { state, StateOptions } from './plugins-tailwind/state';
8
5
  import { shadow } from './plugins-tailwind/shadow';
9
6
 
10
7
  export type ConfigJs = FontPluginOptions & StateOptions;
@@ -52,5 +49,6 @@ export const main = plugin.withOptions<ConfigJs>((args) => {
52
49
  font(options).handler(api);
53
50
  state(options).handler(api);
54
51
  shadow.handler(api);
52
+ animation(options).handler(api);
55
53
  };
56
54
  });
@@ -2,11 +2,13 @@ import { FontPlugin, PluginAbstract } from '@udixio/theme';
2
2
 
3
3
  import {
4
4
  TailwindImplPluginBrowser,
5
- TailwindPluginOptions,
5
+ TailwindPluginOptions as TailwindPluginBrowserOptions,
6
6
  } from '../browser/tailwind.plugin';
7
7
 
8
8
  import { ConfigCss } from '../main';
9
9
 
10
+ export type TailwindPluginOptions = TailwindPluginBrowserOptions;
11
+
10
12
  export class TailwindPlugin extends PluginAbstract<
11
13
  TailwindImplPlugin,
12
14
  TailwindPluginOptions
@@ -0,0 +1,561 @@
1
+ import plugin, { PluginAPI } from 'tailwindcss/plugin';
2
+ import { kebabCase } from 'text-case';
3
+
4
+ export interface AnimationPluginOptions {
5
+ prefix?: string;
6
+ }
7
+
8
+ const createAnimationFunc =
9
+ ({
10
+ addBase,
11
+ prefix,
12
+ matchUtilities,
13
+ addUtilities,
14
+ animationNames,
15
+ }: {
16
+ addBase: PluginAPI['addBase'];
17
+ matchUtilities: PluginAPI['matchUtilities'];
18
+ addUtilities: PluginAPI['addUtilities'];
19
+ prefix: string;
20
+ animationNames: Set<string>;
21
+ }) =>
22
+ (
23
+ name: string,
24
+ styles: (
25
+ param: (propertyName: string) => string,
26
+ ) => Record<string, Record<string, string>>,
27
+ values: Record<
28
+ string,
29
+ {
30
+ as?: string;
31
+ DEFAULT: string;
32
+ values: Record<string, string>;
33
+ }
34
+ >,
35
+ callback?: (args: {
36
+ variableName: (propertyName: string) => string;
37
+ name: string;
38
+ dependencies: string[];
39
+ }) => void,
40
+ ) => {
41
+ animationNames.add(name);
42
+
43
+ const variableName = (propertyName: string) => {
44
+ return `--${prefix}-${propertyName}`;
45
+ };
46
+
47
+ const param = (propertyName: string) => {
48
+ const defaultValue = values[propertyName]?.DEFAULT;
49
+ return `var(${variableName(propertyName)} ${defaultValue ? `, ${defaultValue}` : ''})`;
50
+ };
51
+
52
+ const dependencies: string[] = [];
53
+
54
+ Object.values(styles(param)).forEach((step) => {
55
+ Object.keys(step).forEach((key) => {
56
+ dependencies.push(kebabCase(key));
57
+ });
58
+ });
59
+
60
+ addBase({
61
+ [`@keyframes ${prefix}-${name}`]: styles(param),
62
+ });
63
+
64
+ addUtilities({
65
+ [`.${prefix}-${name}, .${prefix}-${name}-in, .${prefix}-${name}-out`]: {
66
+ [`--${prefix}-name-${name}`]: `${prefix}-${name}`,
67
+ [`--${prefix}-dependencies-${name}`]: dependencies.join(', '),
68
+ animationDuration: `var(--${prefix}-durations, 300ms)`,
69
+ animationDelay: `var(--${prefix}-delays, 0)`,
70
+ animationTimingFunction: `var(--${prefix}-eases, cubic-bezier(0.4, 0, 0.2, 1))`,
71
+ animationFillMode: 'both',
72
+ },
73
+ [`.${prefix}-${name}, .${prefix}-${name}-in`]: {
74
+ animationPlayState: `var(--${prefix}-in-state, paused)`,
75
+ },
76
+ [`.${prefix}-${name}-out`]: {
77
+ animationPlayState: `var(--${prefix}-out-state, paused)`,
78
+ },
79
+ });
80
+
81
+ addUtilities({
82
+ [`.${prefix}-${name}-scroll`]: {
83
+ [`--${prefix}-name-${name}`]: `${prefix}-${name}`,
84
+ [`--${prefix}-dependencies-${name}`]: dependencies.join(', '),
85
+ animationTimeline: `var(--${prefix}-timeline, view())`,
86
+ animationRangeStart: `var(--${prefix}-range-start, entry 20%)`,
87
+ animationRangeEnd: `var(--${prefix}-range-end, cover 50%)`,
88
+ animationFillMode: 'both',
89
+ },
90
+ });
91
+
92
+ Object.entries(values).forEach(([key, value], index) => {
93
+ let as = value.as;
94
+ if (index !== 0 && !value.as) {
95
+ as = key;
96
+ }
97
+ matchUtilities(
98
+ {
99
+ [`${prefix}-${name}${as ? '-' + as : ''}`]: (value) => ({
100
+ [variableName(key)]: value,
101
+ }),
102
+ },
103
+ {
104
+ values: value.values,
105
+ },
106
+ );
107
+ });
108
+
109
+ callback?.({ variableName, name, dependencies });
110
+ };
111
+ // Animations inspired by temps.js but without overlapping Tailwind's transition utilities
112
+ // - prefixed utilities for animation properties: {prefix}-duration-*, {prefix}-delay-*, {prefix}-ease-*, {prefix}-fill-*, {prefix}-direction-*, {prefix}-repeat
113
+ // - usage: compose triggers ({prefix}-in|{prefix}-out or {prefix}-view*) + effects (fade/scale/slide/spin) + params
114
+ export const animation = plugin.withOptions(
115
+ ({ prefix = 'anim' }: AnimationPluginOptions) => {
116
+ return ({ addBase, matchUtilities, addUtilities }: PluginAPI) => {
117
+ const animationNames: Set<string> = new Set();
118
+
119
+ const createAnimation = createAnimationFunc({
120
+ addBase,
121
+ prefix,
122
+ matchUtilities,
123
+ addUtilities,
124
+ animationNames,
125
+ });
126
+
127
+ addBase({
128
+ '@keyframes enter': {
129
+ from: {
130
+ opacity: `var(--${prefix}-enter-opacity, 1)`,
131
+ transform: `translate3d(var(--${prefix}-enter-translate-x, 0), var(--${prefix}-enter-translate-y, 0), 0) scale3d(var(--${prefix}-enter-scale, 1), var(--${prefix}-enter-scale, 1), var(--${prefix}-enter-scale, 1)) rotate(var(--${prefix}-enter-rotate, 0))`,
132
+ },
133
+ },
134
+ '@keyframes exit': {
135
+ to: {
136
+ opacity: `var(--${prefix}-exit-opacity, 1)`,
137
+ transform: `translate3d(var(--${prefix}-exit-translate-x, 0), var(--${prefix}-exit-translate-y, 0), 0) scale3d(var(--${prefix}-exit-scale, 1), var(--${prefix}-exit-scale, 1), var(--${prefix}-exit-scale, 1)) rotate(var(--${prefix}-exit-rotate, 0))`,
138
+ },
139
+ },
140
+ });
141
+
142
+ // Triggers (unifiés): in/out + view*
143
+ addUtilities({
144
+ // in/out
145
+ // run/pause state
146
+ [`.${prefix}-in-run`]: { [`--${prefix}-in-state`]: 'running' },
147
+ [`.${prefix}-in-paused`]: { [`--${prefix}-in-state`]: 'paused' },
148
+ // scroll-driven
149
+ [`.${prefix}-timeline-block`]: {
150
+ animationTimeline: 'view(block)',
151
+ },
152
+ [`.${prefix}-timeline-inline`]: {
153
+ animationTimeline: 'view(inline)',
154
+ },
155
+ // aliases
156
+ [`.${prefix}-timeline-y`]: {
157
+ animationTimeline: 'view(block)',
158
+ },
159
+ [`.${prefix}-timeline-x`]: {
160
+ animationTimeline: 'view(inline)',
161
+ },
162
+ });
163
+
164
+ // Data-attribute triggers
165
+ addBase({
166
+ [`[data-${prefix}-in-run]`]: { [`--${prefix}-in-state`]: 'running' },
167
+ [`[data-${prefix}-in-paused]`]: { [`--${prefix}-in-state`]: 'paused' },
168
+ });
169
+
170
+ createAnimation(
171
+ 'fade',
172
+ (v) => ({
173
+ from: {
174
+ opacity: v('opacity'),
175
+ },
176
+ }),
177
+ {
178
+ opacity: {
179
+ DEFAULT: '0',
180
+ values: {
181
+ 0: '0',
182
+ 5: '0.05',
183
+ 10: '0.1',
184
+ 20: '0.2',
185
+ 25: '0.25',
186
+ 30: '0.3',
187
+ 40: '0.4',
188
+ 50: '0.5',
189
+ 60: '0.6',
190
+ 70: '0.7',
191
+ 75: '0.75',
192
+ 80: '0.8',
193
+ 90: '0.9',
194
+ 95: '0.95',
195
+ 100: '1',
196
+ },
197
+ },
198
+ },
199
+ );
200
+
201
+ createAnimation(
202
+ 'scale',
203
+ (v) => ({
204
+ from: {
205
+ scale: v('scale'),
206
+ },
207
+ }),
208
+ {
209
+ scale: {
210
+ DEFAULT: '.95',
211
+ values: {
212
+ 0: '0',
213
+ 50: '.5',
214
+ 75: '.75',
215
+ 90: '.9',
216
+ 95: '.95',
217
+ 100: '1',
218
+ 105: '1.05',
219
+ 110: '1.1',
220
+ 125: '1.25',
221
+ 150: '1.5',
222
+ },
223
+ },
224
+ },
225
+ );
226
+
227
+ // createAnimation(
228
+ // {
229
+ // name: 'spin',
230
+ // addBase,
231
+ // prefix,
232
+ // matchUtilities,
233
+ // addUtilities,
234
+ // },
235
+ // (v) => ({
236
+ // opacity: v('opacity'),
237
+ // }),
238
+ // {
239
+ // to: 'inherit',
240
+ // from: '6deg',
241
+ // values: {
242
+ // 1: '1deg',
243
+ // 2: '2deg',
244
+ // 3: '3deg',
245
+ // 6: '6deg',
246
+ // 12: '12deg',
247
+ // 30: '30deg',
248
+ // 45: '45deg',
249
+ // 90: '90deg',
250
+ // 180: '180deg',
251
+ // },
252
+ // },
253
+ // );
254
+
255
+ const slideValues = {
256
+ DEFAULT: '2rem',
257
+ values: {
258
+ full: '100%',
259
+ 0: '0px',
260
+ px: '1px',
261
+ 0.5: '0.125rem',
262
+ 1: '0.25rem',
263
+ 1.5: '0.375rem',
264
+ 2: '0.5rem',
265
+ 2.5: '0.625rem',
266
+ 3: '0.75rem',
267
+ 3.5: '0.875rem',
268
+ 4: '1rem',
269
+ 5: '1.25rem',
270
+ 6: '1.5rem',
271
+ 7: '1.75rem',
272
+ 8: '2rem',
273
+ 9: '2.25rem',
274
+ 10: '2.5rem',
275
+ 11: '2.75rem',
276
+ 12: '3rem',
277
+ 14: '3.5rem',
278
+ 16: '4rem',
279
+ 20: '5rem',
280
+ 24: '6rem',
281
+ 28: '7rem',
282
+ 32: '8rem',
283
+ 36: '9rem',
284
+ 40: '10rem',
285
+ 44: '11rem',
286
+ 48: '12rem',
287
+ 52: '13rem',
288
+ 56: '14rem',
289
+ 60: '15rem',
290
+ 64: '16rem',
291
+ 72: '18rem',
292
+ 80: '20rem',
293
+ 96: '24rem',
294
+ },
295
+ };
296
+ createAnimation(
297
+ 'slide',
298
+ (param) => ({
299
+ from: {
300
+ translate: `calc(${param('distance')} * ${param('dx')}) calc(${param('distance')} * ${param('dy')});`,
301
+ },
302
+ to: {
303
+ translate: `var(--tw-translate-x, 0) var(--tw-translate-y, 0)`,
304
+ },
305
+ }),
306
+ {
307
+ distance: {
308
+ ...slideValues,
309
+ },
310
+ },
311
+ ({ name, variableName, dependencies }) => {
312
+ [
313
+ 'up',
314
+ 'down',
315
+ 'left',
316
+ 'right',
317
+ 'from-top',
318
+ 'from-bottom',
319
+ 'from-left',
320
+ 'from-right',
321
+ 'from-top-left',
322
+ 'from-top-right',
323
+ 'from-bottom-left',
324
+ 'from-bottom-right',
325
+ 'up-left',
326
+ 'up-right',
327
+ 'down-left',
328
+ 'down-right',
329
+ ].forEach((directionAlias) => {
330
+ let direction:
331
+ | 'from-top'
332
+ | 'from-bottom'
333
+ | 'from-left'
334
+ | 'from-right'
335
+ | 'from-top-left'
336
+ | 'from-top-right'
337
+ | 'from-bottom-left'
338
+ | 'from-bottom-right' = '';
339
+
340
+ if (directionAlias.startsWith('from-')) {
341
+ direction = directionAlias;
342
+ } else if (directionAlias === 'up') {
343
+ direction = 'from-bottom';
344
+ } else if (directionAlias === 'down') {
345
+ direction = 'from-top';
346
+ } else if (directionAlias === 'left') {
347
+ direction = 'from-right';
348
+ } else if (directionAlias === 'right') {
349
+ direction = 'from-left';
350
+ } else if (directionAlias === 'up-left') {
351
+ direction = 'from-bottom-right';
352
+ } else if (directionAlias === 'up-right') {
353
+ direction = 'from-bottom-left';
354
+ } else if (directionAlias === 'down-left') {
355
+ direction = 'from-top-right';
356
+ } else if (directionAlias === 'down-right') {
357
+ direction = 'from-top-left';
358
+ }
359
+ if (!direction) {
360
+ throw new Error(`Invalid direction: ${directionAlias}`);
361
+ }
362
+
363
+ const dxdy: Record<typeof direction, { dx: string; dy: string }> = {
364
+ 'from-top': { dx: '0', dy: '1' },
365
+ 'from-bottom': { dx: '0', dy: '-1' },
366
+ 'from-left': { dx: '1', dy: '0' },
367
+ 'from-right': { dx: '-1', dy: '0' },
368
+ 'from-top-left': { dx: '1', dy: '1' },
369
+ 'from-top-right': { dx: '-1', dy: '1' },
370
+ 'from-bottom-left': { dx: '1', dy: '-1' },
371
+ 'from-bottom-right': { dx: '-1', dy: '-1' },
372
+ } as const;
373
+ const { dx, dy } = dxdy[direction];
374
+
375
+ addUtilities({
376
+ [`.${prefix}-${name}-${directionAlias}, .${prefix}-${name}-in-${directionAlias}, .${prefix}-${name}-out-${directionAlias}`]:
377
+ {
378
+ [`--${prefix}-name-${name}-${directionAlias}`]: `${prefix}-${name}`,
379
+ [`--${prefix}-name-${name}`]: `${prefix}-${name}`,
380
+ [`--${prefix}-dependencies-${name}`]: dependencies.join(', '),
381
+
382
+ animationDuration: `var(--${prefix}-durations, 300ms)`,
383
+ animationDelay: `var(--${prefix}-delays, 0)`,
384
+ animationTimingFunction: `var(--${prefix}-eases, cubic-bezier(0.4, 0, 0.2, 1))`,
385
+ animationFillMode: 'both',
386
+
387
+ [variableName('dx')]: dx,
388
+ [variableName('dy')]: dy,
389
+ },
390
+ [`.${prefix}-${name}-${directionAlias}, .${prefix}-${name}-in-${directionAlias}`]:
391
+ {
392
+ animationPlayState: `var(--${prefix}-in-state, paused)`,
393
+ },
394
+ [`.${prefix}-${name}-out-${directionAlias}`]: {
395
+ animationPlayState: `var(--${prefix}-out-state, paused)`,
396
+ },
397
+ });
398
+
399
+ addUtilities({
400
+ [`.${prefix}-${name}-scroll-${directionAlias}`]: {
401
+ [`--${prefix}-name-${name}`]: `${prefix}-${name}`,
402
+ [`--${prefix}-dependencies-${name}`]: dependencies.join(', '),
403
+ animationTimeline: `var(--${prefix}-timeline, view())`,
404
+ animationRangeStart: `var(--${prefix}-range-start, entry 20%)`,
405
+ animationRangeEnd: `var(--${prefix}-range-end, cover 50%)`,
406
+ animationFillMode: 'both',
407
+
408
+ [variableName('dx')]: dx,
409
+ [variableName('dy')]: dy,
410
+ },
411
+ });
412
+ });
413
+ },
414
+ );
415
+
416
+ // Paramètres (propriétés CSS) sous le même prefix
417
+ matchUtilities(
418
+ {
419
+ [`${prefix}-duration`]: (value) => ({ animationDuration: value }),
420
+ },
421
+ {
422
+ values: {
423
+ 75: '75ms',
424
+ 100: '100ms',
425
+ 150: '150ms',
426
+ 200: '200ms',
427
+ 300: '300ms',
428
+ 500: '500ms',
429
+ 700: '700ms',
430
+ 1000: '1000ms',
431
+ 1500: '1500ms',
432
+ 2000: '2000ms',
433
+ 3000: '3000ms',
434
+ },
435
+ },
436
+ );
437
+
438
+ matchUtilities(
439
+ { [`${prefix}-delay`]: (value) => ({ animationDelay: value }) },
440
+ {
441
+ values: {
442
+ 0: '0ms',
443
+ 75: '75ms',
444
+ 100: '100ms',
445
+ 150: '150ms',
446
+ 200: '200ms',
447
+ 300: '300ms',
448
+ 500: '500ms',
449
+ 700: '700ms',
450
+ 1000: '1000ms',
451
+ 1500: '1500ms',
452
+ 2000: '2000ms',
453
+ 3000: '3000ms',
454
+ },
455
+ },
456
+ );
457
+
458
+ matchUtilities(
459
+ { [`${prefix}-ease`]: (value) => ({ animationTimingFunction: value }) },
460
+ {
461
+ values: {
462
+ linear: 'linear',
463
+ in: 'cubic-bezier(0.4, 0, 1, 1)',
464
+ out: 'cubic-bezier(0, 0, 0.2, 1)',
465
+ 'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
466
+ },
467
+ },
468
+ );
469
+
470
+ matchUtilities(
471
+ { [`${prefix}-fill`]: (value) => ({ animationFillMode: value }) },
472
+ {
473
+ values: {
474
+ none: 'none',
475
+ forwards: 'forwards',
476
+ backwards: 'backwards',
477
+ both: 'both',
478
+ },
479
+ },
480
+ );
481
+
482
+ // Scroll-driven params utilities (work with the CSS vars used by -scroll classes)
483
+ // Timeline variable (useful when composing with `*.scroll` animation utilities)
484
+ matchUtilities(
485
+ {
486
+ [`${prefix}-timeline`]: (value) => ({
487
+ [`--${prefix}-timeline`]: value,
488
+ }),
489
+ },
490
+ {
491
+ values: {
492
+ view: 'view()',
493
+ 'view-block': 'view(block)',
494
+ 'view-inline': 'view(inline)',
495
+ },
496
+ },
497
+ );
498
+
499
+ // Range start utilities (presets + arbitrary values via [..])
500
+ matchUtilities(
501
+ {
502
+ [`${prefix}-range-start`]: (value) => ({
503
+ [`--${prefix}-range-start`]: value,
504
+ }),
505
+ },
506
+ {
507
+ values: {
508
+ 'entry-0': 'entry 0%',
509
+ 'entry-20': 'entry 20%',
510
+ 'entry-50': 'entry 50%',
511
+ 'entry-80': 'entry 80%',
512
+ 'entry-100': 'entry 100%',
513
+ 'contain-0': 'contain 0%',
514
+ 'cover-0': 'cover 0%',
515
+ 'cover-50': 'cover 50%',
516
+ 'cover-100': 'cover 100%',
517
+ 'exit-0': 'exit 0%',
518
+ 'exit-20': 'exit 20%',
519
+ 'exit-100': 'exit 100%',
520
+ },
521
+ },
522
+ );
523
+
524
+ // Range end utilities (presets + arbitrary values via [..])
525
+ matchUtilities(
526
+ {
527
+ [`${prefix}-range-end`]: (value) => ({
528
+ [`--${prefix}-range-end`]: value,
529
+ }),
530
+ },
531
+ {
532
+ values: {
533
+ 'entry-0': 'entry 0%',
534
+ 'entry-20': 'entry 20%',
535
+ 'entry-50': 'entry 50%',
536
+ 'entry-80': 'entry 80%',
537
+ 'entry-100': 'entry 100%',
538
+ 'contain-0': 'contain 0%',
539
+ 'cover-0': 'cover 0%',
540
+ 'cover-50': 'cover 50%',
541
+ 'cover-100': 'cover 100%',
542
+ 'exit-0': 'exit 0%',
543
+ 'exit-20': 'exit 20%',
544
+ 'exit-100': 'exit 100%',
545
+ },
546
+ },
547
+ );
548
+
549
+ addBase({
550
+ [`[class*="${prefix}-"]`]: {
551
+ animationName: Array.from(animationNames)
552
+ .map((name) => `var(--${prefix}-name-${name}, noop)`)
553
+ .join(', '),
554
+ ['will-change']: Array.from(animationNames)
555
+ .map((name) => `var(--${prefix}-dependencies-${name}, noop)`)
556
+ .join(', '),
557
+ },
558
+ });
559
+ };
560
+ },
561
+ );
@@ -1,2 +1,3 @@
1
1
  export * from './state';
2
2
  export * from './font';
3
+ export * from './animation';