@multiplatform.one/config 7.43.0 → 7.45.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/README.md +7 -2
- package/design-lint.mjs +44 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -143,8 +143,13 @@ the enclosing `Svg` has a `viewBox`, including one passed through a spread, or
|
|
|
143
143
|
when the mark is a fragment drawn into an `Svg` elsewhere. Primitives inside an
|
|
144
144
|
`Svg` with no `viewBox`, and the `Svg` element's own size, are still reported.
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
A `focusStyle`, `focusVisibleStyle` or `focusWithinStyle` that paints its own
|
|
147
|
+
outline, box shadow, shadow or elevation is reported as `field-focus`. Focus
|
|
148
|
+
looks come from MPO: fields take `FIELD_FOCUS_STYLE` (the accent border), other
|
|
149
|
+
controls the theme's focus ring. Zeroing those keys is allowed.
|
|
150
|
+
|
|
151
|
+
Every violation is tagged with its rule: `field-focus`, `hex`, `geometry`,
|
|
152
|
+
`inline-spacing`, `raw-control`, `styled-mpo` or `token-file`.
|
|
148
153
|
|
|
149
154
|
#### Ratchet
|
|
150
155
|
|
package/design-lint.mjs
CHANGED
|
@@ -51,6 +51,11 @@ const svgPrimitives = new Set([
|
|
|
51
51
|
"Use",
|
|
52
52
|
]);
|
|
53
53
|
const svgRoots = new Set(["Svg", "Symbol"]);
|
|
54
|
+
// FZ-7717: focus looks come from MPO (FIELD_FOCUS_STYLE / the control ring).
|
|
55
|
+
// A use site that paints its own focus ring or shadow forks the look.
|
|
56
|
+
const focusPaint =
|
|
57
|
+
/^(?:outline(?:Width|Color|Offset)?|boxShadow|shadow(?:Color|Opacity|Radius|Offset)|elevation)$/;
|
|
58
|
+
const focusStates = new Set(["focusStyle", "focusVisibleStyle", "focusWithinStyle"]);
|
|
54
59
|
const tokenFactories = new Set([
|
|
55
60
|
"createTokens",
|
|
56
61
|
"createTamagui",
|
|
@@ -59,6 +64,7 @@ const tokenFactories = new Set([
|
|
|
59
64
|
"createFont",
|
|
60
65
|
]);
|
|
61
66
|
export const designRules = [
|
|
67
|
+
"field-focus",
|
|
62
68
|
"hex",
|
|
63
69
|
"geometry",
|
|
64
70
|
"inline-spacing",
|
|
@@ -224,6 +230,42 @@ export function inspectDesign(source, filename, projectRoot = process.cwd()) {
|
|
|
224
230
|
return spacing(value.whenTrue) || spacing(value.whenFalse);
|
|
225
231
|
return false;
|
|
226
232
|
}
|
|
233
|
+
function inert(node) {
|
|
234
|
+
const value = resolve(node);
|
|
235
|
+
if (ts.isNumericLiteral(value)) return Number(value.text) === 0;
|
|
236
|
+
if (ts.isStringLiteralLike(value)) return /^(?:0(?:px)?|none|transparent)$/.test(value.text);
|
|
237
|
+
return value.kind === ts.SyntaxKind.UndefinedKeyword || value.getText(file) === "undefined";
|
|
238
|
+
}
|
|
239
|
+
function paintsFocus(node, seen = new Set()) {
|
|
240
|
+
const value = resolve(node);
|
|
241
|
+
if (seen.has(value)) return undefined;
|
|
242
|
+
seen.add(value);
|
|
243
|
+
if (ts.isConditionalExpression(value))
|
|
244
|
+
return paintsFocus(value.whenTrue, seen) ?? paintsFocus(value.whenFalse, seen);
|
|
245
|
+
if (!ts.isObjectLiteralExpression(value)) return undefined;
|
|
246
|
+
for (const prop of value.properties) {
|
|
247
|
+
if (ts.isSpreadAssignment(prop)) {
|
|
248
|
+
const inner = paintsFocus(prop.expression, seen);
|
|
249
|
+
if (inner) return inner;
|
|
250
|
+
} else if (
|
|
251
|
+
ts.isPropertyAssignment(prop) &&
|
|
252
|
+
focusPaint.test(name(prop.name)) &&
|
|
253
|
+
!inert(prop.initializer)
|
|
254
|
+
)
|
|
255
|
+
return prop;
|
|
256
|
+
}
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
function checkFocus(key, value, node) {
|
|
260
|
+
if (!focusStates.has(key)) return;
|
|
261
|
+
const painted = paintsFocus(value);
|
|
262
|
+
if (painted)
|
|
263
|
+
report(
|
|
264
|
+
node,
|
|
265
|
+
"field-focus",
|
|
266
|
+
`${key} paints its own ${name(painted.name)}; focus comes from MPO (FIELD_FOCUS_STYLE).`,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
227
269
|
function report(node, rule, message) {
|
|
228
270
|
const { line, character } = file.getLineAndCharacterOfPosition(node.getStart(file));
|
|
229
271
|
errors.push(`${filename}:${line + 1}:${character + 1}: [${rule}] ${message}`);
|
|
@@ -260,6 +302,7 @@ export function inspectDesign(source, filename, projectRoot = process.cwd()) {
|
|
|
260
302
|
: prop.initializer;
|
|
261
303
|
if (!initializer) return;
|
|
262
304
|
const key = name(prop.name);
|
|
305
|
+
checkFocus(key, initializer, prop);
|
|
263
306
|
if (layout.test(key) && numeric(initializer))
|
|
264
307
|
report(prop, "geometry", `${name(prop.name)} requires a token, not a numeric literal.`);
|
|
265
308
|
if (/style$/i.test(key) && spacing(initializer))
|
|
@@ -346,6 +389,7 @@ export function inspectDesign(source, filename, projectRoot = process.cwd()) {
|
|
|
346
389
|
const value = ts.isJsxExpression(node.initializer)
|
|
347
390
|
? node.initializer.expression
|
|
348
391
|
: node.initializer;
|
|
392
|
+
if (value) checkFocus(key, value, node);
|
|
349
393
|
if (value && (key.startsWith("$") || /style$/i.test(key))) inspectProps(value);
|
|
350
394
|
if (value && layout.test(key) && numeric(value) && !svgArtwork(node.parent.parent))
|
|
351
395
|
report(node, "geometry", `${key} requires a token, not a numeric literal.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/config",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.45.0",
|
|
4
4
|
"description": "Shared build and test configuration presets for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"config",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"access": "public"
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"@multiplatform.one/utils": "^7.
|
|
109
|
+
"@multiplatform.one/utils": "^7.45.0",
|
|
110
110
|
"@tamagui/vite-plugin": "2.7.6",
|
|
111
111
|
"@vitejs/plugin-react": "^6.1.2",
|
|
112
112
|
"dotenv": "^17.4.2",
|