@adia-ai/adia-ui-forge 0.1.2
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/.claude-plugin/plugin.json +23 -0
- package/CHANGELOG.md +26 -0
- package/README.md +54 -0
- package/bin/forge-lint +263 -0
- package/bin/lib/audit-axes.mjs +555 -0
- package/bin/lib/dry-run-irreversible.mjs +236 -0
- package/bin/lib/run-skill-evals.mjs +487 -0
- package/bin/lib/teach-router.mjs +250 -0
- package/commands/adia-forge-a2ui.md +10 -0
- package/commands/adia-forge-author.md +10 -0
- package/commands/adia-forge-dogfood.md +8 -0
- package/commands/adia-forge-llm.md +8 -0
- package/commands/adia-forge-orient.md +10 -0
- package/commands/adia-forge-release.md +8 -0
- package/commands/adia-forge-review.md +10 -0
- package/hooks/hooks.json +15 -0
- package/package.json +41 -0
- package/references/shared/content-trust.md +76 -0
- package/references/shared/pev-rationale.md +64 -0
- package/references/shared/skill-conventions.md +133 -0
- package/skills/adia-ui-a2ui/CHANGELOG.md +32 -0
- package/skills/adia-ui-a2ui/SKILL.md +243 -0
- package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +75 -0
- package/skills/adia-ui-a2ui/evals/routing-corpus.json +31 -0
- package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +100 -0
- package/skills/adia-ui-a2ui/references/anti-patterns.md +24 -0
- package/skills/adia-ui-a2ui/references/chunk-authoring.md +88 -0
- package/skills/adia-ui-a2ui/references/corpus-discipline.md +56 -0
- package/skills/adia-ui-a2ui/references/eval-diagnostics.md +127 -0
- package/skills/adia-ui-a2ui/references/fragment-graph.md +91 -0
- package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +106 -0
- package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +398 -0
- package/skills/adia-ui-a2ui/references/pipeline-overview.md +175 -0
- package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +120 -0
- package/skills/adia-ui-a2ui/references/strategy-engines.md +111 -0
- package/skills/adia-ui-a2ui/references/teach-protocol.md +220 -0
- package/skills/adia-ui-a2ui/references/zettel-calibration.md +93 -0
- package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +96 -0
- package/skills/adia-ui-a2ui/scripts/teach-route.mjs +157 -0
- package/skills/adia-ui-a2ui/skill.json +38 -0
- package/skills/adia-ui-authoring/CHANGELOG.md +32 -0
- package/skills/adia-ui-authoring/SKILL.md +256 -0
- package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +101 -0
- package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +109 -0
- package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +113 -0
- package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +138 -0
- package/skills/adia-ui-authoring/evals/routing-corpus.json +245 -0
- package/skills/adia-ui-authoring/references/anti-patterns.md +606 -0
- package/skills/adia-ui-authoring/references/api-contract.md +205 -0
- package/skills/adia-ui-authoring/references/authoring-cycle.md +211 -0
- package/skills/adia-ui-authoring/references/canonical-pattern-index.md +179 -0
- package/skills/adia-ui-authoring/references/code-style.md +329 -0
- package/skills/adia-ui-authoring/references/common-gotchas.md +93 -0
- package/skills/adia-ui-authoring/references/composite-demo-protocol.md +1084 -0
- package/skills/adia-ui-authoring/references/css-patterns.md +364 -0
- package/skills/adia-ui-authoring/references/lifecycle-patterns.md +302 -0
- package/skills/adia-ui-authoring/references/llm-bridge.md +254 -0
- package/skills/adia-ui-authoring/references/module-promotion.md +289 -0
- package/skills/adia-ui-authoring/references/primitive-audit.md +123 -0
- package/skills/adia-ui-authoring/references/shell-patterns.md +561 -0
- package/skills/adia-ui-authoring/references/teach-protocol.md +428 -0
- package/skills/adia-ui-authoring/references/token-contract.md +120 -0
- package/skills/adia-ui-authoring/references/worked-example.md +351 -0
- package/skills/adia-ui-authoring/references/yaml-contract.md +224 -0
- package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +148 -0
- package/skills/adia-ui-authoring/scripts/build-canonical-pattern-index.mjs +199 -0
- package/skills/adia-ui-authoring/skill.json +45 -0
- package/skills/adia-ui-dogfood/CHANGELOG.md +17 -0
- package/skills/adia-ui-dogfood/README.md +62 -0
- package/skills/adia-ui-dogfood/SKILL.md +866 -0
- package/skills/adia-ui-dogfood/scripts/analyze.mjs +603 -0
- package/skills/adia-ui-dogfood/skill.json +40 -0
- package/skills/adia-ui-forge/SKILL.md +88 -0
- package/skills/adia-ui-forge/evals/routing-corpus.json +30 -0
- package/skills/adia-ui-gen-review/CHANGELOG.md +108 -0
- package/skills/adia-ui-gen-review/SKILL.md +266 -0
- package/skills/adia-ui-gen-review/references/loop-protocol.md +712 -0
- package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +144 -0
- package/skills/adia-ui-gen-review/references/rubric-decompose.md +117 -0
- package/skills/adia-ui-gen-review/references/rubric-score.md +249 -0
- package/skills/adia-ui-gen-review/references/scores.schema.json +125 -0
- package/skills/adia-ui-gen-review/references/teach-protocol.md +214 -0
- package/skills/adia-ui-gen-review/scripts/gen-review-coverage-audit.mjs +127 -0
- package/skills/adia-ui-gen-review/scripts/gen-review-decompose.mjs +569 -0
- package/skills/adia-ui-gen-review/scripts/gen-review-status.mjs +176 -0
- package/skills/adia-ui-gen-review/scripts/validate-cycle-scores.mjs +198 -0
- package/skills/adia-ui-gen-review/skill.json +22 -0
- package/skills/adia-ui-llm/CHANGELOG.md +25 -0
- package/skills/adia-ui-llm/SKILL.md +165 -0
- package/skills/adia-ui-llm/evals/adversarial-corpus.json +75 -0
- package/skills/adia-ui-llm/evals/routing-corpus.json +30 -0
- package/skills/adia-ui-llm/evals/teach-routing-cases.json +73 -0
- package/skills/adia-ui-llm/references/adapter-contract.md +99 -0
- package/skills/adia-ui-llm/references/add-a-provider.md +90 -0
- package/skills/adia-ui-llm/references/bridge-facade.md +94 -0
- package/skills/adia-ui-llm/references/browser-proxy-boundary.md +89 -0
- package/skills/adia-ui-llm/references/model-registry.md +75 -0
- package/skills/adia-ui-llm/references/streaming-sse.md +95 -0
- package/skills/adia-ui-llm/references/teach-protocol.md +78 -0
- package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +93 -0
- package/skills/adia-ui-llm/scripts/teach-route.mjs +119 -0
- package/skills/adia-ui-llm/skill.json +33 -0
- package/skills/adia-ui-release/CHANGELOG.md +23 -0
- package/skills/adia-ui-release/SKILL.md +295 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +144 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +155 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +114 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +139 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +124 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +125 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +142 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +97 -0
- package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +147 -0
- package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +22 -0
- package/skills/adia-ui-release/evals/evals.json +164 -0
- package/skills/adia-ui-release/references/changelog-discipline.md +250 -0
- package/skills/adia-ui-release/references/cycle-happy-path.md +520 -0
- package/skills/adia-ui-release/references/exe-deploy.md +149 -0
- package/skills/adia-ui-release/references/gates-catalog.md +778 -0
- package/skills/adia-ui-release/references/ledger-discipline.md +232 -0
- package/skills/adia-ui-release/references/migration-guide-authoring.md +174 -0
- package/skills/adia-ui-release/references/multi-agent-baseline.md +207 -0
- package/skills/adia-ui-release/references/notes-authoring.md +212 -0
- package/skills/adia-ui-release/references/recovery-paths.md +215 -0
- package/skills/adia-ui-release/references/rollup-notes.md +208 -0
- package/skills/adia-ui-release/references/teach-protocol.md +468 -0
- package/skills/adia-ui-release/scripts/assert-monorepo-root.mjs +49 -0
- package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +196 -0
- package/skills/adia-ui-release/scripts/bump.mjs +118 -0
- package/skills/adia-ui-release/scripts/dispatch-publish.mjs +151 -0
- package/skills/adia-ui-release/scripts/insert-stub.mjs +127 -0
- package/skills/adia-ui-release/scripts/make-ledger.mjs +179 -0
- package/skills/adia-ui-release/scripts/promote-unreleased.mjs +88 -0
- package/skills/adia-ui-release/scripts/release-pack.mjs +350 -0
- package/skills/adia-ui-release/scripts/tag-lockstep.mjs +110 -0
- package/skills/adia-ui-release/skill.json +75 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# API Contract — Props, Attributes, Reflection
|
|
2
|
+
|
|
3
|
+
Deep dive on declaring component APIs in AdiaUI. Read this when adding a new prop whose shape doesn't match any obvious pattern in the good-citizen references.
|
|
4
|
+
|
|
5
|
+
## The `static properties` block
|
|
6
|
+
|
|
7
|
+
Every `AdiaElement` subclass declares its public API as a `static properties` object. Keys are camelCase JS names; values describe type, default, reflection, and attribute mapping.
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
static properties = {
|
|
11
|
+
disabled: { type: Boolean, default: false, reflect: true },
|
|
12
|
+
placeholder: { type: String, default: '', reflect: true },
|
|
13
|
+
value: { type: String, default: '' },
|
|
14
|
+
maxLength: { type: Number, default: null, reflect: true, attribute: 'max-length' },
|
|
15
|
+
};
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Field rules:**
|
|
19
|
+
|
|
20
|
+
- `type` — one of `String`, `Number`, `Boolean`, `Object`, `Array`. The runtime uses this to coerce attribute strings into typed values.
|
|
21
|
+
- `default` — the value the prop takes when no attribute is present AND no JS value has been assigned. For `Boolean` props, default is ALWAYS `false` (see rule 1). For numeric props, default is `0`, a real value, or `null` for indeterminate — NEVER a sentinel like `-1`.
|
|
22
|
+
- `reflect` — when `true`, JS property changes write back to the HTML attribute so CSS can match it. Required for every state-bearing Boolean. Usually safe to omit for large value props (long strings, big objects).
|
|
23
|
+
- `attribute` — explicit kebab-case mapping when the JS name doesn't auto-convert cleanly. `camelCase` → `camel-case` automatic; override via `attribute: 'max-length'` when you want non-default behavior.
|
|
24
|
+
|
|
25
|
+
## The `attr:` silent-typo trap
|
|
26
|
+
|
|
27
|
+
A real bug caught in iteration 4:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
// BROKEN — silent
|
|
31
|
+
allowHalf: { type: Boolean, default: false, reflect: true, attr: 'allow-half' },
|
|
32
|
+
|
|
33
|
+
// FIXED
|
|
34
|
+
allowHalf: { type: Boolean, default: false, reflect: true, attribute: 'allow-half' },
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`attr:` is not a recognized key. The mapper ignores it. The default auto-conversion (`allowHalf` → `allow-half`) happens to produce the same result, so the bug hides — until someone changes the prop name and notices the attribute never wired.
|
|
38
|
+
|
|
39
|
+
Use `attribute:` verbatim. If you think you're writing `attr:`, stop and correct it before saving.
|
|
40
|
+
|
|
41
|
+
## Boolean prop naming — the flip rule
|
|
42
|
+
|
|
43
|
+
AdiaUI conventions require `default: false` on all Booleans. The naming follows:
|
|
44
|
+
|
|
45
|
+
| Intended default behavior | Wrong name (default:true) | Right name (default:false) |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Modal can be dismissed | `closable` | `permanent` |
|
|
48
|
+
| Skeleton animates | `animate` | `static` |
|
|
49
|
+
| Stream shows blinking cursor | `cursor` | `hideCursor` |
|
|
50
|
+
| Chart shows average line | `average` | `hideAverage` |
|
|
51
|
+
| Toggle group allows multi-select | `multiple` | `single` |
|
|
52
|
+
| Swiper pauses on hover | `pause-on-hover` | `noPauseOnHover` |
|
|
53
|
+
|
|
54
|
+
**Naming patterns:**
|
|
55
|
+
|
|
56
|
+
- `permanent` / `static` / `readonly` — describes the non-default state positively.
|
|
57
|
+
- `no*` / `hide*` / `disable*` — prefixes for "opt-out of a default."
|
|
58
|
+
|
|
59
|
+
**Don't write:**
|
|
60
|
+
|
|
61
|
+
- `enabled` (invert to `disabled`), `visible` (invert to `hidden`) — these clash with standard HTML attribute vocabulary.
|
|
62
|
+
- Double-negatives like `unhide` or `dontSkip`.
|
|
63
|
+
|
|
64
|
+
## Numeric props — `null` over sentinels
|
|
65
|
+
|
|
66
|
+
Indeterminate, unknown, or "not yet set" numeric state uses `null`, not `-1` or `Infinity`:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// BROKEN — `-1` is a magic sentinel
|
|
70
|
+
value: { type: Number, default: -1, reflect: true }
|
|
71
|
+
// Consumer: if (this.value !== -1) { ... }
|
|
72
|
+
|
|
73
|
+
// FIXED
|
|
74
|
+
value: { type: Number, default: null, reflect: true }
|
|
75
|
+
// Consumer: if (this.value != null) { ... }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The `progress-ui` component carried `-1` for "indeterminate" for a long time. Branching on a specific number is fragile — someone assigns `-1` meaningfully later and the indeterminate check breaks silently. `null` is unambiguous.
|
|
79
|
+
|
|
80
|
+
**Back-compat coercion is allowed:**
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
set value(v) {
|
|
84
|
+
if (v === -1) v = null; // legacy input coercion, remove in a future cycle
|
|
85
|
+
this._value = v;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Reserved-name anti-patterns
|
|
90
|
+
|
|
91
|
+
These prop names collide with HTML semantics, framework-wide conventions, or create ambiguity in audit. Pick alternatives:
|
|
92
|
+
|
|
93
|
+
### `title`
|
|
94
|
+
|
|
95
|
+
HTML's global `title` attribute is the browser tooltip. Using `title` on a custom element makes any custom-element heading a tooltip by default, which is almost never intended. Use `heading`.
|
|
96
|
+
|
|
97
|
+
### `active` on a parent component
|
|
98
|
+
|
|
99
|
+
Children can have per-item `active` (a Boolean describing that item's state). Parents use `value` (for a selection) or `step` (for an index into a series).
|
|
100
|
+
|
|
101
|
+
- `<timeline-item-ui active>` — OK, per-item Boolean state.
|
|
102
|
+
- `<timeline-ui step="3">` — correct: parent holds the index.
|
|
103
|
+
- `<timeline-ui active="3">` — wrong: `active` shouldn't carry a non-boolean payload.
|
|
104
|
+
|
|
105
|
+
### `error` as a variant
|
|
106
|
+
|
|
107
|
+
Reserve `error` for validation state (`[error]` on form inputs matches ARIA patterns). For visual emphasis meaning "destructive/negative," use `danger`, matching the semantic family (`--a-danger-*` tokens).
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<!-- wrong -->
|
|
111
|
+
<tag-ui variant="error">Failed</tag-ui>
|
|
112
|
+
|
|
113
|
+
<!-- right -->
|
|
114
|
+
<tag-ui variant="danger">Failed</tag-ui>
|
|
115
|
+
|
|
116
|
+
<!-- separate use -->
|
|
117
|
+
<input-ui error>Please enter a valid email</input-ui>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `disabled` on a non-form component
|
|
121
|
+
|
|
122
|
+
`disabled` has form-participating semantics — it removes the element from the tab order, blocks submission, etc. On a non-form component (a diagram, a toolbar, a noodle editor), use `readonly`:
|
|
123
|
+
|
|
124
|
+
- `<input-ui disabled>` — correct: input is form-participating.
|
|
125
|
+
- `<noodles-ui readonly>` — correct: diagram is read-only, not form-disabled.
|
|
126
|
+
|
|
127
|
+
### `multiple` with exclusion semantics
|
|
128
|
+
|
|
129
|
+
`<select multiple>` in HTML means "allow multiple selections." A prop named `multiple` means "multi-select is the default." If you want single-select as the default behavior:
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<!-- wrong: implies multiple was default, which violates Boolean-false rule -->
|
|
133
|
+
<toggle-group-ui multiple>...</toggle-group-ui>
|
|
134
|
+
|
|
135
|
+
<!-- right: single-select is the opt-out, matches Boolean-false -->
|
|
136
|
+
<toggle-group-ui single>...</toggle-group-ui>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Three-way name consistency
|
|
140
|
+
|
|
141
|
+
The component has three names that must agree:
|
|
142
|
+
|
|
143
|
+
- **File path:** `packages/web-components/components/foo/foo.js`
|
|
144
|
+
- **Class name:** `class AdiaFoo extends AdiaElement`
|
|
145
|
+
- **Custom element tag:** `customElements.define('foo-ui', AdiaFoo)`
|
|
146
|
+
|
|
147
|
+
A fourth consistency requirement: the CSS file at `packages/web-components/components/foo/foo.css` uses `@scope (foo-ui)`.
|
|
148
|
+
|
|
149
|
+
## Extending `AdiaFormElement`
|
|
150
|
+
|
|
151
|
+
Form-participating components extend `AdiaFormElement` (which extends `AdiaElement`) and get `ElementInternals` wiring, form-reset handling, and `.form` / `.labels` / `.validity` accessors for free.
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
import { AdiaFormElement } from '../../core/form.js';
|
|
155
|
+
|
|
156
|
+
class AdiaInput extends AdiaFormElement {
|
|
157
|
+
static properties = {
|
|
158
|
+
...AdiaFormElement.properties, // inherit name, value, disabled, required, etc.
|
|
159
|
+
placeholder: { type: String, default: '', reflect: true },
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
connected() {
|
|
163
|
+
super.connected(); // MUST call — registers ElementInternals
|
|
164
|
+
// ...
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
disconnected() {
|
|
168
|
+
super.disconnected(); // MUST call
|
|
169
|
+
// ...
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Override `value` getter/setter if the form-submitted value differs
|
|
173
|
+
// from the stored one
|
|
174
|
+
get value() { return this._value ?? ''; }
|
|
175
|
+
set value(v) { this._value = v; this.syncValue(String(v)); }
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Key details:
|
|
180
|
+
|
|
181
|
+
- **Always `super.connected()` and `super.disconnected()`** — without them, form-association doesn't register.
|
|
182
|
+
- **`this.syncValue(str)`** — call this whenever the value changes to update the form-submitted string. Accepts a string.
|
|
183
|
+
- **Inheriting properties** — spread `AdiaFormElement.properties` into your own `static properties` so you don't re-declare `name`, `disabled`, `required`.
|
|
184
|
+
|
|
185
|
+
## Event conventions
|
|
186
|
+
|
|
187
|
+
- Bubble custom events: `new CustomEvent('foo', { bubbles: true, detail: {...} })`.
|
|
188
|
+
- Reuse standard events where possible: `input`, `change`, `submit`, `focus`.
|
|
189
|
+
- Custom event names are kebab-case: `cot-toggle`, `noodle-connected`.
|
|
190
|
+
- When dispatching state changes, fire `input` during interaction and `change` on commit. Matches native form semantics.
|
|
191
|
+
|
|
192
|
+
## When to add the `render()` method
|
|
193
|
+
|
|
194
|
+
`render()` runs when reflected attributes change. Use it to update internal DOM that depends on props:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
render() {
|
|
198
|
+
if (this.#textareaEl) {
|
|
199
|
+
this.#textareaEl.disabled = this.disabled;
|
|
200
|
+
this.#textareaEl.placeholder = this.placeholder;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Rule of thumb: if CSS can do the work via an attribute selector (`:scope[disabled] { ... }`), prefer CSS. Reserve `render()` for propagating state into child inputs, recalculating positions, or reflecting data changes that attribute selectors can't express.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Authoring cycle — modes 1 & 2 (NEW or MODIFY primitive)
|
|
2
|
+
|
|
3
|
+
The 5-step procedure run AFTER [primitive-audit.md](primitive-audit.md) clears (mode 1) or jumping straight to Step 2 (mode 2: modify existing).
|
|
4
|
+
|
|
5
|
+
Absorbed from the legacy author skill's Workflow section.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Step 1 — Read the contract and the reference components
|
|
10
|
+
|
|
11
|
+
Before writing or editing, load these four files. They are the ground truth:
|
|
12
|
+
|
|
13
|
+
- `docs/specs/component-token-contract.md` — the authoritative invariants. Skim the whole thing if you haven't read it this session; focus on "Variants vs Modes" and "Sanctioned Mode Attributes" if you're adding a new layout-affecting attribute.
|
|
14
|
+
- `packages/web-components/core/element.js` — `AdiaElement` base class. The `static properties` schema, `connected()`/`disconnected()`/`render()` lifecycle, and attribute-mapping conventions are all defined here.
|
|
15
|
+
- `packages/web-components/core/form.js` — `AdiaFormElement`. Only needed if the new component participates in forms (inputs, selects, checkboxes, etc.).
|
|
16
|
+
- At least one good-citizen reference that matches the shape of what you're building. Pick from: `button-ui`, `card-ui`, `input-ui`, `textarea-ui`, `check-ui`. Read both the `.js` and the `.css`.
|
|
17
|
+
|
|
18
|
+
## Step 2 — Classify the work before you write
|
|
19
|
+
|
|
20
|
+
Before typing, answer:
|
|
21
|
+
|
|
22
|
+
1. **Is this cosmetic or structural?** If the change affects `display`, `flex-direction`, `grid-template`, `padding`, layout geometry — it's a mode, not a variant. Modes require an entry in the Sanctioned Mode Attributes table (`docs/specs/component-token-contract.md` `Modes` section). Do not introduce undocumented layout-changing variants.
|
|
23
|
+
|
|
24
|
+
2. **Does the new prop fit the Boolean-default-false rule?** If the default behavior is "on," negate the prop name before writing (`closable` is wrong if closable is the default; `permanent` is right).
|
|
25
|
+
|
|
26
|
+
3. **Does the component hold state that CSS needs to read?** If yes, every state-bearing Boolean declares `{ type: Boolean, default: false, reflect: true }`.
|
|
27
|
+
|
|
28
|
+
4. **Does the component add listeners, timers, or observers?** If yes, plan the `disconnected()` method at the same time as `connected()` — do not defer. The symmetric pair is one unit of work, never two.
|
|
29
|
+
|
|
30
|
+
## Step 3 — Apply the non-negotiable rules
|
|
31
|
+
|
|
32
|
+
These rules are the distilled lessons from a 5-iteration audit. Each one corresponds to a real bug that was fixed in the codebase. Full rationale and the bug histories are in [anti-patterns.md](anti-patterns.md).
|
|
33
|
+
|
|
34
|
+
### API / Attributes
|
|
35
|
+
|
|
36
|
+
1. **Boolean defaults are `false`.** If the expected default is "on," rename: `closable` → `permanent`, `animate` → `static`, `cursor` → `hideCursor`, `average` → `hideAverage`, `pause-on-hover` → `noPauseOnHover`.
|
|
37
|
+
|
|
38
|
+
2. **No magic-value sentinels in numeric props.** Indeterminate = `null`, not `-1`. Consumers branch on `value == null`, which is explicit.
|
|
39
|
+
|
|
40
|
+
3. **Use `attribute:` not `attr:`.** `attr:` is a silent typo — the mapper ignores it and the kebab-case HTML attribute never wires. This cost a real bug in `rating-ui`.
|
|
41
|
+
|
|
42
|
+
4. **State-bearing Booleans reflect.** `{ type: Boolean, default: false, reflect: true }`. Without `reflect`, CSS can't match `:scope[disabled]`, hover/active/selected states break silently.
|
|
43
|
+
|
|
44
|
+
5. **Reserved-name anti-patterns.** Avoid: `title` (collides with HTML tooltip attribute), `active` on parent components (use `value` for a selection or `step` for an index — per-item `active` on children is fine), `error` in variant names (use `danger`; reserve `error` for validation state), `disabled` on non-form-participating components (use `readonly`), `multiple` with exclusion semantics (use a negated positive like `single`).
|
|
45
|
+
|
|
46
|
+
6. **Element tag ends in `-ui`; JS class is `Adia<Component>`.** `<foo-ui>` ↔ `class AdiaFoo extends AdiaElement`. Three-way consistency: filename, class name, custom-element tag. The sanctioned `-n` carve-out is `cot-ui` (the chain-of-thought streaming component); `nav-ui` was deprecated in favor of the `-ui` replacements. New `-n` tags require a contract-doc update — see `docs/specs/component-token-contract.md`.
|
|
47
|
+
|
|
48
|
+
### CSS
|
|
49
|
+
|
|
50
|
+
1. **Two-block `@scope` structure** is mandatory:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
@scope (component-ui) {
|
|
54
|
+
:where(:scope) {
|
|
55
|
+
/* ── Tokens ── */
|
|
56
|
+
--component-bg: var(--a-bg);
|
|
57
|
+
--component-fg: var(--a-fg);
|
|
58
|
+
/* ...all component tokens here, zero-specificity */
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:scope {
|
|
62
|
+
/* ── Base styles — consume only component tokens ── */
|
|
63
|
+
background: var(--component-bg);
|
|
64
|
+
color: var(--component-fg);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ── Variants / states third — override TOKENS only ── */
|
|
68
|
+
:scope[variant="outlined"] {
|
|
69
|
+
--component-bg: transparent;
|
|
70
|
+
--component-border: var(--a-border);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
2. **Variants override tokens only.** A variant body may only contain `--component-*: var(...)` lines. Never `padding`, `display`, `position`, `width`, `height`, `margin`, `gap`, `flex`, `grid`, `overflow`, `border-radius`. Layout changes are modes, see rule 3 in Step 2.
|
|
76
|
+
|
|
77
|
+
3. **Zero raw colors in component CSS.** No `#hex`, `rgb()`, `rgba()`, `oklch()` outside `packages/web-components/styles/colors/semantics.css` and `packages/web-components/styles/tokens.css`. Every color goes through a token.
|
|
78
|
+
|
|
79
|
+
4. **Raw px ≥ 3 is forbidden.** Use `var(--a-space-*)`. Stroke/border widths (1–2px) and documented component-intrinsic constants are carve-outs, and each carve-out needs a one-line code comment explaining why the literal.
|
|
80
|
+
|
|
81
|
+
5. **Component tokens follow `--<tag-stem>-<prop>`.** `--button-bg`, not `--btn-bg`. Files hosting multiple `@scope` blocks (e.g. `layout.css` with `col-ui`, `row-ui`, `stack-ui`) use each scope's own stem (`--col-gap`, `--row-gap`, `--stack-gap`).
|
|
82
|
+
|
|
83
|
+
6. **Consume L3, not L2.** In a variant/state body, alias from the role×state matrix, not the family base. Right: `--button-fg-hover: var(--a-accent-fg-hover)`. Wrong: `--button-fg: var(--a-accent)`.
|
|
84
|
+
|
|
85
|
+
7. **No BEM, no `::part()`, no `::slotted()`.** AdiaUI is light-DOM; the shadow-DOM escape hatches don't apply. Slots are styled through slotted attribute selectors (`:scope > [slot="foo"]`), not `::slotted()`.
|
|
86
|
+
|
|
87
|
+
### JS Lifecycle
|
|
88
|
+
|
|
89
|
+
1. **Every `addEventListener` in `connected()` has a matching `removeEventListener` in `disconnected()`.** Handler must be a stable `#field` arrow (`#onClick = (e) => { ... }`), never an inline arrow passed to `addEventListener`. Inline arrows can't be removed — `removeEventListener` needs reference equality.
|
|
90
|
+
|
|
91
|
+
2. **`AdiaFormElement` subclasses call `super.connected()` and `super.disconnected()`.** `ElementInternals` registration depends on it. Omitting `super` strands the form-association.
|
|
92
|
+
|
|
93
|
+
3. **Timers and observers are torn down.** `clearInterval`, `clearTimeout`, `ResizeObserver.disconnect()`, `MutationObserver.disconnect()`, `IntersectionObserver.disconnect()` all in `disconnected()`.
|
|
94
|
+
|
|
95
|
+
4. **Null cached DOM refs in `disconnected()`.** `this.#fooEl = null` after removing its listeners. Prevents stale-tree GC pinning when the component is re-attached.
|
|
96
|
+
|
|
97
|
+
5. **Never declare `disconnected()` twice in one class.** The second silently overrides the first — this exact bug lost `ResizeObserver` cleanup in `chart.js` for several commits. If you find yourself needing a "second disconnected," merge it into the existing one.
|
|
98
|
+
|
|
99
|
+
6. **Popover/tooltip overlays created in `connected()` are removed in `disconnected()`.** Anything appended to `document.body` or `<body>` via the Popover API needs explicit cleanup; they don't GC with the host.
|
|
100
|
+
|
|
101
|
+
7. **Inline arrows on dynamically created ephemeral DOM are tolerated only when the container is guaranteed fully-detached before re-render.** If a row is built fresh per render and the parent's `innerHTML` replacement detaches the old subtree, GC collects the listeners with their nodes. If the container persists, use stable handlers or event delegation on the parent.
|
|
102
|
+
|
|
103
|
+
### Field composition
|
|
104
|
+
|
|
105
|
+
1. **Do not add a `label` attribute to a new form-associated control.** `<field-ui label="…">` is the canonical labeled-field wrapper. It owns the real `<label for="…">` and binds to the slotted control's id for proper click-to-focus — a pattern the embedded per-control `label` attribute can't provide (no `[for]`, just a shadow slot). Existing controls (input-ui, select-ui, textarea-ui, switch-ui, check-ui, radio-ui, slider-ui, calendar-picker-ui, upload-ui, range-ui) still accept the legacy `label` attr but log a one-shot console.warn; **no new control should declare one**. Wrap instead:
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<!-- right -->
|
|
109
|
+
<field-ui label="Email">
|
|
110
|
+
<input-ui type="email" value="…"></input-ui>
|
|
111
|
+
</field-ui>
|
|
112
|
+
|
|
113
|
+
<!-- wrong (deprecated) -->
|
|
114
|
+
<input-ui label="Email" type="email" value="…"></input-ui>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`field-ui` also carries `[slot="trailing"]` and `[slot="action"]` composition slots + an `inline` mode attribute (stacked vs. single-row). See the Field component at `packages/web-components/components/field/`.
|
|
118
|
+
|
|
119
|
+
### Nested-control composition
|
|
120
|
+
|
|
121
|
+
1. **Composite hosts own the focus ring; nested form controls suppress theirs.** When a composite wraps a form control as an internal implementation detail (textarea-ui inside chat-input-ui is the canonical example), the composite IS the primary surface from a user's perspective. Focus should wrap the whole composite, not just the inner control. Pattern:
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
@scope (my-composite-ui) {
|
|
125
|
+
/* 1. Composite paints the ring via :focus-within —
|
|
126
|
+
wraps both the control and any siblings inside the shell. */
|
|
127
|
+
:scope:focus-within {
|
|
128
|
+
box-shadow: var(--my-composite-focus-ring);
|
|
129
|
+
}
|
|
130
|
+
:scope[aria-invalid="true"]:focus-within,
|
|
131
|
+
:scope[error]:focus-within {
|
|
132
|
+
box-shadow: var(--my-composite-focus-ring-invalid);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* 2. Suppress the inner control's own focus affordance.
|
|
136
|
+
The @scope block's containment IS the signal — no data
|
|
137
|
+
attribute or explicit opt-in needed; selectors targeting
|
|
138
|
+
inner elements only apply when they're inside this host. */
|
|
139
|
+
textarea-ui [slot="text"]:focus {
|
|
140
|
+
box-shadow: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Tokens follow the L3 pattern from rule 12:
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
--my-composite-focus-ring: var(--a-focus-ring);
|
|
149
|
+
--my-composite-focus-ring-invalid: var(--a-focus-ring-invalid);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**When to use this (not field-ui):**
|
|
153
|
+
- **field-ui** is a _wrapper composite_ — it adds chrome (label / hint / error / required) around a control, but the control is still the primary focus target. Control owns the ring.
|
|
154
|
+
- **chat-input-ui** (and future equivalents) are _shell composites_ — the composite IS the control; the inner textarea is an implementation detail. Host owns the ring.
|
|
155
|
+
|
|
156
|
+
A user's mental model is the discriminator: do they think of the composite as a single control, or as a labeled/wrapped version of an inner control? The former is a shell; the latter is a wrapper.
|
|
157
|
+
|
|
158
|
+
## Step 4 — Run the 30-second self-check
|
|
159
|
+
|
|
160
|
+
Before declaring the work done, run through this checklist. If anything fails, fix before committing.
|
|
161
|
+
|
|
162
|
+
### Attributes
|
|
163
|
+
|
|
164
|
+
- [ ] No Boolean prop has `default: true`.
|
|
165
|
+
- [ ] No numeric prop uses `-1` or other sentinels (indeterminate = `null`).
|
|
166
|
+
- [ ] Every `static properties` entry uses `attribute:` (not `attr:`).
|
|
167
|
+
- [ ] Every state-bearing Boolean has `reflect: true`.
|
|
168
|
+
- [ ] No reserved-name anti-patterns (`title`, parent-level `active`, `error` variant, `disabled` on non-form, exclusion-`multiple`).
|
|
169
|
+
- [ ] Element tag ends in `-ui`; class is `Adia<Component>`.
|
|
170
|
+
|
|
171
|
+
### CSS
|
|
172
|
+
|
|
173
|
+
- [ ] File opens with `@scope (component-ui) {` and has both `:where(:scope)` (tokens) and `:scope` (base styles) blocks.
|
|
174
|
+
- [ ] Variants in the file contain ONLY `--component-*: var(...)` lines.
|
|
175
|
+
- [ ] Zero `#hex` / `rgb()` / `rgba()` / `oklch()` in the file.
|
|
176
|
+
- [ ] Zero raw `px` values ≥ 3 (or each has a one-line justification comment).
|
|
177
|
+
- [ ] Component tokens prefixed with the scope's tag-stem.
|
|
178
|
+
- [ ] Variant/state bodies alias from L3 (`--a-<family>-<role>-<state>`), not L2 (`--a-<family>`).
|
|
179
|
+
|
|
180
|
+
### Lifecycle
|
|
181
|
+
|
|
182
|
+
- [ ] Every `addEventListener` in `connected()` has a paired `removeEventListener` in `disconnected()`.
|
|
183
|
+
- [ ] All handlers passed to `addEventListener` are stable `#field` arrows (or bound method refs), not inline arrows.
|
|
184
|
+
- [ ] If the class extends `AdiaFormElement`, both `connected()` and `disconnected()` call `super`.
|
|
185
|
+
- [ ] Every timer/observer created in `connected()` is disposed in `disconnected()`.
|
|
186
|
+
- [ ] Cached DOM refs (`this.#fooEl`) are nulled in `disconnected()`.
|
|
187
|
+
- [ ] Class declares `disconnected()` exactly once.
|
|
188
|
+
|
|
189
|
+
## Step 5 — Run the project's verification gates
|
|
190
|
+
|
|
191
|
+
Before committing, run the project's verify scripts. These catch the drift-shaped bugs the checklist can miss:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npm run verify:components # component schema integrity (catalog)
|
|
195
|
+
npm run verify:palette # CVD thresholds across theme × scheme
|
|
196
|
+
node -c path/to/new/file.js # JS syntax check
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The full release-side gate roster lives in the **adia-ui-release** skill's gate catalog. Invoke `adia-ui-release` mode "Just verify" for the comprehensive sweep after any structural change.
|
|
200
|
+
|
|
201
|
+
If a gate fails, fix before declaring done.
|
|
202
|
+
|
|
203
|
+
## Cross-references
|
|
204
|
+
|
|
205
|
+
- [primitive-audit.md](primitive-audit.md) — mode 1 §0 gate (run BEFORE this)
|
|
206
|
+
- [api-contract.md](api-contract.md) — deep dive on prop naming, type choices, reflection policy
|
|
207
|
+
- [css-patterns.md](css-patterns.md) — exhaustive CSS architecture (@scope, variants, modes)
|
|
208
|
+
- [lifecycle-patterns.md](lifecycle-patterns.md) — timers, observers, popovers, listener patterns
|
|
209
|
+
- [anti-patterns.md](anti-patterns.md) — full failure-mode catalogue, file:line refs
|
|
210
|
+
- [worked-example.md](worked-example.md) — badge-ui + counter-ui walkthroughs
|
|
211
|
+
- [token-contract.md](token-contract.md) — mode 5 audit (post-implementation token check)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Canonical Pattern Index — survey targets for Mode 8 (composite-demo-protocol.md)
|
|
2
|
+
|
|
3
|
+
**Auto-generated** by `scripts/build-canonical-pattern-index.mjs`. Do not edit by hand — re-run the build script after adding new canonicals to `apps/`, `catalog/`, or `playgrounds/`.
|
|
4
|
+
|
|
5
|
+
This file is the checked-in snapshot the build script produces; the entries below are **representative** of a typical monorepo state (file lists + line counts will differ on your tree — re-run the build to refresh). The durable content is the **UI-type taxonomy** (the section headers + the lift-guidance under each): that taxonomy is the Phase 2 survey-target schema, and `ui_type` in Phase 1 must resolve to one of these section slugs.
|
|
6
|
+
|
|
7
|
+
## How to use this index
|
|
8
|
+
|
|
9
|
+
1. From Phase 1 of [composite-demo-protocol.md](composite-demo-protocol.md), name the UI type.
|
|
10
|
+
2. Find the matching section below.
|
|
11
|
+
3. Read every `.contents.html` listed (or the closest 2-3 if the section has many).
|
|
12
|
+
4. Extract primitive composition per Phase 3 of the protocol.
|
|
13
|
+
5. Cite the path in your demo's `<!-- Pattern source: ... -->` comment.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## billing
|
|
18
|
+
|
|
19
|
+
> Billing dashboards (current plan, invoices, payment methods, usage). Lift card-ui + section + col-ui + field-ui chain from billing.contents.html.
|
|
20
|
+
|
|
21
|
+
- `apps/saas/app/billing/billing.contents.html` (from SaaS app dashboards)
|
|
22
|
+
- `apps/user-flow/app/registration/billing/billing.contents.html` (from User-flow templates)
|
|
23
|
+
|
|
24
|
+
## dashboard
|
|
25
|
+
|
|
26
|
+
> Admin dashboards (KPI grids, overview cards). Lift grid-ui responsive columns from admin-dashboard.contents.html.
|
|
27
|
+
|
|
28
|
+
- `apps/saas/app/admin-dashboard/admin-dashboard.contents.html` (from SaaS app dashboards)
|
|
29
|
+
|
|
30
|
+
## settings
|
|
31
|
+
|
|
32
|
+
> Settings pages (preferences, security, appearance). Lift card-ui per setting group + col-ui spacing.
|
|
33
|
+
|
|
34
|
+
- `apps/saas/app/settings-page/settings-page.contents.html` (from SaaS app dashboards)
|
|
35
|
+
- `apps/user-flow/app/onboarding/notification-prefs/notification-prefs.contents.html` (from User-flow templates)
|
|
36
|
+
- `catalog/ui-patterns/app/settings-appearance/settings-appearance.contents.html` (from UI-pattern atomics)
|
|
37
|
+
- `catalog/ui-patterns/app/settings-notifications/settings-notifications.contents.html` (from UI-pattern atomics)
|
|
38
|
+
- `catalog/page-shells/app/settings-page/settings-page.contents.html` (from Page-shell templates)
|
|
39
|
+
|
|
40
|
+
## auth-flow
|
|
41
|
+
|
|
42
|
+
> Authentication flows (sign-in, MFA, OAuth, password reset). Lift single-column form layout from sign-in.contents.html siblings.
|
|
43
|
+
|
|
44
|
+
- `apps/user-flow/app/auth/forgot-password/forgot-password.contents.html` (from User-flow templates)
|
|
45
|
+
- `apps/user-flow/app/auth/reset-password/reset-password.contents.html` (from User-flow templates)
|
|
46
|
+
- `apps/user-flow/app/auth/sign-in/mfa/mfa.contents.html` (from User-flow templates)
|
|
47
|
+
- `apps/user-flow/app/auth/sign-in/sign-in.contents.html` (from User-flow templates)
|
|
48
|
+
- `apps/user-flow/app/auth/sign-up/mfa-setup/mfa-setup.contents.html` (from User-flow templates)
|
|
49
|
+
|
|
50
|
+
## onboarding-wizard
|
|
51
|
+
|
|
52
|
+
> Onboarding multi-step wizards. Lift step-progress + section + cta-row pattern.
|
|
53
|
+
|
|
54
|
+
- `apps/user-flow/app/onboarding/first-action/first-action.contents.html` (from User-flow templates)
|
|
55
|
+
- `apps/user-flow/app/onboarding/welcome/welcome.contents.html` (from User-flow templates)
|
|
56
|
+
|
|
57
|
+
## registration-wizard
|
|
58
|
+
|
|
59
|
+
> Registration multi-step flows. Lift wizard step + form composition.
|
|
60
|
+
|
|
61
|
+
- `apps/saas/app/profile-security/profile-security.contents.html` (from SaaS app dashboards)
|
|
62
|
+
- `apps/user-flow/app/auth/sign-up/profile/profile.contents.html` (from User-flow templates)
|
|
63
|
+
- `catalog/ui-patterns/app/user-profile-card/user-profile-card.contents.html` (from UI-pattern atomics)
|
|
64
|
+
|
|
65
|
+
## list-with-detail
|
|
66
|
+
|
|
67
|
+
> List + detail compositions (entity rows + drawer/modal detail). Lift entity-item + drawer pattern.
|
|
68
|
+
|
|
69
|
+
- `apps/saas/app/members/members.contents.html` (from SaaS app dashboards)
|
|
70
|
+
- `catalog/ui-patterns/app/users-table-badge/users-table-badge.contents.html` (from UI-pattern atomics)
|
|
71
|
+
|
|
72
|
+
## integrations-list
|
|
73
|
+
|
|
74
|
+
> Searchable integration/connector grids. Lift grid-ui + card-ui + empty-state-inside-card pattern.
|
|
75
|
+
|
|
76
|
+
- `apps/saas/app/integrations/integrations.contents.html` (from SaaS app dashboards)
|
|
77
|
+
- `apps/user-flow/app/registration/integrations/integrations.contents.html` (from User-flow templates)
|
|
78
|
+
|
|
79
|
+
## agent-activity
|
|
80
|
+
|
|
81
|
+
> Agent activity / reasoning feeds. Lift activity-feed scroll + collapsed-reasoning pattern.
|
|
82
|
+
|
|
83
|
+
- `catalog/ui-patterns/app/agent-activity-feed/agent-activity-feed.contents.html` (from UI-pattern atomics)
|
|
84
|
+
- `catalog/ui-patterns/app/agent-reasoning-collapsed/agent-reasoning-collapsed.contents.html` (from UI-pattern atomics)
|
|
85
|
+
- `catalog/page-shells/app/agent-canvas/agent-canvas.contents.html` (from Page-shell templates)
|
|
86
|
+
|
|
87
|
+
## chat
|
|
88
|
+
|
|
89
|
+
> Chat surfaces (thread, composer, sidebar). Lift chat-streaming-surface composition.
|
|
90
|
+
|
|
91
|
+
- `apps/genui/app/factory-chat/factory-chat.contents.html` (from GenUI app routes)
|
|
92
|
+
- `catalog/ui-patterns/app/chat-streaming-surface/chat-streaming-surface.contents.html` (from UI-pattern atomics)
|
|
93
|
+
- `catalog/page-shells/app/chat-page/chat-page.contents.html` (from Page-shell templates)
|
|
94
|
+
|
|
95
|
+
## editor
|
|
96
|
+
|
|
97
|
+
> Editor panes (code, preview, toolbar). Lift editor-shell composition.
|
|
98
|
+
|
|
99
|
+
- `apps/genui/app/a2ui-editor/a2ui-editor.contents.html` (from GenUI app routes)
|
|
100
|
+
- `catalog/ui-patterns/app/editor-code-pane/editor-code-pane.contents.html` (from UI-pattern atomics)
|
|
101
|
+
- `catalog/page-shells/app/editor-page/editor-page.contents.html` (from Page-shell templates)
|
|
102
|
+
|
|
103
|
+
## kanban
|
|
104
|
+
|
|
105
|
+
> Kanban / column-based boards. Lift kanban-board-3col pattern.
|
|
106
|
+
|
|
107
|
+
- `catalog/ui-patterns/app/kanban-board-3col/kanban-board-3col.contents.html` (from UI-pattern atomics)
|
|
108
|
+
- `catalog/page-shells/app/kanban-page/kanban-page.contents.html` (from Page-shell templates)
|
|
109
|
+
|
|
110
|
+
## data-table
|
|
111
|
+
|
|
112
|
+
> Data tables with badges/inline actions. Lift users-table-badge composition.
|
|
113
|
+
|
|
114
|
+
- `apps/user-flow/app/onboarding/import-data/import-data.contents.html` (from User-flow templates)
|
|
115
|
+
|
|
116
|
+
## command
|
|
117
|
+
|
|
118
|
+
> Command palette / global search. Lift command-palette overlay pattern.
|
|
119
|
+
|
|
120
|
+
- `catalog/ui-patterns/app/command-palette/command-palette.contents.html` (from UI-pattern atomics)
|
|
121
|
+
|
|
122
|
+
## overlay
|
|
123
|
+
|
|
124
|
+
> Modals, drawers, popovers. Lift destructive-confirm-modal pattern for confirmations.
|
|
125
|
+
|
|
126
|
+
- `apps/user-flow/app/registration/confirmation/confirmation.contents.html` (from User-flow templates)
|
|
127
|
+
- `catalog/ui-patterns/app/destructive-confirm-modal/destructive-confirm-modal.contents.html` (from UI-pattern atomics)
|
|
128
|
+
|
|
129
|
+
## multi-step-funnel
|
|
130
|
+
|
|
131
|
+
> Multi-step conversion funnels. Lift conversion-funnel-6step composition.
|
|
132
|
+
|
|
133
|
+
- `catalog/ui-patterns/app/conversion-funnel-6step/conversion-funnel-6step.contents.html` (from UI-pattern atomics)
|
|
134
|
+
|
|
135
|
+
## feed
|
|
136
|
+
|
|
137
|
+
> Activity / event feeds. Lift activity-feed composition.
|
|
138
|
+
|
|
139
|
+
- `apps/genui/app/gen-ui-feed/gen-ui-feed.contents.html` (from GenUI app routes)
|
|
140
|
+
|
|
141
|
+
## marketing
|
|
142
|
+
|
|
143
|
+
> Marketing pages, hero CTAs. Lift marketing-hero-cta composition.
|
|
144
|
+
|
|
145
|
+
- `catalog/ui-patterns/app/marketing-hero-cta/marketing-hero-cta.contents.html` (from UI-pattern atomics)
|
|
146
|
+
- `catalog/page-shells/app/marketing-page/marketing-page.contents.html` (from Page-shell templates)
|
|
147
|
+
|
|
148
|
+
## error-page
|
|
149
|
+
|
|
150
|
+
> Error states (404, 500, forbidden, expired). Lift centered single-card error pattern.
|
|
151
|
+
|
|
152
|
+
- `apps/user-flow/app/auth/account-locked/account-locked.contents.html` (from User-flow templates)
|
|
153
|
+
- `apps/user-flow/app/auth/session-expired/session-expired.contents.html` (from User-flow templates)
|
|
154
|
+
- `catalog/page-shells/app/error-page/error-page.contents.html` (from Page-shell templates)
|
|
155
|
+
|
|
156
|
+
## demo-playground
|
|
157
|
+
|
|
158
|
+
> Internal demo + playground surfaces. Use these as reference for composition style; not always production-grade.
|
|
159
|
+
|
|
160
|
+
- `apps/genui/app/a2ui/a2ui.contents.html` (from GenUI app routes)
|
|
161
|
+
- `apps/genui/app/css-channel-demo/css-channel-demo.contents.html` (from GenUI app routes)
|
|
162
|
+
|
|
163
|
+
## other
|
|
164
|
+
|
|
165
|
+
> Misc canonicals. Inspect contents.html to determine UI type.
|
|
166
|
+
|
|
167
|
+
- Any `.contents.html` whose slug fragment matches none of the heuristics above lands here. Inspect each to determine its UI type, or extend the `inferUiType()` regex (see Maintenance).
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Maintenance
|
|
172
|
+
|
|
173
|
+
Re-build this index:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
node scripts/build-canonical-pattern-index.mjs
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
If a heuristic misclassifies a path (the file lands in `other` or the wrong UI type), update the `inferUiType()` regex in `scripts/build-canonical-pattern-index.mjs`.
|