@assure-one/design-system 1.34.0 → 1.36.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 +53 -0
- package/codemods/README.md +225 -10
- package/codemods/lib/jsx-edit.mjs +63 -4
- package/codemods/lib/registry.mjs +7 -0
- package/codemods/transforms/cm-04-button-variant-intent.mjs +223 -0
- package/codemods/transforms/cm-05-button-icon-slots.mjs +117 -0
- package/codemods/transforms/cm-06-tone-to-intent.mjs +190 -0
- package/codemods/transforms/cm-07-input-size.mjs +104 -0
- package/codemods/transforms/cm-08-search-select-to-combobox.mjs +236 -0
- package/codemods/transforms/cm-10-date-picker-value-change.mjs +416 -0
- package/codemods/transforms/cm-14-hidden-mirrors.mjs +2 -2
- package/codemods/transforms/cm-19-progress-explicit-intent.mjs +192 -0
- package/dist/css/components.css +1 -1
- package/dist/css/legacy-aliases.css +5 -0
- package/dist/css/tokens.css +5 -0
- package/dist/design-system-provider-cPUklDJv.d.ts +220 -0
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.js +1833 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index-CQwzTm0v.d.ts +509 -0
- package/dist/index.d.ts +2967 -823
- package/dist/index.js +7644 -3062
- package/dist/index.js.map +1 -1
- package/dist/next/index.d.ts +20 -0
- package/dist/next/index.js +16 -0
- package/dist/next/index.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/testing/index.cjs +133 -11
- package/dist/testing/index.d.cts +98 -2
- package/dist/testing/index.d.ts +98 -2
- package/dist/testing/index.js +132 -12
- package/docs/components.md +601 -0
- package/docs/components.registry.json +1586 -0
- package/docs/for-ai-agents.md +153 -0
- package/package.json +21 -3
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CM-19 — ProgressBar / ProgressRing: explicit `intent`, the value → colour
|
|
3
|
+
* rule written down (class R; plan §29 seq 7, registry `C-PROGRESS`).
|
|
4
|
+
*
|
|
5
|
+
* The two meters colour themselves **by value** when no colour is passed
|
|
6
|
+
* (`< 50%` brand, `≥ 50%` warning, `≥ 80%` success) — a business mapping the
|
|
7
|
+
* design system should not own (Tax lists it as a gotcha), which 2.0 switches
|
|
8
|
+
* off (W9-10). W3-21 added `intent` to the family; passing it disables the
|
|
9
|
+
* rule. CM-19 makes every call site say what it renders today, so the flip
|
|
10
|
+
* changes nothing a consumer did not write down:
|
|
11
|
+
*
|
|
12
|
+
* - `variant="<legacy word>"` becomes `intent="<the same colour>"`
|
|
13
|
+
* (`default` → `brand`, `destructive` → `danger`, the rest keep their name);
|
|
14
|
+
* - a meter with no colour and a **literal** `value` (and literal or absent
|
|
15
|
+
* `max`) gets the `intent` the rule picks for that value — the auto-colour
|
|
16
|
+
* result, preserved and now visible;
|
|
17
|
+
* - `value={null}` (indeterminate `ProgressBar`) gets `intent="brand"`.
|
|
18
|
+
*
|
|
19
|
+
* The rename to the unified `Progress variant="bar" | "ring"` of target
|
|
20
|
+
* architecture §26 is the second half of this codemod and lands with that
|
|
21
|
+
* component; today's edit is what makes it a pure rename later.
|
|
22
|
+
*
|
|
23
|
+
* ## What it reports
|
|
24
|
+
*
|
|
25
|
+
* | rule | action | severity | why |
|
|
26
|
+
* | --------------------------- | ------- | -------- | ---------------------------------------------------------------------- |
|
|
27
|
+
* | `variant-renamed` | applied | low | the colour word moved to the `intent` axis |
|
|
28
|
+
* | `auto-colour-made-explicit` | applied | medium | the intent the rule picked for a literal value is now written down — a human confirms that colour was the point, not the number |
|
|
29
|
+
* | `indeterminate-brand` | applied | low | an indeterminate track was always brand |
|
|
30
|
+
* | `dynamic-value` | review | high | no colour and `value={expr}`: the colour depends on runtime data, which is business logic (plan §29 never automates it) |
|
|
31
|
+
* | `dynamic-variant` | review | high | `variant={expr}`: map the expression's values by hand |
|
|
32
|
+
* | `spread-props` | review | medium | `{...props}` may carry `variant`, `intent` or `value` |
|
|
33
|
+
* | `unknown-variant` | review | high | a word the component never accepted |
|
|
34
|
+
*
|
|
35
|
+
* `SegmentedProgress` and `SuiteProgress` have no value → colour rule; their
|
|
36
|
+
* `tone` moves to `intent` through CM-06. Elements that already pass `intent`
|
|
37
|
+
* are not touched (idempotency); local components with the same names and
|
|
38
|
+
* test files are skipped.
|
|
39
|
+
*/
|
|
40
|
+
import { analyseForms } from "../lib/forms.mjs";
|
|
41
|
+
import {
|
|
42
|
+
applyEdits,
|
|
43
|
+
attributeNamed,
|
|
44
|
+
insertAttribute,
|
|
45
|
+
openingOf,
|
|
46
|
+
replaceAttribute,
|
|
47
|
+
} from "../lib/jsx-edit.mjs";
|
|
48
|
+
|
|
49
|
+
export const meta = {
|
|
50
|
+
id: "CM-19",
|
|
51
|
+
title: "ProgressBar/ProgressRing: explicit intent, auto-colour written down",
|
|
52
|
+
class: "R",
|
|
53
|
+
oneShot: false,
|
|
54
|
+
requires: { codemods: [], dsVersion: null },
|
|
55
|
+
parses: ["code"],
|
|
56
|
+
includeTests: false,
|
|
57
|
+
usesTypeScript: true,
|
|
58
|
+
usesPostcss: false,
|
|
59
|
+
registryIds: ["C-PROGRESS"],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** The meters that colour by value (src/primitives/progress-{bar,ring}.tsx). */
|
|
63
|
+
export const AUTO_COLOURED = new Set(["ProgressBar", "ProgressRing"]);
|
|
64
|
+
|
|
65
|
+
/** `variant` → `intent` (src/foundation/progress-intent.ts `PROGRESS_LEGACY_TO_INTENT`). */
|
|
66
|
+
export const VARIANT_MAP = {
|
|
67
|
+
default: "brand",
|
|
68
|
+
success: "success",
|
|
69
|
+
warning: "warning",
|
|
70
|
+
destructive: "danger",
|
|
71
|
+
info: "info",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** The default `max` of both meters. */
|
|
75
|
+
export const DEFAULT_MAX = 100;
|
|
76
|
+
|
|
77
|
+
/** The intent the value rule picks (src/foundation/progress-intent.ts `autoProgressIntent`). */
|
|
78
|
+
export function autoIntent(value, max = DEFAULT_MAX) {
|
|
79
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
80
|
+
return percentage >= 80 ? "success" : percentage >= 50 ? "warning" : "brand";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The number a JSX attribute passes, when it is a literal: `value={42}`,
|
|
85
|
+
* `value={-1}`, `value={1.5}`. `null` for `value={null}`, `undefined` for
|
|
86
|
+
* anything else (an expression, a missing attribute, a string).
|
|
87
|
+
*/
|
|
88
|
+
export function literalNumber(ts, attr) {
|
|
89
|
+
if (!attr) return undefined;
|
|
90
|
+
const init = attr.initializer;
|
|
91
|
+
if (!init || !ts.isJsxExpression(init) || !init.expression) return undefined;
|
|
92
|
+
let expr = init.expression;
|
|
93
|
+
while (ts.isParenthesizedExpression(expr)) expr = expr.expression;
|
|
94
|
+
if (expr.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
95
|
+
if (ts.isNumericLiteral(expr)) return Number(expr.text);
|
|
96
|
+
if (
|
|
97
|
+
ts.isPrefixUnaryExpression(expr) &&
|
|
98
|
+
expr.operator === ts.SyntaxKind.MinusToken &&
|
|
99
|
+
ts.isNumericLiteral(expr.operand)
|
|
100
|
+
) {
|
|
101
|
+
return -Number(expr.operand.text);
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function transform(file, { ts }) {
|
|
107
|
+
const facts = analyseForms(ts, file.source, file.rel);
|
|
108
|
+
const findings = [];
|
|
109
|
+
const edits = [];
|
|
110
|
+
|
|
111
|
+
for (const el of facts.elements) {
|
|
112
|
+
if (!el.isDs || !AUTO_COLOURED.has(el.base) || el.component !== el.base) continue;
|
|
113
|
+
if (el.props.has("intent")) continue;
|
|
114
|
+
|
|
115
|
+
const opening = openingOf(ts, el.node);
|
|
116
|
+
const variant = el.props.get("variant");
|
|
117
|
+
const base = {
|
|
118
|
+
line: el.line,
|
|
119
|
+
registryId: "C-PROGRESS",
|
|
120
|
+
match: `<${el.tag}>`,
|
|
121
|
+
component: el.component,
|
|
122
|
+
gate: null,
|
|
123
|
+
detail: {
|
|
124
|
+
variant: variant ? (variant.expression ? null : (variant.literals[0] ?? null)) : undefined,
|
|
125
|
+
value: undefined,
|
|
126
|
+
max: undefined,
|
|
127
|
+
intent: undefined,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
const review = (rule, severity, detail = {}) =>
|
|
131
|
+
findings.push({
|
|
132
|
+
...base,
|
|
133
|
+
rule,
|
|
134
|
+
severity,
|
|
135
|
+
action: "review",
|
|
136
|
+
detail: { ...base.detail, ...detail },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (el.spread) {
|
|
140
|
+
review("spread-props", "medium");
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (variant) {
|
|
145
|
+
if (variant.expression || variant.literals.length !== 1) {
|
|
146
|
+
review("dynamic-variant", "high");
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const intent = VARIANT_MAP[variant.literals[0]];
|
|
150
|
+
if (!intent) {
|
|
151
|
+
review("unknown-variant", "high");
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
edits.push(replaceAttribute(ts, facts.sf, opening, "variant", `intent="${intent}"`));
|
|
155
|
+
findings.push({
|
|
156
|
+
...base,
|
|
157
|
+
rule: "variant-renamed",
|
|
158
|
+
severity: "low",
|
|
159
|
+
action: "applied",
|
|
160
|
+
detail: { ...base.detail, intent },
|
|
161
|
+
});
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const value = literalNumber(ts, attributeNamed(ts, opening, "value"));
|
|
166
|
+
const maxAttr = attributeNamed(ts, opening, "max");
|
|
167
|
+
const max = maxAttr ? literalNumber(ts, maxAttr) : DEFAULT_MAX;
|
|
168
|
+
if (value === undefined || max === undefined || max === null) {
|
|
169
|
+
review("dynamic-value", "high", {
|
|
170
|
+
value: value === undefined ? null : value,
|
|
171
|
+
max: max ?? null,
|
|
172
|
+
});
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const intent = value === null ? "brand" : autoIntent(value, max);
|
|
176
|
+
edits.push(insertAttribute(ts, facts.sf, opening, `intent="${intent}"`, { after: "value" }));
|
|
177
|
+
findings.push({
|
|
178
|
+
...base,
|
|
179
|
+
rule: value === null ? "indeterminate-brand" : "auto-colour-made-explicit",
|
|
180
|
+
severity: value === null ? "low" : "medium",
|
|
181
|
+
action: "applied",
|
|
182
|
+
detail: { ...base.detail, value, max, intent },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
output: edits.length ? applyEdits(file.source, edits) : file.source,
|
|
188
|
+
findings,
|
|
189
|
+
notTransformed: [],
|
|
190
|
+
parseErrors: facts.parseErrors,
|
|
191
|
+
};
|
|
192
|
+
}
|