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