@fusion.dev/helix-docs 0.186.1 → 0.188.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/content/building-on-the-headless-tier.mdx +42 -0
- package/content/coding-agents.mdx +96 -41
- package/content/metrics.mdx +221 -221
- package/content/using-helix-with-an-agent.mdx +70 -61
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -3
- package/dist/pages.generated.js +1 -1
- package/dist/reference.d.ts +14 -13
- package/dist/reference.js +13 -7
- package/dist/sources.generated.js +429 -323
- package/package.json +9 -9
- package/dist/catalog.d.ts +0 -194
- package/dist/catalog.js +0 -163
- package/dist/naming.d.ts +0 -14
- package/dist/naming.js +0 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Five mistakes that look like Helix bugs, and the files an agent should read.
|
|
3
3
|
parent: coding-agents
|
|
4
4
|
section: Getting started
|
|
5
5
|
title: Using Helix with an agent
|
|
@@ -8,58 +8,63 @@ title: Using Helix with an agent
|
|
|
8
8
|
|
|
9
9
|
# Using Helix with an agent
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
as `.claude/skills/using-helix/SKILL.md`, a file format that one vendor reads in
|
|
13
|
-
a repository. Every other vendor reads its own file:
|
|
11
|
+
This guide is in two places, and both say the same thing:
|
|
14
12
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
13
|
+
- this page, which [llms.txt](https://fusion.dev/llms.txt) indexes
|
|
14
|
+
- `skills/helix/SKILL.md` inside `@fusion.dev/helix`, which matches the version
|
|
15
|
+
you installed and works offline
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
[Link your tool to this guide](#link-your-tool-to-this-guide) says how to point
|
|
18
|
+
each tool at one of them. [The MCP server](./coding-agents) works with any
|
|
19
|
+
vendor and runs code, and Claude, Cursor, Windsurf, and Zed all support it.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
[llms.txt](https://fusion.dev/llms.txt) indexes and that each of those files can
|
|
23
|
-
link to. Paste the link into the file your tool reads. [The MCP
|
|
24
|
-
server](./coding-agents) works with any vendor and runs code, and Claude,
|
|
25
|
-
Cursor, Windsurf, and Zed all support it.
|
|
26
|
-
|
|
27
|
-
## Read the manifest before writing a tag
|
|
21
|
+
## Read the family before writing its tags
|
|
28
22
|
|
|
29
23
|
```
|
|
30
|
-
https://fusion.dev/helix/
|
|
31
|
-
|
|
24
|
+
https://fusion.dev/helix/components/<family>.md
|
|
25
|
+
https://fusion.dev/helix/components/<family>.json
|
|
32
26
|
```
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
Each family's file lists:
|
|
35
29
|
|
|
30
|
+
- the import lines for the family
|
|
36
31
|
- every tag
|
|
37
32
|
- every property, with its literal union
|
|
38
|
-
- every event, with its class
|
|
33
|
+
- every event, with its class and its React prop
|
|
39
34
|
- every slot, part, and custom property
|
|
35
|
+
- the examples, each with the import lines it needs
|
|
40
36
|
|
|
41
|
-
**If a tag is not in
|
|
42
|
-
a declared union is invalid. Property types are literal unions for this
|
|
43
|
-
`'ghost' | 'outlined' | 'solid' | 'subtle'` shows you the values, and a
|
|
44
|
-
type such as `ButtonEmphasis` sends you somewhere else to find them.
|
|
45
|
-
|
|
46
|
-
When you need one family, fetch it as data:
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
https://fusion.dev/helix/components/<family>.json
|
|
50
|
-
https://fusion.dev/helix/components/<family>.md
|
|
51
|
-
```
|
|
37
|
+
**If a tag is not in a family's file, it does not exist.** A property value
|
|
38
|
+
outside a declared union is invalid. Property types are literal unions for this
|
|
39
|
+
reason. `'ghost' | 'outlined' | 'solid' | 'subtle'` shows you the values, and a
|
|
40
|
+
named type such as `ButtonEmphasis` sends you somewhere else to find them.
|
|
52
41
|
|
|
53
|
-
The
|
|
54
|
-
|
|
55
|
-
request, it names every
|
|
42
|
+
The manifest at `https://fusion.dev/helix/custom-elements.json` holds every
|
|
43
|
+
family in one file, which is several megabytes. Read the families you use.
|
|
44
|
+
Start from `https://fusion.dev/llms.txt`. In one request, it names every
|
|
45
|
+
document and the machine-readable sources.
|
|
56
46
|
|
|
57
|
-
##
|
|
47
|
+
## Five mistakes that look like Helix bugs
|
|
58
48
|
|
|
59
49
|
Each of these looks like a bug in Helix. They are listed from the most common to
|
|
60
50
|
the least common.
|
|
61
51
|
|
|
62
|
-
### 1.
|
|
52
|
+
### 1. Writing a tag without importing its family
|
|
53
|
+
|
|
54
|
+
Each tag needs its family's entry imported. A family does not register another
|
|
55
|
+
family's elements that you write inside it, so a Select needs Option imported
|
|
56
|
+
beside it, and a Data Table needs Table:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import '@fusion.dev/helix/select'
|
|
60
|
+
import '@fusion.dev/helix/option'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Without the second line, the options are unknown elements and the Select offers
|
|
64
|
+
nothing. Each family's Usage block and each example list the lines to import.
|
|
65
|
+
Copy them with the markup.
|
|
66
|
+
|
|
67
|
+
### 2. Blocking a change without `preventDefault()`
|
|
63
68
|
|
|
64
69
|
**Setting `value`, `open`, `checked`, or `active` sets the starting state and
|
|
65
70
|
corrects the current state.** The element starts in that state and then applies
|
|
@@ -91,7 +96,7 @@ block a change, call `preventDefault()` on the matching `helix-before-*` event:
|
|
|
91
96
|
A form reset returns the element to `default-value` and the matching attributes
|
|
92
97
|
for the other states. See [State and control](./state-and-control).
|
|
93
98
|
|
|
94
|
-
###
|
|
99
|
+
### 3. Using the exact event name
|
|
95
100
|
|
|
96
101
|
In React, write `onhelix-before-open`. `onHelixOpen` and `onOpen` do not work.
|
|
97
102
|
React removes `on` from the prop name and listens for exactly the rest, so the
|
|
@@ -105,7 +110,7 @@ so a menu closing inside a dialog does not close the dialog. `helix-select`,
|
|
|
105
110
|
listen for them on a container. If a listener on a wrapper receives nothing, the
|
|
106
111
|
event is a lifecycle event. Put the listener on the element.
|
|
107
112
|
|
|
108
|
-
###
|
|
113
|
+
### 4. Styling a disabled control with `:disabled`
|
|
109
114
|
|
|
110
115
|
```css
|
|
111
116
|
helix-input:disabled { … } /* right: matches a disabled fieldset too */
|
|
@@ -116,7 +121,7 @@ The browser disables a control inside `<fieldset disabled>` without adding an
|
|
|
116
121
|
attribute to it. The `[disabled]` selector does not match it, so the control
|
|
117
122
|
looks enabled while it does not accept input.
|
|
118
123
|
|
|
119
|
-
###
|
|
124
|
+
### 5. Loading every style layer before the elements
|
|
120
125
|
|
|
121
126
|
```ts
|
|
122
127
|
import '@fusion.dev/helix-styles/helix.css'
|
|
@@ -212,20 +217,28 @@ If you are adding a script to a recipe, use the component.
|
|
|
212
217
|
|
|
213
218
|
## Link your tool to this guide
|
|
214
219
|
|
|
215
|
-
**
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
**Point your tool at the guide, and do not copy it.** A copy starts to go stale
|
|
221
|
+
as soon as you paste it, and the guide changes with the library.
|
|
222
|
+
|
|
223
|
+
The skill in the package matches the Helix you installed. In Claude Code, link
|
|
224
|
+
it into your project's skills folder:
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
mkdir -p .claude/skills
|
|
228
|
+
ln -s ../../node_modules/@fusion.dev/helix/skills/helix .claude/skills/helix
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Other tools read a file in your repository. Add a line to it that names the
|
|
232
|
+
skill, or this page:
|
|
219
233
|
|
|
220
234
|
```md
|
|
221
|
-
Helix: read
|
|
222
|
-
|
|
223
|
-
for the API.
|
|
235
|
+
Helix: read node_modules/@fusion.dev/helix/skills/helix/SKILL.md before
|
|
236
|
+
writing components, and node_modules/@fusion.dev/helix/api.json for the API.
|
|
224
237
|
```
|
|
225
238
|
|
|
226
239
|
| Tool | Where it goes |
|
|
227
240
|
|---|---|
|
|
228
|
-
| Claude Code | `AGENTS.md` or `CLAUDE.md
|
|
241
|
+
| Claude Code | `.claude/skills/helix`, or a line in `AGENTS.md` or `CLAUDE.md` |
|
|
229
242
|
| Cursor | `.cursor/rules/` |
|
|
230
243
|
| GitHub Copilot | `.github/copilot-instructions.md` |
|
|
231
244
|
| Anything else | Whatever it reads. The line is the same |
|
|
@@ -233,22 +246,19 @@ for the API.
|
|
|
233
246
|
We do not write those files for you, and we chose this on purpose. You would
|
|
234
247
|
have to maintain a file we generated in your repository against our changes. A
|
|
235
248
|
tool that rewrote it on install would be a dependency you did not ask for, in a
|
|
236
|
-
directory you own. You
|
|
249
|
+
directory you own. You add the link or the line, and you can delete it.
|
|
237
250
|
|
|
238
251
|
## Install the Helix MCP server
|
|
239
252
|
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
"mcpServers": {
|
|
243
|
-
"helix": { "command": "helix", "args": ["mcp"] }
|
|
244
|
-
}
|
|
245
|
-
}
|
|
253
|
+
```sh
|
|
254
|
+
helix mcp init --client claude
|
|
246
255
|
```
|
|
247
256
|
|
|
248
|
-
`helix mcp`
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
`helix mcp` answers from the Helix packages your project installs: families,
|
|
258
|
+
examples, import lines, tokens, and the theme a brand color produces. `--client`
|
|
259
|
+
takes `claude`, `cursor`, or `vscode`, and writes the server into the file that
|
|
260
|
+
client reads. [Coding agents](./coding-agents) lists the tools. It runs on your
|
|
261
|
+
machine, talks to a client you chose, and makes no network requests.
|
|
252
262
|
|
|
253
263
|
## What this guide does not cover
|
|
254
264
|
|
|
@@ -256,10 +266,9 @@ you chose, and makes no network requests.
|
|
|
256
266
|
and hooks change with the library, and they are in a file you can fetch. A list
|
|
257
267
|
of them here would be a second copy that goes stale. Fetch the family.
|
|
258
268
|
|
|
259
|
-
**The theme a brand color produces.** Helix computes it, so
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
machine, and we do not host it.
|
|
269
|
+
**The theme a brand color produces.** Helix computes it, so call
|
|
270
|
+
`helix_derive_theme`, or run `helix theme build`. Both take the same JSON that a
|
|
271
|
+
`helix.theme.json` file holds.
|
|
263
272
|
|
|
264
273
|
**Whether a component fits your case.** Read the examples to decide. Every
|
|
265
274
|
family's `.md` file includes them as text, and
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export type { ApiMember, Element, EventDoc, Example, ExampleSource, Family, PropertyDoc, } from '
|
|
2
|
-
export { catalog, findInCatalog } from '
|
|
3
|
-
export {
|
|
4
|
-
export { place, type ReferenceFamily, type ReferenceOptions, reference, referenceFamilies, } from './reference.js';
|
|
1
|
+
export type { ApiMember, Element, EventDoc, Example, ExampleSource, Family, PropertyDoc, } from '@fusion.dev/helix-cem';
|
|
2
|
+
export { catalog, displayName, findInCatalog, place, startCase, tierOf, } from '@fusion.dev/helix-cem';
|
|
3
|
+
export { type ReferenceFamily, type ReferenceOptions, reference, referenceFamilies, } from './reference.js';
|
|
5
4
|
export { contentPath, type DocNavPage, type DocNavSection, type DocPage, type DocSection, findPage, navigation, pages, sections, } from './registry.js';
|
|
6
5
|
export { findSection } from './sections.js';
|
|
7
6
|
export { docSources } from './sources.generated.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export { catalog, findInCatalog } from '
|
|
2
|
-
export {
|
|
3
|
-
export { place, reference, referenceFamilies, } from './reference.js';
|
|
1
|
+
export { catalog, displayName, findInCatalog, place, startCase, tierOf, } from '@fusion.dev/helix-cem';
|
|
2
|
+
export { reference, referenceFamilies, } from './reference.js';
|
|
4
3
|
export { contentPath, findPage, navigation, pages, sections, } from './registry.js';
|
|
5
4
|
export { findSection } from './sections.js';
|
|
6
5
|
export { docSources } from './sources.generated.js';
|
package/dist/pages.generated.js
CHANGED
|
@@ -258,7 +258,7 @@ export const docPages = [
|
|
|
258
258
|
title: 'Typography',
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
|
-
description: '
|
|
261
|
+
description: 'Five mistakes that look like Helix bugs, and the files an agent should read.',
|
|
262
262
|
parent: 'coding-agents',
|
|
263
263
|
section: 'Getting started',
|
|
264
264
|
slug: 'using-helix-with-an-agent',
|
package/dist/reference.d.ts
CHANGED
|
@@ -32,7 +32,14 @@ export interface ReferenceExample {
|
|
|
32
32
|
css: string;
|
|
33
33
|
description: string;
|
|
34
34
|
html: string;
|
|
35
|
+
/** The import lines that register what the example writes, printed above it. */
|
|
36
|
+
imports?: string[];
|
|
35
37
|
label: string;
|
|
38
|
+
/** The baseline pictures, linked under the example beside the family's `.md`. */
|
|
39
|
+
renders?: {
|
|
40
|
+
file: string;
|
|
41
|
+
shot: string;
|
|
42
|
+
}[];
|
|
36
43
|
}
|
|
37
44
|
/** What to put above the reference, for a caller that generates a file. */
|
|
38
45
|
export interface ReferenceOptions {
|
|
@@ -54,8 +61,8 @@ export interface ReferenceOptions {
|
|
|
54
61
|
* Frontmatter, emitted above the heading.
|
|
55
62
|
*
|
|
56
63
|
* Provenance rather than decoration: a generated document should say what it
|
|
57
|
-
* was generated from, so a reader who finds one
|
|
58
|
-
*
|
|
64
|
+
* was generated from, so a reader who finds one on its own can still tell
|
|
65
|
+
* where to look. Keys are written in the order given, because
|
|
59
66
|
* a reader scans the first line and `title` is what they want there.
|
|
60
67
|
*/
|
|
61
68
|
frontmatter?: Array<[string, string]>;
|
|
@@ -63,18 +70,12 @@ export interface ReferenceOptions {
|
|
|
63
70
|
lede?: string[];
|
|
64
71
|
/** Top-level heading. */
|
|
65
72
|
title?: string;
|
|
73
|
+
/**
|
|
74
|
+
* The import block for each family, keyed by family slug, printed under a
|
|
75
|
+
* Usage heading before the first element. The catalog's `usage` is it.
|
|
76
|
+
*/
|
|
77
|
+
usage?: Record<string, string[]>;
|
|
66
78
|
}
|
|
67
|
-
/**
|
|
68
|
-
* The family and part a declaration belongs to, from where its file is.
|
|
69
|
-
*
|
|
70
|
-
* Not from the tag name. A tag is a string the family prefix can only be
|
|
71
|
-
* guessed out of: `helix-button-group` is one family and `helix-tab` is a
|
|
72
|
-
* part of another, and nothing in the name says which. The path says both.
|
|
73
|
-
*/
|
|
74
|
-
export declare const place: (path: string | undefined) => {
|
|
75
|
-
family: string;
|
|
76
|
-
part: string;
|
|
77
|
-
};
|
|
78
79
|
/** One family's declarations, in the order a reference prints them. */
|
|
79
80
|
export interface ReferenceFamily {
|
|
80
81
|
family: string;
|
package/dist/reference.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { startCase } from '
|
|
1
|
+
import { place, startCase } from '@fusion.dev/helix-cem';
|
|
2
2
|
const INFRASTRUCTURE = new Set(['HelixElement']);
|
|
3
3
|
const isPublic = (member) => member.privacy !== 'private' &&
|
|
4
4
|
member.privacy !== 'protected' &&
|
|
@@ -14,10 +14,6 @@ const table = (depth, heading, columns, rows) => {
|
|
|
14
14
|
const body = rows.map((row) => `| ${row.join(' | ')} |`).join('\n');
|
|
15
15
|
return `\n${'#'.repeat(depth)} ${heading}\n\n${head}\n${rule}\n${body}\n`;
|
|
16
16
|
};
|
|
17
|
-
export const place = (path) => {
|
|
18
|
-
const [, family = '', part = ''] = /^src\/([^/]+)\/([^/]+)\//.exec(path ?? '') ?? [];
|
|
19
|
-
return { family, part };
|
|
20
|
-
};
|
|
21
17
|
export const referenceFamilies = (manifest) => {
|
|
22
18
|
const families = new Map();
|
|
23
19
|
for (const module of manifest.modules ?? []) {
|
|
@@ -79,7 +75,7 @@ const element = (depth, declaration, part) => {
|
|
|
79
75
|
return lines;
|
|
80
76
|
};
|
|
81
77
|
const withoutSummary = (html) => html.replace(/^<!--\s*@summary[\s\S]*?-->\n*/, '');
|
|
82
|
-
const shown = (depth, examples) => {
|
|
78
|
+
const shown = (depth, family, examples) => {
|
|
83
79
|
if (examples.length === 0) {
|
|
84
80
|
return [];
|
|
85
81
|
}
|
|
@@ -89,10 +85,16 @@ const shown = (depth, examples) => {
|
|
|
89
85
|
if (example.description) {
|
|
90
86
|
lines.push(example.description, '');
|
|
91
87
|
}
|
|
88
|
+
if (example.imports && example.imports.length > 0) {
|
|
89
|
+
lines.push('```js', ...example.imports, '```', '');
|
|
90
|
+
}
|
|
92
91
|
lines.push('```html', withoutSummary(example.html), '```', '');
|
|
93
92
|
if (example.css) {
|
|
94
93
|
lines.push('```css', example.css, '```', '');
|
|
95
94
|
}
|
|
95
|
+
if (example.renders && example.renders.length > 0) {
|
|
96
|
+
lines.push(`Pictured: ${example.renders.map((render) => `[${render.shot}](${family}/${render.file})`).join(', ')}.`, '');
|
|
97
|
+
}
|
|
96
98
|
}
|
|
97
99
|
return lines;
|
|
98
100
|
};
|
|
@@ -113,10 +115,14 @@ export const reference = (manifest, options = {}) => {
|
|
|
113
115
|
if (families.length > 1) {
|
|
114
116
|
lines.push(`## ${startCase(family)}`, '');
|
|
115
117
|
}
|
|
118
|
+
const usage = options.usage?.[family] ?? [];
|
|
119
|
+
if (usage.length > 0) {
|
|
120
|
+
lines.push(`${'#'.repeat(depth)} Usage`, '', '```js', ...usage, '```', '');
|
|
121
|
+
}
|
|
116
122
|
for (const { declaration, part } of parts) {
|
|
117
123
|
lines.push(...element(depth, declaration, part));
|
|
118
124
|
}
|
|
119
|
-
lines.push(...shown(depth, options.examples?.[family] ?? []));
|
|
125
|
+
lines.push(...shown(depth, family, options.examples?.[family] ?? []));
|
|
120
126
|
}
|
|
121
127
|
return `${lines
|
|
122
128
|
.join('\n')
|