@ksmv/ui-checks 0.31.0 → 0.33.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/CHANGELOG.md +10 -0
- package/dist/contrast-contract.json +52 -2
- package/dist/rules/nativeDate.js +23 -14
- package/dist/rules/overrideCatalog.js +1 -1
- package/dist/theme-contract.json +16 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.33.0 - 2026-11-01
|
|
4
|
+
|
|
5
|
+
- **Contratos:** tema `3.14.0` e contraste `22.0.0`, de 661 para 685 pares, para o `SideNav` da 0.33.0 (#652, #653). O ícone de aviso passa a ser medido em `--ui-side-nav-warning-icon`, e todo par novo mede um token da própria peça, que o tema pode declarar sem mudar o resto do app. **Quem tem tema próprio mede de novo.**
|
|
6
|
+
|
|
7
|
+
## 0.32.0 - 2026-11-01
|
|
8
|
+
|
|
9
|
+
- **Regra `components/native-date`** (#643). Vale o último atributo que escreve o `type`, inclusive num spread literal aninhado: `type="date" {...{ type: "text" }}` não acusa mais, e um `{ type }` abreviado conta como valor desconhecido.
|
|
10
|
+
- **`h-lh` livre na `Surface`** (#643), como as outras alturas.
|
|
11
|
+
- **Contratos:** tema `3.13.0` e contraste `21.0.0`, com 26 pares novos, para o `SideNav` da 0.32.0. **Quem tem tema próprio mede de novo.**
|
|
12
|
+
|
|
3
13
|
## 0.31.0 - 2026-10-31
|
|
4
14
|
|
|
5
15
|
- **Regra opcional `components/native-date`** (#634). `components.nativeDates: true` recusa `type="date"` e `type="datetime-local"` literais em JSX. Fica desligada por padrão, até cada app ligar.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"contractVersion": "
|
|
2
|
+
"contractVersion": "22.0.0",
|
|
3
3
|
"schemaVersion": 3,
|
|
4
4
|
"pairs": [
|
|
5
5
|
{ "foreground": "--ui-action-primary-text", "background": "--ui-action-primary-bg", "minimum": 4.5, "context": "normal-text" },
|
|
@@ -636,6 +636,56 @@
|
|
|
636
636
|
{ "foreground": "--ui-button-pressed-bg", "background": "--ui-surface-chrome", "minimum": 3, "context": "button-pressed-boundary-chrome" },
|
|
637
637
|
{ "foreground": "--ui-button-pressed-bg-hover", "background": "--ui-surface-chrome", "minimum": 3, "context": "button-pressed-boundary-hover-chrome" },
|
|
638
638
|
{ "foreground": "--ui-action-secondary-border", "background": "--ui-surface-chrome", "minimum": 3, "context": "action-secondary-boundary-chrome" },
|
|
639
|
-
{ "foreground": "--ui-side-nav-count-text", "background": "--ui-side-nav-count-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-count-text-chrome" }
|
|
639
|
+
{ "foreground": "--ui-side-nav-count-text", "background": "--ui-side-nav-count-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-count-text-chrome" },
|
|
640
|
+
{ "foreground": "--ui-side-nav-danger-text", "background": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-danger-detail-chrome" },
|
|
641
|
+
{ "foreground": "--ui-side-nav-danger-text", "background": "--ui-action-ghost-bg-hover", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-danger-detail-hover-chrome" },
|
|
642
|
+
{ "foreground": "--ui-side-nav-danger-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-danger-detail-row" },
|
|
643
|
+
{ "foreground": "--ui-side-nav-warning-text", "background": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-warning-detail-chrome" },
|
|
644
|
+
{ "foreground": "--ui-side-nav-warning-text", "background": "--ui-action-ghost-bg-hover", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-warning-detail-hover-chrome" },
|
|
645
|
+
{ "foreground": "--ui-side-nav-warning-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-warning-detail-row" },
|
|
646
|
+
{ "foreground": "--ui-side-nav-warning-icon", "background": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-warning-icon-chrome" },
|
|
647
|
+
{ "foreground": "--ui-side-nav-warning-icon", "background": "--ui-action-ghost-bg-hover", "over": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-warning-icon-hover-chrome" },
|
|
648
|
+
{ "foreground": "--ui-side-nav-warning-icon", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-warning-icon-row" },
|
|
649
|
+
{ "foreground": "--ui-action-ghost-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-row-ghost" },
|
|
650
|
+
{ "foreground": "--ui-text-primary", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-row-primary" },
|
|
651
|
+
{ "foreground": "--ui-text-secondary", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-row-secondary" },
|
|
652
|
+
{ "foreground": "--ui-text-button-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-row-text-button" },
|
|
653
|
+
{ "foreground": "--ui-text-button-muted-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-row-text-button-muted" },
|
|
654
|
+
{ "foreground": "--ui-action-ghost-text-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 4.5, "context": "side-nav-row-ghost-on-inverse" },
|
|
655
|
+
{ "foreground": "--ui-action-ghost-text-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 4.5, "context": "side-nav-row-ghost-on-inverse-end" },
|
|
656
|
+
{ "foreground": "--ui-text-primary-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 4.5, "context": "side-nav-row-primary-on-inverse" },
|
|
657
|
+
{ "foreground": "--ui-text-primary-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 4.5, "context": "side-nav-row-primary-on-inverse-end" },
|
|
658
|
+
{ "foreground": "--ui-text-secondary-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 4.5, "context": "side-nav-row-secondary-on-inverse" },
|
|
659
|
+
{ "foreground": "--ui-text-secondary-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 4.5, "context": "side-nav-row-secondary-on-inverse-end" },
|
|
660
|
+
{ "foreground": "--ui-text-button-text-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 4.5, "context": "side-nav-row-text-button-on-inverse" },
|
|
661
|
+
{ "foreground": "--ui-text-button-text-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 4.5, "context": "side-nav-row-text-button-on-inverse-end" },
|
|
662
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-danger-on-inverse" },
|
|
663
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-danger-on-inverse-end" },
|
|
664
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-warning-on-inverse" },
|
|
665
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-warning-on-inverse-end" },
|
|
666
|
+
{ "foreground": "--ui-side-nav-icon", "background": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-icon-chrome" },
|
|
667
|
+
{ "foreground": "--ui-side-nav-icon-hover", "background": "--ui-action-ghost-bg-hover", "over": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-icon-hover-chrome" },
|
|
668
|
+
{ "foreground": "--ui-side-nav-icon", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-icon-row" },
|
|
669
|
+
{ "foreground": "--ui-side-nav-icon-hover", "background": "--ui-action-ghost-bg-hover", "over": "--ui-side-nav-row-bg", "minimum": 3, "context": "side-nav-icon-tile" },
|
|
670
|
+
{ "foreground": "--ui-side-nav-success-text", "background": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-success-chrome" },
|
|
671
|
+
{ "foreground": "--ui-side-nav-success-text", "background": "--ui-action-ghost-bg-hover", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-success-hover-chrome" },
|
|
672
|
+
{ "foreground": "--ui-side-nav-success-text", "background": "--ui-side-nav-row-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-success-row" },
|
|
673
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-success-on-inverse" },
|
|
674
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-side-nav-row-bg-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-success-on-inverse-end" },
|
|
675
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-success-hover-on-inverse" },
|
|
676
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-success-hover-on-inverse-end" },
|
|
677
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-warning-hover-on-inverse" },
|
|
678
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-warning-hover-on-inverse-end" },
|
|
679
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-danger-hover-on-inverse" },
|
|
680
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-action-ghost-bg-hover-on-inverse", "over": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-danger-hover-on-inverse-end" },
|
|
681
|
+
{ "foreground": "--ui-side-nav-current-text", "background": "--ui-side-nav-current-bg", "over": "--ui-surface-chrome", "minimum": 4.5, "context": "side-nav-current-text" },
|
|
682
|
+
{ "foreground": "--ui-side-nav-current-border", "background": "--ui-surface", "minimum": 3, "context": "side-nav-current-border" },
|
|
683
|
+
{ "foreground": "--ui-side-nav-current-border", "background": "--ui-surface-chrome", "minimum": 3, "context": "side-nav-current-border-chrome" },
|
|
684
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-success-rest-on-inverse" },
|
|
685
|
+
{ "foreground": "--ui-side-nav-success-on-inverse", "background": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-success-rest-on-inverse-end" },
|
|
686
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-warning-rest-on-inverse" },
|
|
687
|
+
{ "foreground": "--ui-side-nav-warning-on-inverse", "background": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-warning-rest-on-inverse-end" },
|
|
688
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-surface-inverse", "minimum": 3, "context": "side-nav-row-danger-rest-on-inverse" },
|
|
689
|
+
{ "foreground": "--ui-side-nav-danger-on-inverse", "background": "--ui-surface-inverse-end", "minimum": 3, "context": "side-nav-row-danger-rest-on-inverse-end" }
|
|
640
690
|
]
|
|
641
691
|
}
|
package/dist/rules/nativeDate.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isJsxAttribute, isJsxExpression, isJsxOpeningElement, isJsxSelfClosingElement, isJsxSpreadAttribute, isObjectLiteralExpression, isPropertyAssignment, isStringLiteralLikeNode, } from "typescript/unstable/ast";
|
|
1
|
+
import { isJsxAttribute, isJsxExpression, isJsxOpeningElement, isJsxSelfClosingElement, isJsxSpreadAttribute, isObjectLiteralExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isStringLiteralLikeNode, } from "typescript/unstable/ast";
|
|
2
2
|
import { propertyKey, unwrapTypeWrappers } from "./componentOverride.js";
|
|
3
3
|
const nativeDateTypes = new Set(["date", "datetime-local"]);
|
|
4
4
|
function literalOf(initializer) {
|
|
@@ -6,6 +6,20 @@ function literalOf(initializer) {
|
|
|
6
6
|
const written = expression && unwrapTypeWrappers(expression);
|
|
7
7
|
return written && isStringLiteralLikeNode(written) ? written.text : undefined;
|
|
8
8
|
}
|
|
9
|
+
// What a literal object writes to the type, in order: the last key or nested
|
|
10
|
+
// literal spread that writes it is the one that holds.
|
|
11
|
+
function typeWrittenByObject(object) {
|
|
12
|
+
return [...object.properties].reduce((written, property) => {
|
|
13
|
+
if (isPropertyAssignment(property) && propertyKey(property.name) === "type")
|
|
14
|
+
return literalOf(property.initializer) ?? "";
|
|
15
|
+
// A shorthand { type } is a variable, which the rule does not read.
|
|
16
|
+
if (isShorthandPropertyAssignment(property) && propertyKey(property.name) === "type")
|
|
17
|
+
return "";
|
|
18
|
+
if (isSpreadAssignment(property) && isObjectLiteralExpression(property.expression))
|
|
19
|
+
return typeWrittenByObject(property.expression) ?? written;
|
|
20
|
+
return written;
|
|
21
|
+
}, undefined);
|
|
22
|
+
}
|
|
9
23
|
// The native date fields follow the machine's language, so the same screen
|
|
10
24
|
// shows mm/dd on one and dd/mm on another: the house's are DateInput, and the
|
|
11
25
|
// formatters for text. Optional, since an app turns it on when its fields have
|
|
@@ -20,24 +34,19 @@ export function createNativeDateRule() {
|
|
|
20
34
|
const sourceFile = file.sourceFile;
|
|
21
35
|
if (!sourceFile)
|
|
22
36
|
return result;
|
|
23
|
-
|
|
37
|
+
// What an attribute writes to the type: nothing, a literal, or a value
|
|
38
|
+
// the rule cannot read (""), which takes the place of an earlier literal.
|
|
39
|
+
const typeWrittenBy = (attribute) => {
|
|
24
40
|
if (isJsxAttribute(attribute)) {
|
|
25
|
-
return attribute.name.getText(sourceFile) === "type" ? literalOf(attribute.initializer) : undefined;
|
|
41
|
+
return attribute.name.getText(sourceFile) === "type" ? (literalOf(attribute.initializer) ?? "") : undefined;
|
|
26
42
|
}
|
|
27
|
-
|
|
28
|
-
return undefined;
|
|
29
|
-
// The last key is the one that holds.
|
|
30
|
-
const property = [...attribute.expression.properties]
|
|
31
|
-
.reverse()
|
|
32
|
-
.find((entry) => isPropertyAssignment(entry) && propertyKey(entry.name) === "type");
|
|
33
|
-
return property && isPropertyAssignment(property) ? literalOf(property.initializer) : undefined;
|
|
43
|
+
return isJsxSpreadAttribute(attribute) && isObjectLiteralExpression(attribute.expression) ? typeWrittenByObject(attribute.expression) : undefined;
|
|
34
44
|
};
|
|
35
45
|
const visit = (node) => {
|
|
36
46
|
if (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
continue;
|
|
47
|
+
// As in JSX, the last attribute that writes the type is the one that holds.
|
|
48
|
+
const type = node.attributes.properties.reduce((written, attribute) => typeWrittenBy(attribute) ?? written, undefined)?.toLowerCase();
|
|
49
|
+
if (type !== undefined && nativeDateTypes.has(type)) {
|
|
41
50
|
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
42
51
|
result.violations.push({
|
|
43
52
|
anchor: `${node.tagName.getText(sourceFile)}|${type}`,
|
|
@@ -89,7 +89,7 @@ const arrangementUtilities = [
|
|
|
89
89
|
export const arrangingComponents = new Set(["Card", "Surface"]);
|
|
90
90
|
// The Surface's own height, for a panel or a frame that fills its room
|
|
91
91
|
// (0.31.0, a request of the conselhos).
|
|
92
|
-
const surfaceHeight = new RegExp(`^h-(?:${num}|${frac}|px|auto|full|screen|svh|lvh|dvh|min|max|fit|${arb})$`, "u");
|
|
92
|
+
const surfaceHeight = new RegExp(`^h-(?:${num}|${frac}|px|auto|full|screen|svh|lvh|dvh|lh|min|max|fit|${arb})$`, "u");
|
|
93
93
|
export function classifyClass(token, component) {
|
|
94
94
|
const utility = utilityOf(token);
|
|
95
95
|
if (freeUtilities.some((pattern) => pattern.test(utility)))
|
package/dist/theme-contract.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"contractVersion": "3.
|
|
2
|
+
"contractVersion": "3.14.0",
|
|
3
3
|
"schemaVersion": 2,
|
|
4
4
|
"prefix": "--ui-",
|
|
5
5
|
"required": [
|
|
@@ -336,10 +336,24 @@
|
|
|
336
336
|
"--ui-steps-complete-bg": { "kind": "token", "token": "--ui-surface-subtle" },
|
|
337
337
|
"--ui-steps-track-filled": { "kind": "token", "token": "--ui-action-primary-bg" },
|
|
338
338
|
"--ui-steps-track-empty": { "kind": "token", "token": "--ui-border-control" },
|
|
339
|
-
"--ui-side-nav-count-bg": { "kind": "token", "token": "--ui-
|
|
339
|
+
"--ui-side-nav-count-bg": { "kind": "token", "token": "--ui-action-ghost-bg-hover" },
|
|
340
340
|
"--ui-side-nav-count-text": { "kind": "token", "token": "--ui-text-secondary" },
|
|
341
341
|
"--ui-side-nav-count-bg-on-inverse": { "kind": "literal", "value": "transparent" },
|
|
342
342
|
"--ui-side-nav-count-text-on-inverse": { "kind": "token", "token": "--ui-text-secondary-on-inverse" },
|
|
343
|
+
"--ui-side-nav-row-bg": { "kind": "token", "token": "--ui-surface" },
|
|
344
|
+
"--ui-side-nav-row-bg-on-inverse": { "kind": "token", "token": "--ui-surface-tile-bg" },
|
|
345
|
+
"--ui-side-nav-icon": { "kind": "token", "token": "--ui-action-ghost-text" },
|
|
346
|
+
"--ui-side-nav-icon-hover": { "kind": "token", "token": "--ui-action-ghost-text-hover" },
|
|
347
|
+
"--ui-side-nav-warning-icon": { "kind": "token", "token": "--ui-status-warning" },
|
|
348
|
+
"--ui-side-nav-success-text": { "kind": "token", "token": "--ui-status-success-text" },
|
|
349
|
+
"--ui-side-nav-warning-text": { "kind": "token", "token": "--ui-status-warning-text" },
|
|
350
|
+
"--ui-side-nav-danger-text": { "kind": "token", "token": "--ui-status-danger-text" },
|
|
351
|
+
"--ui-side-nav-success-on-inverse": { "kind": "token", "token": "--ui-status-success-on-inverse" },
|
|
352
|
+
"--ui-side-nav-warning-on-inverse": { "kind": "token", "token": "--ui-status-warning-on-inverse" },
|
|
353
|
+
"--ui-side-nav-danger-on-inverse": { "kind": "token", "token": "--ui-status-danger-on-inverse" },
|
|
354
|
+
"--ui-side-nav-current-bg": { "kind": "token", "token": "--ui-action-soft-accent-bg" },
|
|
355
|
+
"--ui-side-nav-current-text": { "kind": "token", "token": "--ui-action-soft-accent-text" },
|
|
356
|
+
"--ui-side-nav-current-border": { "kind": "token", "token": "--ui-action-soft-accent-border" },
|
|
343
357
|
"--ui-side-nav-count-dot": { "kind": "token", "token": "--ui-status-info" },
|
|
344
358
|
"--ui-side-nav-count-dot-ring": { "kind": "token", "token": "--ui-surface" },
|
|
345
359
|
"--ui-side-nav-count-dot-on-inverse": { "kind": "token", "token": "--ui-status-info-on-inverse" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ksmv/ui-checks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Static and computed quality checks for semantic UI token contracts.",
|
|
5
5
|
"keywords": ["accessibility", "design-tokens", "quality", "static-analysis"],
|
|
6
6
|
"license": "Apache-2.0",
|