@adia-ai/adia-ui-factory 0.2.4 → 0.8.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/.claude-plugin/plugin.json +5 -7
- package/.mcp.json +1 -1
- package/CHANGELOG.md +27 -67
- package/README.md +32 -53
- package/agents/app-architect.md +28 -0
- package/agents/routing-corpus.json +202 -0
- package/agents/screen-composer.md +27 -0
- package/bin/adia-lint +17 -2
- package/commands/adia-genui.md +5 -8
- package/commands/adia-migrate.md +5 -6
- package/commands/adia-orient.md +5 -10
- package/commands/adia-scaffold.md +7 -13
- package/commands/adia-verify.md +5 -6
- package/package.json +5 -6
- package/references/a2ui-mcp-tools.md +11 -8
- package/references/authoring-components.md +25 -1
- package/references/component-model.md +52 -4
- package/references/contracts/a2ui-mcp-surface.md +35 -0
- package/references/contracts/migration-guide-format.md +34 -0
- package/references/data-and-hydration.md +8 -5
- package/references/genui-a2ui.md +12 -6
- package/references/llm.md +22 -39
- package/references/migration.md +110 -36
- package/references/project-shapes.md +11 -13
- package/references/shell-admin.md +5 -2
- package/references/shell-chat.md +5 -3
- package/references/shell-editor.md +1 -1
- package/references/shell-embed.md +40 -26
- package/references/shell-simple.md +5 -2
- package/references/spa-architecture.md +28 -73
- package/references/ssr-integration.md +1 -1
- package/references/verification.md +8 -12
- package/skills/adia-compose/SKILL.md +52 -0
- package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/Guidelines.md +3 -3
- package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/components.md +1 -1
- package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/styles.md +1 -1
- package/skills/{adia-ui-kit → adia-compose}/assets/figma-make/guidelines/tokens.md +3 -3
- package/skills/{adia-ui-kit → adia-compose}/assets/templates/FEEDBACK.template.md +7 -7
- package/skills/{adia-ui-kit → adia-compose}/assets/templates/RESPONSE.template.md +6 -7
- package/skills/adia-compose/references/composition-traps.md +58 -0
- package/skills/adia-compose/references/feedback-discipline.md +20 -0
- package/skills/adia-compose/references/spec-to-ui-reasoning.md +158 -0
- package/skills/adia-data/SKILL.md +78 -0
- package/skills/adia-genui/SKILL.md +83 -0
- package/skills/adia-host/SKILL.md +119 -0
- package/skills/adia-llm/SKILL.md +36 -0
- package/skills/adia-migrate/SKILL.md +76 -0
- package/skills/adia-orient/SKILL.md +123 -0
- package/skills/adia-project/SKILL.md +83 -0
- package/skills/adia-shells/SKILL.md +74 -0
- package/skills/adia-verify/SKILL.md +43 -0
- package/skills/adia-verify/references/verification.md +42 -0
- package/commands/adia-compose.md +0 -10
- package/commands/adia-wire.md +0 -13
- package/skills/adia-ui-compose/SKILL.md +0 -57
- package/skills/adia-ui-data/SKILL.md +0 -62
- package/skills/adia-ui-factory/SKILL.md +0 -113
- package/skills/adia-ui-genui/SKILL.md +0 -74
- package/skills/adia-ui-kit/CHANGELOG.md +0 -41
- package/skills/adia-ui-kit/SKILL.md +0 -442
- package/skills/adia-ui-kit/assets/team-scaffold/archive-README.md +0 -30
- package/skills/adia-ui-kit/assets/team-scaffold/drafts-README.md +0 -57
- package/skills/adia-ui-kit/assets/team-scaffold/inbox-README.md +0 -76
- package/skills/adia-ui-kit/assets/team-scaffold/outbox-README.md +0 -46
- package/skills/adia-ui-kit/assets/team-scaffold/team-root.README.md +0 -51
- package/skills/adia-ui-kit/assets/team-scaffold/tickets-README.md +0 -208
- package/skills/adia-ui-kit/assets/team-scaffold/tickets-REGISTRY.md +0 -81
- package/skills/adia-ui-kit/assets/templates/AGENTS.template.md +0 -128
- package/skills/adia-ui-kit/assets/templates/CLAUDE.template.md +0 -1
- package/skills/adia-ui-kit/assets/templates/figma-make-guidelines.md +0 -90
- package/skills/adia-ui-kit/evals/adversarial-content-trust.json +0 -83
- package/skills/adia-ui-kit/evals/evals.json +0 -55
- package/skills/adia-ui-kit/evals/routing-corpus.json +0 -121
- package/skills/adia-ui-kit/evals/teach-routing-cases.json +0 -92
- package/skills/adia-ui-kit/references/capabilities.md +0 -245
- package/skills/adia-ui-kit/references/catalog-lookup.md +0 -186
- package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v1.md +0 -8
- package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v2.md +0 -3585
- package/skills/adia-ui-kit/references/changelog-archive/CHANGELOG-v3.md +0 -1899
- package/skills/adia-ui-kit/references/common-gotchas-consumer.md +0 -522
- package/skills/adia-ui-kit/references/component-literacy.md +0 -291
- package/skills/adia-ui-kit/references/composition.md +0 -245
- package/skills/adia-ui-kit/references/correction-loop.md +0 -462
- package/skills/adia-ui-kit/references/css-policy.md +0 -343
- package/skills/adia-ui-kit/references/decision-model.md +0 -158
- package/skills/adia-ui-kit/references/diagnostic-output.md +0 -57
- package/skills/adia-ui-kit/references/docs-catalog.md +0 -239
- package/skills/adia-ui-kit/references/exclusions.md +0 -225
- package/skills/adia-ui-kit/references/feedback-authoring.md +0 -466
- package/skills/adia-ui-kit/references/figma-make.md +0 -244
- package/skills/adia-ui-kit/references/flows-auth.md +0 -307
- package/skills/adia-ui-kit/references/flows-content.md +0 -206
- package/skills/adia-ui-kit/references/flows-data.md +0 -348
- package/skills/adia-ui-kit/references/flows-interaction.md +0 -181
- package/skills/adia-ui-kit/references/flows-shells.md +0 -336
- package/skills/adia-ui-kit/references/gap-detection.md +0 -266
- package/skills/adia-ui-kit/references/harness.md +0 -284
- package/skills/adia-ui-kit/references/loading-protocol.md +0 -406
- package/skills/adia-ui-kit/references/local-link.md +0 -198
- package/skills/adia-ui-kit/references/mcp.md +0 -401
- package/skills/adia-ui-kit/references/migration.md +0 -116
- package/skills/adia-ui-kit/references/mission.md +0 -194
- package/skills/adia-ui-kit/references/mode-routing.md +0 -298
- package/skills/adia-ui-kit/references/patterns-agent.md +0 -223
- package/skills/adia-ui-kit/references/patterns-data.md +0 -1065
- package/skills/adia-ui-kit/references/patterns-forms.md +0 -223
- package/skills/adia-ui-kit/references/patterns-layout.md +0 -326
- package/skills/adia-ui-kit/references/patterns-recipes.md +0 -1416
- package/skills/adia-ui-kit/references/patterns-shells.md +0 -1097
- package/skills/adia-ui-kit/references/patterns-traits.md +0 -259
- package/skills/adia-ui-kit/references/patterns-wiring.md +0 -339
- package/skills/adia-ui-kit/references/pev-rationale.md +0 -137
- package/skills/adia-ui-kit/references/reasoning-gate.md +0 -146
- package/skills/adia-ui-kit/references/reasoning-methodologies.md +0 -112
- package/skills/adia-ui-kit/references/recon.md +0 -192
- package/skills/adia-ui-kit/references/rendering-model.md +0 -431
- package/skills/adia-ui-kit/references/response-authoring.md +0 -398
- package/skills/adia-ui-kit/references/session-log-schema.md +0 -203
- package/skills/adia-ui-kit/references/session-log-template.md +0 -118
- package/skills/adia-ui-kit/references/setup.md +0 -652
- package/skills/adia-ui-kit/references/skill-hygiene.md +0 -135
- package/skills/adia-ui-kit/references/spec-to-ui-reasoning.md +0 -394
- package/skills/adia-ui-kit/references/state.md +0 -229
- package/skills/adia-ui-kit/references/teach-protocol.md +0 -421
- package/skills/adia-ui-kit/references/theme.md +0 -142
- package/skills/adia-ui-kit/references/version-check.md +0 -69
- package/skills/adia-ui-kit/scripts/audit-decision-trace.mjs +0 -198
- package/skills/adia-ui-kit/scripts/audit-kit-roster.mjs +0 -366
- package/skills/adia-ui-kit/scripts/changelog-archive.mjs +0 -126
- package/skills/adia-ui-kit/scripts/check-adia-versions.py +0 -404
- package/skills/adia-ui-kit/scripts/run-skill-evals.mjs +0 -358
- package/skills/adia-ui-kit/scripts/validate-session-log.mjs +0 -242
- package/skills/adia-ui-kit/skill.json +0 -102
- package/skills/adia-ui-llm/SKILL.md +0 -51
- package/skills/adia-ui-migrate/SKILL.md +0 -64
- package/skills/adia-ui-migration/CHANGELOG.md +0 -47
- package/skills/adia-ui-migration/SKILL.md +0 -381
- package/skills/adia-ui-migration/skill.json +0 -29
- package/skills/adia-ui-project/SKILL.md +0 -77
- package/skills/adia-ui-shells/SKILL.md +0 -62
- package/skills/adia-ui-spa/SKILL.md +0 -52
- package/skills/adia-ui-ssr/SKILL.md +0 -52
- package/skills/adia-ui-verify/SKILL.md +0 -44
- /package/skills/{adia-ui-kit → adia-compose}/assets/templates/FEEDBACK-OMISSIONS-DEFENSE.template.md +0 -0
package/references/migration.md
CHANGED
|
@@ -1,57 +1,131 @@
|
|
|
1
|
-
|
|
2
|
-
name: migration
|
|
3
|
-
load-when: migrating an adia-ui app — version upgrade, port-to-adia, or mode change
|
|
4
|
-
load-size: ~2.5k tokens
|
|
5
|
-
required-for: [adia-ui-migrate — all types]
|
|
6
|
-
---
|
|
1
|
+
# Migration — types, history, sweep depth
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
Consumer migrations: the durable method + the shape of past breaks. The framework MIGRATION
|
|
4
|
+
GUIDE (`.claude/docs/MIGRATION GUIDE.md` in the framework repo — the space in the filename is
|
|
5
|
+
intentional) is the per-version source of truth; its required shape is
|
|
6
|
+
[`contracts/migration-guide-format.md`](contracts/migration-guide-format.md). Loaded by
|
|
7
|
+
`adia-migrate` (all migration types). Versions and examples below are a snapshot, not a registry.
|
|
11
8
|
|
|
12
9
|
## Types
|
|
13
10
|
|
|
14
|
-
- **version-upgrade** — bump `@adia-ai/*` X→Y (lockstep; all packages move together). PATCH
|
|
15
|
-
|
|
16
|
-
- **
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
- **version-upgrade** — bump `@adia-ai/*` X→Y (lockstep; all packages move together). PATCH
|
|
12
|
+
cuts are drop-in; MINOR/MAJOR carry breaking items.
|
|
13
|
+
- **port-to-adia** — an existing app (raw HTML, or legacy `@agent-ui-kit`) → adia-ui: a tag
|
|
14
|
+
rename map (`aui-button`→`button-ui`, `<button>`→`<button-ui>`) + token namespace swap
|
|
15
|
+
(`--n-*`→`--a-*`).
|
|
16
|
+
- **mode-change** — SPA↔SSR: re-own routing (framework router vs `<router-ui>`), registration
|
|
17
|
+
(top-level vs client-hook), and state (signals vs cookies). `adia-host` carries both paths.
|
|
18
|
+
|
|
19
|
+
## The 5-step sweep — depth
|
|
20
|
+
|
|
21
|
+
1. **Read the guide** for the version span: index bullets → per-cut sections. Each breaking
|
|
22
|
+
item ships an old form, a new form, and a greppable pattern (the contract above). A missing
|
|
23
|
+
section, or an item without a pattern/verify command, is a producer defect — pause, report
|
|
24
|
+
upstream; don't improvise a breaking surface.
|
|
25
|
+
2. **Audit** — `git grep -nE '<pattern>'` per item; cluster by component; report file +
|
|
26
|
+
occurrence counts and show the list before changing anything. Consumer code has edge cases
|
|
27
|
+
the canonical regexes don't anticipate (a `variant="danger"` on a non-button custom element
|
|
28
|
+
that shares the prefix).
|
|
29
|
+
3. **Sweep** — mechanical per approved cluster:
|
|
23
30
|
|
|
24
31
|
```bash
|
|
25
32
|
git grep -lE 'button-ui[^>]*variant="danger"' \
|
|
26
33
|
| xargs perl -i -pe 's/(<button-ui[^>]*?)variant="danger"/$1color="danger"/g'
|
|
27
34
|
```
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
Judgment items (below) are flagged, never swept.
|
|
37
|
+
4. **Verify** — `adia-lint` clean of `LEGACY-SHELL`/`NATIVE-PRIMITIVE`; the app's own build +
|
|
38
|
+
the browser gate ([`verification.md`](verification.md)); then the leftover-drift pass below.
|
|
32
39
|
5. **Report** — per-axis counts, manual-review list, gate results, next actions.
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
### Sweep anti-patterns (each shipped a real regression)
|
|
35
42
|
|
|
36
|
-
- **
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- **
|
|
43
|
+
- **One component per sweep.** `<(toast|alert|tag)-ui[^>]*variant="error"` looks efficient, but
|
|
44
|
+
perl/sed alternation captures don't substitute the matched alternative cleanly — loop
|
|
45
|
+
`for tag in toast alert tag` instead.
|
|
46
|
+
- **HTML-attribute regexes don't cover JS property sites.** `<chat-input-ui busy>` and
|
|
47
|
+
`el.busy = true` are two audits — sweep `\.busy\s*=` separately, scoped to app code.
|
|
48
|
+
- **`git grep -lE | xargs perl -i`, never `find … -exec perl`.** git grep excludes
|
|
49
|
+
`node_modules/`, `dist/`, `.git/`; a raw find doesn't.
|
|
40
50
|
|
|
41
|
-
##
|
|
42
|
-
|
|
43
|
-
Semantic flips (`[open]`→`[collapsed]` inverts default visibility), Boolean opt-out inversions (default changes), attribution transfers (`field-ui error` → child input may not exist yet). Surface these with their call sites; let the author decide.
|
|
44
|
-
|
|
45
|
-
## What the path-only sweep misses (leftover-drift categories)
|
|
51
|
+
## Real breaking-change history (before → after)
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
- **v0.0.20 (10 items):** `<button-ui variant="danger">` → `variant="solid" color="danger"`
|
|
54
|
+
(canonical form; the guide's mechanical sweep emits just `color="danger"`, leaning on `solid`
|
|
55
|
+
being the default variant); stage Booleans (`completed`/`active`) → `status="completed|active"`
|
|
56
|
+
enum (timeline/stepper/pipeline); `<table-toolbar-ui>` opt-out Booleans **inverted**
|
|
57
|
+
(`searchable="false"` → `no-search`; default flipped); `<chat-input-ui busy>` → `loading`;
|
|
58
|
+
`variant="error"` alias removed → `danger`; event prefixes dropped (`chat-submit`→`submit`,
|
|
59
|
+
`legend-toggle`→`toggle`, `slide-change`→`change`); `<field-ui error>` moved to the child
|
|
60
|
+
input; `<agent-trace-ui open>` → `collapsed` (**semantic flip — default-visible now**); kebab
|
|
61
|
+
prop keys → camelCase (JS only). Safari floor → 18.
|
|
62
|
+
- **v0.0.29 — three-tier extraction:** `patterns/` moved `@adia-ai/web-components/patterns/*` →
|
|
63
|
+
`@adia-ai/web-modules/{shell,chat,editor,runtime}/*`. Import-path rewrite + add the
|
|
64
|
+
`web-modules` dep.
|
|
65
|
+
- **v0.4.0 — legacy shell shapes retired (ADR-0024):** `<aside data-sidebar>`→`<admin-sidebar
|
|
66
|
+
slot>`; `<dialog data-command>`→`<admin-command>`; `[data-chat-messages/input/empty]`→
|
|
67
|
+
`<chat-thread>/<chat-composer>/<chat-empty>`; `[data-editor-body]/[data-canvas]`→
|
|
68
|
+
`<editor-canvas>` + `<editor-sidebar>`. JS selectors move with the markup. (`adia-lint`
|
|
69
|
+
`LEGACY-SHELL` flags the remnants.)
|
|
70
|
+
- **v0.6.0/0.6.1:** `stat-ui.{js,css}`→`stat.{js,css}` (deep-import only); `<link-ui>` token
|
|
71
|
+
rename `--link-color-*`→`--link-fg-*` (only if you override).
|
|
72
|
+
|
|
73
|
+
## Judgment items (flag with call sites — the author decides, never a sweep)
|
|
74
|
+
|
|
75
|
+
- **Semantic flips** — `<agent-trace-ui open>`→`[collapsed]` is an inversion, not a rename:
|
|
76
|
+
`[open]` was default-hidden/opt-in, `[collapsed]` is default-visible/opt-out. Trace meant to
|
|
77
|
+
show? drop the attribute. Meant hidden? write `collapsed`.
|
|
78
|
+
- **Boolean opt-out inversions** — `<table-toolbar-ui>`: the legacy Booleans defaulted to
|
|
79
|
+
`true`, so a bare `filterable` was a no-op; only an explicit `searchable="false"` carried
|
|
80
|
+
intent (→ `no-search`). A regex can't tell the two apart.
|
|
81
|
+
- **Attribution transfers** — `<field-ui error="…">` moves the message to the child input,
|
|
82
|
+
which may not exist yet in the markup.
|
|
83
|
+
- **JS-only key renames** — kebab property keys (`el['submit-label']`→`el.submitLabel`): the
|
|
84
|
+
HTML attribute form is unchanged, so attribute-only consumers need no change. Audit
|
|
85
|
+
programmatic access only.
|
|
86
|
+
|
|
87
|
+
## Leftover drift — what the path-only sweep misses
|
|
88
|
+
|
|
89
|
+
A vocabulary migration touches the markup but not the CSS selectors that style it, the JS
|
|
90
|
+
comments that mention it, or the metadata that indexes it — different files, so a markup-only
|
|
91
|
+
commit looks complete. Close with a pre/post grep diff:
|
|
48
92
|
|
|
49
93
|
```bash
|
|
50
94
|
grep -rln 'OLD_NAME' . --include='*.md' --include='*.json' | sort > /tmp/pre.txt
|
|
51
95
|
# … sweep …
|
|
52
|
-
grep -rln 'OLD_NAME' . --include='*.md' --include='*.json' | sort > /tmp/post.txt
|
|
96
|
+
grep -rln 'OLD_NAME' . --include='*.md' --include='*.json' | sort > /tmp/post.txt
|
|
97
|
+
diff /tmp/pre.txt /tmp/post.txt # anything left post-sweep is a stale ref to investigate
|
|
53
98
|
```
|
|
54
99
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
100
|
+
Categories that have survived full-path sweeps:
|
|
101
|
+
|
|
102
|
+
- **Bare-name prose mentions** in narrative docs and inventory tables (README, roadmap-style
|
|
103
|
+
indexes) — grep `\b<old-name>\b` over `*.md` / `*.yaml`, not just paths.
|
|
104
|
+
- **Directories named after the renamed thing** (skill dirs, config dirs) — dir vs frontmatter
|
|
105
|
+
mismatch check:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
for skill in $(find . -name 'SKILL.md' -not -path '*/node_modules/*'); do
|
|
109
|
+
dir=$(basename $(dirname "$skill")); name=$(grep -m1 '^name:' "$skill" | sed 's/name: *//')
|
|
110
|
+
[ "$dir" != "$name" ] && echo "MISMATCH: $skill (dir=$dir, name=$name)"
|
|
111
|
+
done
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **JSON metadata at filename granularity** (highest impact — a stale `source`/`page` field is
|
|
115
|
+
a *silent* harvest miss on the next rebuild; no error is raised):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
for f in 'old-name.html' 'old-name.contents.html' 'old-name.contents.js'; do
|
|
119
|
+
grep -rn "$f" --include='*.json' | grep -v '/dist/' | grep -v '/node_modules/'
|
|
120
|
+
done
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- **Refs to the directory itself, not the tag** — barrel JS exports, CSS `@import`s, HTML link
|
|
124
|
+
rels, sitemap/content paths name the old *dir*; a tag-rename sweep never touches them. Grep
|
|
125
|
+
the old directory name separately.
|
|
126
|
+
- **Relative-import depth after `git mv`** — grep each moved file for `../` imports and fix the
|
|
127
|
+
depth; builds don't load them, so the breakage surfaces only in the browser. A doc move needs
|
|
128
|
+
a *different* rewrite per linking file's own depth — precompute per file.
|
|
129
|
+
- **Hard-coded source lists in build scripts** — `SOURCES = […]` / include-dir arrays silently
|
|
130
|
+
drop renamed or new siblings while the build runs clean; diff output counts against the
|
|
131
|
+
pre-rename baseline after any rename.
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: project-shapes
|
|
3
|
-
load-when: classifying or laying out an adia-ui app's structure — picking the project shape, the four-axis layout, or page-trio vs page-DUO
|
|
4
|
-
load-size: ~2.5k tokens
|
|
5
|
-
required-for: [adia-ui-factory shape classifier, adia-ui-project (scaffold / add-surface / add-page)]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
1
|
# Project shapes & structure
|
|
9
2
|
|
|
10
|
-
How real adia-ui apps are laid out (synthesized from the chat-ui apps). Three shapes over one four-axis layout, with a page-trio/DUO rule. The **structure rubric** at the bottom is the gate; `bin/adia-scaffold` mechanizes the layout.
|
|
3
|
+
How real adia-ui apps are laid out (synthesized from the chat-ui apps). Three shapes over one four-axis layout, with a page-trio/DUO rule. The **structure rubric** at the bottom is the gate; `bin/adia-scaffold` mechanizes the layout. Loaded by `adia-orient` (shape classifier) and `adia-project` (layout / scaffold / inventory).
|
|
11
4
|
|
|
12
5
|
## The four-axis layout (all shapes)
|
|
13
6
|
|
|
@@ -56,7 +49,7 @@ Use for: a suite of related surfaces (a SaaS admin, a flow set, a demo gallery).
|
|
|
56
49
|
|
|
57
50
|
### Shared-foundation — sibling apps over a shared core
|
|
58
51
|
|
|
59
|
-
Root-level `spec/plan/` for cross-app concerns; each app under `app/<name>/` with its own `spec/plan/src/`; a shared `app/shared/` (DataClient, loaders, mappers, tokens). The embed pattern lives here
|
|
52
|
+
Root-level `spec/plan/` for cross-app concerns; each app under `app/<name>/` with its own `spec/plan/src/`; a shared `app/shared/` (DataClient, loaders, mappers, tokens). The embed pattern lives here — the shell is **`<embed-shell>`** (ships in `@adia-ai/web-modules`, shell cluster); depth: [shell-embed.md](shell-embed.md).
|
|
60
53
|
|
|
61
54
|
```text
|
|
62
55
|
app/
|
|
@@ -75,13 +68,18 @@ Use for: multiple embedded surfaces sharing data context, components, and an emb
|
|
|
75
68
|
|
|
76
69
|
The `.html` shell fetches `.contents.html`, injects it, then dynamically imports `.contents.js` if present. **Rule:** add `.contents.js` only when there's behavior to wire — a DUO with a dead `.contents.js` and a trio missing its setup are both smells.
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
Two adjacent contracts:
|
|
72
|
+
|
|
73
|
+
- `setup` must be `async function setup(host)` when its body contains top-level `await` — extracting inline page script into a non-async `.contents.js` controller turns that `await` into a parse-time SyntaxError.
|
|
74
|
+
- CSS never takes the `.contents.` infix. HTML/JS get it because they're the dynamically-injected fragment + controller; CSS loads statically via `<link>` in the `.html` shell head and styles chrome + contents together, so its name follows scope (per-app / shared / per-component), not the page-form convention.
|
|
75
|
+
|
|
76
|
+
## State & data — which pattern
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
The state/data pattern follows the shape, not taste — but the choice is owned by `adia-data`: see [data-and-hydration.md](data-and-hydration.md) for the shape → pattern map.
|
|
81
79
|
|
|
82
80
|
## Components
|
|
83
81
|
|
|
84
|
-
One folder per tag, mirroring the framework: `components/<tag>/<tag>.{js,css}` (folder name = custom-element tag). Authoring discipline:
|
|
82
|
+
One folder per tag, mirroring the framework: `components/<tag>/<tag>.{js,css}` (folder name = custom-element tag). Authoring discipline: [authoring-components.md](authoring-components.md).
|
|
85
83
|
|
|
86
84
|
## Structure rubric `[gate]`
|
|
87
85
|
|
|
@@ -93,4 +91,4 @@ A project is well-structured when (gate = all `[gate]` hold):
|
|
|
93
91
|
- **Components foldered** `[gate]` — every custom element is `components/<tag>/<tag>.{js,css}`.
|
|
94
92
|
- **No duplicated cross-surface code** `[review]` — shared logic lives in `app/shared/` (or `_shared/`), not copied per page.
|
|
95
93
|
|
|
96
|
-
Verify target for a scaffold/edit: this rubric passes, and any new surface renders through `adia-
|
|
94
|
+
Verify target for a scaffold/edit: this rubric passes, and any new surface renders through `adia-verify`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: shell-admin
|
|
3
3
|
load-when: authoring or debugging an admin-shell app frame (sidebar + topbar + command palette + pages)
|
|
4
4
|
load-size: ~2.5k tokens
|
|
5
|
-
required-for: [adia-
|
|
5
|
+
required-for: [adia-shells — admin path]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# admin-shell — the app frame
|
|
@@ -49,7 +49,7 @@ Full SaaS/admin chrome from `@adia-ai/web-modules`. Register the **cluster barre
|
|
|
49
49
|
|
|
50
50
|
## SPA vs SSR
|
|
51
51
|
|
|
52
|
-
SPA mounts the full markup. SSR keeps the shell + chrome fixed and swaps only the **page body** via the framework outlet — replace the inner page content with `{children}` / `<slot/>`; never mount `<router-ui>` (see `adia-
|
|
52
|
+
SPA mounts the full markup. SSR keeps the shell + chrome fixed and swaps only the **page body** via the framework outlet — replace the inner page content with `{children}` / `<slot/>`; never mount `<router-ui>` (see `adia-host`).
|
|
53
53
|
|
|
54
54
|
## Gotchas (mechanized where noted)
|
|
55
55
|
|
|
@@ -61,5 +61,8 @@ SPA mounts the full markup. SSR keeps the shell + chrome fixed and swaps only th
|
|
|
61
61
|
- **Multiple `<admin-page>` in one `<admin-scroll>`** → single-axis scroll breaks; one page per scroll.
|
|
62
62
|
- **`@container (…)` instead of `@container page-content (…)`** → won't react to sidebar collapse.
|
|
63
63
|
- **Legacy shapes** (`<aside data-sidebar>`, `<dialog data-command>`) — retired v0.4.0 (`adia-lint` `LEGACY-SHELL`).
|
|
64
|
+
- **Sidebar nav is `<nav-ui>` + `<nav-item-ui>`**, never `<menu-ui>`/`<menu-item-ui>` — menu-ui is for Popover-API dropdowns, not persistent navigation.
|
|
65
|
+
- **Full-height mount:** an intermediate wrapper (`<main id="app">`) between `body { height: 100dvh; display: flex }` and the shell needs `flex: 1; display: flex; min-height: 0` — without it the flex chain breaks and the shell collapses to content height.
|
|
66
|
+
- **`header-ui` has no CSS of its own** — its icon/heading/description/action grid comes from the parent's `@scope` (`admin-page-header` provides it); bespoke chrome reusing the header-ui vocabulary must supply the grid + text ellipsis locally.
|
|
64
67
|
|
|
65
68
|
Real usage: `apps/saas/app/admin-dashboard/`.
|
package/references/shell-chat.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
name: shell-chat
|
|
3
3
|
load-when: authoring a chat-shell LLM conversation surface
|
|
4
4
|
load-size: ~1.5k tokens
|
|
5
|
-
required-for: [adia-
|
|
5
|
+
required-for: [adia-shells — chat path]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# chat-shell — the conversation surface
|
|
9
9
|
|
|
10
|
-
LLM chat chrome from `@adia-ai/web-modules`. Register: `import '@adia-ai/web-modules/chat'`. The **LLM client/proxy/security** lives in `adia-
|
|
10
|
+
LLM chat chrome from `@adia-ai/web-modules`. Register: `import '@adia-ai/web-modules/chat'`. The **LLM client/proxy/security** lives in `adia-llm` — this is the _surface_; that is the _wiring_.
|
|
11
11
|
|
|
12
12
|
## Cluster roster
|
|
13
13
|
|
|
@@ -33,12 +33,14 @@ LLM chat chrome from `@adia-ai/web-modules`. Register: `import '@adia-ai/web-mod
|
|
|
33
33
|
|
|
34
34
|
## Wiring to the LLM
|
|
35
35
|
|
|
36
|
-
Set `proxy-url` (or, dev-only, `apiKey`) and the shell **auto-sends on submit** via `streamChat` and renders the stream for you. Otherwise it just emits `submit` — you call your endpoint and drive the UI with `appendChunk`/`done`/`error`. **Security:** the production pattern is a same-origin smart proxy that holds the key server-side — never ship a provider key to the browser. Full client/proxy contract: `adia-
|
|
36
|
+
Set `proxy-url` (or, dev-only, `apiKey`) and the shell **auto-sends on submit** via `streamChat` and renders the stream for you. Otherwise it just emits `submit` — you call your endpoint and drive the UI with `appendChunk`/`done`/`error`. **Security:** the production pattern is a same-origin smart proxy that holds the key server-side — never ship a provider key to the browser. Full client/proxy contract: `adia-llm`.
|
|
37
37
|
|
|
38
38
|
## Gotchas
|
|
39
39
|
|
|
40
40
|
- Import the **chat barrel**; piecemeal imports leave children unregistered.
|
|
41
|
+
- `chat-input-ui` internally renders `textarea-ui` + `select-ui` (web-components primitives, invisible in your authored HTML) — the app must register those primitives too, or they stay undefined and collapse to 0px.
|
|
41
42
|
- Legacy shapes (`[data-chat-messages]`, `[data-chat-input]`, `[data-chat-empty]`, `[data-chat-name]`) were retired v0.4.0 — use the bespoke tags (`adia-lint` `LEGACY-SHELL`).
|
|
42
43
|
- SSR: register `<chat-shell>` client-side like any component; keep the key server-side.
|
|
44
|
+
- **Reasoning/trace panels must surface their own reliability** — a bare status label (`Domain: data`) reads identically at 3% and 95% confidence; a label that hides the data needed to judge it is pragmatically deceptive. Show the confidence with the claim.
|
|
43
45
|
|
|
44
46
|
Real usage: `apps/genui/app/factory-chat/`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: shell-editor
|
|
3
3
|
load-when: authoring an editor-shell — a design tool / canvas with resizable side panes
|
|
4
4
|
load-size: ~1.2k tokens
|
|
5
|
-
required-for: [adia-
|
|
5
|
+
required-for: [adia-shells — editor path]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# editor-shell — the canvas + panes
|
|
@@ -1,43 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: shell-embed
|
|
3
|
-
load-when: authoring an embedded adia-ui surface
|
|
3
|
+
load-when: authoring an embedded adia-ui surface — a `<embed-shell>` framing a primary app plus secondary panels a host page sizes/centers
|
|
4
4
|
load-size: ~1.5k tokens
|
|
5
|
-
required-for: [adia-
|
|
5
|
+
required-for: [adia-shells — embed path]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# embed-shell — embedded multi-surface frame
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Embedded chrome from `@adia-ai/web-modules` (shell cluster). Register: `import '@adia-ai/web-modules/shell'`. Peer of admin/editor/chat shells; light-DOM, content-agnostic — it orchestrates layout of whatever `[app]` + `[panel]` children it's given, never the content or data.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Cluster roster
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
`<embed-shell>` (host coordinator) — the only tag. Its children are consumer-supplied: one `[app]` primary surface + any number of `[panel="<name>"]` secondary surfaces. Extends `UIElement`, so `traits="resizable"` applies the real `resizable` trait (drag any edge + a `resize-end` event), not a CSS stand-in.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- **The host sizes/centers it.** The placer page positions the element (absolute + `translate(-50%, -50%)`); the surface does **not** hardcode width/height (size-agnostic — the consumer owns extent).
|
|
18
|
-
- **Panel layout:** pinned header/footer + scrollable body via flex + `min-block-size: 0` on the scroll region.
|
|
19
|
-
- **Data via projection.** `DataClient.read({ type, params })` returns typed projections from pure mappers (`app/shared/corpus/mappers/`); the surface never calls a backend directly. **Every `mutate` carries `action_source`** (attribution is required; the client throws without it). Depth: `adia-ui-data`.
|
|
20
|
-
- **Routing (in-DOM tabs):** a content-less `<router-ui>` whose URL you manage yourself with `history.replaceState()` to preserve the host's query params — do **not** set `router.routes` (that fetches + replaces). (This is the one place an embedded surface uses `<router-ui>`; it's a self-contained SPA island, not an SSR page — see the hybrid note in `adia-ui-data`.)
|
|
21
|
-
- **Shared foundation.** Multiple embedded surfaces live under a `shared-foundation` project shape (`app/shared/` for DataClient/mappers/tokens) — see `project-shapes.md`.
|
|
16
|
+
## Canonical skeleton
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
```html
|
|
19
|
+
<embed-shell>
|
|
20
|
+
<patient-labs app></patient-labs> <!-- the primary surface (exactly one) -->
|
|
21
|
+
<settings-panel panel="settings"></settings-panel><!-- a secondary surface (any number) -->
|
|
22
|
+
<chat-panel panel="chat"></chat-panel>
|
|
23
|
+
<!-- triggers anywhere inside, delegated: -->
|
|
24
|
+
<button-ui opens="chat">Chat</button-ui> <!-- toggles the named panel -->
|
|
25
|
+
<button-ui close></button-ui> <!-- dismisses the open panel -->
|
|
26
|
+
</embed-shell>
|
|
27
|
+
```
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
2. Author the surface as a self-booting light-DOM container (`#booted` guard, render in `connected()`).
|
|
27
|
-
3. Wire data through `DataClient`/mappers; attribute every mutation.
|
|
28
|
-
4. Keep it size-agnostic; let the host place it.
|
|
29
|
-
5. Verify in a host harness (renders, zero console errors, non-zero box) — `adia-ui-verify`.
|
|
29
|
+
## Contract · state · events
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
- **Children:** `[app]` = primary (one); `[panel="<name>"]` = secondaries. `[opens="<name>"]` toggles a panel; `[close]` dismisses the open one — both delegated off a click on any descendant.
|
|
32
|
+
- **State (reflected, ADR-0023):** `embed-shell[panel="chat"]` = which panel is open (`''`/absent = none); the open panel carries `[active]` (the CSS show/slide hook).
|
|
33
|
+
- **Events:** `embed:open` (in) `detail:{panel}` = request to open/toggle; `embed:change` (out) `detail:{panel}` = emitted after the open panel changes.
|
|
34
|
+
- **Methods:** `.open(name)` · `.close()` · `.toggle(name)`; getter `.panel` (open name or `''`). Escape closes the open panel.
|
|
35
|
+
- **Layout (embed-shell.css):** ≥760px the open panel is a 50/50 column beside the app; <760px it's a cover sheet (`translateY` — **identity at rest**, so popovers inside still anchor via CSS anchor-positioning; an offsetting `translate(-50%,-50%)` would break them).
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
## Authoring the surfaces inside it
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
- `apps/embedded-app/app/population-health/` — population-health surface (coverage metrics, facility breakdown)
|
|
37
|
-
- `apps/embedded-app/app/shared/` — DataClient, CorpusLoader, mappers, shared tokens
|
|
39
|
+
The shell owns the frame; each `[app]`/`[panel]` surface is a self-booting light-DOM container you author to the embedded-surface pattern:
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
- **Self-booting** — `connected()` guarded by a `#booted` flag (it re-fires on DOM moves), fetches its data, renders its own subtree. No shadow DOM.
|
|
42
|
+
- **Size-agnostic** — the surface never hardcodes width/height; the shell (and the host page) own extent.
|
|
43
|
+
- **Data via projection** — `DataClient.read({ type, params })` returns typed projections from pure mappers (`app/shared/corpus/mappers/`); the surface never calls a backend directly. **Every `mutate` carries `action_source`** — the client throws without it. Depth: [`data-and-hydration.md`](data-and-hydration.md).
|
|
44
|
+
- **In-DOM tabs** — a content-less `<router-ui>` whose URL you manage with `history.replaceState()` to preserve the host's query params; do **not** set `router.routes` (that fetches + `innerHTML`-replaces).
|
|
45
|
+
- **Shared foundation** — multiple embedded surfaces live under a `shared-foundation` project shape (`app/shared/` for DataClient/mappers/tokens); see [`project-shapes.md`](project-shapes.md).
|
|
40
46
|
|
|
41
|
-
##
|
|
47
|
+
## SPA vs SSR
|
|
42
48
|
|
|
43
|
-
The
|
|
49
|
+
The shell mounts the full markup in SPA. For SSR, register it client-side like any component and keep any data keys server-side; it's a self-contained SPA island, not an SSR page (see the hybrid note in [`data-and-hydration.md`](data-and-hydration.md)).
|
|
50
|
+
|
|
51
|
+
## Gotchas
|
|
52
|
+
|
|
53
|
+
- **Piecemeal import** → `EmbedShell` unregistered; `.open()`/`.toggle()` undefined and panels collapse. Import the **shell barrel**.
|
|
54
|
+
- **A trigger `opens="x"` with no matching `[panel="x"]` child** → `.open()` no-ops silently.
|
|
55
|
+
- **Wrapping `[app]`/`[panel]` children in a layout `<div>`** → breaks the `:scope > [panel]` direct-child selectors the shell and CSS use.
|
|
56
|
+
|
|
57
|
+
Real usage: `apps/embedded-app/` — patient-labs and population-health surfaces built to the shared-foundation shape (`app/patient-labs/`, `app/population-health/`, shared `app/shared/`). Read it before authoring a new embedded surface.
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
name: shell-simple
|
|
3
3
|
load-when: authoring a simple-shell — marketing / error / landing / auth page (minimal centered chrome)
|
|
4
4
|
load-size: ~0.8k tokens
|
|
5
|
-
required-for: [adia-
|
|
5
|
+
required-for: [adia-shells — simple path]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# simple-shell — minimal centered chrome
|
|
9
9
|
|
|
10
|
-
The lightest shell from `@adia-ai/web-modules` — for marketing, landing, error (404/500/maintenance), thank-you, and auth pages. Register: `import '@adia-ai/web-modules/
|
|
10
|
+
The lightest shell from `@adia-ai/web-modules` — for marketing, landing, error (404/500/maintenance), thank-you, and auth pages. Register: `import '@adia-ai/web-modules/simple'` (simple is its own cluster barrel — the `/shell` barrel does not register it). Behavior-only host + two CSS-only children.
|
|
11
11
|
|
|
12
12
|
## Cluster roster
|
|
13
13
|
|
|
@@ -34,5 +34,8 @@ The lightest shell from `@adia-ai/web-modules` — for marketing, landing, error
|
|
|
34
34
|
|
|
35
35
|
- Controls inside are `*-ui` (`button-ui`, `link-ui`), not raw `<button>`/`<a>` (`adia-lint` `NATIVE-PRIMITIVE`).
|
|
36
36
|
- For an error page, a page-DUO (no `.contents.js`) is usually right — see `project-shapes.md`.
|
|
37
|
+
- **Where the message goes on a status page:** an `<alert-ui>` carries the full message when the user is a *passive* recipient (session expired, account locked); the header `text-ui` carries it when the user is *actively* confirming something they initiated — the alert then only supplements.
|
|
38
|
+
- **Prose/marketing header:** the centered pattern is a `<col-ui>` inside `<header>` with kicker + display heading + deck — not ad-hoc heading stacks.
|
|
39
|
+
- Reach for this canonical shell before hand-rolling centered chrome: a new auth/status/maintenance surface (centered card, brand mark, heading, content) composes `simple-shell` + `<card-ui raw>` — authoring a parallel bespoke shell is how a 117-line stylesheet earns a 33-line replacement.
|
|
37
40
|
|
|
38
41
|
Real usage: `apps/errors/`, `apps/user-flow/` (auth).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# SPA architecture
|
|
2
2
|
|
|
3
|
-
The client-rendered path
|
|
3
|
+
The client-rendered path: a static host, Vite or vanilla. The framework is SPA-native — components register at load, the page is one document, routing and state live in the browser. Inside Next/Nuxt/SvelteKit/Astro instead? That's the **SSR** path — [ssr-integration.md](ssr-integration.md); the two diverge sharply on registration, routing, and state.
|
|
4
4
|
|
|
5
5
|
## The host document
|
|
6
6
|
|
|
7
|
-
One static `index.html` whose job is to load CSS in cascade order and register components once:
|
|
7
|
+
One static `index.html` whose job is to load CSS in cascade order and register components once. npm-consumer paths, which is what `adia-scaffold spa` emits (pre-wired for Vite — `vite.config.js` + `package.json` included):
|
|
8
8
|
|
|
9
9
|
```html
|
|
10
10
|
<!doctype html>
|
|
@@ -12,13 +12,12 @@ One static `index.html` whose job is to load CSS in cascade order and register c
|
|
|
12
12
|
<head>
|
|
13
13
|
<meta charset="utf-8" />
|
|
14
14
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
-
<link rel="stylesheet" href="/
|
|
16
|
-
<link rel="stylesheet" href="/
|
|
17
|
-
<link rel="stylesheet" href="/
|
|
18
|
-
<link rel="stylesheet" href="./index.css" />
|
|
19
|
-
<link rel="stylesheet" href="./components/my-surface/my-surface.css" />
|
|
20
|
-
<script type="module" src="/
|
|
21
|
-
<script type="module" src="./components/my-surface/my-surface.js"></script>
|
|
15
|
+
<link rel="stylesheet" href="/node_modules/@adia-ai/web-components/styles/host.css" /> <!-- foundation: tokens + resets + page frame -->
|
|
16
|
+
<link rel="stylesheet" href="/node_modules/@adia-ai/web-components/styles/index.css" /> <!-- barrel: every component's CSS (link BOTH) -->
|
|
17
|
+
<link rel="stylesheet" href="/node_modules/@adia-ai/web-components/styles/verse.css" /> <!-- opt-in register (only if a surface uses [verse]) -->
|
|
18
|
+
<link rel="stylesheet" href="./index.css" /> <!-- page framing: sizes + centers the surface -->
|
|
19
|
+
<link rel="stylesheet" href="./components/my-surface/my-surface.css" /> <!-- the surface's own chrome -->
|
|
20
|
+
<script type="module" src="./components/my-surface/my-surface.js"></script> <!-- its FIRST import is the registration barrel -->
|
|
22
21
|
</head>
|
|
23
22
|
<body>
|
|
24
23
|
<my-surface verse></my-surface>
|
|
@@ -26,54 +25,33 @@ One static `index.html` whose job is to load CSS in cascade order and register c
|
|
|
26
25
|
</html>
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
>
|
|
31
|
-
> - **Vite (recommended):** `npm install @adia-ai/web-components`, add a `vite.config.js` (the `adia-scaffold spa` bin emits one), then replace the paths with `/node_modules/@adia-ai/web-components/styles/host.css` etc. — Vite serves node_modules at that prefix during dev and bundles them at build time. Bare `@adia-ai/*` specifiers in `.js` files resolve automatically.
|
|
32
|
-
> - **Import-map / CDN (no bundler):** add an `<script type="importmap">` mapping `"@adia-ai/web-components"` to your CDN URL (e.g. `https://esm.sh/@adia-ai/web-components`), and adjust the CSS link hrefs to match.
|
|
33
|
-
>
|
|
34
|
-
> The `adia-scaffold spa` output is pre-wired for the Vite path (`vite.config.js` + `package.json` included).
|
|
28
|
+
Vite serves `/node_modules/...` hrefs during dev and bundles them at build; bare `@adia-ai/*` specifiers in `.js` files resolve automatically. Two alternatives:
|
|
35
29
|
|
|
36
|
-
**
|
|
30
|
+
- **Import-map / CDN (no bundler):** a `<script type="importmap">` mapping `"@adia-ai/web-components"` to a CDN URL (e.g. `https://esm.sh/@adia-ai/web-components`); adjust the CSS hrefs to match.
|
|
31
|
+
- **Monorepo dev server (framework contributors only):** `/packages/web-components/styles/*.css` + `/packages/web-components/index.js` paths — not a consumer deployment mode.
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
- **One** registration script (`/packages/web-components/index.js`). Don't piecemeal-import primitives across the page.
|
|
40
|
-
- Never hand-roll `:where(html,body){}` — the foundation owns the page frame; re-rolling it drifts from the system (the classic serif-leak bug).
|
|
41
|
-
- A register has two halves: link `verse.css` **and** put `verse` on the surface. One without the other is a no-op.
|
|
42
|
-
|
|
43
|
-
## Four-axis project structure
|
|
44
|
-
|
|
45
|
-
```text
|
|
46
|
-
my-app/
|
|
47
|
-
├── spec/ design axis — BRIEF · ARCHITECTURE · SPEC · screen specs
|
|
48
|
-
├── plan/ execution axis — ROADMAP · MILESTONES · PLAN
|
|
49
|
-
├── skills/ procedural-knowledge axis — the app's own expert skill (optional)
|
|
50
|
-
└── app/
|
|
51
|
-
├── shared/ cross-surface source — DataClient, loaders, mappers, images
|
|
52
|
-
└── <surface>/src/
|
|
53
|
-
├── index.html the host shell (above)
|
|
54
|
-
├── index.css page framing
|
|
55
|
-
└── components/<tag>/<tag>.{js,css}
|
|
56
|
-
```
|
|
33
|
+
## Registration & cascade invariants
|
|
57
34
|
|
|
58
|
-
|
|
35
|
+
**Cascade order is load-bearing** (later wins): foundation → barrel → register → page → component.
|
|
59
36
|
|
|
60
|
-
|
|
37
|
+
- Link **both** `host.css` and `styles/index.css`. The styles barrel is split: `host.css` carries only the foundation (tokens + resets + page frame), so linking it alone renders primitives unstyled.
|
|
38
|
+
- CSS arrives via `<link>`, never via the JS import — Vite serves component CSS outside the module graph, so a JS-only side-effect import registers the element but leaves it unstyled.
|
|
39
|
+
- **One registration script** — the side-effecting barrel `import '@adia-ai/web-components'`. Don't piecemeal-import primitives: composites render internal `*-ui` tags (e.g. `chat-input-ui` internally renders `textarea-ui` + `select-ui`) that stay unregistered and collapse to 0px unless the barrel ran.
|
|
40
|
+
- Bespoke shell children need the **cluster barrel** (`@adia-ai/web-modules/shell`, `/chat`, `/editor`, `/simple`) — importing `admin-shell.js` alone registers only the host tag, not `admin-sidebar` / `admin-page` / the other children.
|
|
41
|
+
- Never hand-roll `:where(html,body){}` — the foundation owns the page frame; re-rolling it drifts from the system (the classic serif-leak bug).
|
|
42
|
+
- A `verse` register has two halves: link `verse.css` **and** put `verse` on the surface. One without the other is a no-op.
|
|
43
|
+
- `themes.css` (named palettes) is **not** in the styles barrel — link it separately. `data-scheme` switches light/dark; `data-theme` picks the named palette.
|
|
44
|
+
- Guards: `defineIfFree(tag, ctor)` (`core/register.js`) for defines; a `#booted` flag in `connected()` — the callback re-fires on DOM moves. And `customElements.whenDefined(name)` never rejects: a `Promise.all([...whenDefined])` boot gate hangs forever on one unimported tag — chrome renders (tag-keyed CSS), the page stays "empty", zero console errors.
|
|
61
45
|
|
|
62
|
-
|
|
46
|
+
## The surface container
|
|
63
47
|
|
|
64
|
-
|
|
65
|
-
| --- | --- |
|
|
66
|
-
| `<page>.html` | static shell — meta, CSS/script links, a mount point |
|
|
67
|
-
| `<page>.contents.html` | the markup, **fetched** and injected at runtime |
|
|
68
|
-
| `<page>.contents.js` | `setup(root)` — wires behavior after the markup lands |
|
|
48
|
+
An app surface is a self-booting custom element — it fetches its data and renders its own subtree in `connected()`:
|
|
69
49
|
|
|
70
50
|
```js
|
|
71
|
-
|
|
72
|
-
root.innerHTML = await (await fetch('./page.contents.html')).text();
|
|
73
|
-
(await import('./page.contents.js')).default?.(root); // setup(root)
|
|
51
|
+
connected() { if (this.#booted) return; this.#booted = true; this.#load(); }
|
|
74
52
|
```
|
|
75
53
|
|
|
76
|
-
|
|
54
|
+
Standalone demo/playground pages use the page-trio instead; the trio/DUO decision table, the four-axis layout, and the structure rubric live in [project-shapes.md](project-shapes.md) (owned by `adia-project`).
|
|
77
55
|
|
|
78
56
|
## Routing — content-less `<router-ui>`
|
|
79
57
|
|
|
@@ -91,33 +69,10 @@ my-surface router-ui[data-route-path="/live"] .live { display: flex; }
|
|
|
91
69
|
|
|
92
70
|
A **content-mode** route (one carrying `content`) makes the router fetch and `innerHTML`-replace — which wipes stamped views, scroll, and focus. That's the wrong tool for in-DOM tabs. Never `innerHTML` a view on switch; show/hide.
|
|
93
71
|
|
|
94
|
-
## Data
|
|
95
|
-
|
|
96
|
-
The UI never talks to a backend. It reads typed **projections** from a `DataClient`; a pure mapper is the swap seam between fixtures and a real API:
|
|
97
|
-
|
|
98
|
-
```text
|
|
99
|
-
DataClient.read({ type: 'LabRecommendationSet', params }) ← the only surface the UI sees
|
|
100
|
-
→ runMapper(query, loader) ← pure (sources) => Projection; the v1-fixture ⇄ v2-API seam
|
|
101
|
-
→ CorpusLoader.load*() ← fetches the source data
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
- Components consume **projections only** — no backend calls, no re-deriving projections in the view, no per-view reshaping (the projection type _is_ the contract).
|
|
105
|
-
- **Attribution is structural:** every `mutate` requires an `action_source`; the client throws without it.
|
|
106
|
-
|
|
107
|
-
```js
|
|
108
|
-
await client.mutate({ type: 'order', payload }, { action_source: btn.dataset.action });
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## State — single owner
|
|
112
|
-
|
|
113
|
-
One owner per piece of state, no shadow copies:
|
|
114
|
-
|
|
115
|
-
- the **route** owns which view is active,
|
|
116
|
-
- the **component** owns selection sets / UI toggles,
|
|
117
|
-
- the **DataClient** owns fetched data.
|
|
72
|
+
## Data & state
|
|
118
73
|
|
|
119
|
-
|
|
74
|
+
Owned by `adia-data` — see [data-and-hydration.md](data-and-hydration.md) for the five data-flow patterns, the DataClient → projection pipeline, the attribution gate (`mutate` throws without an `action_source`), and single-owner state (the route owns the active view; a control mutates the route, an observer/CSS reflects it back — never a second source of truth).
|
|
120
75
|
|
|
121
76
|
## Exit gate
|
|
122
77
|
|
|
123
|
-
A surface isn't done when it compiles — it's done when it passes the **browser gate
|
|
78
|
+
A surface isn't done when it compiles — it's done when it passes the **browser gate**: zero console errors on load, non-zero bounding boxes, and the screenshot actually read. That gate is the `adia-verify` skill.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Consuming adia-ui components **inside an SSR framework** (Next.js, Nuxt, SvelteKit, Astro, …). Same components, same UI, **wildly different architecture** from the SPA path — the framework owns routing, registration must be deferred to the client, and state can't live in component-lifetime signals.
|
|
4
4
|
|
|
5
|
-
> **Honesty about sources.** The
|
|
5
|
+
> **Honesty about sources.** The kit's own documentation explicitly covers Next/Nuxt/SvelteKit/Astro — those patterns are marked **[D]** (documented) below. Frameworks it names in its routing table but doesn't give wiring for (Remix, Rails/Turbo, Django/HTMX, Phoenix) are marked **[G]** — the _rule_ (one route owner; client-only registration) holds, but the wiring is your framework's standard pattern, not something the kit ships. Don't present **[G]** patterns as kit-guaranteed.
|
|
6
6
|
|
|
7
7
|
## Why SSR is different
|
|
8
8
|
|