@mlola-ui/engine 1.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/LICENSE +21 -0
- package/README.md +51 -0
- package/build.mjs +123 -0
- package/generated/agents.md +369 -0
- package/generated/assets.json +729 -0
- package/generated/contract.json +1234 -0
- package/generated/foundations.css +154 -0
- package/generated/manifest.json +5 -0
- package/generated/materials.css +55 -0
- package/generated/mlola.css +10 -0
- package/generated/motion.css +93 -0
- package/generated/recipes.css +6504 -0
- package/generated/theme-spec.schema.json +199 -0
- package/generated/theme.css +1 -0
- package/generated/themes.json +258 -0
- package/generated/tokens.css +812 -0
- package/generated/tokens.json +4751 -0
- package/package.json +56 -0
- package/src/behavior-spec.mjs +291 -0
- package/src/color.mjs +150 -0
- package/src/config.mjs +170 -0
- package/src/contract.mjs +103 -0
- package/src/contrast.mjs +68 -0
- package/src/declarations.mjs +131 -0
- package/src/deprecations.mjs +29 -0
- package/src/library-recipes.mjs +105 -0
- package/src/palette.mjs +286 -0
- package/src/render.mjs +190 -0
- package/src/spec.mjs +318 -0
- package/src/spring.mjs +46 -0
- package/src/theme-css.mjs +69 -0
- package/src/theme-distance.mjs +107 -0
- package/src/theme.mjs +97 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/* Foundation layer. */
|
|
2
|
+
*,
|
|
3
|
+
*::before,
|
|
4
|
+
*::after {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
html {
|
|
9
|
+
-webkit-text-size-adjust: 100%;
|
|
10
|
+
text-size-adjust: 100%;
|
|
11
|
+
font-family: var(--ml-font-sans);
|
|
12
|
+
background: var(--ml-background);
|
|
13
|
+
color: var(--ml-text);
|
|
14
|
+
scroll-behavior: smooth;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body {
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
margin: 0;
|
|
20
|
+
background: var(--ml-background);
|
|
21
|
+
color: var(--ml-text);
|
|
22
|
+
font-family: var(--ml-font-sans);
|
|
23
|
+
font-size: 1rem;
|
|
24
|
+
line-height: var(--ml-body-leading);
|
|
25
|
+
letter-spacing: var(--ml-tracking);
|
|
26
|
+
font-synthesis: none;
|
|
27
|
+
text-rendering: optimizeLegibility;
|
|
28
|
+
-webkit-font-smoothing: antialiased;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:where(h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd) {
|
|
32
|
+
margin: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:where(ul,ol)[role="list"] {
|
|
36
|
+
list-style: none;
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
:where(img,picture,video,canvas,svg) {
|
|
42
|
+
display: block;
|
|
43
|
+
max-width: 100%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:where(button,input,textarea,select) {
|
|
47
|
+
font: inherit;
|
|
48
|
+
color: inherit;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:where(button,[role="button"]) {
|
|
52
|
+
touch-action: manipulation;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:where(button,input,select,textarea,a[href],[tabindex]:not([tabindex="-1"])) {
|
|
56
|
+
scroll-margin-block: 1rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:where(a) {
|
|
60
|
+
color: inherit;
|
|
61
|
+
text-decoration-thickness: .08em;
|
|
62
|
+
text-underline-offset: .18em;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:where(h1,h2,h3) {
|
|
66
|
+
font-family: var(--ml-font-display);
|
|
67
|
+
font-weight: var(--ml-display-weight);
|
|
68
|
+
line-height: 1.08;
|
|
69
|
+
letter-spacing: -.025em;
|
|
70
|
+
text-wrap: balance;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
h1 {
|
|
74
|
+
font-size: clamp(2.25rem,5vw,4.75rem);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
h2 {
|
|
78
|
+
font-size: clamp(1.75rem,3.2vw,3rem);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
h3 {
|
|
82
|
+
font-size: clamp(1.25rem,2vw,1.75rem);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
:where(code,kbd,samp,pre) {
|
|
86
|
+
font-family: var(--ml-font-mono);
|
|
87
|
+
font-size: .925em;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
:where(pre) {
|
|
91
|
+
max-width: 100%;
|
|
92
|
+
overflow: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
::selection {
|
|
96
|
+
background: color-mix(in srgb,var(--ml-primary) 28%,transparent);
|
|
97
|
+
color: var(--ml-text);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
::placeholder {
|
|
101
|
+
color: var(--ml-text-faint);
|
|
102
|
+
opacity: 1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
:where(a,button,input,select,textarea,[role="button"],[tabindex]):focus-visible {
|
|
106
|
+
outline: 2px solid var(--ml-focus);
|
|
107
|
+
outline-offset: 2px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
:where(button,input,select,textarea):disabled,
|
|
111
|
+
[aria-disabled="true"] {
|
|
112
|
+
cursor: not-allowed;
|
|
113
|
+
opacity: .5;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@media (pointer:coarse) {
|
|
117
|
+
:where(button,[role="button"],input:not([type="hidden"]),select,textarea) {
|
|
118
|
+
min-height: var(--ml-target-min);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (prefers-reduced-transparency:reduce) {
|
|
123
|
+
* {
|
|
124
|
+
backdrop-filter: none!important;
|
|
125
|
+
-webkit-backdrop-filter: none!important;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@media (forced-colors:active) {
|
|
130
|
+
:root {
|
|
131
|
+
--ml-border: CanvasText;
|
|
132
|
+
--ml-focus: Highlight;
|
|
133
|
+
--ml-primary: Highlight;
|
|
134
|
+
--ml-primary-foreground: HighlightText;
|
|
135
|
+
--ml-primary-text: LinkText;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:where(a,button,input,select,textarea,[role="button"]) {
|
|
139
|
+
forced-color-adjust: auto;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Box-shadow rings vanish in forced colours; the system highlight stands in. */
|
|
143
|
+
:focus-visible {
|
|
144
|
+
outline: 2px solid Highlight!important;
|
|
145
|
+
outline-offset: 2px!important;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* The page scrollbar is left to the platform: styling it with
|
|
150
|
+
::-webkit-scrollbar forces a classic, space-taking scrollbar even where the
|
|
151
|
+
system uses overlay scrollbars, and the page then shifts whenever an
|
|
152
|
+
overlay locks scrolling. The theme's color-scheme already tints it for dark
|
|
153
|
+
mode. Scroll areas inside components opt into a thin, themed scrollbar
|
|
154
|
+
with the standard properties in their own stylesheets. */
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* Material recipes: apply a material to one surface regardless of theme. */
|
|
2
|
+
.ml-material-solid {
|
|
3
|
+
background: var(--ml-surface);
|
|
4
|
+
border: var(--ml-border-width) solid var(--ml-border);
|
|
5
|
+
box-shadow: var(--ml-shadow-xs);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ml-material-elevated {
|
|
9
|
+
background: var(--ml-surface-elevated);
|
|
10
|
+
border: var(--ml-border-width) solid var(--ml-border);
|
|
11
|
+
box-shadow: var(--ml-shadow-md);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ml-material-glass {
|
|
15
|
+
background: color-mix(in srgb,var(--ml-surface) 86%,transparent);
|
|
16
|
+
border: var(--ml-border-width) solid color-mix(in srgb,var(--ml-border) 78%,transparent);
|
|
17
|
+
box-shadow: var(--ml-shadow-sm);
|
|
18
|
+
backdrop-filter: blur(calc(10px + 12px * var(--ml-theme-depth))) saturate(145%);
|
|
19
|
+
-webkit-backdrop-filter: blur(calc(10px + 12px * var(--ml-theme-depth))) saturate(145%);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.ml-material-anodized {
|
|
23
|
+
background: linear-gradient(145deg,color-mix(in srgb,var(--ml-surface-elevated) 94%,var(--ml-text)),var(--ml-surface));
|
|
24
|
+
border: var(--ml-border-width) solid var(--ml-border);
|
|
25
|
+
box-shadow: inset 0 1px color-mix(in srgb,var(--ml-text) 10%,transparent),var(--ml-shadow-sm);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ml-material-paper {
|
|
29
|
+
background-color: var(--ml-surface);
|
|
30
|
+
background-image: radial-gradient(color-mix(in srgb,var(--ml-text) calc(var(--ml-texture-opacity) * 100%),transparent) .6px,transparent .7px);
|
|
31
|
+
background-size: 4px 4px;
|
|
32
|
+
border: var(--ml-border-width) solid var(--ml-border);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ml-material-specular {
|
|
36
|
+
position: relative;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
background: var(--ml-surface);
|
|
39
|
+
border: var(--ml-border-width) solid var(--ml-border);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ml-material-specular::after {
|
|
43
|
+
content: "";
|
|
44
|
+
position: absolute;
|
|
45
|
+
inset: 0;
|
|
46
|
+
pointer-events: none;
|
|
47
|
+
background: linear-gradient(135deg,oklch(1 0 0/.2),transparent 46%,oklch(0 0 0/.05));
|
|
48
|
+
mix-blend-mode: soft-light;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@supports not (backdrop-filter:blur(1px)) {
|
|
52
|
+
.ml-material-glass {
|
|
53
|
+
background: var(--ml-surface-elevated);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* Generated by @mlola-ui/engine. React and Tailwind are not required. */
|
|
2
|
+
@layer mlola.tokens, mlola.foundations, mlola.materials, mlola.recipes, mlola.motion, mlola.accessibility;
|
|
3
|
+
@import "./tokens.css" layer(mlola.tokens);
|
|
4
|
+
/* The project theme is a token source too, imported last within the same
|
|
5
|
+
layer so a brand wins over every canonical theme. */
|
|
6
|
+
@import "./theme.css" layer(mlola.tokens);
|
|
7
|
+
@import "./foundations.css" layer(mlola.foundations);
|
|
8
|
+
@import "./materials.css" layer(mlola.materials);
|
|
9
|
+
@import "./recipes.css" layer(mlola.recipes);
|
|
10
|
+
@import "./motion.css" layer(mlola.motion);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* Motion and accessibility layer. */
|
|
2
|
+
@keyframes ml-spin { to{transform:rotate(360deg)} }
|
|
3
|
+
|
|
4
|
+
@keyframes ml-pulse { 50%{opacity:.5} }
|
|
5
|
+
|
|
6
|
+
@keyframes ml-fade-in { from{opacity:0}to{opacity:1} }
|
|
7
|
+
|
|
8
|
+
@keyframes ml-pop-in { from{opacity:0;transform:translateY(4px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)} }
|
|
9
|
+
|
|
10
|
+
@keyframes ml-dialog-in { from{opacity:0;transform:translate(-50%,-48%) scale(.96)}to{opacity:1;transform:translate(-50%,-50%) scale(1)} }
|
|
11
|
+
|
|
12
|
+
@keyframes ml-toast-in { from{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)} }
|
|
13
|
+
|
|
14
|
+
@keyframes ml-slide-left { from{transform:translateX(100%)}to{transform:translateX(0)} }
|
|
15
|
+
|
|
16
|
+
@keyframes ml-slide-right { from{transform:translateX(-100%)}to{transform:translateX(0)} }
|
|
17
|
+
|
|
18
|
+
@keyframes ml-slide-up { from{transform:translateY(100%)}to{transform:translateY(0)} }
|
|
19
|
+
|
|
20
|
+
@keyframes ml-slide-down { from{transform:translateY(-100%)}to{transform:translateY(0)} }
|
|
21
|
+
|
|
22
|
+
/* An overlay panel entering from wherever it sits: the element sets
|
|
23
|
+
--ml-enter-from to the transform it starts at. */
|
|
24
|
+
@keyframes ml-panel-in { from{opacity:0;transform:var(--ml-enter-from)} }
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@keyframes ml-shimmer { from{background-position:200% center}to{background-position:-200% center} }
|
|
29
|
+
|
|
30
|
+
.ml-animate-pop {
|
|
31
|
+
animation: ml-pop-in var(--ml-duration-normal) var(--ml-ease-bounce) both;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.ml-animate-slide-left {
|
|
35
|
+
animation: ml-slide-left var(--ml-duration-normal) var(--ml-ease-spring) both;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ml-text-shimmer {
|
|
39
|
+
color: var(--ml-primary-text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@supports ((-webkit-background-clip:text) or (background-clip:text)) {
|
|
43
|
+
.ml-text-shimmer {
|
|
44
|
+
background: linear-gradient(90deg,var(--ml-text),var(--ml-primary),var(--ml-text));
|
|
45
|
+
background-size: 200% auto;
|
|
46
|
+
background-clip: text;
|
|
47
|
+
-webkit-background-clip: text;
|
|
48
|
+
color: transparent;
|
|
49
|
+
-webkit-text-fill-color: transparent;
|
|
50
|
+
animation: ml-shimmer 3s ease-in-out infinite;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Glyph motion: an animated glyph draws itself, stroke by stroke, and its
|
|
55
|
+
filled details fade in after. It runs once when a glyph becomes active
|
|
56
|
+
(a check on success, a bell on a new alert) and never while idle. Shapes
|
|
57
|
+
carry pathLength="1", so one dash length fits every stroke. */
|
|
58
|
+
@keyframes mlola-glyph-draw { from{stroke-dashoffset:1} }
|
|
59
|
+
|
|
60
|
+
@keyframes mlola-glyph-fill { from{opacity:0} }
|
|
61
|
+
|
|
62
|
+
.mlola-glyph[data-animated] > * {
|
|
63
|
+
stroke-dasharray: 1 1;
|
|
64
|
+
animation: mlola-glyph-draw var(--ml-duration-slow) var(--ml-ease-standard) both;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.mlola-glyph[data-animated] > *:nth-child(2) { animation-delay: 60ms; }
|
|
68
|
+
|
|
69
|
+
.mlola-glyph[data-animated] > *:nth-child(3) { animation-delay: 120ms; }
|
|
70
|
+
|
|
71
|
+
.mlola-glyph[data-animated] > *:nth-child(n+4) { animation-delay: 180ms; }
|
|
72
|
+
|
|
73
|
+
.mlola-glyph[data-animated] > [fill="currentColor"] {
|
|
74
|
+
stroke-dasharray: none;
|
|
75
|
+
animation-name: mlola-glyph-fill;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media (prefers-reduced-motion:reduce) {
|
|
79
|
+
html {
|
|
80
|
+
scroll-behavior: auto;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
*,
|
|
84
|
+
*::before,
|
|
85
|
+
*::after {
|
|
86
|
+
animation-delay: 0s!important;
|
|
87
|
+
animation-duration: .01ms!important;
|
|
88
|
+
animation-iteration-count: 1!important;
|
|
89
|
+
scroll-behavior: auto!important;
|
|
90
|
+
transition-delay: 0s!important;
|
|
91
|
+
transition-duration: .01ms!important;
|
|
92
|
+
}
|
|
93
|
+
}
|