emily-css 1.2.0 → 1.2.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/src/generators.js CHANGED
@@ -1,885 +1,3 @@
1
- // ============================================================================
2
- // UTILITY GENERATORS MODULE
3
- // Organized by category, each function returns a string of CSS rules
4
- // ============================================================================
1
+ 'use strict'
5
2
 
6
- // Helper function to escape special characters in class names
7
- function escapeClassName(key) {
8
- return key.replace(/\./g, '\\.');
9
- }
10
-
11
- // Display & Visibility
12
- function displayUtilities() {
13
- return `/* Display & Visibility */
14
- .block { display: block; }
15
- .inline { display: inline; }
16
- .inline-block { display: inline-block; }
17
- .flow-root { display: flow-root; }
18
- .flex { display: flex; }
19
- .inline-flex { display: inline-flex; }
20
- .grid { display: grid; }
21
- .inline-grid { display: inline-grid; }
22
- .contents { display: contents; }
23
- .list-item { display: list-item; }
24
- .hidden { display: none; }
25
- .table { display: table; }
26
- .inline-table { display: inline-table; }
27
- .table-caption { display: table-caption; }
28
- .table-cell { display: table-cell; }
29
- .table-column { display: table-column; }
30
- .table-column-group { display: table-column-group; }
31
- .table-footer-group { display: table-footer-group; }
32
- .table-header-group { display: table-header-group; }
33
- .table-row-group { display: table-row-group; }
34
- .table-row { display: table-row; }
35
- .visible { visibility: visible; }
36
- .invisible { visibility: hidden; }
37
- .collapse { visibility: collapse; }
38
- .float-start { float: inline-start; }
39
- .float-end { float: inline-end; }
40
- .float-right { float: right; }
41
- .float-left { float: left; }
42
- .float-none { float: none; }
43
- .clear-start { clear: inline-start; }
44
- .clear-end { clear: inline-end; }
45
- .clear-left { clear: left; }
46
- .clear-right { clear: right; }
47
- .clear-both { clear: both; }
48
- .clear-none { clear: none; }
49
-
50
- `;
51
- }
52
-
53
- // Sizing (Width & Height)
54
- function sizingUtilities(spacing) {
55
- let css = `/* Sizing */\n`;
56
-
57
- Object.entries(spacing).forEach(([key, value]) => {
58
- const escaped = escapeClassName(key);
59
- css += `.w-${escaped} { width: ${value}; }\n`;
60
- css += `.h-${escaped} { height: ${value}; }\n`;
61
- css += `.size-${escaped} { width: ${value}; height: ${value}; }\n`;
62
- css += `.min-w-${escaped} { min-width: ${value}; }\n`;
63
- css += `.min-h-${escaped} { min-height: ${value}; }\n`;
64
- css += `.max-w-${escaped} { max-width: ${value}; }\n`;
65
- css += `.max-h-${escaped} { max-height: ${value}; }\n`;
66
- });
67
-
68
- const fractions = {
69
- '1\\/2': '50%', '1\\/3': '33.333333%', '2\\/3': '66.666667%',
70
- '1\\/4': '25%', '2\\/4': '50%', '3\\/4': '75%',
71
- '1\\/5': '20%', '2\\/5': '40%', '3\\/5': '60%', '4\\/5': '80%',
72
- '1\\/6': '16.666667%', '2\\/6': '33.333333%', '3\\/6': '50%', '4\\/6': '66.666667%', '5\\/6': '83.333333%',
73
- '1\\/12': '8.333333%', '2\\/12': '16.666667%', '3\\/12': '25%', '4\\/12': '33.333333%', '5\\/12': '41.666667%', '6\\/12': '50%', '7\\/12': '58.333333%', '8\\/12': '66.666667%', '9\\/12': '75%', '10\\/12': '83.333333%', '11\\/12': '91.666667%'
74
- };
75
-
76
- Object.entries(fractions).forEach(([name, value]) => {
77
- css += `.w-${name} { width: ${value}; }\n`;
78
- css += `.h-${name} { height: ${value}; }\n`;
79
- css += `.size-${name} { width: ${value}; height: ${value}; }\n`;
80
- });
81
-
82
- css += `.w-auto { width: auto; }\n`;
83
- css += `.h-auto { height: auto; }\n`;
84
- css += `.size-auto { width: auto; height: auto; }\n`;
85
- css += `.w-full { width: 100%; }\n`;
86
- css += `.h-full { height: 100%; }\n`;
87
- css += `.size-full { width: 100%; height: 100%; }\n`;
88
- css += `.w-screen { width: 100vw; }\n`;
89
- css += `.h-screen { height: 100vh; }\n`;
90
- css += `.w-svw { width: 100svw; }\n`;
91
- css += `.h-svh { height: 100svh; }\n`;
92
- css += `.w-lvw { width: 100lvw; }\n`;
93
- css += `.h-lvh { height: 100lvh; }\n`;
94
- css += `.w-dvw { width: 100dvw; }\n`;
95
- css += `.h-dvh { height: 100dvh; }\n`;
96
- css += `.w-min { width: min-content; }\n`;
97
- css += `.w-max { width: max-content; }\n`;
98
- css += `.w-fit { width: fit-content; }\n`;
99
- css += `.h-min { height: min-content; }\n`;
100
- css += `.h-max { height: max-content; }\n`;
101
- css += `.h-fit { height: fit-content; }\n`;
102
-
103
- css += `.min-w-0 { min-width: 0; }\n`;
104
- css += `.min-w-full { min-width: 100%; }\n`;
105
- css += `.min-w-min { min-width: min-content; }\n`;
106
- css += `.min-w-max { min-width: max-content; }\n`;
107
- css += `.min-w-fit { min-width: fit-content; }\n`;
108
- css += `.min-h-0 { min-height: 0; }\n`;
109
- css += `.min-h-full { min-height: 100%; }\n`;
110
- css += `.min-h-screen { min-height: 100vh; }\n`;
111
- css += `.min-h-svh { min-height: 100svh; }\n`;
112
- css += `.min-h-lvh { min-height: 100lvh; }\n`;
113
- css += `.min-h-dvh { min-height: 100dvh; }\n`;
114
- css += `.min-h-min { min-height: min-content; }\n`;
115
- css += `.min-h-max { min-height: max-content; }\n`;
116
- css += `.min-h-fit { min-height: fit-content; }\n`;
117
-
118
- css += `.max-w-0 { max-width: 0; }\n`;
119
- css += `.max-w-none { max-width: none; }\n`;
120
- css += `.max-w-full { max-width: 100%; }\n`;
121
- css += `.max-w-min { max-width: min-content; }\n`;
122
- css += `.max-w-max { max-width: max-content; }\n`;
123
- css += `.max-w-fit { max-width: fit-content; }\n`;
124
- css += `.max-h-0 { max-height: 0; }\n`;
125
- css += `.max-h-full { max-height: 100%; }\n`;
126
- css += `.max-h-screen { max-height: 100vh; }\n`;
127
- css += `.max-h-svh { max-height: 100svh; }\n`;
128
- css += `.max-h-lvh { max-height: 100lvh; }\n`;
129
- css += `.max-h-dvh { max-height: 100dvh; }\n`;
130
- css += `.max-h-min { max-height: min-content; }\n`;
131
- css += `.max-h-max { max-height: max-content; }\n`;
132
- css += `.max-h-fit { max-height: fit-content; }\n`;
133
-
134
- const maxWidths = {
135
- xs: '20rem', sm: '24rem', md: '28rem', lg: '32rem', xl: '36rem',
136
- '2xl': '42rem', '3xl': '48rem', '4xl': '56rem', '5xl': '64rem',
137
- '6xl': '72rem', '7xl': '80rem', prose: '65ch', screen: '100vw',
138
- 'screen-sm': '640px', 'screen-md': '768px', 'screen-lg': '1024px',
139
- 'screen-xl': '1280px', 'screen-2xl': '1536px'
140
- };
141
- Object.entries(maxWidths).forEach(([name, value]) => {
142
- css += `.max-w-${name} { max-width: ${value}; }\n`;
143
- });
144
-
145
- css += `.aspect-auto { aspect-ratio: auto; }\n`;
146
- css += `.aspect-square { aspect-ratio: 1; }\n`;
147
- css += `.aspect-video { aspect-ratio: 16 / 9; }\n`;
148
- css += `.aspect-3\\/2 { aspect-ratio: 3 / 2; }\n`;
149
- css += `.aspect-4\\/3 { aspect-ratio: 4 / 3; }\n`;
150
- css += `.aspect-16\\/9 { aspect-ratio: 16 / 9; }\n`;
151
-
152
- css += `\n`;
153
- return css;
154
- }
155
-
156
- // Positioning
157
- function positioningUtilities(spacing) {
158
- let css = `/* Positioning */\n`;
159
-
160
- css += `.static { position: static; }\n`;
161
- css += `.relative { position: relative; }\n`;
162
- css += `.absolute { position: absolute; }\n`;
163
- css += `.fixed { position: fixed; }\n`;
164
- css += `.sticky { position: sticky; }\n`;
165
-
166
- Object.entries(spacing).forEach(([key, value]) => {
167
- const escaped = escapeClassName(key);
168
- css += `.top-${escaped} { top: ${value}; }\n`;
169
- css += `.right-${escaped} { right: ${value}; }\n`;
170
- css += `.bottom-${escaped} { bottom: ${value}; }\n`;
171
- css += `.left-${escaped} { left: ${value}; }\n`;
172
- css += `.inset-${escaped} { inset: ${value}; }\n`;
173
- css += `.inset-x-${escaped} { left: ${value}; right: ${value}; }\n`;
174
- css += `.inset-y-${escaped} { top: ${value}; bottom: ${value}; }\n`;
175
- if (value !== '0' && value !== '0px') {
176
- css += `.-top-${escaped} { top: -${value}; }\n`;
177
- css += `.-right-${escaped} { right: -${value}; }\n`;
178
- css += `.-bottom-${escaped} { bottom: -${value}; }\n`;
179
- css += `.-left-${escaped} { left: -${value}; }\n`;
180
- css += `.-inset-${escaped} { inset: -${value}; }\n`;
181
- css += `.-inset-x-${escaped} { left: -${value}; right: -${value}; }\n`;
182
- css += `.-inset-y-${escaped} { top: -${value}; bottom: -${value}; }\n`;
183
- }
184
- });
185
-
186
- css += `.inset-auto { inset: auto; }\n`;
187
- css += `.inset-x-auto { left: auto; right: auto; }\n`;
188
- css += `.inset-y-auto { top: auto; bottom: auto; }\n`;
189
- css += `.top-auto { top: auto; }\n`;
190
- css += `.right-auto { right: auto; }\n`;
191
- css += `.bottom-auto { bottom: auto; }\n`;
192
- css += `.left-auto { left: auto; }\n`;
193
-
194
- const zIndices = {
195
- 'auto': 'auto', '0': '0', '10': '10', '20': '20', '30': '30', '40': '40', '50': '50',
196
- 'dropdown': '1000', 'sticky': '1020', 'fixed': '1030', 'modal': '1040', 'popover': '1060', 'tooltip': '1070'
197
- };
198
- Object.entries(zIndices).forEach(([name, value]) => {
199
- css += `.z-${name} { z-index: ${value}; }\n`;
200
- });
201
-
202
- css += `\n`;
203
- return css;
204
- }
205
-
206
- // Overflow & Clipping
207
- function overflowUtilities() {
208
- return `/* Overflow & Clipping */
209
- .overflow-auto { overflow: auto; }
210
- .overflow-hidden { overflow: hidden; }
211
- .overflow-clip { overflow: clip; }
212
- .overflow-visible { overflow: visible; }
213
- .overflow-scroll { overflow: scroll; }
214
- .overflow-x-auto { overflow-x: auto; }
215
- .overflow-x-hidden { overflow-x: hidden; }
216
- .overflow-x-clip { overflow-x: clip; }
217
- .overflow-x-visible { overflow-x: visible; }
218
- .overflow-x-scroll { overflow-x: scroll; }
219
- .overflow-y-auto { overflow-y: auto; }
220
- .overflow-y-hidden { overflow-y: hidden; }
221
- .overflow-y-clip { overflow-y: clip; }
222
- .overflow-y-visible { overflow-y: visible; }
223
- .overflow-y-scroll { overflow-y: scroll; }
224
- .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
225
- .text-ellipsis { text-overflow: ellipsis; }
226
- .text-clip { text-overflow: clip; }
227
- .line-clamp-none { overflow: visible; display: block; -webkit-box-orient: horizontal; -webkit-line-clamp: unset; }
228
- .line-clamp-1 { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
229
- .line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
230
- .line-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
231
- .line-clamp-4 { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
232
- .line-clamp-5 { display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
233
- .line-clamp-6 { display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
234
-
235
- `;
236
- }
237
-
238
- // Opacity
239
- function opacityUtilities() {
240
- const opacities = [0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 95, 100];
241
- let css = `/* Opacity */\n`;
242
-
243
- opacities.forEach(op => {
244
- css += `.opacity-${op} { opacity: ${op / 100}; }\n`;
245
- });
246
-
247
- css += `\n`;
248
- return css;
249
- }
250
-
251
- // Transitions & Transforms
252
- function transitionUtilities() {
253
- return `/* Transitions */
254
- .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
255
- .transition-none { transition-property: none; }
256
- .transition-colors { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
257
- .transition-opacity { transition-property: opacity; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
258
- .transition-transform { transition-property: transform; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
259
- .duration-75 { transition-duration: 75ms; }
260
- .duration-100 { transition-duration: 100ms; }
261
- .duration-150 { transition-duration: 150ms; }
262
- .duration-200 { transition-duration: 200ms; }
263
- .duration-300 { transition-duration: 300ms; }
264
- .duration-500 { transition-duration: 500ms; }
265
- .duration-700 { transition-duration: 700ms; }
266
- .duration-1000 { transition-duration: 1000ms; }
267
- .ease-linear { transition-timing-function: linear; }
268
- .ease-in { transition-timing-function: cubic-bezier(0.4, 0, 1, 1); }
269
- .ease-out { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); }
270
- .ease-in-out { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); }
271
- .delay-75 { transition-delay: 75ms; }
272
- .delay-100 { transition-delay: 100ms; }
273
- .delay-150 { transition-delay: 150ms; }
274
- .delay-200 { transition-delay: 200ms; }
275
- .delay-300 { transition-delay: 300ms; }
276
- .delay-500 { transition-delay: 500ms; }
277
-
278
- `;
279
- }
280
-
281
- // Transforms
282
- function transformUtilities(spacing) {
283
- let css = `/* Transforms */\n`;
284
- const composedTransform = 'translate(var(--translate-x, 0), var(--translate-y, 0)) rotate(var(--rotate, 0)) skewX(var(--skew-x, 0)) skewY(var(--skew-y, 0)) scaleX(var(--scale-x, 1)) scaleY(var(--scale-y, 1))';
285
-
286
- css += `.transform { transform: translateZ(0); }\n`;
287
- css += `.transform-gpu { transform: translate3d(0, 0, 0); }\n`;
288
- css += `.transform-none { transform: none; }\n`;
289
-
290
- // Translate
291
- Object.entries(spacing).forEach(([key, value]) => {
292
- const escaped = escapeClassName(key);
293
- css += `.translate-x-${escaped} { --translate-x: ${value}; transform: ${composedTransform}; }\n`;
294
- css += `.translate-y-${escaped} { --translate-y: ${value}; transform: ${composedTransform}; }\n`;
295
- css += `.-translate-x-${escaped} { --translate-x: -${value}; transform: ${composedTransform}; }\n`;
296
- css += `.-translate-y-${escaped} { --translate-y: -${value}; transform: ${composedTransform}; }\n`;
297
- });
298
-
299
- // Rotate
300
- const rotations = [0, 1, 2, 3, 6, 12, 45, 90, 180];
301
- rotations.forEach(deg => {
302
- css += `.rotate-${deg} { --rotate: ${deg}deg; transform: ${composedTransform}; }\n`;
303
- if (deg > 0) css += `.-rotate-${deg} { --rotate: -${deg}deg; transform: ${composedTransform}; }\n`;
304
- });
305
-
306
- // Scale
307
- const scales = [0, 50, 75, 90, 95, 100, 110, 125, 150];
308
- scales.forEach(scale => {
309
- css += `.scale-${scale} { --scale-x: ${scale / 100}; --scale-y: ${scale / 100}; transform: ${composedTransform}; }\n`;
310
- });
311
-
312
- // Skew
313
- const skews = [0, 1, 2, 3];
314
- skews.forEach(sk => {
315
- css += `.skew-x-${sk} { --skew-x: ${sk}deg; transform: ${composedTransform}; }\n`;
316
- css += `.skew-y-${sk} { --skew-y: ${sk}deg; transform: ${composedTransform}; }\n`;
317
- });
318
-
319
- // Transform origin
320
- css += `.origin-center { transform-origin: center; }\n`;
321
- css += `.origin-top { transform-origin: top; }\n`;
322
- css += `.origin-top-right { transform-origin: top right; }\n`;
323
- css += `.origin-right { transform-origin: right; }\n`;
324
- css += `.origin-bottom-right { transform-origin: bottom right; }\n`;
325
- css += `.origin-bottom { transform-origin: bottom; }\n`;
326
- css += `.origin-bottom-left { transform-origin: bottom left; }\n`;
327
- css += `.origin-left { transform-origin: left; }\n`;
328
- css += `.origin-top-left { transform-origin: top left; }\n`;
329
-
330
- css += `\n`;
331
- return css;
332
- }
333
-
334
- // Shadows
335
- function shadowUtilities() {
336
- return `/* Shadows */
337
- .shadow-none { box-shadow: none; }
338
- .shadow-sm { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); }
339
- .shadow { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06); }
340
- .shadow-md { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06); }
341
- .shadow-lg { box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05); }
342
- .shadow-xl { box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04); }
343
- .shadow-2xl { box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25); }
344
- .shadow-inner { box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06); }
345
-
346
- `;
347
- }
348
-
349
- // Rings & Outlines (Focus states)
350
- function ringUtilities(colours) {
351
- let css = `/* Rings & Outlines */\n`;
352
-
353
- css += `.ring-0 { --ring-offset-width: 0px; --ring-offset-color: #fff; --ring-color: currentColor; box-shadow: 0 0 0 var(--ring-offset-width, 0px) var(--ring-offset-color, #fff), 0 0 0 var(--ring-offset-width, 0px) transparent; }\n`;
354
- css += `.ring-1 { --ring-offset-width: 0px; --ring-offset-color: #fff; --ring-color: currentColor; box-shadow: 0 0 0 var(--ring-offset-width, 0px) var(--ring-offset-color, #fff), 0 0 0 calc(1px + var(--ring-offset-width, 0px)) var(--ring-color, currentColor); }\n`;
355
- css += `.ring-2 { --ring-offset-width: 0px; --ring-offset-color: #fff; --ring-color: currentColor; box-shadow: 0 0 0 var(--ring-offset-width, 0px) var(--ring-offset-color, #fff), 0 0 0 calc(2px + var(--ring-offset-width, 0px)) var(--ring-color, currentColor); }\n`;
356
-
357
- css += `.ring-offset-0 { --ring-offset-width: 0px; }\n`;
358
- css += `.ring-offset-2 { --ring-offset-width: 2px; }\n`;
359
- css += `.ring-offset-4 { --ring-offset-width: 4px; }\n`;
360
- css += `.ring-offset-white { --ring-offset-color: #fff; }\n`;
361
- css += `.ring-offset-black { --ring-offset-color: #000; }\n`;
362
-
363
- // Ring colours
364
- Object.entries(colours).forEach(([colourName, shades]) => {
365
- Object.entries(shades).forEach(([shade]) => {
366
- css += `.ring-${colourName}-${shade} { --ring-color: var(--color-${colourName}-${shade}); }\n`;
367
- css += `.ring-offset-${colourName}-${shade} { --ring-offset-color: var(--color-${colourName}-${shade}); }\n`;
368
- });
369
- });
370
-
371
- css += `.outline-none { outline: 2px solid transparent; outline-offset: 2px; }\n`;
372
- css += `.outline { outline: 1px solid currentColor; }\n`;
373
- css += `.outline-0 { outline-width: 0; }\n`;
374
- css += `.outline-1 { outline-width: 1px; }\n`;
375
- css += `.outline-2 { outline-width: 2px; }\n`;
376
- css += `.outline-offset-0 { outline-offset: 0px; }\n`;
377
- css += `.outline-offset-1 { outline-offset: 1px; }\n`;
378
- css += `.outline-offset-2 { outline-offset: 2px; }\n`;
379
- css += `.outline-offset-4 { outline-offset: 4px; }\n`;
380
- css += `.outline-offset-8 { outline-offset: 8px; }\n`;
381
-
382
- css += `\n`;
383
- return css;
384
- }
385
-
386
- // Object Fit & Position
387
- function objectUtilities() {
388
- return `/* Object Fit & Position */
389
- .object-contain { object-fit: contain; }
390
- .object-cover { object-fit: cover; }
391
- .object-fill { object-fit: fill; }
392
- .object-none { object-fit: none; }
393
- .object-scale-down { object-fit: scale-down; }
394
- .object-center { object-position: center; }
395
- .object-top { object-position: top; }
396
- .object-bottom { object-position: bottom; }
397
- .object-left { object-position: left; }
398
- .object-right { object-position: right; }
399
- .object-top-left { object-position: top left; }
400
- .object-top-right { object-position: top right; }
401
- .object-bottom-left { object-position: bottom left; }
402
- .object-bottom-right { object-position: bottom right; }
403
-
404
- `;
405
- }
406
-
407
- // Tables & Lists
408
- function tableListUtilities() {
409
- return `/* Tables & Lists */
410
- .border-collapse { border-collapse: collapse; }
411
- .border-separate { border-collapse: separate; }
412
- .table-auto { table-layout: auto; }
413
- .table-fixed { table-layout: fixed; }
414
- .caption-top { caption-side: top; }
415
- .caption-bottom { caption-side: bottom; }
416
- .list-none { list-style-type: none; }
417
- .list-disc { list-style-type: disc; }
418
- .list-decimal { list-style-type: decimal; }
419
- .list-inside { list-style-position: inside; }
420
- .list-outside { list-style-position: outside; }
421
-
422
- `;
423
- }
424
-
425
- // SVG Utilities
426
- function svgUtilities(colours) {
427
- let css = `/* SVG */\n`;
428
-
429
- css += `.fill-current { fill: currentColor; }\n`;
430
- css += `.stroke-current { stroke: currentColor; }\n`;
431
- css += `.fill-white { fill: #FAFAFA; }\n`;
432
- css += `.fill-black { fill: #111110; }\n`;
433
- css += `.fill-transparent { fill: transparent; }\n`;
434
- css += `.stroke-white { stroke: #FAFAFA; }\n`;
435
- css += `.stroke-black { stroke: #111110; }\n`;
436
- css += `.stroke-transparent { stroke: transparent; }\n`;
437
- css += `.stroke-0 { stroke-width: 0; }\n`;
438
- css += `.stroke-1 { stroke-width: 1; }\n`;
439
- css += `.stroke-2 { stroke-width: 2; }\n`;
440
-
441
- // Fill colours
442
- Object.entries(colours).forEach(([colourName, shades]) => {
443
- Object.entries(shades).forEach(([shade]) => {
444
- css += `.fill-${colourName}-${shade} { fill: var(--color-${colourName}-${shade}); }\n`;
445
- });
446
- });
447
-
448
- // Stroke colours
449
- Object.entries(colours).forEach(([colourName, shades]) => {
450
- Object.entries(shades).forEach(([shade]) => {
451
- css += `.stroke-${colourName}-${shade} { stroke: var(--color-${colourName}-${shade}); }\n`;
452
- });
453
- });
454
-
455
- css += `\n`;
456
- return css;
457
- }
458
-
459
- // Forms
460
- function formUtilities() {
461
- return `/* Forms */
462
- .appearance-none { appearance: none; }
463
- .caret-transparent { caret-color: transparent; }
464
- .caret-current { caret-color: currentColor; }
465
- .placeholder-transparent::placeholder { color: transparent; }
466
- .placeholder-current::placeholder { color: currentColor; }
467
- .autofill\\:bg-transparent:autofill { background-color: transparent !important; }
468
- .autofill\\:text-current:autofill { color: currentColor !important; }
469
- .accent-current { accent-color: currentColor; }
470
- .checked\\:bg-current:checked { background-color: currentColor; }
471
- .indeterminate\\:bg-current:indeterminate { background-color: currentColor; }
472
- .default\\:ring-0:default { box-shadow: 0 0 0 0px transparent; }
473
- .disabled\\:opacity-50:disabled { opacity: 0.5; }
474
- .enabled\\:opacity-100:enabled { opacity: 1; }
475
- .read-only\\:bg-gray-100:read-only { background-color: rgb(243, 244, 246); }
476
-
477
- `;
478
- }
479
-
480
- // Vertical Align
481
- function verticalAlignUtilities() {
482
- return `/* Vertical Align */
483
- .align-baseline { vertical-align: baseline; }
484
- .align-top { vertical-align: top; }
485
- .align-middle { vertical-align: middle; }
486
- .align-bottom { vertical-align: bottom; }
487
- .align-text-top { vertical-align: text-top; }
488
- .align-text-bottom { vertical-align: text-bottom; }
489
- .align-sub { vertical-align: sub; }
490
- .align-super { vertical-align: super; }
491
-
492
- `;
493
- }
494
-
495
- // Content Visibility & Scroll
496
- function contentScrollUtilities() {
497
- return `/* Content Visibility & Scroll */
498
- .content-normal { content-visibility: normal; }
499
- .content-hidden { content-visibility: hidden; }
500
- .content-auto { content-visibility: auto; }
501
- .scroll-auto { scroll-behavior: auto; }
502
- .scroll-smooth { scroll-behavior: smooth; }
503
- .scroll-m-0 { scroll-margin: 0; }
504
- .snap-none { scroll-snap-type: none; }
505
- .snap-x { scroll-snap-type: x var(--emily-scroll-snap-strictness); }
506
- .snap-y { scroll-snap-type: y var(--emily-scroll-snap-strictness); }
507
- .snap-both { scroll-snap-type: both var(--emily-scroll-snap-strictness); }
508
- .snap-mandatory { --emily-scroll-snap-strictness: mandatory; }
509
- .snap-proximity { --emily-scroll-snap-strictness: proximity; }
510
- .snap-start { scroll-snap-align: start; }
511
- .snap-center { scroll-snap-align: center; }
512
- .snap-end { scroll-snap-align: end; }
513
- .snap-align-none { scroll-snap-align: none; }
514
-
515
- `;
516
- }
517
-
518
- // Blend Modes
519
- function blendUtilities() {
520
- return `/* Blend Modes */
521
- .mix-normal { mix-blend-mode: normal; }
522
- .mix-multiply { mix-blend-mode: multiply; }
523
- .mix-screen { mix-blend-mode: screen; }
524
- .mix-overlay { mix-blend-mode: overlay; }
525
- .mix-darken { mix-blend-mode: darken; }
526
- .mix-lighten { mix-blend-mode: lighten; }
527
- .mix-color-dodge { mix-blend-mode: color-dodge; }
528
- .mix-color-burn { mix-blend-mode: color-burn; }
529
- .mix-hard-light { mix-blend-mode: hard-light; }
530
- .mix-soft-light { mix-blend-mode: soft-light; }
531
- .mix-difference { mix-blend-mode: difference; }
532
- .mix-exclusion { mix-blend-mode: exclusion; }
533
- .mix-hue { mix-blend-mode: hue; }
534
- .mix-saturation { mix-blend-mode: saturation; }
535
- .mix-color { mix-blend-mode: color; }
536
- .mix-luminosity { mix-blend-mode: luminosity; }
537
-
538
- `;
539
- }
540
-
541
- // Cursors & Interactions
542
- function cursorUtilities() {
543
- return `/* Cursors & Interactions */
544
- .cursor-auto { cursor: auto; }
545
- .cursor-default { cursor: default; }
546
- .cursor-pointer { cursor: pointer; }
547
- .cursor-wait { cursor: wait; }
548
- .cursor-text { cursor: text; }
549
- .cursor-move { cursor: move; }
550
- .cursor-help { cursor: help; }
551
- .cursor-not-allowed { cursor: not-allowed; }
552
- .cursor-none { cursor: none; }
553
- .cursor-context-menu { cursor: context-menu; }
554
- .cursor-progress { cursor: progress; }
555
- .cursor-cell { cursor: cell; }
556
- .cursor-crosshair { cursor: crosshair; }
557
- .cursor-vertical-text { cursor: vertical-text; }
558
- .cursor-alias { cursor: alias; }
559
- .cursor-copy { cursor: copy; }
560
- .cursor-no-drop { cursor: no-drop; }
561
- .cursor-grab { cursor: grab; }
562
- .cursor-grabbing { cursor: grabbing; }
563
- .cursor-all-scroll { cursor: all-scroll; }
564
- .cursor-col-resize { cursor: col-resize; }
565
- .cursor-row-resize { cursor: row-resize; }
566
- .cursor-n-resize { cursor: n-resize; }
567
- .cursor-e-resize { cursor: e-resize; }
568
- .cursor-s-resize { cursor: s-resize; }
569
- .cursor-w-resize { cursor: w-resize; }
570
- .cursor-ne-resize { cursor: ne-resize; }
571
- .cursor-nw-resize { cursor: nw-resize; }
572
- .cursor-se-resize { cursor: se-resize; }
573
- .cursor-sw-resize { cursor: sw-resize; }
574
- .cursor-ew-resize { cursor: ew-resize; }
575
- .cursor-ns-resize { cursor: ns-resize; }
576
- .cursor-nesw-resize { cursor: nesw-resize; }
577
- .cursor-nwse-resize { cursor: nwse-resize; }
578
- .cursor-zoom-in { cursor: zoom-in; }
579
- .cursor-zoom-out { cursor: zoom-out; }
580
- .pointer-events-auto { pointer-events: auto; }
581
- .pointer-events-none { pointer-events: none; }
582
- .select-none { user-select: none; }
583
- .select-text { user-select: text; }
584
- .select-all { user-select: all; }
585
- .select-auto { user-select: auto; }
586
- .resize-none { resize: none; }
587
- .resize { resize: both; }
588
- .resize-x { resize: horizontal; }
589
- .resize-y { resize: vertical; }
590
- .touch-auto { touch-action: auto; }
591
- .touch-none { touch-action: none; }
592
- .touch-pan-x { touch-action: pan-x; }
593
- .touch-pan-left { touch-action: pan-left; }
594
- .touch-pan-right { touch-action: pan-right; }
595
- .touch-pan-y { touch-action: pan-y; }
596
- .touch-pan-up { touch-action: pan-up; }
597
- .touch-pan-down { touch-action: pan-down; }
598
- .touch-pinch-zoom { touch-action: pinch-zoom; }
599
- .touch-manipulation { touch-action: manipulation; }
600
- .isolate { isolation: isolate; }
601
- .isolation-auto { isolation: auto; }
602
- .will-change-auto { will-change: auto; }
603
- .will-change-scroll { will-change: scroll-position; }
604
- .will-change-contents { will-change: contents; }
605
- .will-change-transform { will-change: transform; }
606
-
607
- `;
608
- }
609
-
610
- // Accessibility
611
- function accessibilityUtilities() {
612
- return `/* Accessibility */
613
- .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
614
- .not-sr-only { position: static; width: auto; height: auto; padding: 0; margin: 0; overflow: visible; clip: auto; white-space: normal; }
615
- .sr-only-focusable:not(:focus):not(:focus-within) { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
616
- .focus-ring:focus-visible { outline: 2px solid var(--color-brand-80); outline-offset: 2px; }
617
- .focus-ring-inset:focus-visible { outline: 2px solid var(--color-brand-80); outline-offset: -2px; }
618
- .focus-ring-none:focus-visible { outline: none; }
619
- .focus-visible:focus { outline: 2px solid currentColor; outline-offset: 2px; }
620
- .focus\\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
621
-
622
- /* Touch target — WCAG 2.2 SC 2.5.8 minimum 24x24px hit area */
623
- .touch-target { position: relative; }
624
- .touch-target::before { content: ''; position: absolute; top: 50%; left: 50%; width: max(100%, 24px); height: max(100%, 24px); transform: translate(-50%, -50%); }
625
-
626
- /* Skip link — reveals on focus for keyboard/AT users */
627
- .skip-link { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
628
- .skip-link:focus { position: fixed; top: 1rem; left: 1rem; z-index: 1070; width: auto; height: auto; padding: 0.75rem 1.25rem; background-color: #ffffff; color: #000000; font-weight: 700; text-decoration: underline; border: 2px solid currentColor; border-radius: 4px; clip: auto; white-space: normal; }
629
-
630
- @media (prefers-reduced-motion: reduce) {
631
- .motion-reduce\\:transition-none { transition-property: none; }
632
- .motion-reduce\\:animate-none { animation: none; }
633
- }
634
- @media (prefers-reduced-motion: no-preference) {
635
- .motion-safe\\:transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
636
- }
637
- @media (forced-colors: active) {
638
- .forced-colors\\:outline { outline: 1px solid CanvasText; }
639
- .forced-colors\\:outline-1 { outline: 1px solid CanvasText; }
640
- .forced-colors\\:forced-color-adjust-none { forced-color-adjust: none; }
641
- }
642
-
643
- `;
644
- }
645
-
646
- // Container Queries (Forward-looking)
647
- function containerUtilities() {
648
- return `/* Container Queries */
649
- .container-type-inline { container-type: inline-size; }
650
- .container-type-size { container-type: size; }
651
- .container-type-normal { container-type: normal; }
652
- .container-name-none { container-name: none; }
653
-
654
- `;
655
- }
656
-
657
- // ============================================================================
658
- // CODE BLOCK UTILITIES
659
- // ============================================================================
660
- // Styles pre/code elements to look like a VSCode Dark+ editor out of the box.
661
- // All colours are fixed VSCode Dark+ values — not config-driven, because code
662
- // editor chrome should always look like a code editor regardless of brand.
663
- function codeUtilities() {
664
- return `/* Code — window chrome */
665
- .code-window { border-radius: 8px; overflow: hidden; border: 1px solid #3c3c3c; }
666
- .code-title-bar { background-color: #2d2d2d; padding: 0.5rem 1rem; display: flex; align-items: center; gap: 0.5rem; border-bottom: 1px solid #3c3c3c; }
667
- .code-dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
668
- .code-dot-red { background-color: #ff5f57; }
669
- .code-dot-yellow { background-color: #ffbd2e; }
670
- .code-dot-green { background-color: #28c840; }
671
- .code-filename { font-family: "Menlo", "Monaco", "Courier New", monospace; font-size: 0.85rem; color: white; margin-left: 0.5rem; }
672
-
673
- /* Code — VSCode Dark+ token colours */
674
- .token-tag { color: #569cd6; }
675
- .token-attr { color: #9cdcfe; }
676
- .token-string { color: #ce9178; }
677
- .token-number { color: #b5cea8; }
678
- .token-variant { color: #4ec9b0; }
679
- .token-utility { color: #dcdcaa; }
680
- .token-colour { color: #6a9955; }
681
- .token-comment { color: #6a9955; opacity: 0.75; font-style: italic; }
682
- .token-keyword { color: #c586c0; }
683
- .token-operator { color: #d4d4d4; }
684
- .token-line-number { color: #858585; user-select: none; padding-right: 1rem; display: inline-block; min-width: 2rem; text-align: right; }
685
-
686
- `;
687
- }
688
-
689
- // Animations
690
- function animationUtilities() {
691
- return `/* Animations — keyframes */
692
- @keyframes spin {
693
- to { transform: rotate(360deg); }
694
- }
695
- @keyframes ping {
696
- 75%, 100% { transform: scale(2); opacity: 0; }
697
- }
698
- @keyframes pulse {
699
- 50% { opacity: 0.5; }
700
- }
701
- @keyframes bounce {
702
- 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
703
- 50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
704
- }
705
-
706
- /* Animations — utilities */
707
- .animate-none { animation: none; }
708
- .animate-spin { animation: spin 1s linear infinite; }
709
- .animate-ping { animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; }
710
- .animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
711
- .animate-bounce { animation: bounce 1s infinite; }
712
-
713
- `;
714
- }
715
-
716
-
717
- // Backdrop Filters
718
- function backdropUtilities() {
719
- return `/* Backdrop Filters */
720
- .backdrop-blur-none { backdrop-filter: blur(0); }
721
- .backdrop-blur-sm { backdrop-filter: blur(4px); }
722
- .backdrop-blur { backdrop-filter: blur(8px); }
723
- .backdrop-blur-md { backdrop-filter: blur(12px); }
724
- .backdrop-blur-lg { backdrop-filter: blur(16px); }
725
- .backdrop-blur-xl { backdrop-filter: blur(24px); }
726
- .backdrop-blur-2xl { backdrop-filter: blur(40px); }
727
-
728
- `;
729
- }
730
-
731
- // Space Between
732
- function spaceUtilities(spacing) {
733
- let css = `/* Space Between */\n`;
734
- Object.entries(spacing).forEach(([key, value]) => {
735
- const escaped = key.replace(/\./g, '\\.');
736
- css += `.space-x-${escaped} > * + * { margin-left: ${value}; }\n`;
737
- css += `.space-y-${escaped} > * + * { margin-top: ${value}; }\n`;
738
- css += `.-space-x-${escaped} > * + * { margin-left: -${value}; }\n`;
739
- css += `.-space-y-${escaped} > * + * { margin-top: -${value}; }\n`;
740
- });
741
- css += `.space-x-auto > * + * { margin-left: auto; }\n`;
742
- css += `.space-y-auto > * + * { margin-top: auto; }\n`;
743
- css += `\n`;
744
- return css;
745
- }
746
-
747
- // Divide
748
- function divideUtilities(spacing, colours) {
749
- let css = `/* Divide */\n`;
750
- // Widths
751
- css += `.divide-x > * + * { border-left-width: 1px; border-left-style: solid; }\n`;
752
- css += `.divide-y > * + * { border-top-width: 1px; border-top-style: solid; }\n`;
753
- css += `.divide-x-0 > * + * { border-left-width: 0px; }\n`;
754
- css += `.divide-y-0 > * + * { border-top-width: 0px; }\n`;
755
- css += `.divide-x-2 > * + * { border-left-width: 2px; border-left-style: solid; }\n`;
756
- css += `.divide-y-2 > * + * { border-top-width: 2px; border-top-style: solid; }\n`;
757
- css += `.divide-x-4 > * + * { border-left-width: 4px; border-left-style: solid; }\n`;
758
- css += `.divide-y-4 > * + * { border-top-width: 4px; border-top-style: solid; }\n`;
759
- // Styles
760
- css += `.divide-solid > * + * { border-style: solid; }\n`;
761
- css += `.divide-dashed > * + * { border-style: dashed; }\n`;
762
- css += `.divide-dotted > * + * { border-style: dotted; }\n`;
763
- css += `.divide-none > * + * { border-style: none; }\n`;
764
- // Colours
765
- Object.entries(colours).forEach(([colourName, shades]) => {
766
- Object.entries(shades).forEach(([shade]) => {
767
- css += `.divide-${colourName}-${shade} > * + * { border-color: var(--color-${colourName}-${shade}); }\n`;
768
- });
769
- });
770
- css += `.divide-white > * + * { border-color: #FAFAFA; }\n`;
771
- css += `.divide-black > * + * { border-color: #111110; }\n`;
772
- css += `.divide-transparent > * + * { border-color: transparent; }\n`;
773
- css += `\n`;
774
- return css;
775
- }
776
-
777
- // Background Utilities
778
- function backgroundUtilities() {
779
- return `/* Background */
780
- .bg-fixed { background-attachment: fixed; }
781
- .bg-local { background-attachment: local; }
782
- .bg-scroll { background-attachment: scroll; }
783
- .bg-clip-border { background-clip: border-box; }
784
- .bg-clip-padding { background-clip: padding-box; }
785
- .bg-clip-content { background-clip: content-box; }
786
- .bg-clip-text { -webkit-background-clip: text; background-clip: text; }
787
- .bg-repeat { background-repeat: repeat; }
788
- .bg-no-repeat { background-repeat: no-repeat; }
789
- .bg-repeat-x { background-repeat: repeat-x; }
790
- .bg-repeat-y { background-repeat: repeat-y; }
791
- .bg-repeat-round { background-repeat: round; }
792
- .bg-repeat-space { background-repeat: space; }
793
- .bg-auto { background-size: auto; }
794
- .bg-cover { background-size: cover; }
795
- .bg-contain { background-size: contain; }
796
- .bg-center { background-position: center; }
797
- .bg-top { background-position: top; }
798
- .bg-bottom { background-position: bottom; }
799
- .bg-left { background-position: left; }
800
- .bg-right { background-position: right; }
801
- .bg-left-top { background-position: left top; }
802
- .bg-left-bottom { background-position: left bottom; }
803
- .bg-right-top { background-position: right top; }
804
- .bg-right-bottom { background-position: right bottom; }
805
-
806
- `;
807
- }
808
-
809
- // CSS Filters
810
- function filterUtilities() {
811
- return `/* Filters */
812
- .filter-none { filter: none; }
813
- .blur-none { filter: blur(0); }
814
- .blur-sm { filter: blur(4px); }
815
- .blur { filter: blur(8px); }
816
- .blur-md { filter: blur(12px); }
817
- .blur-lg { filter: blur(16px); }
818
- .blur-xl { filter: blur(24px); }
819
- .brightness-0 { filter: brightness(0); }
820
- .brightness-50 { filter: brightness(.5); }
821
- .brightness-75 { filter: brightness(.75); }
822
- .brightness-90 { filter: brightness(.9); }
823
- .brightness-100 { filter: brightness(1); }
824
- .brightness-110 { filter: brightness(1.1); }
825
- .brightness-125 { filter: brightness(1.25); }
826
- .brightness-150 { filter: brightness(1.5); }
827
- .brightness-200 { filter: brightness(2); }
828
- .contrast-0 { filter: contrast(0); }
829
- .contrast-50 { filter: contrast(.5); }
830
- .contrast-75 { filter: contrast(.75); }
831
- .contrast-100 { filter: contrast(1); }
832
- .contrast-125 { filter: contrast(1.25); }
833
- .contrast-150 { filter: contrast(1.5); }
834
- .contrast-200 { filter: contrast(2); }
835
- .grayscale-0 { filter: grayscale(0); }
836
- .grayscale { filter: grayscale(100%); }
837
- .invert-0 { filter: invert(0); }
838
- .invert { filter: invert(100%); }
839
- .sepia-0 { filter: sepia(0); }
840
- .sepia { filter: sepia(100%); }
841
- .saturate-0 { filter: saturate(0); }
842
- .saturate-50 { filter: saturate(.5); }
843
- .saturate-100 { filter: saturate(1); }
844
- .saturate-150 { filter: saturate(1.5); }
845
- .saturate-200 { filter: saturate(2); }
846
- .hue-rotate-0 { filter: hue-rotate(0deg); }
847
- .hue-rotate-15 { filter: hue-rotate(15deg); }
848
- .hue-rotate-30 { filter: hue-rotate(30deg); }
849
- .hue-rotate-60 { filter: hue-rotate(60deg); }
850
- .hue-rotate-90 { filter: hue-rotate(90deg); }
851
- .hue-rotate-180 { filter: hue-rotate(180deg); }
852
- .-hue-rotate-30 { filter: hue-rotate(-30deg); }
853
- .-hue-rotate-60 { filter: hue-rotate(-60deg); }
854
- .-hue-rotate-90 { filter: hue-rotate(-90deg); }
855
-
856
- `;
857
- }
858
- module.exports = {
859
- displayUtilities,
860
- sizingUtilities,
861
- positioningUtilities,
862
- overflowUtilities,
863
- opacityUtilities,
864
- transitionUtilities,
865
- transformUtilities,
866
- shadowUtilities,
867
- ringUtilities,
868
- objectUtilities,
869
- tableListUtilities,
870
- svgUtilities,
871
- formUtilities,
872
- verticalAlignUtilities,
873
- contentScrollUtilities,
874
- blendUtilities,
875
- cursorUtilities,
876
- accessibilityUtilities,
877
- containerUtilities,
878
- codeUtilities,
879
- animationUtilities,
880
- backdropUtilities,
881
- spaceUtilities,
882
- divideUtilities,
883
- backgroundUtilities,
884
- filterUtilities,
885
- };
3
+ module.exports = require('./generators/index.js');