css-tags 0.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/LICENSE +21 -0
- package/README.md +875 -0
- package/carousel.js +86 -0
- package/components/accessibility.css +51 -0
- package/components/actions.css +76 -0
- package/components/alert.css +122 -0
- package/components/application-patterns.css +122 -0
- package/components/badge.css +125 -0
- package/components/box-extra.css +220 -0
- package/components/box.css +75 -0
- package/components/card.css +130 -0
- package/components/carousel.css +76 -0
- package/components/chip.css +71 -0
- package/components/container.css +55 -0
- package/components/content-patterns.css +234 -0
- package/components/disclosure.css +581 -0
- package/components/divider.css +68 -0
- package/components/flex.css +59 -0
- package/components/form-patterns.css +273 -0
- package/components/form.css +130 -0
- package/components/grid.css +82 -0
- package/components/identity.css +59 -0
- package/components/img-container.css +141 -0
- package/components/img-container.js +75 -0
- package/components/list.css +69 -0
- package/components/loading.css +112 -0
- package/components/masonry.css +48 -0
- package/components/modal.css +73 -0
- package/components/navigation-patterns.css +245 -0
- package/components/navigation.css +200 -0
- package/components/popover.css +49 -0
- package/components/site-shell.css +180 -0
- package/components/status.css +110 -0
- package/components/table.css +98 -0
- package/components/tabs.css +103 -0
- package/components/tooltip.css +87 -0
- package/components/tooltips.css +73 -0
- package/components/view-transition.css +73 -0
- package/core/base.css +62 -0
- package/core/defaults.css +490 -0
- package/core/engine.css +32 -0
- package/core/mixins.css +376 -0
- package/core/palette-accent.css +8 -0
- package/core/palette-base.css +107 -0
- package/core/palette-extended.css +142 -0
- package/core/palette-feedback.css +62 -0
- package/core/palette.css +7 -0
- package/core/reset.css +270 -0
- package/core/text.css +171 -0
- package/core/theme.css +608 -0
- package/core/tokens.css +488 -0
- package/core/typography.css +327 -0
- package/index.css +66 -0
- package/layouts/layout-extra.css +204 -0
- package/layouts/layout-extras-helpers.css +19 -0
- package/layouts/layout.css +348 -0
- package/package.json +66 -0
- package/theme-generator.css +979 -0
- package/themes/example-brand.css +59 -0
- package/themes/theme-packs.css +31 -0
- package/types/css-tags.d.ts +482 -0
- package/utilities/utilities.css +564 -0
- package/view-transition.js +111 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A token-driven image frame with semantic loading and error states.
|
|
3
|
+
* Supports <img-container>, [data-img-container], and .img-container hosts.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
:is(img-container, [data-img-container], .img-container) {
|
|
7
|
+
--ic-aspect-ratio: attr(aspect-ratio type(*), auto);
|
|
8
|
+
--ic-object-fit: attr(object-fit type(*), cover);
|
|
9
|
+
--ic-object-position: attr(object-position type(*), center);
|
|
10
|
+
--ic-radius: attr(radius type(*), 0);
|
|
11
|
+
--ic-shadow: attr(shadow type(*), none);
|
|
12
|
+
--ic-bg: attr(bg type(*), transparent);
|
|
13
|
+
--ic-transition: attr(transition type(*), opacity 0.3s ease);
|
|
14
|
+
--ic-loading-start: var(--surface-muted, #f0f0f0);
|
|
15
|
+
--ic-loading-middle: var(--surface-overt, #e0e0e0);
|
|
16
|
+
--ic-error-bg: var(--surface-error, #fee);
|
|
17
|
+
--ic-error-border: var(--outline-error, #fcc);
|
|
18
|
+
--ic-error-color: var(--text-error, #a22);
|
|
19
|
+
|
|
20
|
+
position: relative;
|
|
21
|
+
display: block;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
aspect-ratio: var(--ic-aspect-ratio);
|
|
24
|
+
border-radius: var(--ic-radius);
|
|
25
|
+
box-shadow: var(--ic-shadow);
|
|
26
|
+
background-color: var(--ic-bg);
|
|
27
|
+
transition: var(--ic-transition);
|
|
28
|
+
|
|
29
|
+
&::before,
|
|
30
|
+
&::after {
|
|
31
|
+
position: absolute;
|
|
32
|
+
inset: 0;
|
|
33
|
+
z-index: 1;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* aria-busy is the primary loading-state contract. */
|
|
38
|
+
&::before {
|
|
39
|
+
content: '';
|
|
40
|
+
background: linear-gradient(
|
|
41
|
+
90deg,
|
|
42
|
+
var(--ic-loading-start) 25%,
|
|
43
|
+
var(--ic-loading-middle) 50%,
|
|
44
|
+
var(--ic-loading-start) 75%
|
|
45
|
+
);
|
|
46
|
+
background-size: 200% 100%;
|
|
47
|
+
opacity: 0;
|
|
48
|
+
transition: opacity 0.2s ease;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&[aria-busy="true"]::before,
|
|
52
|
+
&:has(img[data-loading])::before {
|
|
53
|
+
opacity: 1;
|
|
54
|
+
animation: img-container-loading 1.5s linear infinite;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&[data-error],
|
|
58
|
+
&:has(img[data-error]) {
|
|
59
|
+
background: var(--ic-error-bg);
|
|
60
|
+
border: var(--border-width, 1px) dashed var(--ic-error-border);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&[data-error]::after,
|
|
64
|
+
&:has(img[data-error])::after {
|
|
65
|
+
content: attr(error-message, "Image failed to load");
|
|
66
|
+
display: grid;
|
|
67
|
+
place-items: center;
|
|
68
|
+
padding: var(--space-md, 1rem);
|
|
69
|
+
color: var(--ic-error-color);
|
|
70
|
+
background: var(--ic-error-bg);
|
|
71
|
+
font-size: var(--font-size-sm, 0.875rem);
|
|
72
|
+
text-align: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
& :is(img, picture, video) {
|
|
76
|
+
display: block;
|
|
77
|
+
width: 100%;
|
|
78
|
+
height: 100%;
|
|
79
|
+
object-fit: var(--ic-object-fit);
|
|
80
|
+
object-position: var(--ic-object-position);
|
|
81
|
+
border-radius: inherit;
|
|
82
|
+
transition: inherit;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
& picture > img {
|
|
86
|
+
width: 100%;
|
|
87
|
+
height: 100%;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
& img[data-loading] {
|
|
91
|
+
opacity: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
& img:is([loaded], [data-loaded]) {
|
|
95
|
+
opacity: 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
& img[data-error] {
|
|
99
|
+
visibility: hidden;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@keyframes img-container-loading {
|
|
104
|
+
from { background-position: 200% 0; }
|
|
105
|
+
to { background-position: -200% 0; }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Viewport fallbacks for attribute-driven responsive aspect ratios. */
|
|
109
|
+
@media (max-width: 480px) {
|
|
110
|
+
:is(img-container, [data-img-container], .img-container)[responsive] {
|
|
111
|
+
--ic-aspect-ratio: attr(mobile-aspect-ratio type(*), var(--ic-aspect-ratio));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@media (min-width: 768px) {
|
|
116
|
+
:is(img-container, [data-img-container], .img-container)[responsive] {
|
|
117
|
+
--ic-aspect-ratio: attr(desktop-aspect-ratio type(*), var(--ic-aspect-ratio));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
:is(img-container, [data-img-container], .img-container)[theme="card"] {
|
|
122
|
+
--ic-radius: var(--radius-lg, 0.75rem);
|
|
123
|
+
--ic-shadow: var(--shadow-md, none);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:is(img-container, [data-img-container], .img-container)[theme="hero"] {
|
|
127
|
+
--ic-shadow: var(--shadow-lg, none);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
:is(img-container, [data-img-container], .img-container)[theme="thumbnail"] {
|
|
131
|
+
--ic-radius: var(--radius-md, 0.5rem);
|
|
132
|
+
--ic-aspect-ratio: 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@media (prefers-reduced-motion: reduce) {
|
|
136
|
+
:is(img-container, [data-img-container], .img-container),
|
|
137
|
+
:is(img-container, [data-img-container], .img-container)::before {
|
|
138
|
+
animation: none;
|
|
139
|
+
transition: none;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Progressive enhancement for image-container loading, fallback, and host shorthands. */
|
|
2
|
+
|
|
3
|
+
function initializeImageContainers(root = document) {
|
|
4
|
+
const containers = root.querySelectorAll(':is(img-container, [data-img-container], .img-container)');
|
|
5
|
+
|
|
6
|
+
containers.forEach(container => {
|
|
7
|
+
if (container.dataset.imgContainerInitialized === 'true') return;
|
|
8
|
+
|
|
9
|
+
const img = container.querySelector('img');
|
|
10
|
+
if (!img) return;
|
|
11
|
+
|
|
12
|
+
container.dataset.imgContainerInitialized = 'true';
|
|
13
|
+
container.setAttribute('aria-busy', 'true');
|
|
14
|
+
img.setAttribute('data-loading', '');
|
|
15
|
+
|
|
16
|
+
const markLoaded = () => {
|
|
17
|
+
img.removeAttribute('data-loading');
|
|
18
|
+
img.removeAttribute('data-error');
|
|
19
|
+
img.setAttribute('data-loaded', '');
|
|
20
|
+
img.setAttribute('loaded', '');
|
|
21
|
+
container.setAttribute('aria-busy', 'false');
|
|
22
|
+
container.removeAttribute('data-error');
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const markFailed = () => {
|
|
26
|
+
const fallback = container.getAttribute('fallback-src');
|
|
27
|
+
|
|
28
|
+
if (fallback && container.dataset.fallbackAttempted !== 'true') {
|
|
29
|
+
container.dataset.fallbackAttempted = 'true';
|
|
30
|
+
img.removeAttribute('data-error');
|
|
31
|
+
img.setAttribute('data-loading', '');
|
|
32
|
+
img.src = fallback;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
img.removeAttribute('data-loading');
|
|
37
|
+
img.setAttribute('data-error', '');
|
|
38
|
+
container.setAttribute('aria-busy', 'false');
|
|
39
|
+
container.setAttribute('data-error', '');
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
img.addEventListener('load', markLoaded);
|
|
43
|
+
img.addEventListener('error', markFailed);
|
|
44
|
+
|
|
45
|
+
if (container.hasAttribute('lazy') && !img.hasAttribute('loading')) {
|
|
46
|
+
img.loading = 'lazy';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const src = container.getAttribute('src') || img.getAttribute('data-src');
|
|
50
|
+
const srcset = container.getAttribute('srcset') || img.getAttribute('data-srcset');
|
|
51
|
+
const sizes = container.getAttribute('sizes');
|
|
52
|
+
const alt = container.getAttribute('alt');
|
|
53
|
+
|
|
54
|
+
if (srcset) img.srcset = srcset;
|
|
55
|
+
if (sizes) img.sizes = sizes;
|
|
56
|
+
if (alt && !img.hasAttribute('alt')) img.alt = alt;
|
|
57
|
+
if (src && !img.getAttribute('src')) img.src = src;
|
|
58
|
+
|
|
59
|
+
img.removeAttribute('data-src');
|
|
60
|
+
img.removeAttribute('data-srcset');
|
|
61
|
+
|
|
62
|
+
if (img.complete && img.currentSrc) {
|
|
63
|
+
if (img.naturalWidth > 0) markLoaded();
|
|
64
|
+
else markFailed();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (document.readyState === 'loading') {
|
|
70
|
+
document.addEventListener('DOMContentLoaded', () => initializeImageContainers(), { once: true });
|
|
71
|
+
} else {
|
|
72
|
+
initializeImageContainers();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { initializeImageContainers };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list.css
|
|
3
|
+
*
|
|
4
|
+
* A flexible and styleable list component.
|
|
5
|
+
* ------------------------------------------------------------------------------
|
|
6
|
+
* @feature {CSS Nesting} - For organized styling of items and markers.
|
|
7
|
+
* @feature {::marker} - For direct styling of list item markers.
|
|
8
|
+
* @feature {attr()} - For custom icon URLs and colors via CSS masks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
:is(list, [data-list], .list) {
|
|
12
|
+
--b-p: attr(padding type(*), 0);
|
|
13
|
+
--b-m: attr(margin type(*), 0);
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: attr(gap type(*), var(--l-gap, 0.5rem));
|
|
17
|
+
padding-block: var(--b-p);
|
|
18
|
+
padding-inline-end: var(--b-p);
|
|
19
|
+
padding-inline-start: attr(indent type(*), max(var(--b-p), 1.5rem));
|
|
20
|
+
list-style-position: outside;
|
|
21
|
+
margin: var(--b-m);
|
|
22
|
+
/* Style for inline lists */
|
|
23
|
+
&[inline] {
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
flex-wrap: wrap;
|
|
26
|
+
padding-inline-start: 0;
|
|
27
|
+
list-style: none;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
& > :is(list-item, [data-list-item], .list-item) {
|
|
31
|
+
display: list-item;
|
|
32
|
+
position: relative;
|
|
33
|
+
|
|
34
|
+
/* Style the native list item marker */
|
|
35
|
+
&::marker {
|
|
36
|
+
color: attr(marker-color type(*), var(--theme-primary));
|
|
37
|
+
content: '• ';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&[type]::marker { content: attr(type) ' '; }
|
|
41
|
+
|
|
42
|
+
/* Support for custom icons using modern CSS masks */
|
|
43
|
+
&[icon] {
|
|
44
|
+
list-style: none;
|
|
45
|
+
padding-inline-start: calc(attr(icon-size type(*), 1.2em) + 0.5rem);
|
|
46
|
+
|
|
47
|
+
&::before {
|
|
48
|
+
content: '';
|
|
49
|
+
position: absolute;
|
|
50
|
+
inset-inline-start: 0; /* Logical property */
|
|
51
|
+
top: 0.15em;
|
|
52
|
+
width: attr(icon-size type(*), 1.2em);
|
|
53
|
+
height: attr(icon-size type(*), 1.2em);
|
|
54
|
+
background-color: attr(icon-color type(*), var(--theme-primary));
|
|
55
|
+
mask-image: attr(icon type(<url>), none);
|
|
56
|
+
mask-size: contain;
|
|
57
|
+
mask-repeat: no-repeat;
|
|
58
|
+
mask-position: center;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
& > :is(list-divider, [data-list-divider], .list-divider) {
|
|
64
|
+
block-size: var(--list-divider-size, var(--divider-size, 1px));
|
|
65
|
+
background-color: var(--list-divider-color, var(--divider-color, var(--divider-color-subtle, var(--outline-subtle))));
|
|
66
|
+
margin-block: attr(gap type(*), 0.5rem); /* Logical property */
|
|
67
|
+
border: 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loading.css
|
|
3
|
+
*
|
|
4
|
+
* Semantic, token-driven loading feedback.
|
|
5
|
+
* `aria-busy="true"` is the spinner state; `.skeleton` and
|
|
6
|
+
* `[data-skeleton]` provide lightweight placeholder surfaces.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
@keyframes loading-spin {
|
|
10
|
+
to { transform: rotate(1turn); }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@keyframes skeleton-shimmer {
|
|
14
|
+
to { background-position-x: -200%; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:where([aria-busy="true"]) {
|
|
18
|
+
--_spinner-size: var(--spinner-size, 1.25em);
|
|
19
|
+
--_spinner-stroke: var(--spinner-stroke-width, 0.16em);
|
|
20
|
+
--_spinner-color: var(--spinner-color, currentColor);
|
|
21
|
+
--_spinner-track: var(--spinner-track-color, oklch(from currentColor l c h / 0.25));
|
|
22
|
+
--_spinner-speed: var(--spinner-speed, 700ms);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:where([aria-busy="true"])[data-spinner="small"] {
|
|
26
|
+
--_spinner-size: var(--spinner-size-small, 0.9em);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:where([aria-busy="true"])[data-spinner="large"] {
|
|
30
|
+
--_spinner-size: var(--spinner-size-large, 2rem);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:where([aria-busy="true"]):not([data-spinner="overlay"])::before {
|
|
34
|
+
content: "";
|
|
35
|
+
display: inline-block;
|
|
36
|
+
inline-size: var(--_spinner-size);
|
|
37
|
+
block-size: var(--_spinner-size);
|
|
38
|
+
margin-inline-end: 0.55em;
|
|
39
|
+
vertical-align: -0.18em;
|
|
40
|
+
border: var(--_spinner-stroke) solid var(--_spinner-track);
|
|
41
|
+
border-block-start-color: var(--_spinner-color);
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
animation: loading-spin var(--_spinner-speed) linear infinite;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:where([aria-busy="true"]:empty):not([data-spinner="overlay"])::before {
|
|
47
|
+
margin-inline-end: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
:where([aria-busy="true"])[data-spinner="overlay"] {
|
|
51
|
+
position: relative;
|
|
52
|
+
isolation: isolate;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:where([aria-busy="true"])[data-spinner="overlay"]::after {
|
|
56
|
+
content: "";
|
|
57
|
+
position: absolute;
|
|
58
|
+
z-index: 1;
|
|
59
|
+
inset: 0;
|
|
60
|
+
border-radius: inherit;
|
|
61
|
+
background: var(--spinner-overlay-backdrop, oklch(from var(--surface-default, white) l c h / 0.72));
|
|
62
|
+
backdrop-filter: blur(var(--spinner-overlay-blur, 2px));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:where([aria-busy="true"])[data-spinner="overlay"]::before {
|
|
66
|
+
content: "";
|
|
67
|
+
position: absolute;
|
|
68
|
+
z-index: 2;
|
|
69
|
+
inset: 50% auto auto 50%;
|
|
70
|
+
translate: -50% -50%;
|
|
71
|
+
inline-size: var(--_spinner-size);
|
|
72
|
+
block-size: var(--_spinner-size);
|
|
73
|
+
border: var(--_spinner-stroke) solid var(--_spinner-track);
|
|
74
|
+
border-block-start-color: var(--_spinner-color);
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
animation: loading-spin var(--_spinner-speed) linear infinite;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:is(.skeleton, [data-skeleton]) {
|
|
80
|
+
--_skeleton-bg: var(--skeleton-background, var(--surface-muted, #e5e7eb));
|
|
81
|
+
--_skeleton-highlight: var(--skeleton-highlight, oklch(from var(--_skeleton-bg) calc(l + 0.08) c h));
|
|
82
|
+
|
|
83
|
+
color: transparent;
|
|
84
|
+
border-radius: var(--skeleton-radius, var(--radius-sm, 0.375rem));
|
|
85
|
+
background-image: linear-gradient(
|
|
86
|
+
100deg,
|
|
87
|
+
var(--_skeleton-bg) 30%,
|
|
88
|
+
var(--_skeleton-highlight) 50%,
|
|
89
|
+
var(--_skeleton-bg) 70%
|
|
90
|
+
);
|
|
91
|
+
background-size: 200% 100%;
|
|
92
|
+
animation: skeleton-shimmer var(--skeleton-shimmer-duration, 1.4s) linear infinite;
|
|
93
|
+
cursor: wait;
|
|
94
|
+
user-select: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
:is(.skeleton, [data-skeleton]).line {
|
|
98
|
+
min-block-size: 0.85em;
|
|
99
|
+
max-inline-size: 100%;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
:is(.skeleton, [data-skeleton]).box {
|
|
103
|
+
min-block-size: var(--skeleton-box-min-height, 8rem);
|
|
104
|
+
inline-size: 100%;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@media (prefers-reduced-motion: reduce) {
|
|
108
|
+
:where([aria-busy="true"])::before,
|
|
109
|
+
:is(.skeleton, [data-skeleton]) {
|
|
110
|
+
animation: none;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* masonry.css
|
|
3
|
+
*
|
|
4
|
+
* A declarative component and mixin for the experimental CSS Masonry Layout.
|
|
5
|
+
* ------------------------------------------------------------------------------
|
|
6
|
+
* ⚠️ IMPORTANT: EXPERIMENTAL FEATURE - Requires browser flag in Edge/Chrome 140+.
|
|
7
|
+
*
|
|
8
|
+
* @feature {CSS Masonry} - For creating packed, brick-like layouts.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* 1. MIXIN (for use in CSS) */
|
|
12
|
+
@mixin --masonry(
|
|
13
|
+
--direction type(*): 'column',
|
|
14
|
+
--tracks type(*): 'repeat(auto-fill, auto)',
|
|
15
|
+
--gap type(*): 1.5rem
|
|
16
|
+
) {
|
|
17
|
+
display: masonry;
|
|
18
|
+
masonry-direction: var(--direction);
|
|
19
|
+
gap: var(--gap);
|
|
20
|
+
@when (var(--direction) = 'column') { grid-template-columns: var(--tracks); }
|
|
21
|
+
@when (var(--direction) = 'row') { grid-template-rows: var(--tracks); }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* 2. COMPONENT (for use in HTML)
|
|
25
|
+
* Standard grid is the baseline. Browsers with masonry support enhance it. */
|
|
26
|
+
:is(masonry-layout, [data-masonry], .masonry-layout) {
|
|
27
|
+
display: grid;
|
|
28
|
+
masonry-direction: attr(direction type(*), column);
|
|
29
|
+
gap: attr(gap type(*), 1.5rem);
|
|
30
|
+
item-tolerance: attr(tolerance type(*), 0);
|
|
31
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
|
|
32
|
+
grid-template-columns: attr(cols type(*), repeat(auto-fit, minmax(min(100%, 16rem), 1fr)));
|
|
33
|
+
grid-template-rows: attr(rows type(*), none);
|
|
34
|
+
grid-auto-flow: dense;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@supports (display: masonry) {
|
|
38
|
+
:is(masonry-layout, [data-masonry], .masonry-layout) {
|
|
39
|
+
display: masonry;
|
|
40
|
+
grid-auto-flow: initial;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Item spanning for the component */
|
|
45
|
+
:is(masonry-layout, [data-masonry], .masonry-layout) > * {
|
|
46
|
+
grid-column: attr(col type(*), auto);
|
|
47
|
+
grid-row: attr(row type(*), auto);
|
|
48
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialog and legacy modal surfaces.
|
|
3
|
+
*
|
|
4
|
+
* Native `<dialog>` is the canonical interactive API. `modal-dialog` is an
|
|
5
|
+
* optional visual host; consumers must still provide dialog behaviour and
|
|
6
|
+
* accessibility semantics when they do not use the native element.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
:is(dialog[data-modal], dialog.modal, modal-dialog) {
|
|
10
|
+
width: min(var(--modal-width, 36rem), calc(100% - 2rem));
|
|
11
|
+
max-height: min(var(--modal-max-height, 85dvh), calc(100% - 2rem));
|
|
12
|
+
margin: auto;
|
|
13
|
+
padding: var(--modal-padding, var(--space-lg, 1.5rem));
|
|
14
|
+
overflow: auto;
|
|
15
|
+
color: var(--modal-text, var(--text-default, CanvasText));
|
|
16
|
+
background: var(--modal-bg, var(--surface-default, Canvas));
|
|
17
|
+
border: var(--modal-border-width, 1px) solid
|
|
18
|
+
var(--modal-border-color, var(--outline-default, currentColor));
|
|
19
|
+
border-radius: var(--modal-radius, var(--radius-lg, 0.75rem));
|
|
20
|
+
box-shadow: var(--modal-shadow, 0 1.25rem 3rem rgb(0 0 0 / 0.24));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:is(dialog[data-modal], dialog.modal, modal-dialog)::backdrop {
|
|
24
|
+
background: var(--modal-backdrop, rgb(0 0 0 / 0.55));
|
|
25
|
+
backdrop-filter: blur(var(--modal-backdrop-blur, 3px));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:is(dialog[data-modal], dialog.modal, modal-dialog) > :first-child {
|
|
29
|
+
margin-block-start: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:is(dialog[data-modal], dialog.modal, modal-dialog) > :last-child {
|
|
33
|
+
margin-block-end: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Backwards-compatible overlay for applications that already manage the
|
|
37
|
+
interaction and focus lifecycle themselves. */
|
|
38
|
+
:is([data-modal-overlay], .modal-overlay) {
|
|
39
|
+
position: fixed;
|
|
40
|
+
z-index: var(--modal-z-index, 1000);
|
|
41
|
+
inset: 0;
|
|
42
|
+
display: grid;
|
|
43
|
+
place-items: center;
|
|
44
|
+
padding: var(--space-lg, 1.5rem);
|
|
45
|
+
background: var(--modal-backdrop, rgb(0 0 0 / 0.55));
|
|
46
|
+
backdrop-filter: blur(var(--modal-backdrop-blur, 3px));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:is([data-modal-overlay], .modal-overlay) > :is(.modal__panel, [data-modal-panel]) {
|
|
50
|
+
width: min(var(--modal-width, 36rem), 100%);
|
|
51
|
+
max-height: var(--modal-max-height, 85dvh);
|
|
52
|
+
padding: var(--modal-padding, var(--space-lg, 1.5rem));
|
|
53
|
+
overflow: auto;
|
|
54
|
+
color: var(--modal-text, var(--text-default, CanvasText));
|
|
55
|
+
background: var(--modal-bg, var(--surface-default, Canvas));
|
|
56
|
+
border: var(--modal-border-width, 1px) solid
|
|
57
|
+
var(--modal-border-color, var(--outline-default, currentColor));
|
|
58
|
+
border-radius: var(--modal-radius, var(--radius-lg, 0.75rem));
|
|
59
|
+
box-shadow: var(--modal-shadow, 0 1.25rem 3rem rgb(0 0 0 / 0.24));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
63
|
+
:is(dialog[data-modal], dialog.modal)[open] {
|
|
64
|
+
animation: modal-enter var(--modal-duration, 160ms) ease-out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes modal-enter {
|
|
68
|
+
from {
|
|
69
|
+
opacity: 0;
|
|
70
|
+
transform: translateY(0.5rem) scale(0.98);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|