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