@mlola-ui/engine 1.0.6 → 1.0.7
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/generated/agents.json +6 -2
- package/generated/agents.md +3 -3
- package/generated/assets.json +6 -6
- package/generated/recipes.css +6 -3
- package/generated/tokens.css +92 -47
- package/generated/tokens.json +659 -59
- package/package.json +1 -1
- package/src/declarations.mjs +3 -3
- package/src/palette.mjs +38 -11
- package/src/spec.mjs +5 -0
package/package.json
CHANGED
package/src/declarations.mjs
CHANGED
|
@@ -115,9 +115,9 @@ export function themeDeclarations(spec) {
|
|
|
115
115
|
*/
|
|
116
116
|
export const PALETTE_DERIVED = [
|
|
117
117
|
"--ml-focus: var(--ml-primary-text)",
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
118
|
+
// Neutral hover and pressed fills are the ink at low strength. A colored
|
|
119
|
+
// fill's hover (--ml-primary-hover, --ml-danger-hover…) is solved in the
|
|
120
|
+
// palette, so hovering never costs its label contrast.
|
|
121
121
|
"--ml-fill-hover: color-mix(in oklab, var(--ml-text) 5%, transparent)",
|
|
122
122
|
"--ml-fill-active: color-mix(in oklab, var(--ml-text) 9%, transparent)",
|
|
123
123
|
// A soft, translucent track for switches, meters and sliders that stays
|
package/src/palette.mjs
CHANGED
|
@@ -124,6 +124,19 @@ function neutralsDark(spec) {
|
|
|
124
124
|
|
|
125
125
|
const isAchromatic = (color) => color.C < 0.03;
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* WCAG 2's ratio favours dark ink on mid-tone saturated colors, but eyes read
|
|
129
|
+
* white on a violet, blue, green or red far better. In light mode a chromatic,
|
|
130
|
+
* non-warm fill darkens a little (at most 0.12 L) so white clears the target;
|
|
131
|
+
* yellows and oranges keep dark ink, as convention expects.
|
|
132
|
+
*/
|
|
133
|
+
function deepenForWhite(fill, mode) {
|
|
134
|
+
const warm = fill.H > 40 && fill.H < 130;
|
|
135
|
+
if (mode !== "light" || isAchromatic(fill) || warm || contrast(WHITE, fill) >= TARGETS.body) return fill;
|
|
136
|
+
const deeper = solveLightness(fill, WHITE, TARGETS.body, "darker");
|
|
137
|
+
return fill.L - deeper.L <= 0.12 ? deeper : fill;
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
function primaryFor(spec, mode, neutrals) {
|
|
128
141
|
const seedText = mode === "dark" ? spec.color.primaryDark ?? spec.color.primary : spec.color.primary;
|
|
129
142
|
const seed = parseColor(seedText) ?? { L: 0.21, C: 0.006, H: 286 };
|
|
@@ -140,17 +153,12 @@ function primaryFor(spec, mode, neutrals) {
|
|
|
140
153
|
if (contrast(fill, neutrals.background) < TARGETS.separation) {
|
|
141
154
|
fill = solveLightness(fill, neutrals.background, TARGETS.separation, mode === "light" ? "darker" : "lighter");
|
|
142
155
|
}
|
|
143
|
-
|
|
144
|
-
// white on a violet, blue or red far better. In light mode a chromatic,
|
|
145
|
-
// non-warm brand darkens a little (at most 0.12 L) so white clears the
|
|
146
|
-
// target; yellows and oranges keep dark ink, as convention expects.
|
|
147
|
-
const warm = fill.H > 40 && fill.H < 130;
|
|
148
|
-
if (mode === "light" && !isAchromatic(fill) && !warm && contrast(WHITE, fill) < TARGETS.body) {
|
|
149
|
-
const deeper = solveLightness(fill, WHITE, TARGETS.body, "darker");
|
|
150
|
-
if (fill.L - deeper.L <= 0.12) fill = deeper;
|
|
151
|
-
}
|
|
156
|
+
fill = deepenForWhite(fill, mode);
|
|
152
157
|
const pair = fillPair(fill, TARGETS.body, mode === "dark");
|
|
153
|
-
|
|
158
|
+
// Links and focus rings follow the brand. A monochrome brand inverted for
|
|
159
|
+
// the night reads as the inverted ink, not a mid gray lifted from the day's.
|
|
160
|
+
const textSeed = mode === "dark" && !spec.color.primaryDark && isAchromatic(seed) ? fill : seed;
|
|
161
|
+
const text = solveText({ L: textSeed.L, C: textSeed.C, H: textSeed.H }, neutrals, TARGETS.body, mode === "light" ? "darker" : "lighter");
|
|
154
162
|
const subtleChroma = isAchromatic(seed) ? Math.max(spec.color.neutral.chroma, 0.003) : Math.min(seed.C * 0.35, 0.06);
|
|
155
163
|
const subtle = mode === "light"
|
|
156
164
|
? { L: neutrals.subtle.L + 0.01, C: subtleChroma, H: seed.H }
|
|
@@ -160,7 +168,7 @@ function primaryFor(spec, mode, neutrals) {
|
|
|
160
168
|
|
|
161
169
|
function statusFor(name, mode, neutrals) {
|
|
162
170
|
const { H, C, light, dark } = STATUS[name];
|
|
163
|
-
const start = { L: mode === "light" ? light : dark, C, H };
|
|
171
|
+
const start = deepenForWhite({ L: mode === "light" ? light : dark, C, H }, mode);
|
|
164
172
|
const pair = fillPair(start, TARGETS.body, mode === "dark" || name === "warning");
|
|
165
173
|
const text = solveText(
|
|
166
174
|
{ L: mode === "light" ? Math.min(light, 0.55) : Math.max(dark, 0.72), C, H },
|
|
@@ -202,6 +210,18 @@ function chartPalette(spec, mode, neutrals) {
|
|
|
202
210
|
});
|
|
203
211
|
}
|
|
204
212
|
|
|
213
|
+
/**
|
|
214
|
+
* The fill under a pointer. It moves a little toward the page, as a hover
|
|
215
|
+
* does, unless that would cost its label contrast; then it moves away from
|
|
216
|
+
* the label instead. Either way hovering never drops below the target.
|
|
217
|
+
*/
|
|
218
|
+
function hoverFor(fill, foreground, neutrals) {
|
|
219
|
+
const toward = { L: fill.L + (neutrals.background.L - fill.L) * 0.12, C: fill.C * 0.88, H: fill.H };
|
|
220
|
+
if (contrast(foreground, toward) >= TARGETS.body) return toward;
|
|
221
|
+
const away = foreground.L > fill.L ? -0.05 : 0.05;
|
|
222
|
+
return solveLightness({ L: Math.min(1, Math.max(0, fill.L + away)), C: fill.C, H: fill.H }, foreground, TARGETS.body, away < 0 ? "darker" : "lighter");
|
|
223
|
+
}
|
|
224
|
+
|
|
205
225
|
/** Every palette token for one mode, as serialised OKLCH strings. */
|
|
206
226
|
export function derivePalette(spec, mode = "light") {
|
|
207
227
|
const neutrals = mode === "dark" ? neutralsDark(spec) : neutralsLight(spec);
|
|
@@ -218,6 +238,7 @@ export function derivePalette(spec, mode = "light") {
|
|
|
218
238
|
"border-subtle": neutrals.borderSubtle,
|
|
219
239
|
primary: primary.primary,
|
|
220
240
|
"primary-foreground": primary.foreground,
|
|
241
|
+
"primary-hover": hoverFor(primary.primary, primary.foreground, neutrals),
|
|
221
242
|
"primary-text": primary.text,
|
|
222
243
|
"primary-subtle": primary.subtle,
|
|
223
244
|
};
|
|
@@ -225,6 +246,7 @@ export function derivePalette(spec, mode = "light") {
|
|
|
225
246
|
const status = statusFor(name, mode, neutrals);
|
|
226
247
|
palette[name] = status.fill;
|
|
227
248
|
palette[`${name}-foreground`] = status.foreground;
|
|
249
|
+
palette[`${name}-hover`] = hoverFor(status.fill, status.foreground, neutrals);
|
|
228
250
|
palette[`${name}-text`] = status.text;
|
|
229
251
|
}
|
|
230
252
|
chartPalette(spec, mode, neutrals).forEach((color, index) => {
|
|
@@ -259,6 +281,11 @@ export const GUARANTEED_PAIRS = [
|
|
|
259
281
|
["primary-text", "background", 4.5],
|
|
260
282
|
["primary-text", "surface", 4.5],
|
|
261
283
|
["primary-foreground", "primary", 4.5],
|
|
284
|
+
["primary-foreground", "primary-hover", 4.5],
|
|
285
|
+
["success-foreground", "success-hover", 4.5],
|
|
286
|
+
["warning-foreground", "warning-hover", 4.5],
|
|
287
|
+
["danger-foreground", "danger-hover", 4.5],
|
|
288
|
+
["info-foreground", "info-hover", 4.5],
|
|
262
289
|
["success-foreground", "success", 4.5],
|
|
263
290
|
["warning-foreground", "warning", 4.5],
|
|
264
291
|
["danger-foreground", "danger", 4.5],
|
package/src/spec.mjs
CHANGED
|
@@ -104,19 +104,24 @@ export const PALETTE_TOKENS = [
|
|
|
104
104
|
"border-subtle",
|
|
105
105
|
"primary",
|
|
106
106
|
"primary-foreground",
|
|
107
|
+
"primary-hover",
|
|
107
108
|
"primary-text",
|
|
108
109
|
"primary-subtle",
|
|
109
110
|
"success",
|
|
110
111
|
"success-foreground",
|
|
112
|
+
"success-hover",
|
|
111
113
|
"success-text",
|
|
112
114
|
"warning",
|
|
113
115
|
"warning-foreground",
|
|
116
|
+
"warning-hover",
|
|
114
117
|
"warning-text",
|
|
115
118
|
"danger",
|
|
116
119
|
"danger-foreground",
|
|
120
|
+
"danger-hover",
|
|
117
121
|
"danger-text",
|
|
118
122
|
"info",
|
|
119
123
|
"info-foreground",
|
|
124
|
+
"info-hover",
|
|
120
125
|
"info-text",
|
|
121
126
|
"chart-1",
|
|
122
127
|
"chart-2",
|