emily-css 1.0.15 → 1.0.17
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/CHANGELOG.md +16 -0
- package/package.json +1 -1
- package/src/generators.js +209 -2
- package/src/index.js +94 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to `emily-css` are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## v1.0.17 — May 2026
|
|
8
|
+
|
|
9
|
+
**added new utilties, and added component patterns**
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- added new utilties, and added component patterns
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
## v1.0.16 — May 2026
|
|
16
|
+
|
|
17
|
+
**feat: add Round 2 utility set — 156/156 tests passing**
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- feat: add Round 2 utility set — 156/156 tests passing
|
|
21
|
+
|
|
22
|
+
---
|
|
7
23
|
## v1.0.15 — May 2026
|
|
8
24
|
|
|
9
25
|
**updated readme**
|
package/package.json
CHANGED
package/src/generators.js
CHANGED
|
@@ -65,6 +65,7 @@ function sizingUtilities(spacing) {
|
|
|
65
65
|
css += `.max-w-5xl { max-width: 64rem; }\n`;
|
|
66
66
|
css += `.max-w-6xl { max-width: 72rem; }\n`;
|
|
67
67
|
css += `.max-w-7xl { max-width: 80rem; }\n`;
|
|
68
|
+
css += `.max-w-prose { max-width: 65ch; }\n`;
|
|
68
69
|
|
|
69
70
|
// Aspect ratio
|
|
70
71
|
css += `.aspect-auto { aspect-ratio: auto; }\n`;
|
|
@@ -137,6 +138,7 @@ function overflowUtilities() {
|
|
|
137
138
|
.overflow-y-auto { overflow-y: auto; }
|
|
138
139
|
.overflow-y-hidden { overflow-y: hidden; }
|
|
139
140
|
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
141
|
+
.line-clamp-1 { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
|
|
140
142
|
.line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
141
143
|
.line-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
|
142
144
|
.line-clamp-4 { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
|
@@ -148,7 +150,7 @@ function overflowUtilities() {
|
|
|
148
150
|
|
|
149
151
|
// Opacity
|
|
150
152
|
function opacityUtilities() {
|
|
151
|
-
const opacities = [0, 5, 10, 25, 50, 75, 90, 95, 100];
|
|
153
|
+
const opacities = [0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 95, 100];
|
|
152
154
|
let css = `/* Opacity */\n`;
|
|
153
155
|
|
|
154
156
|
opacities.forEach(op => {
|
|
@@ -277,6 +279,11 @@ function ringUtilities(colours) {
|
|
|
277
279
|
css += `.outline-0 { outline-width: 0; }\n`;
|
|
278
280
|
css += `.outline-1 { outline-width: 1px; }\n`;
|
|
279
281
|
css += `.outline-2 { outline-width: 2px; }\n`;
|
|
282
|
+
css += `.outline-offset-0 { outline-offset: 0px; }\n`;
|
|
283
|
+
css += `.outline-offset-1 { outline-offset: 1px; }\n`;
|
|
284
|
+
css += `.outline-offset-2 { outline-offset: 2px; }\n`;
|
|
285
|
+
css += `.outline-offset-4 { outline-offset: 4px; }\n`;
|
|
286
|
+
css += `.outline-offset-8 { outline-offset: 8px; }\n`;
|
|
280
287
|
|
|
281
288
|
css += `\n`;
|
|
282
289
|
return css;
|
|
@@ -353,6 +360,8 @@ function svgUtilities(colours) {
|
|
|
353
360
|
function formUtilities() {
|
|
354
361
|
return `/* Forms */
|
|
355
362
|
.appearance-none { appearance: none; }
|
|
363
|
+
.caret-transparent { caret-color: transparent; }
|
|
364
|
+
.caret-current { caret-color: currentColor; }
|
|
356
365
|
.placeholder-transparent::placeholder { color: transparent; }
|
|
357
366
|
.placeholder-current::placeholder { color: currentColor; }
|
|
358
367
|
.autofill\\:bg-transparent:autofill { background-color: transparent !important; }
|
|
@@ -398,6 +407,10 @@ function contentScrollUtilities() {
|
|
|
398
407
|
.snap-both { scroll-snap-type: both var(--emily-scroll-snap-strictness); }
|
|
399
408
|
.snap-mandatory { --emily-scroll-snap-strictness: mandatory; }
|
|
400
409
|
.snap-proximity { --emily-scroll-snap-strictness: proximity; }
|
|
410
|
+
.snap-start { scroll-snap-align: start; }
|
|
411
|
+
.snap-center { scroll-snap-align: center; }
|
|
412
|
+
.snap-end { scroll-snap-align: end; }
|
|
413
|
+
.snap-align-none { scroll-snap-align: none; }
|
|
401
414
|
|
|
402
415
|
`;
|
|
403
416
|
}
|
|
@@ -442,6 +455,16 @@ function cursorUtilities() {
|
|
|
442
455
|
.select-text { user-select: text; }
|
|
443
456
|
.select-all { user-select: all; }
|
|
444
457
|
.select-auto { user-select: auto; }
|
|
458
|
+
.resize-none { resize: none; }
|
|
459
|
+
.resize { resize: both; }
|
|
460
|
+
.resize-x { resize: horizontal; }
|
|
461
|
+
.resize-y { resize: vertical; }
|
|
462
|
+
.isolate { isolation: isolate; }
|
|
463
|
+
.isolation-auto { isolation: auto; }
|
|
464
|
+
.will-change-auto { will-change: auto; }
|
|
465
|
+
.will-change-scroll { will-change: scroll-position; }
|
|
466
|
+
.will-change-contents { will-change: contents; }
|
|
467
|
+
.will-change-transform { will-change: transform; }
|
|
445
468
|
|
|
446
469
|
`;
|
|
447
470
|
}
|
|
@@ -453,6 +476,15 @@ function accessibilityUtilities() {
|
|
|
453
476
|
.not-sr-only { position: static; width: auto; height: auto; padding: 0; margin: 0; overflow: visible; clip: auto; white-space: normal; }
|
|
454
477
|
.focus-visible:focus { outline: 2px solid currentColor; outline-offset: 2px; }
|
|
455
478
|
.focus\\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
|
|
479
|
+
|
|
480
|
+
/* Touch target — WCAG 2.2 SC 2.5.8 minimum 24x24px hit area */
|
|
481
|
+
.touch-target { position: relative; }
|
|
482
|
+
.touch-target::before { content: ''; position: absolute; top: 50%; left: 50%; width: max(100%, 24px); height: max(100%, 24px); transform: translate(-50%, -50%); }
|
|
483
|
+
|
|
484
|
+
/* Skip link — reveals on focus for keyboard/AT users */
|
|
485
|
+
.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; }
|
|
486
|
+
.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; }
|
|
487
|
+
|
|
456
488
|
@media (prefers-reduced-motion: reduce) {
|
|
457
489
|
.motion-reduce\\:transition-none { transition-property: none; }
|
|
458
490
|
.motion-reduce\\:animate-none { animation: none; }
|
|
@@ -515,6 +547,175 @@ function codeUtilities() {
|
|
|
515
547
|
`;
|
|
516
548
|
}
|
|
517
549
|
|
|
550
|
+
// Animations
|
|
551
|
+
function animationUtilities() {
|
|
552
|
+
return `/* Animations — keyframes */
|
|
553
|
+
@keyframes spin {
|
|
554
|
+
to { transform: rotate(360deg); }
|
|
555
|
+
}
|
|
556
|
+
@keyframes ping {
|
|
557
|
+
75%, 100% { transform: scale(2); opacity: 0; }
|
|
558
|
+
}
|
|
559
|
+
@keyframes pulse {
|
|
560
|
+
50% { opacity: 0.5; }
|
|
561
|
+
}
|
|
562
|
+
@keyframes bounce {
|
|
563
|
+
0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
|
|
564
|
+
50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/* Animations — utilities */
|
|
568
|
+
.animate-none { animation: none; }
|
|
569
|
+
.animate-spin { animation: spin 1s linear infinite; }
|
|
570
|
+
.animate-ping { animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; }
|
|
571
|
+
.animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
|
|
572
|
+
.animate-bounce { animation: bounce 1s infinite; }
|
|
573
|
+
|
|
574
|
+
`;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
// Backdrop Filters
|
|
579
|
+
function backdropUtilities() {
|
|
580
|
+
return `/* Backdrop Filters */
|
|
581
|
+
.backdrop-blur-none { backdrop-filter: blur(0); }
|
|
582
|
+
.backdrop-blur-sm { backdrop-filter: blur(4px); }
|
|
583
|
+
.backdrop-blur { backdrop-filter: blur(8px); }
|
|
584
|
+
.backdrop-blur-md { backdrop-filter: blur(12px); }
|
|
585
|
+
.backdrop-blur-lg { backdrop-filter: blur(16px); }
|
|
586
|
+
.backdrop-blur-xl { backdrop-filter: blur(24px); }
|
|
587
|
+
.backdrop-blur-2xl { backdrop-filter: blur(40px); }
|
|
588
|
+
|
|
589
|
+
`;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Space Between
|
|
593
|
+
function spaceUtilities(spacing) {
|
|
594
|
+
let css = `/* Space Between */\n`;
|
|
595
|
+
Object.entries(spacing).forEach(([key, value]) => {
|
|
596
|
+
const escaped = key.replace(/\./g, '\\.');
|
|
597
|
+
css += `.space-x-${escaped} > * + * { margin-left: ${value}; }\n`;
|
|
598
|
+
css += `.space-y-${escaped} > * + * { margin-top: ${value}; }\n`;
|
|
599
|
+
css += `.-space-x-${escaped} > * + * { margin-left: -${value}; }\n`;
|
|
600
|
+
css += `.-space-y-${escaped} > * + * { margin-top: -${value}; }\n`;
|
|
601
|
+
});
|
|
602
|
+
css += `.space-x-auto > * + * { margin-left: auto; }\n`;
|
|
603
|
+
css += `.space-y-auto > * + * { margin-top: auto; }\n`;
|
|
604
|
+
css += `\n`;
|
|
605
|
+
return css;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Divide
|
|
609
|
+
function divideUtilities(spacing, colours) {
|
|
610
|
+
let css = `/* Divide */\n`;
|
|
611
|
+
// Widths
|
|
612
|
+
css += `.divide-x > * + * { border-left-width: 1px; border-left-style: solid; }\n`;
|
|
613
|
+
css += `.divide-y > * + * { border-top-width: 1px; border-top-style: solid; }\n`;
|
|
614
|
+
css += `.divide-x-0 > * + * { border-left-width: 0px; }\n`;
|
|
615
|
+
css += `.divide-y-0 > * + * { border-top-width: 0px; }\n`;
|
|
616
|
+
css += `.divide-x-2 > * + * { border-left-width: 2px; border-left-style: solid; }\n`;
|
|
617
|
+
css += `.divide-y-2 > * + * { border-top-width: 2px; border-top-style: solid; }\n`;
|
|
618
|
+
css += `.divide-x-4 > * + * { border-left-width: 4px; border-left-style: solid; }\n`;
|
|
619
|
+
css += `.divide-y-4 > * + * { border-top-width: 4px; border-top-style: solid; }\n`;
|
|
620
|
+
// Styles
|
|
621
|
+
css += `.divide-solid > * + * { border-style: solid; }\n`;
|
|
622
|
+
css += `.divide-dashed > * + * { border-style: dashed; }\n`;
|
|
623
|
+
css += `.divide-dotted > * + * { border-style: dotted; }\n`;
|
|
624
|
+
css += `.divide-none > * + * { border-style: none; }\n`;
|
|
625
|
+
// Colours
|
|
626
|
+
Object.entries(colours).forEach(([colourName, shades]) => {
|
|
627
|
+
Object.entries(shades).forEach(([shade]) => {
|
|
628
|
+
css += `.divide-${colourName}-${shade} > * + * { border-color: var(--color-${colourName}-${shade}); }\n`;
|
|
629
|
+
});
|
|
630
|
+
});
|
|
631
|
+
css += `.divide-white > * + * { border-color: #ffffff; }\n`;
|
|
632
|
+
css += `.divide-black > * + * { border-color: #000000; }\n`;
|
|
633
|
+
css += `.divide-transparent > * + * { border-color: transparent; }\n`;
|
|
634
|
+
css += `\n`;
|
|
635
|
+
return css;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Background Utilities
|
|
639
|
+
function backgroundUtilities() {
|
|
640
|
+
return `/* Background */
|
|
641
|
+
.bg-fixed { background-attachment: fixed; }
|
|
642
|
+
.bg-local { background-attachment: local; }
|
|
643
|
+
.bg-scroll { background-attachment: scroll; }
|
|
644
|
+
.bg-clip-border { background-clip: border-box; }
|
|
645
|
+
.bg-clip-padding { background-clip: padding-box; }
|
|
646
|
+
.bg-clip-content { background-clip: content-box; }
|
|
647
|
+
.bg-clip-text { -webkit-background-clip: text; background-clip: text; }
|
|
648
|
+
.bg-repeat { background-repeat: repeat; }
|
|
649
|
+
.bg-no-repeat { background-repeat: no-repeat; }
|
|
650
|
+
.bg-repeat-x { background-repeat: repeat-x; }
|
|
651
|
+
.bg-repeat-y { background-repeat: repeat-y; }
|
|
652
|
+
.bg-repeat-round { background-repeat: round; }
|
|
653
|
+
.bg-repeat-space { background-repeat: space; }
|
|
654
|
+
.bg-auto { background-size: auto; }
|
|
655
|
+
.bg-cover { background-size: cover; }
|
|
656
|
+
.bg-contain { background-size: contain; }
|
|
657
|
+
.bg-center { background-position: center; }
|
|
658
|
+
.bg-top { background-position: top; }
|
|
659
|
+
.bg-bottom { background-position: bottom; }
|
|
660
|
+
.bg-left { background-position: left; }
|
|
661
|
+
.bg-right { background-position: right; }
|
|
662
|
+
.bg-left-top { background-position: left top; }
|
|
663
|
+
.bg-left-bottom { background-position: left bottom; }
|
|
664
|
+
.bg-right-top { background-position: right top; }
|
|
665
|
+
.bg-right-bottom { background-position: right bottom; }
|
|
666
|
+
|
|
667
|
+
`;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// CSS Filters
|
|
671
|
+
function filterUtilities() {
|
|
672
|
+
return `/* Filters */
|
|
673
|
+
.filter-none { filter: none; }
|
|
674
|
+
.blur-none { filter: blur(0); }
|
|
675
|
+
.blur-sm { filter: blur(4px); }
|
|
676
|
+
.blur { filter: blur(8px); }
|
|
677
|
+
.blur-md { filter: blur(12px); }
|
|
678
|
+
.blur-lg { filter: blur(16px); }
|
|
679
|
+
.blur-xl { filter: blur(24px); }
|
|
680
|
+
.brightness-0 { filter: brightness(0); }
|
|
681
|
+
.brightness-50 { filter: brightness(.5); }
|
|
682
|
+
.brightness-75 { filter: brightness(.75); }
|
|
683
|
+
.brightness-90 { filter: brightness(.9); }
|
|
684
|
+
.brightness-100 { filter: brightness(1); }
|
|
685
|
+
.brightness-110 { filter: brightness(1.1); }
|
|
686
|
+
.brightness-125 { filter: brightness(1.25); }
|
|
687
|
+
.brightness-150 { filter: brightness(1.5); }
|
|
688
|
+
.brightness-200 { filter: brightness(2); }
|
|
689
|
+
.contrast-0 { filter: contrast(0); }
|
|
690
|
+
.contrast-50 { filter: contrast(.5); }
|
|
691
|
+
.contrast-75 { filter: contrast(.75); }
|
|
692
|
+
.contrast-100 { filter: contrast(1); }
|
|
693
|
+
.contrast-125 { filter: contrast(1.25); }
|
|
694
|
+
.contrast-150 { filter: contrast(1.5); }
|
|
695
|
+
.contrast-200 { filter: contrast(2); }
|
|
696
|
+
.grayscale-0 { filter: grayscale(0); }
|
|
697
|
+
.grayscale { filter: grayscale(100%); }
|
|
698
|
+
.invert-0 { filter: invert(0); }
|
|
699
|
+
.invert { filter: invert(100%); }
|
|
700
|
+
.sepia-0 { filter: sepia(0); }
|
|
701
|
+
.sepia { filter: sepia(100%); }
|
|
702
|
+
.saturate-0 { filter: saturate(0); }
|
|
703
|
+
.saturate-50 { filter: saturate(.5); }
|
|
704
|
+
.saturate-100 { filter: saturate(1); }
|
|
705
|
+
.saturate-150 { filter: saturate(1.5); }
|
|
706
|
+
.saturate-200 { filter: saturate(2); }
|
|
707
|
+
.hue-rotate-0 { filter: hue-rotate(0deg); }
|
|
708
|
+
.hue-rotate-15 { filter: hue-rotate(15deg); }
|
|
709
|
+
.hue-rotate-30 { filter: hue-rotate(30deg); }
|
|
710
|
+
.hue-rotate-60 { filter: hue-rotate(60deg); }
|
|
711
|
+
.hue-rotate-90 { filter: hue-rotate(90deg); }
|
|
712
|
+
.hue-rotate-180 { filter: hue-rotate(180deg); }
|
|
713
|
+
.-hue-rotate-30 { filter: hue-rotate(-30deg); }
|
|
714
|
+
.-hue-rotate-60 { filter: hue-rotate(-60deg); }
|
|
715
|
+
.-hue-rotate-90 { filter: hue-rotate(-90deg); }
|
|
716
|
+
|
|
717
|
+
`;
|
|
718
|
+
}
|
|
518
719
|
module.exports = {
|
|
519
720
|
displayUtilities,
|
|
520
721
|
sizingUtilities,
|
|
@@ -535,5 +736,11 @@ module.exports = {
|
|
|
535
736
|
cursorUtilities,
|
|
536
737
|
accessibilityUtilities,
|
|
537
738
|
containerUtilities,
|
|
538
|
-
codeUtilities
|
|
739
|
+
codeUtilities,
|
|
740
|
+
animationUtilities,
|
|
741
|
+
backdropUtilities,
|
|
742
|
+
spaceUtilities,
|
|
743
|
+
divideUtilities,
|
|
744
|
+
backgroundUtilities,
|
|
745
|
+
filterUtilities,
|
|
539
746
|
};
|
package/src/index.js
CHANGED
|
@@ -288,7 +288,13 @@ const {
|
|
|
288
288
|
cursorUtilities,
|
|
289
289
|
accessibilityUtilities,
|
|
290
290
|
containerUtilities,
|
|
291
|
-
codeUtilities
|
|
291
|
+
codeUtilities,
|
|
292
|
+
animationUtilities,
|
|
293
|
+
backdropUtilities,
|
|
294
|
+
spaceUtilities,
|
|
295
|
+
divideUtilities,
|
|
296
|
+
backgroundUtilities,
|
|
297
|
+
filterUtilities,
|
|
292
298
|
} = require('./generators');
|
|
293
299
|
|
|
294
300
|
// ============================================================================
|
|
@@ -498,6 +504,27 @@ function generateTypographyUtilities(config) {
|
|
|
498
504
|
css += `.underline { text-decoration: underline; }\n`;
|
|
499
505
|
css += `.no-underline { text-decoration: none; }\n`;
|
|
500
506
|
css += `.line-through { text-decoration: line-through; }\n`;
|
|
507
|
+
css += `.underline-offset-auto { text-underline-offset: auto; }\n`;
|
|
508
|
+
css += `.underline-offset-1 { text-underline-offset: 1px; }\n`;
|
|
509
|
+
css += `.underline-offset-2 { text-underline-offset: 2px; }\n`;
|
|
510
|
+
css += `.underline-offset-4 { text-underline-offset: 4px; }\n`;
|
|
511
|
+
css += `.underline-offset-8 { text-underline-offset: 8px; }\n`;
|
|
512
|
+
css += `.decoration-auto { text-decoration-thickness: auto; }\n`;
|
|
513
|
+
css += `.decoration-from-font { text-decoration-thickness: from-font; }\n`;
|
|
514
|
+
css += `.decoration-1 { text-decoration-thickness: 1px; }\n`;
|
|
515
|
+
css += `.decoration-2 { text-decoration-thickness: 2px; }\n`;
|
|
516
|
+
css += `.decoration-4 { text-decoration-thickness: 4px; }\n`;
|
|
517
|
+
|
|
518
|
+
// Font variant numeric
|
|
519
|
+
css += `.normal-nums { font-variant-numeric: normal; }\n`;
|
|
520
|
+
css += `.ordinal { font-variant-numeric: ordinal; }\n`;
|
|
521
|
+
css += `.slashed-zero { font-variant-numeric: slashed-zero; }\n`;
|
|
522
|
+
css += `.lining-nums { font-variant-numeric: lining-nums; }\n`;
|
|
523
|
+
css += `.oldstyle-nums { font-variant-numeric: oldstyle-nums; }\n`;
|
|
524
|
+
css += `.proportional-nums { font-variant-numeric: proportional-nums; }\n`;
|
|
525
|
+
css += `.tabular-nums { font-variant-numeric: tabular-nums; }\n`;
|
|
526
|
+
css += `.diagonal-fractions { font-variant-numeric: diagonal-fractions; }\n`;
|
|
527
|
+
css += `.stacked-fractions { font-variant-numeric: stacked-fractions; }\n`;
|
|
501
528
|
|
|
502
529
|
// Text transform
|
|
503
530
|
css += `.uppercase { text-transform: uppercase; }\n`;
|
|
@@ -739,6 +766,7 @@ function addStateVariants(css) {
|
|
|
739
766
|
const states = [
|
|
740
767
|
{ name: 'hover', selector: ':hover' },
|
|
741
768
|
{ name: 'focus', selector: ':focus' },
|
|
769
|
+
{ name: 'focus-within', selector: ':focus-within' },
|
|
742
770
|
{ name: 'focus-visible', selector: ':focus-visible' },
|
|
743
771
|
{ name: 'active', selector: ':active' },
|
|
744
772
|
{ name: 'disabled', selector: ':disabled' }
|
|
@@ -774,6 +802,63 @@ function addStateVariants(css) {
|
|
|
774
802
|
return variantCss;
|
|
775
803
|
}
|
|
776
804
|
|
|
805
|
+
|
|
806
|
+
// ============================================================================
|
|
807
|
+
// PATTERN COMPONENTS
|
|
808
|
+
// ============================================================================
|
|
809
|
+
// Composite classes that combine multiple utilities into named patterns.
|
|
810
|
+
// These live in @layer components so utilities always take precedence in the cascade.
|
|
811
|
+
// Gap values reference spacing variables generated from emily.config.json,
|
|
812
|
+
// with pixel fallbacks so they work even without the variables in scope.
|
|
813
|
+
|
|
814
|
+
function generatePatternComponents() {
|
|
815
|
+
return `
|
|
816
|
+
/* ---- Centering ---- */
|
|
817
|
+
|
|
818
|
+
/* Full-viewport overlay centering — use for modals, lightboxes, toasts */
|
|
819
|
+
.center-screen {
|
|
820
|
+
position: fixed;
|
|
821
|
+
inset: 0;
|
|
822
|
+
display: flex;
|
|
823
|
+
align-items: center;
|
|
824
|
+
justify-content: center;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/* Transform-based centering within a relative/absolute parent */
|
|
828
|
+
.center-absolute {
|
|
829
|
+
position: absolute;
|
|
830
|
+
top: 50%;
|
|
831
|
+
left: 50%;
|
|
832
|
+
transform: translate(-50%, -50%);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/* ---- Reading / Prose ---- */
|
|
836
|
+
|
|
837
|
+
/* Comfortable reading column — limits line length, centers the block */
|
|
838
|
+
.prose {
|
|
839
|
+
max-width: 65ch;
|
|
840
|
+
margin-inline: auto;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/* ---- Composition ---- */
|
|
844
|
+
|
|
845
|
+
/* Vertical stack with consistent gap — replaces manual margin chains */
|
|
846
|
+
.stack {
|
|
847
|
+
display: flex;
|
|
848
|
+
flex-direction: column;
|
|
849
|
+
gap: var(--space-4, 1rem);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/* Horizontal grouping with wrapping — for tags, button rows, icon lists */
|
|
853
|
+
.cluster {
|
|
854
|
+
display: flex;
|
|
855
|
+
flex-wrap: wrap;
|
|
856
|
+
gap: var(--space-4, 1rem);
|
|
857
|
+
align-items: center;
|
|
858
|
+
}
|
|
859
|
+
`;
|
|
860
|
+
}
|
|
861
|
+
|
|
777
862
|
// ============================================================================
|
|
778
863
|
// BUILD FUNCTION
|
|
779
864
|
// ============================================================================
|
|
@@ -831,6 +916,12 @@ function buildFullFramework() {
|
|
|
831
916
|
utilityCss += accessibilityUtilities();
|
|
832
917
|
utilityCss += containerUtilities();
|
|
833
918
|
utilityCss += codeUtilities();
|
|
919
|
+
utilityCss += animationUtilities();
|
|
920
|
+
utilityCss += backdropUtilities();
|
|
921
|
+
utilityCss += spaceUtilities(spacing);
|
|
922
|
+
utilityCss += divideUtilities(spacing, colours);
|
|
923
|
+
utilityCss += backgroundUtilities();
|
|
924
|
+
utilityCss += filterUtilities();
|
|
834
925
|
|
|
835
926
|
// Add state, dark mode, and responsive variants to utilities
|
|
836
927
|
utilityCss = addStateVariants(utilityCss);
|
|
@@ -931,7 +1022,7 @@ ${bodyFont}`;
|
|
|
931
1022
|
css += `@layer theme {\n${variablesCss}}\n\n`;
|
|
932
1023
|
const baseStylesCss = generateBaseStyles(config);
|
|
933
1024
|
css += `@layer base {${baseCss}${baseStylesCss}}\n\n`;
|
|
934
|
-
css += `@layer components {\n
|
|
1025
|
+
css += `@layer components {\n${generatePatternComponents()}}\n\n`;
|
|
935
1026
|
css += `@layer utilities {\n${utilityCss}}\n`;
|
|
936
1027
|
|
|
937
1028
|
// Write output
|
|
@@ -1059,4 +1150,4 @@ module.exports = {
|
|
|
1059
1150
|
addResponsiveVariants,
|
|
1060
1151
|
generateFontCSS,
|
|
1061
1152
|
codeUtilities,
|
|
1062
|
-
};
|
|
1153
|
+
};
|