@pixerate/editor 0.223.7 → 0.223.9
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/dist/tools/skill-evals.d.cts +10 -1
- package/dist/tools/skill-evals.d.ts +10 -1
- package/package.json +1 -1
- package/skills/README.md +7 -2
- package/skills/pixerate-accessibility-audit/SKILL.md +98 -0
- package/skills/pixerate-accessibility-audit/evals/button-label-contrast.json +97 -0
- package/skills/pixerate-accessibility-audit/evals/distinct-for-cvd.json +160 -0
- package/skills/pixerate-accessibility-audit/evals/icon-non-text-contrast.json +109 -0
- package/skills/pixerate-brand-application/SKILL.md +99 -0
- package/skills/pixerate-brand-application/evals/apply-palette.json +148 -0
- package/skills/pixerate-brand-application/evals/readable-on-brand.json +104 -0
- package/skills/pixerate-brand-application/evals/snap-to-palette.json +148 -0
- package/skills/pixerate-canvas/SKILL.md +8 -0
- package/skills/pixerate-canvas-design-system-components/SKILL.md +103 -0
- package/skills/pixerate-canvas-design-system-components/evals/add-variant.json +172 -0
- package/skills/pixerate-canvas-design-system-components/evals/combine-variants.json +172 -0
- package/skills/pixerate-canvas-design-system-components/evals/make-component.json +103 -0
- package/skills/pixerate-canvas-layout/SKILL.md +95 -0
- package/skills/pixerate-canvas-layout/evals/align-tops.json +98 -0
- package/skills/pixerate-canvas-layout/evals/distribute-evenly.json +98 -0
- package/skills/pixerate-canvas-layout/evals/order-and-lock.json +110 -0
- package/skills/pixerate-color/SKILL.md +8 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Apply our brand palette to this layout: the background is #f1faee, the big panel is primary #1d3557, and the small badge is accent #e63946.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "vector",
|
|
5
|
+
"width": 200,
|
|
6
|
+
"height": 120,
|
|
7
|
+
"colorTools": true,
|
|
8
|
+
"setup": [
|
|
9
|
+
{
|
|
10
|
+
"id": "vector.addShape",
|
|
11
|
+
"params": {
|
|
12
|
+
"kind": "rect",
|
|
13
|
+
"x": 0,
|
|
14
|
+
"y": 0,
|
|
15
|
+
"width": 200,
|
|
16
|
+
"height": 120,
|
|
17
|
+
"name": "Background",
|
|
18
|
+
"fill": "#ffffff",
|
|
19
|
+
"stroke": null
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "vector.addShape",
|
|
24
|
+
"params": {
|
|
25
|
+
"kind": "rect",
|
|
26
|
+
"x": 20,
|
|
27
|
+
"y": 20,
|
|
28
|
+
"width": 160,
|
|
29
|
+
"height": 80,
|
|
30
|
+
"name": "Panel",
|
|
31
|
+
"fill": "#334455",
|
|
32
|
+
"stroke": null
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "vector.addShape",
|
|
37
|
+
"params": {
|
|
38
|
+
"kind": "ellipse",
|
|
39
|
+
"x": 150,
|
|
40
|
+
"y": 10,
|
|
41
|
+
"width": 30,
|
|
42
|
+
"height": 30,
|
|
43
|
+
"name": "Badge",
|
|
44
|
+
"fill": "#ff6600",
|
|
45
|
+
"stroke": null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"checks": [
|
|
51
|
+
{
|
|
52
|
+
"why": "each part in its brand colour",
|
|
53
|
+
"tool": "run_command",
|
|
54
|
+
"args": {
|
|
55
|
+
"id": "vector.list"
|
|
56
|
+
},
|
|
57
|
+
"expect": {
|
|
58
|
+
"result": {
|
|
59
|
+
"nodes": {
|
|
60
|
+
"$expr": "(() => { const f = (n) => (v.find((x) => x.name === n).fill || '').toLowerCase(); return f('Background') === '#f1faee' && f('Panel') === '#1d3557' && f('Badge') === '#e63946'; })()"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"why": "nothing moved",
|
|
67
|
+
"tool": "run_command",
|
|
68
|
+
"args": {
|
|
69
|
+
"id": "vector.list"
|
|
70
|
+
},
|
|
71
|
+
"expect": {
|
|
72
|
+
"result": {
|
|
73
|
+
"nodes": {
|
|
74
|
+
"$some": {
|
|
75
|
+
"name": "Badge",
|
|
76
|
+
"bounds": {
|
|
77
|
+
"x": 150,
|
|
78
|
+
"y": 10,
|
|
79
|
+
"width": 30,
|
|
80
|
+
"height": 30
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"solution": [
|
|
89
|
+
{
|
|
90
|
+
"tool": "run_command",
|
|
91
|
+
"args": {
|
|
92
|
+
"id": "vector.list"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"tool": "run_commands",
|
|
97
|
+
"args": {
|
|
98
|
+
"steps": [
|
|
99
|
+
{
|
|
100
|
+
"id": "vector.setStyle",
|
|
101
|
+
"params": {
|
|
102
|
+
"ids": [
|
|
103
|
+
{
|
|
104
|
+
"$read": "run_command",
|
|
105
|
+
"args": {
|
|
106
|
+
"id": "vector.list"
|
|
107
|
+
},
|
|
108
|
+
"path": "result.nodes.0.id"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"fill": "#f1faee"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "vector.setStyle",
|
|
116
|
+
"params": {
|
|
117
|
+
"ids": [
|
|
118
|
+
{
|
|
119
|
+
"$read": "run_command",
|
|
120
|
+
"args": {
|
|
121
|
+
"id": "vector.list"
|
|
122
|
+
},
|
|
123
|
+
"path": "result.nodes.1.id"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"fill": "#1d3557"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "vector.setStyle",
|
|
131
|
+
"params": {
|
|
132
|
+
"ids": [
|
|
133
|
+
{
|
|
134
|
+
"$read": "run_command",
|
|
135
|
+
"args": {
|
|
136
|
+
"id": "vector.list"
|
|
137
|
+
},
|
|
138
|
+
"path": "result.nodes.2.id"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"fill": "#e63946"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The white text on our light-blue badge fails contrast. Fix it using a colour from our palette (#1d3557, #457b9d, #a8dadc, #f1faee, #e63946), keeping the badge light blue.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "vector",
|
|
5
|
+
"width": 120,
|
|
6
|
+
"height": 60,
|
|
7
|
+
"colorTools": true,
|
|
8
|
+
"setup": [
|
|
9
|
+
{
|
|
10
|
+
"id": "vector.addShape",
|
|
11
|
+
"params": {
|
|
12
|
+
"kind": "rect",
|
|
13
|
+
"x": 10,
|
|
14
|
+
"y": 10,
|
|
15
|
+
"width": 100,
|
|
16
|
+
"height": 40,
|
|
17
|
+
"name": "Badge",
|
|
18
|
+
"fill": "#a8dadc",
|
|
19
|
+
"stroke": null
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "vector.addShape",
|
|
24
|
+
"params": {
|
|
25
|
+
"kind": "rect",
|
|
26
|
+
"x": 30,
|
|
27
|
+
"y": 24,
|
|
28
|
+
"width": 60,
|
|
29
|
+
"height": 12,
|
|
30
|
+
"name": "Text",
|
|
31
|
+
"fill": "#ffffff",
|
|
32
|
+
"stroke": null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"checks": [
|
|
38
|
+
{
|
|
39
|
+
"why": "the text uses a palette colour that reads on the badge at 4.5:1 or more",
|
|
40
|
+
"tool": "run_command",
|
|
41
|
+
"args": {
|
|
42
|
+
"id": "vector.list"
|
|
43
|
+
},
|
|
44
|
+
"expect": {
|
|
45
|
+
"result": {
|
|
46
|
+
"nodes": {
|
|
47
|
+
"$expr": "(() => { const L = (h) => { const c = [1, 3, 5].map((i) => parseInt(h.replace('#', '').padEnd(6, '0').slice(i - 1, i + 1), 16) / 255).map((x) => (x <= 0.04045 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4)); return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]; }; const cr = (a, b) => { const [x, y] = [L(a), L(b)].sort((p, q) => q - p); return (x + 0.05) / (y + 0.05); }; const t = v.find((n) => n.name === 'Text').fill.toLowerCase(); return ['#1d3557', '#457b9d', '#a8dadc', '#f1faee', '#e63946'].includes(t) && cr(t, v.find((n) => n.name === 'Badge').fill) >= 4.5; })()"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"why": "the badge stays light blue",
|
|
54
|
+
"tool": "run_command",
|
|
55
|
+
"args": {
|
|
56
|
+
"id": "vector.list"
|
|
57
|
+
},
|
|
58
|
+
"expect": {
|
|
59
|
+
"result": {
|
|
60
|
+
"nodes": {
|
|
61
|
+
"$some": {
|
|
62
|
+
"name": "Badge",
|
|
63
|
+
"fill": "#a8dadc"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"solution": [
|
|
71
|
+
{
|
|
72
|
+
"tool": "check_color_contrast",
|
|
73
|
+
"args": {
|
|
74
|
+
"foreground": "#ffffff",
|
|
75
|
+
"background": "#a8dadc"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"tool": "check_color_contrast",
|
|
80
|
+
"args": {
|
|
81
|
+
"foreground": "#1d3557",
|
|
82
|
+
"background": "#a8dadc"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"tool": "run_command",
|
|
87
|
+
"args": {
|
|
88
|
+
"id": "vector.setStyle",
|
|
89
|
+
"params": {
|
|
90
|
+
"ids": [
|
|
91
|
+
{
|
|
92
|
+
"$read": "run_command",
|
|
93
|
+
"args": {
|
|
94
|
+
"id": "vector.list"
|
|
95
|
+
},
|
|
96
|
+
"path": "result.nodes.1.id"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"fill": "#1d3557"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "These colours are almost our brand colours but not exact. Snap each shape to the nearest colour in the palette: #1d3557, #457b9d, #a8dadc, #e63946.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "vector",
|
|
5
|
+
"width": 160,
|
|
6
|
+
"height": 40,
|
|
7
|
+
"colorTools": true,
|
|
8
|
+
"setup": [
|
|
9
|
+
{
|
|
10
|
+
"id": "vector.addShape",
|
|
11
|
+
"params": {
|
|
12
|
+
"kind": "rect",
|
|
13
|
+
"x": 0,
|
|
14
|
+
"y": 0,
|
|
15
|
+
"width": 40,
|
|
16
|
+
"height": 40,
|
|
17
|
+
"name": "A",
|
|
18
|
+
"fill": "#1f3759",
|
|
19
|
+
"stroke": null
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "vector.addShape",
|
|
24
|
+
"params": {
|
|
25
|
+
"kind": "rect",
|
|
26
|
+
"x": 40,
|
|
27
|
+
"y": 0,
|
|
28
|
+
"width": 40,
|
|
29
|
+
"height": 40,
|
|
30
|
+
"name": "B",
|
|
31
|
+
"fill": "#4a7fa0",
|
|
32
|
+
"stroke": null
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "vector.addShape",
|
|
37
|
+
"params": {
|
|
38
|
+
"kind": "rect",
|
|
39
|
+
"x": 80,
|
|
40
|
+
"y": 0,
|
|
41
|
+
"width": 40,
|
|
42
|
+
"height": 40,
|
|
43
|
+
"name": "C",
|
|
44
|
+
"fill": "#aadcde",
|
|
45
|
+
"stroke": null
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "vector.addShape",
|
|
50
|
+
"params": {
|
|
51
|
+
"kind": "rect",
|
|
52
|
+
"x": 120,
|
|
53
|
+
"y": 0,
|
|
54
|
+
"width": 40,
|
|
55
|
+
"height": 40,
|
|
56
|
+
"name": "D",
|
|
57
|
+
"fill": "#e43b48",
|
|
58
|
+
"stroke": null
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"checks": [
|
|
64
|
+
{
|
|
65
|
+
"why": "each shape in its nearest brand colour",
|
|
66
|
+
"tool": "run_command",
|
|
67
|
+
"args": {
|
|
68
|
+
"id": "vector.list"
|
|
69
|
+
},
|
|
70
|
+
"expect": {
|
|
71
|
+
"result": {
|
|
72
|
+
"nodes": {
|
|
73
|
+
"$expr": "v.map((n) => (n.fill || '').toLowerCase()).join() === '#1d3557,#457b9d,#a8dadc,#e63946'"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"solution": [
|
|
80
|
+
{
|
|
81
|
+
"tool": "run_commands",
|
|
82
|
+
"args": {
|
|
83
|
+
"steps": [
|
|
84
|
+
{
|
|
85
|
+
"id": "vector.setStyle",
|
|
86
|
+
"params": {
|
|
87
|
+
"ids": [
|
|
88
|
+
{
|
|
89
|
+
"$read": "run_command",
|
|
90
|
+
"args": {
|
|
91
|
+
"id": "vector.list"
|
|
92
|
+
},
|
|
93
|
+
"path": "result.nodes.0.id"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"fill": "#1d3557"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "vector.setStyle",
|
|
101
|
+
"params": {
|
|
102
|
+
"ids": [
|
|
103
|
+
{
|
|
104
|
+
"$read": "run_command",
|
|
105
|
+
"args": {
|
|
106
|
+
"id": "vector.list"
|
|
107
|
+
},
|
|
108
|
+
"path": "result.nodes.1.id"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"fill": "#457b9d"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "vector.setStyle",
|
|
116
|
+
"params": {
|
|
117
|
+
"ids": [
|
|
118
|
+
{
|
|
119
|
+
"$read": "run_command",
|
|
120
|
+
"args": {
|
|
121
|
+
"id": "vector.list"
|
|
122
|
+
},
|
|
123
|
+
"path": "result.nodes.2.id"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"fill": "#a8dadc"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "vector.setStyle",
|
|
131
|
+
"params": {
|
|
132
|
+
"ids": [
|
|
133
|
+
{
|
|
134
|
+
"$read": "run_command",
|
|
135
|
+
"args": {
|
|
136
|
+
"id": "vector.list"
|
|
137
|
+
},
|
|
138
|
+
"path": "result.nodes.3.id"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"fill": "#e63946"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
@@ -25,6 +25,14 @@ from `get_editor_state`; component and set ids from `list_components`. Tools tha
|
|
|
25
25
|
just selected with `canvas_select`. See `pixerate-agent-tools` for namespacing, `run_commands`
|
|
26
26
|
batching and error codes.
|
|
27
27
|
|
|
28
|
+
## Workflow skills
|
|
29
|
+
|
|
30
|
+
For these jobs, load the workflow skill too: it has the method, the checks between steps and
|
|
31
|
+
the pitfalls, and uses the tools below.
|
|
32
|
+
|
|
33
|
+
- `pixerate-canvas-design-system-components`: components, instances, variant sets and overrides.
|
|
34
|
+
- `pixerate-canvas-layout`: align, distribute, order and lock.
|
|
35
|
+
|
|
28
36
|
## Working method
|
|
29
37
|
|
|
30
38
|
1. **Read.** `get_editor_state` with `includeDocument: false` returns `canvas.nodes` and
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-canvas-design-system-components
|
|
3
|
+
description: The design system components workflow in the Pixerate canvas - turning repeated design into main components, placing instances instead of copies, combining versions into a component set with named variant properties and values, adding variants, keeping instances linked, swapping, resetting and pushing overrides, and keeping the library tidy and named. Use when asked to build or tidy a design system, component library or UI kit, make a component, instance, variant or component set, add a state (hover, disabled) or size, rename variant properties, or replace copies with instances, or when create_component, combine_as_variants, add_variant or create_instance are available. Load with pixerate-canvas, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-canvas
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Building design system components
|
|
10
|
+
|
|
11
|
+
A design system replaces copies with components. A main component holds the design; instances
|
|
12
|
+
show it elsewhere and update when it changes, with per-instance overrides where they differ.
|
|
13
|
+
Versions of one thing (styles, states, sizes) become variants in a component set, described by
|
|
14
|
+
properties ("Style=Primary, State=Disabled") a person or agent can switch between. Names and
|
|
15
|
+
properties are the interface: keep them clear and consistent.
|
|
16
|
+
|
|
17
|
+
This skill is the method. `pixerate-canvas` has the full tool reference.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- Anything used more than once is a main component; its uses are linked instances
|
|
22
|
+
(`inspect_instance` `status: "linked"`), not copies.
|
|
23
|
+
- Versions of one element are variants in one component set, with named properties (Style,
|
|
24
|
+
State, Size) and named values (Primary, Disabled, Large), never "Property 1" and "Variant2".
|
|
25
|
+
- Every combination of property values is unique; the default variant is the most common one.
|
|
26
|
+
- Instances keep their link; detach only when one must diverge for good.
|
|
27
|
+
- Components are named by what they are ("Button", "Card"), sets list their options clearly.
|
|
28
|
+
|
|
29
|
+
## Inputs to confirm
|
|
30
|
+
|
|
31
|
+
- **What becomes a component**, and which existing copies should become its instances.
|
|
32
|
+
- **Properties and values** for variants (Style: Primary / Secondary; State: Default / Hover /
|
|
33
|
+
Disabled; Size: Small / Medium / Large).
|
|
34
|
+
- **Naming conventions** of the team's library.
|
|
35
|
+
|
|
36
|
+
## Working method
|
|
37
|
+
|
|
38
|
+
1. **Read.** `list_components` (components, sets, their variants and options) and
|
|
39
|
+
`get_canvas_document` for the nodes.
|
|
40
|
+
**Check:** you know which nodes are already components and which are copies.
|
|
41
|
+
2. **Make components.** `create_component` with the frame's id(s).
|
|
42
|
+
**Check:** `list_components` lists it with its name.
|
|
43
|
+
3. **Replace copies with instances.** `create_instance` with `componentId`, `x`, `y`; remove the
|
|
44
|
+
copies once instances stand in their place.
|
|
45
|
+
**Check:** `get_canvas_document` shows instance nodes where the copies were.
|
|
46
|
+
4. **Combine versions into variants.** `create_component` each version, then
|
|
47
|
+
`combine_as_variants` with their ids; the set gets generic names ("Property 1", "Default",
|
|
48
|
+
"Variant2"). Rename at once: `rename_variant_property` (`name`, `newName`, `setId`) and
|
|
49
|
+
`rename_variant_value` (`property`, `value`, `newValue`, `setId`).
|
|
50
|
+
**Check:** `list_components` `sets[].options` shows the real names; each variant's `variant`
|
|
51
|
+
map is right.
|
|
52
|
+
5. **Add variants.** `add_variant` with `setId` and the new `variant` values (it duplicates the
|
|
53
|
+
default, or `from`); `set_variant_properties` to change a variant's values.
|
|
54
|
+
**Check:** the set lists every combination once.
|
|
55
|
+
6. **Maintain instances.** `swap_instance` to another component or variant, `reset_overrides` to
|
|
56
|
+
go back to the main, `push_overrides` to promote an instance's change to the main,
|
|
57
|
+
`go_to_main_component` to edit the source.
|
|
58
|
+
|
|
59
|
+
## Decision table
|
|
60
|
+
|
|
61
|
+
| Situation | Tool |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| The same element appears several times | `create_component`, then `create_instance` for each use |
|
|
64
|
+
| Versions of one element (styles, states, sizes) | `combine_as_variants`, then rename properties and values |
|
|
65
|
+
| A new state or size | `add_variant` with `variant` values |
|
|
66
|
+
| An instance should look like another variant | `set_instance_properties` or `swap_instance` |
|
|
67
|
+
| An instance's change belongs in the main | `push_overrides` |
|
|
68
|
+
| An instance drifted by accident | `reset_overrides` |
|
|
69
|
+
| One copy must diverge permanently | `detach_instance` (last resort) |
|
|
70
|
+
|
|
71
|
+
## Recipes
|
|
72
|
+
|
|
73
|
+
**Card component with two instances.** `create_component` `{ ids: ["card"] }` →
|
|
74
|
+
`create_instance` `{ componentId: "card", x: 0, y: 150 }` and `{ componentId: "card", x: 240,
|
|
75
|
+
y: 150 }`.
|
|
76
|
+
|
|
77
|
+
**Primary and Secondary variants.** `create_component` each button → `combine_as_variants`
|
|
78
|
+
`{ ids }` → `rename_variant_property` `{ name: "Property 1", newName: "Style", setId }` →
|
|
79
|
+
`rename_variant_value` `Default` → `Primary`, `Variant2` → `Secondary`.
|
|
80
|
+
|
|
81
|
+
**A Disabled variant.** `add_variant` `{ setId, variant: { Style: "Disabled" } }`.
|
|
82
|
+
|
|
83
|
+
## Pitfalls
|
|
84
|
+
|
|
85
|
+
- **Copies instead of instances** drift apart and cannot be updated together.
|
|
86
|
+
- **Generic variant names** ("Property 1", "Variant2") left after combining make the set unusable;
|
|
87
|
+
rename right away.
|
|
88
|
+
- **The rename and add tools need the set** (`setId` from `list_components`) when nothing is
|
|
89
|
+
selected.
|
|
90
|
+
- **Duplicate combinations** are refused; every variant needs a unique set of values.
|
|
91
|
+
- **Detaching to make a small change** loses future updates; override instead.
|
|
92
|
+
- **Combining unrelated components** into one set; a set is one element's versions.
|
|
93
|
+
|
|
94
|
+
## Tools used
|
|
95
|
+
|
|
96
|
+
- `list_components`, `inspect_instance`: components, sets, variants and instance status
|
|
97
|
+
- `get_canvas_document`: the nodes, to check placement
|
|
98
|
+
- `create_component`, `create_instance`: components and their instances
|
|
99
|
+
- `combine_as_variants`, `add_variant`, `remove_variant`, `set_variant_properties`: component sets
|
|
100
|
+
- `rename_variant_property`, `rename_variant_value`: clear property and value names
|
|
101
|
+
- `set_instance_properties`, `swap_instance`, `reset_overrides`, `push_overrides`: instances and overrides
|
|
102
|
+
- `detach_instance`, `go_to_main_component`, `restore_main_component`: break links, edit or restore mains
|
|
103
|
+
- `undo_canvas`: take back a step
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Add a Disabled style to the button component set, as a third variant of its Style property.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "canvas",
|
|
5
|
+
"nodes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "primary",
|
|
8
|
+
"type": "group",
|
|
9
|
+
"position": {
|
|
10
|
+
"x": 0,
|
|
11
|
+
"y": 0
|
|
12
|
+
},
|
|
13
|
+
"width": 120,
|
|
14
|
+
"height": 40,
|
|
15
|
+
"data": {
|
|
16
|
+
"label": "Button / Primary"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "pbg",
|
|
21
|
+
"type": "shape",
|
|
22
|
+
"parentId": "primary",
|
|
23
|
+
"position": {
|
|
24
|
+
"x": 0,
|
|
25
|
+
"y": 0
|
|
26
|
+
},
|
|
27
|
+
"width": 120,
|
|
28
|
+
"height": 40,
|
|
29
|
+
"data": {
|
|
30
|
+
"label": "Bg",
|
|
31
|
+
"shape": {
|
|
32
|
+
"kind": "rect",
|
|
33
|
+
"fill": "#1d3557"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "secondary",
|
|
39
|
+
"type": "group",
|
|
40
|
+
"position": {
|
|
41
|
+
"x": 0,
|
|
42
|
+
"y": 60
|
|
43
|
+
},
|
|
44
|
+
"width": 120,
|
|
45
|
+
"height": 40,
|
|
46
|
+
"data": {
|
|
47
|
+
"label": "Button / Secondary"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "sbg",
|
|
52
|
+
"type": "shape",
|
|
53
|
+
"parentId": "secondary",
|
|
54
|
+
"position": {
|
|
55
|
+
"x": 0,
|
|
56
|
+
"y": 0
|
|
57
|
+
},
|
|
58
|
+
"width": 120,
|
|
59
|
+
"height": 40,
|
|
60
|
+
"data": {
|
|
61
|
+
"label": "Bg",
|
|
62
|
+
"shape": {
|
|
63
|
+
"kind": "rect",
|
|
64
|
+
"fill": "#ffffff"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"setup": [
|
|
70
|
+
{
|
|
71
|
+
"tool": "create_component",
|
|
72
|
+
"args": {
|
|
73
|
+
"ids": [
|
|
74
|
+
"primary"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"tool": "create_component",
|
|
80
|
+
"args": {
|
|
81
|
+
"ids": [
|
|
82
|
+
"secondary"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"tool": "combine_as_variants",
|
|
88
|
+
"args": {
|
|
89
|
+
"ids": [
|
|
90
|
+
"primary",
|
|
91
|
+
"secondary"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"tool": "rename_variant_property",
|
|
97
|
+
"args": {
|
|
98
|
+
"name": "Property 1",
|
|
99
|
+
"newName": "Style",
|
|
100
|
+
"setId": {
|
|
101
|
+
"$read": "list_components",
|
|
102
|
+
"path": "sets.0.id"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"tool": "rename_variant_value",
|
|
108
|
+
"args": {
|
|
109
|
+
"property": "Style",
|
|
110
|
+
"value": "Default",
|
|
111
|
+
"newValue": "Primary",
|
|
112
|
+
"setId": {
|
|
113
|
+
"$read": "list_components",
|
|
114
|
+
"path": "sets.0.id"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"tool": "rename_variant_value",
|
|
120
|
+
"args": {
|
|
121
|
+
"property": "Style",
|
|
122
|
+
"value": "Variant2",
|
|
123
|
+
"newValue": "Secondary",
|
|
124
|
+
"setId": {
|
|
125
|
+
"$read": "list_components",
|
|
126
|
+
"path": "sets.0.id"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"checks": [
|
|
133
|
+
{
|
|
134
|
+
"why": "three variants: Primary, Secondary and Disabled",
|
|
135
|
+
"tool": "list_components",
|
|
136
|
+
"expect": {
|
|
137
|
+
"sets": [
|
|
138
|
+
{
|
|
139
|
+
"variants": {
|
|
140
|
+
"$length": 3
|
|
141
|
+
},
|
|
142
|
+
"options": [
|
|
143
|
+
{
|
|
144
|
+
"name": "Style",
|
|
145
|
+
"values": {
|
|
146
|
+
"$expr": "[...v].sort().join() === 'Disabled,Primary,Secondary'"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
"solution": [
|
|
156
|
+
{
|
|
157
|
+
"tool": "list_components"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"tool": "add_variant",
|
|
161
|
+
"args": {
|
|
162
|
+
"setId": {
|
|
163
|
+
"$read": "list_components",
|
|
164
|
+
"path": "sets.0.id"
|
|
165
|
+
},
|
|
166
|
+
"variant": {
|
|
167
|
+
"Style": "Disabled"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|