@fusion.dev/helix-docs 0.186.1 → 0.187.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.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Four mistakes that look like Helix bugs, and the files an agent should read.
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
@@ -24,42 +24,53 @@ link to. Paste the link into the file your tool reads. [The MCP
24
24
  server](./coding-agents) works with any vendor and runs code, and Claude,
25
25
  Cursor, Windsurf, and Zed all support it.
26
26
 
27
- ## Read the manifest before writing a tag
27
+ ## Read the family before writing its tags
28
28
 
29
29
  ```
30
- https://fusion.dev/helix/custom-elements.json
31
- @fusion.dev/helix/custom-elements.json
30
+ https://fusion.dev/helix/components/<family>.md
31
+ https://fusion.dev/helix/components/<family>.json
32
32
  ```
33
33
 
34
- The manifest lists:
34
+ Each family's file lists:
35
35
 
36
+ - the import lines for the family
36
37
  - every tag
37
38
  - every property, with its literal union
38
- - every event, with its class
39
+ - every event, with its class and its React prop
39
40
  - every slot, part, and custom property
41
+ - the examples, each with the import lines it needs
40
42
 
41
- **If a tag is not in the manifest, it does not exist.** A property value outside
42
- a declared union is invalid. Property types are literal unions for this reason.
43
- `'ghost' | 'outlined' | 'solid' | 'subtle'` shows you the values, and a named
44
- type such as `ButtonEmphasis` sends you somewhere else to find them.
43
+ **If a tag is not in a family's file, it does not exist.** A property value
44
+ outside a declared union is invalid. Property types are literal unions for this
45
+ reason. `'ghost' | 'outlined' | 'solid' | 'subtle'` shows you the values, and a
46
+ named type such as `ButtonEmphasis` sends you somewhere else to find them.
45
47
 
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
- ```
48
+ The manifest at `https://fusion.dev/helix/custom-elements.json` holds every
49
+ family in one file, which is several megabytes. Read the families you use.
50
+ Start from `https://fusion.dev/llms.txt`. In one request, it names every
51
+ document and the machine-readable sources.
52
52
 
53
- The `.md` file has the API tables and the examples. The HTML page leaves the
54
- examples out on purpose. Start from `https://fusion.dev/llms.txt`. In one
55
- request, it names every document and these two sources.
56
-
57
- ## Four mistakes that look like Helix bugs
53
+ ## Five mistakes that look like Helix bugs
58
54
 
59
55
  Each of these looks like a bug in Helix. They are listed from the most common to
60
56
  the least common.
61
57
 
62
- ### 1. Blocking a change without `preventDefault()`
58
+ ### 1. Writing a tag without importing its family
59
+
60
+ Each tag needs its family's entry imported. A family does not register another
61
+ family's elements that you write inside it, so a Select needs Option imported
62
+ beside it, and a Data Table needs Table:
63
+
64
+ ```js
65
+ import '@fusion.dev/helix/select'
66
+ import '@fusion.dev/helix/option'
67
+ ```
68
+
69
+ Without the second line, the options are unknown elements and the Select offers
70
+ nothing. Each family's Usage block and each example list the lines to import.
71
+ Copy them with the markup.
72
+
73
+ ### 2. Blocking a change without `preventDefault()`
63
74
 
64
75
  **Setting `value`, `open`, `checked`, or `active` sets the starting state and
65
76
  corrects the current state.** The element starts in that state and then applies
@@ -91,7 +102,7 @@ block a change, call `preventDefault()` on the matching `helix-before-*` event:
91
102
  A form reset returns the element to `default-value` and the matching attributes
92
103
  for the other states. See [State and control](./state-and-control).
93
104
 
94
- ### 2. Using the exact event name
105
+ ### 3. Using the exact event name
95
106
 
96
107
  In React, write `onhelix-before-open`. `onHelixOpen` and `onOpen` do not work.
97
108
  React removes `on` from the prop name and listens for exactly the rest, so the
@@ -105,7 +116,7 @@ so a menu closing inside a dialog does not close the dialog. `helix-select`,
105
116
  listen for them on a container. If a listener on a wrapper receives nothing, the
106
117
  event is a lifecycle event. Put the listener on the element.
107
118
 
108
- ### 3. Styling a disabled control with `:disabled`
119
+ ### 4. Styling a disabled control with `:disabled`
109
120
 
110
121
  ```css
111
122
  helix-input:disabled { … } /* right: matches a disabled fieldset too */
@@ -116,7 +127,7 @@ The browser disables a control inside `<fieldset disabled>` without adding an
116
127
  attribute to it. The `[disabled]` selector does not match it, so the control
117
128
  looks enabled while it does not accept input.
118
129
 
119
- ### 4. Loading every style layer before the elements
130
+ ### 5. Loading every style layer before the elements
120
131
 
121
132
  ```ts
122
133
  import '@fusion.dev/helix-styles/helix.css'
@@ -237,18 +248,15 @@ directory you own. You paste the line above, and you can delete it.
237
248
 
238
249
  ## Install the Helix MCP server
239
250
 
240
- ```json
241
- {
242
- "mcpServers": {
243
- "helix": { "command": "helix", "args": ["mcp"] }
244
- }
245
- }
251
+ ```sh
252
+ helix mcp init --client claude
246
253
  ```
247
254
 
248
- `helix mcp` is a subcommand of the CLI. It serves MCP over stdio, which Claude,
249
- Cursor, Windsurf, and Zed all read. It computes the theme a given brand color
250
- produces, which no document can list. It runs on your machine, talks to a client
251
- you chose, and makes no network requests.
255
+ `helix mcp` answers from the Helix packages your project installs: families,
256
+ examples, import lines, tokens, and the theme a brand color produces. `--client`
257
+ takes `claude`, `cursor`, or `vscode`, and writes the server into the file that
258
+ client reads. [Coding agents](./coding-agents) lists the tools. It runs on your
259
+ machine, talks to a client you chose, and makes no network requests.
252
260
 
253
261
  ## What this guide does not cover
254
262
 
@@ -256,10 +264,9 @@ you chose, and makes no network requests.
256
264
  and hooks change with the library, and they are in a file you can fetch. A list
257
265
  of them here would be a second copy that goes stale. Fetch the family.
258
266
 
259
- **The theme a brand color produces.** Helix computes it, so use `helix mcp`, an
260
- MCP server over stdio with `helix_audit_theme` and `helix_derive_theme`. Both
261
- take the same JSON that a `helix.theme.json` file holds. It runs on your
262
- machine, and we do not host it.
267
+ **The theme a brand color produces.** Helix computes it, so call
268
+ `helix_derive_theme`, or run `helix theme build`. Both take the same JSON that a
269
+ `helix.theme.json` file holds.
263
270
 
264
271
  **Whether a component fits your case.** Read the examples to decide. Every
265
272
  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 './catalog.js';
2
- export { catalog, findInCatalog } from './catalog.js';
3
- export { displayName, startCase, tierOf } from './naming.js';
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 './catalog.js';
2
- export { displayName, startCase, tierOf } from './naming.js';
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';
@@ -258,7 +258,7 @@ export const docPages = [
258
258
  title: 'Typography',
259
259
  },
260
260
  {
261
- description: 'Four mistakes that look like Helix bugs, and the files an agent should read.',
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',
@@ -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 {
@@ -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 './naming.js';
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')