@radicool/throughline 0.22.0 → 0.24.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.
Files changed (52) hide show
  1. package/README.md +5 -5
  2. package/adapters/codex/prompts/component-builder.md +12 -4
  3. package/adapters/cursor/.cursor/rules/component-builder.mdc +12 -4
  4. package/adapters/generic/skills/component-builder/SKILL.md +12 -4
  5. package/package.json +1 -1
  6. package/references/figma-checks.md +813 -0
  7. package/references/figma-component-standards.md +16 -38
  8. package/references/figma-scripting.md +6 -6
  9. package/references/proof-bundle.md +1 -0
  10. package/references/state-baseline.md +5 -3
  11. package/scripts/README.md +5 -2
  12. package/scripts/build-figma-checks.mjs +111 -0
  13. package/scripts/build-state-baseline.mjs +5 -3
  14. package/scripts/install.mjs +9 -4
  15. package/scripts/lib/component-states.mjs +4 -1
  16. package/scripts/lib/contrast.mjs +5 -2
  17. package/scripts/lib/figma-checks-read.figma.js +174 -0
  18. package/scripts/lib/figma-checks.mjs +385 -0
  19. package/scripts/lib/fixtures/figma-checks/avatar-not-in-table.json +44 -0
  20. package/scripts/lib/fixtures/figma-checks/button-ios-swift-skipped.json +86 -0
  21. package/scripts/lib/fixtures/figma-checks/button-missing-default.json +72 -0
  22. package/scripts/lib/fixtures/figma-checks/button-mui-ring.json +93 -0
  23. package/scripts/lib/fixtures/figma-checks/button-no-focus-variant.json +72 -0
  24. package/scripts/lib/fixtures/figma-checks/button-plain-frames.json +93 -0
  25. package/scripts/lib/fixtures/figma-checks/button-ring-child-not-absolute.json +95 -0
  26. package/scripts/lib/fixtures/figma-checks/button-ring-hidden.json +93 -0
  27. package/scripts/lib/fixtures/figma-checks/button-ring-unbound-colour.json +99 -0
  28. package/scripts/lib/fixtures/figma-checks/button-shadcn-filled.json +93 -0
  29. package/scripts/lib/fixtures/figma-checks/button-sparse.json +135 -0
  30. package/scripts/lib/fixtures/figma-checks/button-spread-zero.json +93 -0
  31. package/scripts/lib/fixtures/figma-checks/button-transparent-ring-child.json +95 -0
  32. package/scripts/lib/fixtures/figma-checks/button-vanilla-inside.json +88 -0
  33. package/scripts/lib/fixtures/figma-checks/button-vanilla-outside.json +88 -0
  34. package/scripts/lib/fixtures/figma-checks/button-wrong-combination.json +93 -0
  35. package/scripts/lib/fixtures/figma-checks/checkbox-checked-axis.real.json +246 -0
  36. package/scripts/lib/fixtures/figma-checks/checkbox-checked-synonym.json +88 -0
  37. package/scripts/lib/fixtures/figma-checks/checkbox-missing-selected.json +80 -0
  38. package/scripts/lib/fixtures/figma-checks/indicator-failed.json +106 -0
  39. package/scripts/lib/fixtures/figma-checks/input-control-layer-missing.json +67 -0
  40. package/scripts/lib/fixtures/figma-checks/input-control-layer-ring-on-wrapper.json +80 -0
  41. package/scripts/lib/fixtures/figma-checks/input-control-layer.json +80 -0
  42. package/scripts/lib/fixtures/figma-checks/input-mui-weight-unbound.json +67 -0
  43. package/scripts/lib/fixtures/figma-checks/input-mui.json +67 -0
  44. package/scripts/lib/fixtures/figma-checks/ring-single-mode.json +112 -0
  45. package/scripts/lib/fixtures/figma-checks/ring-translucent.json +111 -0
  46. package/scripts/lib/fixtures/figma-checks/sample-button.real.json +1498 -0
  47. package/scripts/lib/fixtures/figma-checks/sample-ring-on-muted-raw.json +113 -0
  48. package/scripts/lib/fixtures/figma-checks/sample-ring-passes.json +169 -0
  49. package/scripts/lib/fixtures/figma-checks/surface-missing.json +108 -0
  50. package/scripts/lib/fixtures/figma-checks/surface-single-mode.json +112 -0
  51. package/scripts/lib/fixtures/figma-checks/surface-translucent.json +112 -0
  52. package/scripts/lib/fixtures/figma-checks/zygarden-ring-light-fails.json +113 -0
@@ -0,0 +1,93 @@
1
+ {
2
+ "covers": "ring bound but spread is 0 (invisible)",
3
+ "expect": {
4
+ "name": "Button",
5
+ "matrix": {
6
+ "variant": [
7
+ "primary"
8
+ ],
9
+ "state": [
10
+ "default",
11
+ "hover",
12
+ "focus",
13
+ "active",
14
+ "disabled"
15
+ ]
16
+ },
17
+ "uiFramework": "shadcn"
18
+ },
19
+ "snapshot": {
20
+ "type": "COMPONENT_SET",
21
+ "variantGroupProperties": {
22
+ "Variant": {
23
+ "values": [
24
+ "Primary"
25
+ ]
26
+ },
27
+ "State": {
28
+ "values": [
29
+ "Default",
30
+ "Hover",
31
+ "Focus",
32
+ "Active",
33
+ "Disabled"
34
+ ]
35
+ }
36
+ },
37
+ "children": [
38
+ {
39
+ "type": "COMPONENT",
40
+ "variantProperties": {
41
+ "Variant": "Primary",
42
+ "State": "Default"
43
+ }
44
+ },
45
+ {
46
+ "type": "COMPONENT",
47
+ "variantProperties": {
48
+ "Variant": "Primary",
49
+ "State": "Hover"
50
+ }
51
+ },
52
+ {
53
+ "type": "COMPONENT",
54
+ "variantProperties": {
55
+ "Variant": "Primary",
56
+ "State": "Focus"
57
+ },
58
+ "effects": [
59
+ {
60
+ "type": "DROP_SHADOW",
61
+ "visible": true,
62
+ "spread": 0,
63
+ "colorVariable": "Color/Border/Focus"
64
+ }
65
+ ],
66
+ "strokeAlign": "INSIDE",
67
+ "strokeVariables": [],
68
+ "strokeWeightBound": false,
69
+ "children": []
70
+ },
71
+ {
72
+ "type": "COMPONENT",
73
+ "variantProperties": {
74
+ "Variant": "Primary",
75
+ "State": "Active"
76
+ }
77
+ },
78
+ {
79
+ "type": "COMPONENT",
80
+ "variantProperties": {
81
+ "Variant": "Primary",
82
+ "State": "Disabled"
83
+ }
84
+ }
85
+ ]
86
+ },
87
+ "expected": {
88
+ "structural-read-back": "pass",
89
+ "state-baseline": "pass",
90
+ "focus-indicator": "fail",
91
+ "focus-contrast": "skip"
92
+ }
93
+ }
@@ -0,0 +1,95 @@
1
+ {
2
+ "covers": "transparent variant: ABSOLUTE OUTSIDE ring child, uiFramework null",
3
+ "expect": {
4
+ "name": "Button",
5
+ "matrix": {
6
+ "variant": [
7
+ "outline"
8
+ ],
9
+ "state": [
10
+ "default",
11
+ "hover",
12
+ "focus",
13
+ "active",
14
+ "disabled"
15
+ ]
16
+ },
17
+ "uiFramework": null
18
+ },
19
+ "snapshot": {
20
+ "type": "COMPONENT_SET",
21
+ "variantGroupProperties": {
22
+ "Variant": {
23
+ "values": [
24
+ "Outline"
25
+ ]
26
+ },
27
+ "State": {
28
+ "values": [
29
+ "Default",
30
+ "Hover",
31
+ "Focus",
32
+ "Active",
33
+ "Disabled"
34
+ ]
35
+ }
36
+ },
37
+ "children": [
38
+ {
39
+ "type": "COMPONENT",
40
+ "variantProperties": {
41
+ "Variant": "Outline",
42
+ "State": "Default"
43
+ }
44
+ },
45
+ {
46
+ "type": "COMPONENT",
47
+ "variantProperties": {
48
+ "Variant": "Outline",
49
+ "State": "Hover"
50
+ }
51
+ },
52
+ {
53
+ "type": "COMPONENT",
54
+ "variantProperties": {
55
+ "Variant": "Outline",
56
+ "State": "Focus"
57
+ },
58
+ "effects": [],
59
+ "strokeAlign": "INSIDE",
60
+ "strokeVariables": [],
61
+ "strokeWeightBound": false,
62
+ "children": [
63
+ {
64
+ "layoutPositioning": "ABSOLUTE",
65
+ "strokeAlign": "OUTSIDE",
66
+ "strokeVariables": [
67
+ "border/focus"
68
+ ],
69
+ "strokeWeightBound": true
70
+ }
71
+ ]
72
+ },
73
+ {
74
+ "type": "COMPONENT",
75
+ "variantProperties": {
76
+ "Variant": "Outline",
77
+ "State": "Active"
78
+ }
79
+ },
80
+ {
81
+ "type": "COMPONENT",
82
+ "variantProperties": {
83
+ "Variant": "Outline",
84
+ "State": "Disabled"
85
+ }
86
+ }
87
+ ]
88
+ },
89
+ "expected": {
90
+ "structural-read-back": "pass",
91
+ "state-baseline": "pass",
92
+ "focus-indicator": "pass",
93
+ "focus-contrast": "skip"
94
+ }
95
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "covers": "vanilla: an INSIDE stroke is a fail",
3
+ "expect": {
4
+ "name": "Button",
5
+ "matrix": {
6
+ "variant": [
7
+ "primary"
8
+ ],
9
+ "state": [
10
+ "default",
11
+ "hover",
12
+ "focus",
13
+ "active",
14
+ "disabled"
15
+ ]
16
+ },
17
+ "uiFramework": "vanilla"
18
+ },
19
+ "snapshot": {
20
+ "type": "COMPONENT_SET",
21
+ "variantGroupProperties": {
22
+ "Variant": {
23
+ "values": [
24
+ "Primary"
25
+ ]
26
+ },
27
+ "State": {
28
+ "values": [
29
+ "Default",
30
+ "Hover",
31
+ "Focus",
32
+ "Active",
33
+ "Disabled"
34
+ ]
35
+ }
36
+ },
37
+ "children": [
38
+ {
39
+ "type": "COMPONENT",
40
+ "variantProperties": {
41
+ "Variant": "Primary",
42
+ "State": "Default"
43
+ }
44
+ },
45
+ {
46
+ "type": "COMPONENT",
47
+ "variantProperties": {
48
+ "Variant": "Primary",
49
+ "State": "Hover"
50
+ }
51
+ },
52
+ {
53
+ "type": "COMPONENT",
54
+ "variantProperties": {
55
+ "Variant": "Primary",
56
+ "State": "Focus"
57
+ },
58
+ "effects": [],
59
+ "strokeAlign": "INSIDE",
60
+ "strokeVariables": [
61
+ "border/focus"
62
+ ],
63
+ "strokeWeightBound": false,
64
+ "children": []
65
+ },
66
+ {
67
+ "type": "COMPONENT",
68
+ "variantProperties": {
69
+ "Variant": "Primary",
70
+ "State": "Active"
71
+ }
72
+ },
73
+ {
74
+ "type": "COMPONENT",
75
+ "variantProperties": {
76
+ "Variant": "Primary",
77
+ "State": "Disabled"
78
+ }
79
+ }
80
+ ]
81
+ },
82
+ "expected": {
83
+ "structural-read-back": "pass",
84
+ "state-baseline": "pass",
85
+ "focus-indicator": "fail",
86
+ "focus-contrast": "skip"
87
+ }
88
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "covers": "vanilla-css: OUTSIDE stroke bound to a focus variable on the control",
3
+ "expect": {
4
+ "name": "Button",
5
+ "matrix": {
6
+ "variant": [
7
+ "primary"
8
+ ],
9
+ "state": [
10
+ "default",
11
+ "hover",
12
+ "focus",
13
+ "active",
14
+ "disabled"
15
+ ]
16
+ },
17
+ "uiFramework": "vanilla-css"
18
+ },
19
+ "snapshot": {
20
+ "type": "COMPONENT_SET",
21
+ "variantGroupProperties": {
22
+ "Variant": {
23
+ "values": [
24
+ "Primary"
25
+ ]
26
+ },
27
+ "State": {
28
+ "values": [
29
+ "Default",
30
+ "Hover",
31
+ "Focus",
32
+ "Active",
33
+ "Disabled"
34
+ ]
35
+ }
36
+ },
37
+ "children": [
38
+ {
39
+ "type": "COMPONENT",
40
+ "variantProperties": {
41
+ "Variant": "Primary",
42
+ "State": "Default"
43
+ }
44
+ },
45
+ {
46
+ "type": "COMPONENT",
47
+ "variantProperties": {
48
+ "Variant": "Primary",
49
+ "State": "Hover"
50
+ }
51
+ },
52
+ {
53
+ "type": "COMPONENT",
54
+ "variantProperties": {
55
+ "Variant": "Primary",
56
+ "State": "Focus"
57
+ },
58
+ "effects": [],
59
+ "strokeAlign": "OUTSIDE",
60
+ "strokeVariables": [
61
+ "color/border/focus"
62
+ ],
63
+ "strokeWeightBound": false,
64
+ "children": []
65
+ },
66
+ {
67
+ "type": "COMPONENT",
68
+ "variantProperties": {
69
+ "Variant": "Primary",
70
+ "State": "Active"
71
+ }
72
+ },
73
+ {
74
+ "type": "COMPONENT",
75
+ "variantProperties": {
76
+ "Variant": "Primary",
77
+ "State": "Disabled"
78
+ }
79
+ }
80
+ ]
81
+ },
82
+ "expected": {
83
+ "structural-read-back": "pass",
84
+ "state-baseline": "pass",
85
+ "focus-indicator": "pass",
86
+ "focus-contrast": "skip"
87
+ }
88
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "covers": "right count, wrong value: structural names the missing and extra combination",
3
+ "expect": {
4
+ "name": "Button",
5
+ "matrix": {
6
+ "variant": [
7
+ "primary"
8
+ ],
9
+ "state": [
10
+ "default",
11
+ "hover",
12
+ "focus",
13
+ "active",
14
+ "disabled"
15
+ ]
16
+ },
17
+ "uiFramework": "shadcn"
18
+ },
19
+ "snapshot": {
20
+ "type": "COMPONENT_SET",
21
+ "variantGroupProperties": {
22
+ "Variant": {
23
+ "values": [
24
+ "Primary"
25
+ ]
26
+ },
27
+ "State": {
28
+ "values": [
29
+ "Default",
30
+ "Hover",
31
+ "Focus",
32
+ "Active",
33
+ "Disabled"
34
+ ]
35
+ }
36
+ },
37
+ "children": [
38
+ {
39
+ "type": "COMPONENT",
40
+ "variantProperties": {
41
+ "Variant": "Primary",
42
+ "State": "Default"
43
+ }
44
+ },
45
+ {
46
+ "type": "COMPONENT",
47
+ "variantProperties": {
48
+ "Variant": "Primary",
49
+ "State": "Hovered"
50
+ }
51
+ },
52
+ {
53
+ "type": "COMPONENT",
54
+ "variantProperties": {
55
+ "Variant": "Primary",
56
+ "State": "Focus"
57
+ },
58
+ "effects": [
59
+ {
60
+ "type": "DROP_SHADOW",
61
+ "visible": true,
62
+ "spread": 3,
63
+ "colorVariable": "Color/Border/Focus"
64
+ }
65
+ ],
66
+ "strokeAlign": "INSIDE",
67
+ "strokeVariables": [],
68
+ "strokeWeightBound": false,
69
+ "children": []
70
+ },
71
+ {
72
+ "type": "COMPONENT",
73
+ "variantProperties": {
74
+ "Variant": "Primary",
75
+ "State": "Active"
76
+ }
77
+ },
78
+ {
79
+ "type": "COMPONENT",
80
+ "variantProperties": {
81
+ "Variant": "Primary",
82
+ "State": "Disabled"
83
+ }
84
+ }
85
+ ]
86
+ },
87
+ "expected": {
88
+ "structural-read-back": "fail",
89
+ "state-baseline": "fail",
90
+ "focus-indicator": "pass",
91
+ "focus-contrast": "skip"
92
+ }
93
+ }
@@ -0,0 +1,246 @@
1
+ {
2
+ "covers": "live capture, Throughline Plugin Test Checkbox 12:499 (2026-10-11): selection on its own `checked` axis satisfies `selected`; the ring sits on the `box` control layer",
3
+ "expect": {
4
+ "name": "Checkbox",
5
+ "matrix": {
6
+ "state": [
7
+ "Disabled",
8
+ "Default",
9
+ "Hover",
10
+ "Focus",
11
+ "Active"
12
+ ],
13
+ "checked": [
14
+ "false",
15
+ "true",
16
+ "indeterminate"
17
+ ]
18
+ },
19
+ "uiFramework": "shadcn",
20
+ "controlLayer": "box"
21
+ },
22
+ "expected": {
23
+ "structural-read-back": "pass",
24
+ "state-baseline": "pass",
25
+ "focus-indicator": "pass",
26
+ "focus-contrast": "skip"
27
+ },
28
+ "snapshot": {
29
+ "type": "COMPONENT_SET",
30
+ "variantGroupProperties": {
31
+ "state": {
32
+ "values": [
33
+ "Disabled",
34
+ "Default",
35
+ "Hover",
36
+ "Focus",
37
+ "Active"
38
+ ]
39
+ },
40
+ "checked": {
41
+ "values": [
42
+ "false",
43
+ "true",
44
+ "indeterminate"
45
+ ]
46
+ }
47
+ },
48
+ "children": [
49
+ {
50
+ "type": "COMPONENT",
51
+ "variantProperties": {
52
+ "state": "Disabled",
53
+ "checked": "false"
54
+ }
55
+ },
56
+ {
57
+ "type": "COMPONENT",
58
+ "variantProperties": {
59
+ "state": "Disabled",
60
+ "checked": "true"
61
+ }
62
+ },
63
+ {
64
+ "type": "COMPONENT",
65
+ "variantProperties": {
66
+ "state": "Disabled",
67
+ "checked": "indeterminate"
68
+ }
69
+ },
70
+ {
71
+ "type": "COMPONENT",
72
+ "variantProperties": {
73
+ "state": "Default",
74
+ "checked": "false"
75
+ }
76
+ },
77
+ {
78
+ "type": "COMPONENT",
79
+ "variantProperties": {
80
+ "state": "Default",
81
+ "checked": "true"
82
+ }
83
+ },
84
+ {
85
+ "type": "COMPONENT",
86
+ "variantProperties": {
87
+ "state": "Default",
88
+ "checked": "indeterminate"
89
+ }
90
+ },
91
+ {
92
+ "type": "COMPONENT",
93
+ "variantProperties": {
94
+ "state": "Hover",
95
+ "checked": "false"
96
+ }
97
+ },
98
+ {
99
+ "type": "COMPONENT",
100
+ "variantProperties": {
101
+ "state": "Hover",
102
+ "checked": "true"
103
+ }
104
+ },
105
+ {
106
+ "type": "COMPONENT",
107
+ "variantProperties": {
108
+ "state": "Hover",
109
+ "checked": "indeterminate"
110
+ }
111
+ },
112
+ {
113
+ "type": "COMPONENT",
114
+ "variantProperties": {
115
+ "state": "Focus",
116
+ "checked": "false"
117
+ },
118
+ "strokeAlign": "INSIDE",
119
+ "strokeVariables": [],
120
+ "strokeWeightBound": false,
121
+ "effects": [],
122
+ "children": [
123
+ {
124
+ "strokeAlign": "INSIDE",
125
+ "strokeVariables": [
126
+ "color/border/default"
127
+ ],
128
+ "strokeWeightBound": false,
129
+ "layoutPositioning": "AUTO"
130
+ }
131
+ ],
132
+ "controlLayer": {
133
+ "strokeAlign": "INSIDE",
134
+ "strokeVariables": [
135
+ "color/border/default"
136
+ ],
137
+ "strokeWeightBound": false,
138
+ "effects": [
139
+ {
140
+ "type": "DROP_SHADOW",
141
+ "visible": true,
142
+ "spread": 4,
143
+ "colorVariable": "color/focus/ring"
144
+ }
145
+ ],
146
+ "children": []
147
+ }
148
+ },
149
+ {
150
+ "type": "COMPONENT",
151
+ "variantProperties": {
152
+ "state": "Focus",
153
+ "checked": "true"
154
+ },
155
+ "strokeAlign": "INSIDE",
156
+ "strokeVariables": [],
157
+ "strokeWeightBound": false,
158
+ "effects": [],
159
+ "children": [
160
+ {
161
+ "strokeAlign": "INSIDE",
162
+ "strokeVariables": [
163
+ "color/border/default"
164
+ ],
165
+ "strokeWeightBound": false,
166
+ "layoutPositioning": "AUTO"
167
+ }
168
+ ],
169
+ "controlLayer": {
170
+ "strokeAlign": "INSIDE",
171
+ "strokeVariables": [
172
+ "color/border/default"
173
+ ],
174
+ "strokeWeightBound": false,
175
+ "effects": [
176
+ {
177
+ "type": "DROP_SHADOW",
178
+ "visible": true,
179
+ "spread": 4,
180
+ "colorVariable": "color/focus/ring"
181
+ }
182
+ ],
183
+ "children": []
184
+ }
185
+ },
186
+ {
187
+ "type": "COMPONENT",
188
+ "variantProperties": {
189
+ "state": "Focus",
190
+ "checked": "indeterminate"
191
+ },
192
+ "strokeAlign": "INSIDE",
193
+ "strokeVariables": [],
194
+ "strokeWeightBound": false,
195
+ "effects": [],
196
+ "children": [
197
+ {
198
+ "strokeAlign": "INSIDE",
199
+ "strokeVariables": [
200
+ "color/border/default"
201
+ ],
202
+ "strokeWeightBound": false,
203
+ "layoutPositioning": "AUTO"
204
+ }
205
+ ],
206
+ "controlLayer": {
207
+ "strokeAlign": "INSIDE",
208
+ "strokeVariables": [
209
+ "color/border/default"
210
+ ],
211
+ "strokeWeightBound": false,
212
+ "effects": [
213
+ {
214
+ "type": "DROP_SHADOW",
215
+ "visible": true,
216
+ "spread": 4,
217
+ "colorVariable": "color/focus/ring"
218
+ }
219
+ ],
220
+ "children": []
221
+ }
222
+ },
223
+ {
224
+ "type": "COMPONENT",
225
+ "variantProperties": {
226
+ "state": "Active",
227
+ "checked": "false"
228
+ }
229
+ },
230
+ {
231
+ "type": "COMPONENT",
232
+ "variantProperties": {
233
+ "state": "Active",
234
+ "checked": "true"
235
+ }
236
+ },
237
+ {
238
+ "type": "COMPONENT",
239
+ "variantProperties": {
240
+ "state": "Active",
241
+ "checked": "indeterminate"
242
+ }
243
+ }
244
+ ]
245
+ }
246
+ }