@adia-ai/web-modules 0.3.6 → 0.4.1

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +29 -15
  3. package/chat/chat-shell/chat-shell.js +28 -40
  4. package/chat/chat-shell/css/chat-shell.empty.css +3 -3
  5. package/chat/chat-shell/css/chat-shell.layout.css +2 -2
  6. package/editor/editor-canvas/editor-canvas.examples.html +65 -0
  7. package/editor/editor-canvas/editor-canvas.html +43 -0
  8. package/editor/editor-canvas-empty/editor-canvas-empty.examples.html +65 -0
  9. package/editor/editor-canvas-empty/editor-canvas-empty.html +42 -0
  10. package/editor/editor-shell/css/editor-shell.bespoke.css +67 -2
  11. package/editor/editor-shell/css/editor-shell.layout.css +6 -6
  12. package/editor/editor-shell/editor-shell.js +19 -17
  13. package/editor/editor-sidebar/editor-sidebar.a2ui.json +5 -0
  14. package/editor/editor-sidebar/editor-sidebar.examples.html +65 -0
  15. package/editor/editor-sidebar/editor-sidebar.html +43 -0
  16. package/editor/editor-sidebar/editor-sidebar.js +30 -6
  17. package/editor/editor-sidebar/editor-sidebar.test.js +19 -0
  18. package/editor/editor-sidebar/editor-sidebar.yaml +8 -0
  19. package/editor/editor-statusbar/editor-statusbar.examples.html +65 -0
  20. package/editor/editor-statusbar/editor-statusbar.html +42 -0
  21. package/editor/editor-toolbar/editor-toolbar.examples.html +65 -0
  22. package/editor/editor-toolbar/editor-toolbar.html +43 -0
  23. package/index.js +1 -0
  24. package/package.json +8 -5
  25. package/shell/admin-shell/admin-shell.js +27 -243
  26. package/shell/admin-shell/css/admin-shell.bespoke.css +22 -26
  27. package/shell/admin-shell/css/admin-shell.main.css +2 -2
  28. package/shell/admin-shell/css/admin-shell.shell.css +2 -2
  29. package/shell/admin-shell/css/admin-shell.sidebar.css +35 -33
  30. package/simple/index.js +2 -0
  31. package/simple/simple-content/simple-content.a2ui.json +67 -0
  32. package/simple/simple-content/simple-content.css +29 -0
  33. package/simple/simple-content/simple-content.examples.html +13 -0
  34. package/simple/simple-content/simple-content.html +42 -0
  35. package/simple/simple-content/simple-content.yaml +54 -0
  36. package/simple/simple-hero/simple-hero.a2ui.json +76 -0
  37. package/simple/simple-hero/simple-hero.css +45 -0
  38. package/simple/simple-hero/simple-hero.examples.html +33 -0
  39. package/simple/simple-hero/simple-hero.html +42 -0
  40. package/simple/simple-hero/simple-hero.yaml +57 -0
  41. package/simple/simple-shell/simple-shell.a2ui.json +87 -0
  42. package/simple/simple-shell/simple-shell.css +40 -0
  43. package/simple/simple-shell/simple-shell.examples.html +42 -0
  44. package/simple/simple-shell/simple-shell.html +42 -0
  45. package/simple/simple-shell/simple-shell.js +47 -0
  46. package/simple/simple-shell/simple-shell.test.js +83 -0
  47. package/simple/simple-shell/simple-shell.yaml +78 -0
package/CHANGELOG.md CHANGED
@@ -11,6 +11,50 @@ Built from `@adia-ai/web-components` primitives.
11
11
 
12
12
  _No pending changes._
13
13
 
14
+ ## [0.4.1] - 2026-05-10
15
+
16
+ ### Added
17
+
18
+ - **simple cluster — 4th bespoke shell family** per ADR-0023. Minimal shell for marketing / landing / error pages:
19
+ - `<simple-shell>` (host) — behavior-only orchestrator. 2 reflected attributes: `[centered]` (vertical center), `[full-bleed]` (drops max-width).
20
+ - `<simple-content>` (CSS-only) — article body container with token-correct vertical rhythm.
21
+ - `<simple-hero>` (CSS-only) — optional top strip with 3 named slots (`heading`, `lede`, `actions`).
22
+ - Subpath export: `@adia-ai/web-modules/simple`.
23
+ - 10 unit tests for `<simple-shell>`.
24
+
25
+ ### Changed
26
+
27
+ - Catalog count: 118 → 121 yamls (+3 from simple cluster children).
28
+
29
+ ## [0.4.0] - 2026-05-10
30
+
31
+ **⚠️ BREAKING** — first non-patch release in the 0.x line. Closes the ADR-0023 arc per [ADR-0024](../../.brain/adrs/0024-legacy-shell-shapes-retired.md). All 6 in-repo consumers migrated in v0.3.6; this release retires the legacy authoring shapes from the shell hosts.
32
+
33
+ ### Removed (BREAKING)
34
+
35
+ - **`<admin-shell>`** no longer reads `<aside-ui slot="leading|trailing">`, `<aside data-sidebar>`, `<dialog data-command>`, or `[data-resize]` external handle children. Use `<admin-sidebar slot resizable collapsible>` + `<admin-command>` instead.
36
+ - **`<chat-shell>`** no longer reads `<section data-chat-messages>`, `<chat-input-ui data-chat-input>`, `<empty-state-ui data-chat-empty>`, `<header>` with `[data-chat-name]` / `[data-chat-status]`. Use `<chat-thread>` + `<chat-composer>` + `<chat-empty>` + `<chat-header>` + `<chat-status>` instead.
37
+ - **`<editor-shell>`** no longer reads `<header>` toolbar, `<div data-editor-body>` wrapper, `<pane-ui data-left|data-right>`, `<div data-canvas>`, `<footer>` statusbar. Use `<editor-toolbar>` + `<editor-canvas>` + `<editor-sidebar slot>` + `<editor-statusbar>` + `<editor-canvas-empty>` instead.
38
+
39
+ ### Changed
40
+
41
+ - **`admin-shell.js` host** — 305 → 87 LOC (-71%). The host now does only `[mode]` reflection + 2 attribute-forwarding handlers. All resize / collapse / persistence / dialog wiring is owned by `<admin-sidebar>` and `<admin-command>` per ADR-0023.
42
+ - **`chat-shell.js` host** — `connected()` simplified; only `composer-submit` event recognized (no longer falls back to `submit`).
43
+ - **`editor-shell.js` host** — `connected()` drops dual-shape fallbacks.
44
+ - **CSS layered files** — all `:is(legacy, bespoke)` lifts collapsed to bespoke-only in `admin-shell.sidebar.css`, `admin-shell.shell.css`, `admin-shell.main.css`, `chat-shell.empty.css`, `chat-shell.layout.css`, `editor-shell.layout.css`.
45
+ - **CSS bridge files** — `admin-shell.bespoke.css` / `chat-shell.bespoke.css` / `editor-shell.bespoke.css` updated to canonical-styling commentary (no longer "bridge to existing selectors").
46
+
47
+ ### Verification
48
+
49
+ - Bespoke children unit tests: **78/78** pass (admin 19 + chat 27 + editor 32)
50
+ - `npm run smoke:consumers` Playwright probe: **6/6** pass
51
+ - `npm run build:site`: clean
52
+ - `check-links --all`: 0 broken
53
+
54
+ ### Migration
55
+
56
+ See root [CHANGELOG.md `## [0.4.0]`](../../CHANGELOG.md) for the full diff-style migration recipe. The 6 in-repo consumers (`apps/app-shell/`, `site/index.html`, `apps/chat/`, `apps/genui/gen-ui/`, `apps/construct-canvas/`, `apps/genui/a2ui-editor/`) were all migrated in v0.3.6 — see commit `c477d371`.
57
+
14
58
  ## [0.3.6] - 2026-05-10
15
59
 
16
60
  ### Added
package/README.md CHANGED
@@ -5,6 +5,10 @@ Composite custom elements built from
5
5
  into clusters by use case; each cluster ships as a subpath export so
6
6
  consumers install only what they need.
7
7
 
8
+ Each cluster carries a **shell host** (behavior-only orchestrator) plus
9
+ a **family of bespoke shell-tier children** (cluster-namespaced custom
10
+ elements with state-as-attribute semantics) per [ADR-0023](../../.brain/adrs/0023-bespoke-shell-tier-children.md). The bespoke vocabulary is the only recognized authoring shape since v0.4.0 ([ADR-0024](../../.brain/adrs/0024-legacy-shell-shapes-retired.md)).
11
+
8
12
  > The patterns directory lived inside `@adia-ai/web-components` as
9
13
  > `patterns/` until this package was extracted (see
10
14
  > [ADR-0012](../../.brain/adrs/0012-three-tier-architecture-modules.md)).
@@ -13,16 +17,17 @@ consumers install only what they need.
13
17
 
14
18
  ## Clusters
15
19
 
16
- | Cluster | Elements | What's inside |
17
- |---|---|---|
18
- | `shell` | `<admin-shell>` (nav primitives live in `web-components`: `<nav-ui>`, `<nav-group-ui>`, `<nav-item-ui>`) | Admin-shell composition: header, sidebars, command palette. |
19
- | `chat` | `<chat-shell>` | Conversational surface — messages, streaming, markdown, action bar. |
20
- | `editor` | `<editor-shell>` | A2UI live-editor surface — JSON rendered preview. |
21
- | `runtime` | `<gen-root>`, `<a2ui-root>` | Render roots that turn JSON or gen-UI intents into live DOM. |
20
+ | Cluster | Host | Bespoke children | What's inside |
21
+ |---|---|---|---|
22
+ | `shell` | `<admin-shell>` | `<admin-sidebar>`, `<admin-command>` (JS-bearing); `<admin-content>`, `<admin-topbar>`, `<admin-statusbar>`, `<admin-scroll>`, `<admin-page>`, `<admin-page-header>`, `<admin-page-body>` (CSS-only); 9 children total | Admin-shell composition: sidebars, command palette, page chrome. Resize/collapse/persistence on `<admin-sidebar>`; Cmd+K palette on `<admin-command>`. |
23
+ | `chat` | `<chat-shell>` | `<chat-thread>`, `<chat-composer>`, `<chat-sidebar>` (JS-bearing); `<chat-empty>`, `<chat-header>`, `<chat-status>` (CSS-only); 6 children total | Conversational surface — streaming messages, composer with `[disabled]` propagation, scroll-to-bottom thread, `[streaming]` reflected. |
24
+ | `editor` | `<editor-shell>` | `<editor-toolbar>`, `<editor-canvas>`, `<editor-sidebar>` (JS-bearing); `<editor-statusbar>`, `<editor-canvas-empty>` (CSS-only); 5 children total | Design-tool surface — toolbar with `[full-screen]`, central canvas with `[focused]`/`[empty]`, sidebar wraps `<pane-ui resizable>` for delegation. |
25
+ | `runtime` | `<gen-root>`, `<a2ui-root>` | — | Render roots that turn JSON or gen-UI intents into live DOM. |
22
26
 
23
27
  Future clusters on the strategic horizon: `data` (kanban, filters,
24
- table-toolbar), `agent` (agent-trace, reasoning panels), `admin`
25
- (RBAC matrix, approvals).
28
+ table-toolbar), `agent` (agent-trace, reasoning panels).
29
+
30
+ See [`bespoke-shell-children` skill](../../.agents/skills/bespoke-shell-children/SKILL.md) for the canonical decomposition recipe used by all three families.
26
31
 
27
32
  ## Quick start
28
33
 
@@ -35,17 +40,26 @@ table-toolbar), `agent` (agent-trace, reasoning panels), `admin`
35
40
 
36
41
  <script type="module">
37
42
  import '@adia-ai/web-components'; // primitives + nav family
38
- import '@adia-ai/web-modules/shell'; // admin-shell
39
- import '@adia-ai/web-modules/chat'; // adia-chat
40
- import '@adia-ai/web-modules/runtime'; // gen-ui, a2ui-root
43
+ import '@adia-ai/web-modules/shell'; // admin-shell + bespoke children
44
+ import '@adia-ai/web-modules/chat'; // chat-shell + bespoke children
45
+ import '@adia-ai/web-modules/editor'; // editor-shell + bespoke children
46
+ import '@adia-ai/web-modules/runtime'; // gen-root, a2ui-root
41
47
  </script>
42
48
 
49
+ <!-- Bespoke shape (canonical since v0.4.0): -->
43
50
  <admin-shell mode="rounded">
44
- <aside-ui slot="leading">
45
- <header-ui>…</header-ui>
46
- <section-ui><nav-ui>…</nav-ui></section-ui>
47
- </aside-ui>
51
+ <admin-sidebar slot="leading" resizable collapsible>
52
+ <header-ui>
53
+ <span slot="heading">App</span>
54
+ </header-ui>
55
+ <section-ui>
56
+ <nav-ui>…</nav-ui>
57
+ </section-ui>
58
+ </admin-sidebar>
48
59
  <main>…</main>
60
+ <admin-command>
61
+ <command-ui placeholder="Search..."></command-ui>
62
+ </admin-command>
49
63
  </admin-shell>
50
64
  ```
51
65
 
@@ -15,20 +15,22 @@ let msgId = 0;
15
15
  * Behavior-only orchestrator: stamps no HTML of its own.
16
16
  * The author writes the structure; chat-shell wires the behaviors.
17
17
  *
18
- * Structure:
18
+ * Structure (bespoke vocabulary per ADR-0023; **bespoke-only since v0.4.0**):
19
19
  * <chat-shell proxy-url="/api/chat" model="claude-sonnet-4-20250514">
20
- * <header>
21
- * <span data-chat-name>Claude</span>
22
- * <span data-chat-status></span>
23
- * </header>
24
- * <section data-chat-messages>
25
- * <empty-state-ui data-chat-empty icon="chat-circle"
26
- * heading="Hello!" description="Ask me anything.">
27
- * </empty-state-ui>
28
- * </section>
29
- * <footer>
30
- * <chat-input-ui data-chat-input placeholder="Message..."></chat-input-ui>
31
- * </footer>
20
+ * <chat-header>
21
+ * <span slot="name">Claude</span>
22
+ * <chat-status slot="status"></chat-status>
23
+ * </chat-header>
24
+ * <chat-thread>
25
+ * <chat-empty>
26
+ * <empty-state-ui icon="chat-circle"
27
+ * heading="Hello!" description="Ask me anything.">
28
+ * </empty-state-ui>
29
+ * </chat-empty>
30
+ * </chat-thread>
31
+ * <chat-composer>
32
+ * <chat-input-ui placeholder="Message..."></chat-input-ui>
33
+ * </chat-composer>
32
34
  * </chat-shell>
33
35
  *
34
36
  * Two modes:
@@ -79,36 +81,22 @@ class ChatShell extends UIElement {
79
81
  // ── Lifecycle ──
80
82
 
81
83
  connected() {
82
- // Per ADR-0023 read BOTH legacy (data-* / raw HTML) AND bespoke
83
- // (chat-thread / chat-composer / chat-empty / chat-status) shapes.
84
- // The :is() selectors let consumers mix shapes without breakage.
85
- this.#messagesEl = this.querySelector('chat-thread')
86
- || this.querySelector('[data-chat-messages]')
87
- || this.querySelector('section');
88
- this.#inputEl = this.querySelector('chat-composer')
89
- || this.querySelector('[data-chat-input]')
90
- || this.querySelector('chat-input-ui');
91
- this.#emptyEl = this.querySelector('chat-empty')
92
- || this.querySelector('[data-chat-empty]');
93
- this.#statusEl = this.querySelector('chat-status')
94
- || this.querySelector('[data-chat-status]');
95
-
96
- // Bespoke <chat-composer> emits 'composer-submit' instead of 'submit'
97
- // (so the legacy 'submit' event from inside <chat-input-ui> doesn't
98
- // double-fire). Listen for both depending on which shape is present.
99
- if (this.#inputEl?.tagName?.toLowerCase() === 'chat-composer') {
100
- this.#inputEl.addEventListener('composer-submit', this.#onSubmit);
101
- } else {
102
- this.#inputEl?.addEventListener('submit', this.#onSubmit);
103
- }
84
+ // **Bespoke-only since v0.4.0** (ADR-0023 Phase 3). The legacy
85
+ // shapes (<section data-chat-messages>, <chat-input-ui data-chat-input>,
86
+ // <empty-state-ui data-chat-empty>, [data-chat-status>, [data-chat-name>)
87
+ // are no longer recognized. Consumers MUST use the bespoke vocabulary.
88
+ this.#messagesEl = this.querySelector('chat-thread');
89
+ this.#inputEl = this.querySelector('chat-composer');
90
+ this.#emptyEl = this.querySelector('chat-empty');
91
+ this.#statusEl = this.querySelector('chat-status');
92
+
93
+ // <chat-composer> forwards inner <chat-input-ui> submit as
94
+ // composer-submit (bespoke event name prevents double-fire).
95
+ this.#inputEl?.addEventListener('composer-submit', this.#onSubmit);
104
96
  }
105
97
 
106
98
  disconnected() {
107
- if (this.#inputEl?.tagName?.toLowerCase() === 'chat-composer') {
108
- this.#inputEl.removeEventListener('composer-submit', this.#onSubmit);
109
- } else {
110
- this.#inputEl?.removeEventListener('submit', this.#onSubmit);
111
- }
99
+ this.#inputEl?.removeEventListener('composer-submit', this.#onSubmit);
112
100
  this.abort();
113
101
  }
114
102
 
@@ -2,11 +2,11 @@
2
2
  chat-shell — Empty state
3
3
  ═══════════════════════════════════════════════════════════════ */
4
4
 
5
- chat-shell [data-chat-empty] {
5
+ chat-shell chat-empty {
6
6
  margin: auto;
7
7
  }
8
8
 
9
- chat-shell[streaming] [data-chat-empty],
10
- chat-shell:has([data-role]) [data-chat-empty] {
9
+ chat-shell[streaming] chat-empty,
10
+ chat-shell:has([data-role]) chat-empty {
11
11
  display: none;
12
12
  }
@@ -29,14 +29,14 @@ chat-shell > header [data-chat-name] {
29
29
  font-size: var(--chat-header-name-font);
30
30
  }
31
31
 
32
- chat-shell > header [data-chat-status] {
32
+ chat-shell > header chat-status {
33
33
  font-size: var(--chat-header-status-font);
34
34
  color: var(--chat-header-status-fg);
35
35
  margin-inline-start: auto;
36
36
  }
37
37
 
38
38
  /* Messages scroll container */
39
- chat-shell > [data-chat-messages],
39
+ chat-shell > chat-thread,
40
40
  chat-shell > section {
41
41
  flex: 1;
42
42
  overflow-y: auto;
@@ -0,0 +1,65 @@
1
+ <header>
2
+ <div>
3
+ <h1>Editor Canvas</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">editor-canvas</tag-ui>
6
+ <tag-ui size="sm" variant="ghost">JS-bearing</tag-ui>
7
+ </div>
8
+ </div>
9
+ <p>Module-tier editor canvas surface — replaces legacy <div data-canvas>. Owns scroll/zoom container, [empty] + [focused] reflected.</p>
10
+ </header>
11
+
12
+ <section data-section>
13
+ <h2 variant="section">Role</h2>
14
+ <p>Per <a href="../../../../.brain/adrs/0023-bespoke-shell-tier-children.md">ADR-0023</a>, the editor cluster's bespoke family — <code>&lt;editor-shell&gt;</code> (host), <code>&lt;editor-toolbar&gt;</code>, <code>&lt;editor-canvas&gt;</code>, <code>&lt;editor-sidebar&gt;</code> (JS-bearing) + <code>&lt;editor-statusbar&gt;</code>, <code>&lt;editor-canvas-empty&gt;</code> (CSS-only). Confirms the family pattern is canonical across 3 archetypes (admin/chat/editor).</p>
15
+ </section>
16
+
17
+ <section data-section>
18
+ <h2 variant="section">Composition</h2>
19
+ <p>Typical placement inside <code>&lt;editor-shell&gt;</code>:</p>
20
+ <code-ui language="html">&lt;editor-shell&gt;
21
+ &lt;editor-toolbar&gt;
22
+ &lt;span slot="title"&gt;Untitled.fig&lt;/span&gt;
23
+ &lt;button-ui slot="action" icon="gear"&gt;&lt;/button-ui&gt;
24
+ &lt;/editor-toolbar&gt;
25
+
26
+ &lt;editor-sidebar slot="leading" collapsible&gt;
27
+ &lt;pane-ui resizable&gt;
28
+ &lt;header&gt;Navigator&lt;/header&gt;
29
+ &lt;section&gt;…layers…&lt;/section&gt;
30
+ &lt;/pane-ui&gt;
31
+ &lt;/editor-sidebar&gt;
32
+
33
+ &lt;editor-canvas&gt;
34
+ &lt;editor-canvas-empty&gt;
35
+ &lt;empty-state-ui icon="square" heading="New document" description="Drop content to begin."&gt;&lt;/empty-state-ui&gt;
36
+ &lt;/editor-canvas-empty&gt;
37
+ &lt;/editor-canvas&gt;
38
+
39
+ &lt;editor-sidebar slot="trailing" collapsible&gt;
40
+ &lt;pane-ui resizable&gt;
41
+ &lt;header&gt;Inspector&lt;/header&gt;
42
+ &lt;section&gt;…properties…&lt;/section&gt;
43
+ &lt;/pane-ui&gt;
44
+ &lt;/editor-sidebar&gt;
45
+
46
+ &lt;editor-statusbar&gt;
47
+ &lt;span slot="status"&gt;Saved&lt;/span&gt;
48
+ &lt;span slot="zoom"&gt;100%&lt;/span&gt;
49
+ &lt;/editor-statusbar&gt;
50
+ &lt;/editor-shell&gt;</code-ui>
51
+ </section>
52
+
53
+ <section data-section>
54
+ <h2 variant="section">State as attribute</h2>
55
+ <code-ui language="css">/* Hide all chrome in focus mode */
56
+ editor-shell[focus-mode] :is(editor-toolbar, editor-statusbar, editor-sidebar) {
57
+ display: none;
58
+ }
59
+
60
+ /* Visual treatment for empty canvas */
61
+ editor-canvas[empty] { /* placeholder UI */ }
62
+
63
+ /* Highlight focused canvas */
64
+ editor-canvas[focused] { outline: 2px solid var(--a-accent); }</code-ui>
65
+ </section>
@@ -0,0 +1,43 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="auto">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Editor Canvas — AdiaUI</title>
7
+
8
+ <link rel="stylesheet" href="../../../web-components/styles/resets.css">
9
+ <link rel="stylesheet" href="../../../web-components/styles/tokens.css">
10
+ <link rel="stylesheet" href="../editor-shell/editor-shell.css">
11
+ <link rel="stylesheet" href="../../../web-components/components/code/code.css">
12
+ <link rel="stylesheet" href="../../../web-components/components/tag/tag.css">
13
+
14
+ <script type="module" src="../editor-shell/editor-shell.js"></script>
15
+ <script type="module" src="./editor-canvas.js"></script>
16
+ <script type="module" src="../../../web-components/components/code/code.js"></script>
17
+ <script type="module" src="../../../web-components/components/tag/tag.js"></script>
18
+
19
+ <style>
20
+ :where(html, body) { margin: 0; min-height: 100vh; background: var(--a-bg); color: var(--a-fg); font-family: var(--a-font); }
21
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
22
+ </style>
23
+ </head>
24
+ <body>
25
+
26
+ <main id="demo-root">
27
+ <p>Loading examples…</p>
28
+ </main>
29
+
30
+ <script type="module">
31
+ const root = document.getElementById('demo-root');
32
+ try {
33
+ const res = await fetch('./editor-canvas.examples.html');
34
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
35
+ root.innerHTML = await res.text();
36
+ } catch (err) {
37
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load editor-canvas.examples.html — ${err.message}</p>`;
38
+ console.error('[editor-canvas.html]', err);
39
+ }
40
+ </script>
41
+
42
+ </body>
43
+ </html>
@@ -0,0 +1,65 @@
1
+ <header>
2
+ <div>
3
+ <h1>Editor Canvas Empty</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">editor-canvas-empty</tag-ui>
6
+ <tag-ui size="sm" variant="ghost">CSS-only</tag-ui>
7
+ </div>
8
+ </div>
9
+ <p>Module-tier editor canvas empty state. CSS-only. Visibility driven by parent <editor-canvas>[empty].</p>
10
+ </header>
11
+
12
+ <section data-section>
13
+ <h2 variant="section">Role</h2>
14
+ <p>Per <a href="../../../../.brain/adrs/0023-bespoke-shell-tier-children.md">ADR-0023</a>, the editor cluster's bespoke family — <code>&lt;editor-shell&gt;</code> (host), <code>&lt;editor-toolbar&gt;</code>, <code>&lt;editor-canvas&gt;</code>, <code>&lt;editor-sidebar&gt;</code> (JS-bearing) + <code>&lt;editor-statusbar&gt;</code>, <code>&lt;editor-canvas-empty&gt;</code> (CSS-only). Confirms the family pattern is canonical across 3 archetypes (admin/chat/editor).</p>
15
+ </section>
16
+
17
+ <section data-section>
18
+ <h2 variant="section">Composition</h2>
19
+ <p>Typical placement inside <code>&lt;editor-shell&gt;</code>:</p>
20
+ <code-ui language="html">&lt;editor-shell&gt;
21
+ &lt;editor-toolbar&gt;
22
+ &lt;span slot="title"&gt;Untitled.fig&lt;/span&gt;
23
+ &lt;button-ui slot="action" icon="gear"&gt;&lt;/button-ui&gt;
24
+ &lt;/editor-toolbar&gt;
25
+
26
+ &lt;editor-sidebar slot="leading" collapsible&gt;
27
+ &lt;pane-ui resizable&gt;
28
+ &lt;header&gt;Navigator&lt;/header&gt;
29
+ &lt;section&gt;…layers…&lt;/section&gt;
30
+ &lt;/pane-ui&gt;
31
+ &lt;/editor-sidebar&gt;
32
+
33
+ &lt;editor-canvas&gt;
34
+ &lt;editor-canvas-empty&gt;
35
+ &lt;empty-state-ui icon="square" heading="New document" description="Drop content to begin."&gt;&lt;/empty-state-ui&gt;
36
+ &lt;/editor-canvas-empty&gt;
37
+ &lt;/editor-canvas&gt;
38
+
39
+ &lt;editor-sidebar slot="trailing" collapsible&gt;
40
+ &lt;pane-ui resizable&gt;
41
+ &lt;header&gt;Inspector&lt;/header&gt;
42
+ &lt;section&gt;…properties…&lt;/section&gt;
43
+ &lt;/pane-ui&gt;
44
+ &lt;/editor-sidebar&gt;
45
+
46
+ &lt;editor-statusbar&gt;
47
+ &lt;span slot="status"&gt;Saved&lt;/span&gt;
48
+ &lt;span slot="zoom"&gt;100%&lt;/span&gt;
49
+ &lt;/editor-statusbar&gt;
50
+ &lt;/editor-shell&gt;</code-ui>
51
+ </section>
52
+
53
+ <section data-section>
54
+ <h2 variant="section">State as attribute</h2>
55
+ <code-ui language="css">/* Hide all chrome in focus mode */
56
+ editor-shell[focus-mode] :is(editor-toolbar, editor-statusbar, editor-sidebar) {
57
+ display: none;
58
+ }
59
+
60
+ /* Visual treatment for empty canvas */
61
+ editor-canvas[empty] { /* placeholder UI */ }
62
+
63
+ /* Highlight focused canvas */
64
+ editor-canvas[focused] { outline: 2px solid var(--a-accent); }</code-ui>
65
+ </section>
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="auto">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Editor Canvas Empty — AdiaUI</title>
7
+
8
+ <link rel="stylesheet" href="../../../web-components/styles/resets.css">
9
+ <link rel="stylesheet" href="../../../web-components/styles/tokens.css">
10
+ <link rel="stylesheet" href="../editor-shell/editor-shell.css">
11
+ <link rel="stylesheet" href="../../../web-components/components/code/code.css">
12
+ <link rel="stylesheet" href="../../../web-components/components/tag/tag.css">
13
+
14
+ <script type="module" src="../editor-shell/editor-shell.js"></script>
15
+ <script type="module" src="../../../web-components/components/code/code.js"></script>
16
+ <script type="module" src="../../../web-components/components/tag/tag.js"></script>
17
+
18
+ <style>
19
+ :where(html, body) { margin: 0; min-height: 100vh; background: var(--a-bg); color: var(--a-fg); font-family: var(--a-font); }
20
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
21
+ </style>
22
+ </head>
23
+ <body>
24
+
25
+ <main id="demo-root">
26
+ <p>Loading examples…</p>
27
+ </main>
28
+
29
+ <script type="module">
30
+ const root = document.getElementById('demo-root');
31
+ try {
32
+ const res = await fetch('./editor-canvas-empty.examples.html');
33
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
34
+ root.innerHTML = await res.text();
35
+ } catch (err) {
36
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load editor-canvas-empty.examples.html — ${err.message}</p>`;
37
+ console.error('[editor-canvas-empty.html]', err);
38
+ }
39
+ </script>
40
+
41
+ </body>
42
+ </html>
@@ -129,11 +129,76 @@ editor-sidebar > pane-ui {
129
129
  flex-direction: column;
130
130
  }
131
131
 
132
- /* When sidebar is collapsed, hide pane content but keep the rail */
133
- editor-sidebar[collapsed] > pane-ui > :not(header) {
132
+ /* ── editor-sidebar collapsed-mode polish ──
133
+ When collapsed: pane shrinks to icon-rail width (48px); section
134
+ content hides; header narrows to icon-only with horizontal-center;
135
+ smooth width transition on uncollapse. Mirrors the rail-pattern
136
+ established by admin-sidebar's collapsed state.
137
+ ═══════════════════════════════════════════════════════════════ */
138
+
139
+ editor-sidebar {
140
+ transition: width var(--editor-sidebar-duration, var(--a-duration, 180ms))
141
+ var(--editor-sidebar-easing, var(--a-easing, ease));
142
+ container-type: inline-size;
143
+ container-name: editor-sidebar;
144
+ }
145
+
146
+ /* Inner pane animates the visible width */
147
+ editor-sidebar > pane-ui {
148
+ transition: width var(--editor-sidebar-duration, var(--a-duration, 180ms))
149
+ var(--editor-sidebar-easing, var(--a-easing, ease));
150
+ }
151
+
152
+ /* Collapsed state — hide section/footer content; preserve header icons */
153
+ editor-sidebar[collapsed] > pane-ui {
154
+ width: var(--editor-sidebar-collapsed-width, 48px) !important;
155
+ min-width: var(--editor-sidebar-collapsed-width, 48px);
156
+ overflow: hidden;
157
+ }
158
+
159
+ editor-sidebar[collapsed] > pane-ui > section,
160
+ editor-sidebar[collapsed] > pane-ui > footer {
161
+ display: none;
162
+ }
163
+
164
+ /* Collapsed header — center icons horizontally; hide text labels */
165
+ editor-sidebar[collapsed] > pane-ui > header {
166
+ display: flex;
167
+ flex-direction: column;
168
+ align-items: center;
169
+ justify-content: flex-start;
170
+ gap: var(--a-space-1);
171
+ padding: var(--a-space-2) 0;
172
+ /* Hide direct text nodes via opacity-0 + descendant text containers */
173
+ }
174
+
175
+ /* Collapsed header — hide text labels next to icons */
176
+ editor-sidebar[collapsed] > pane-ui > header :is(
177
+ span:not([data-icon]):not([slot]),
178
+ label,
179
+ h1, h2, h3
180
+ ) {
134
181
  display: none;
135
182
  }
136
183
 
184
+ /* Provide a visual rail affordance */
185
+ editor-sidebar[collapsed] {
186
+ background: var(--editor-sidebar-rail-bg, var(--a-bg-subtle, var(--a-bg)));
187
+ }
188
+
189
+ /* Container query — child elements can adapt to narrow mode */
190
+ @container editor-sidebar (max-width: 96px) {
191
+ /* Children can hide labels / shrink icons via [data-narrow] */
192
+ }
193
+
194
+ /* When resizing — disable transitions to feel responsive */
195
+ editor-sidebar[resizing] {
196
+ transition: none;
197
+ }
198
+ editor-sidebar[resizing] > pane-ui {
199
+ transition: none;
200
+ }
201
+
137
202
  /* ── editor-statusbar — bottom chrome bar ── */
138
203
  editor-shell > editor-statusbar {
139
204
  display: flex;
@@ -4,9 +4,9 @@
4
4
  Structure:
5
5
  editor-shell
6
6
  header — topbar
7
- [data-editor-body] — flex row: pane | canvas | pane
7
+ — flex row: pane | canvas | pane
8
8
  pane-ui — left navigator
9
- [data-canvas] — center canvas
9
+ editor-canvas — center canvas
10
10
  pane-ui — right inspector
11
11
  footer — bottombar
12
12
  ═══════════════════════════════════════════════════════════════ */
@@ -82,7 +82,7 @@ editor-shell > header > [slot="action-leading"] {
82
82
  }
83
83
 
84
84
  /* ── Body: pane | canvas | pane ── */
85
- editor-shell > [data-editor-body] {
85
+ editor-shell > {
86
86
  display: flex;
87
87
  flex: 1;
88
88
  min-width: 0;
@@ -90,7 +90,7 @@ editor-shell > [data-editor-body] {
90
90
  }
91
91
 
92
92
  /* ── Canvas ── */
93
- editor-shell [data-canvas] {
93
+ editor-shell editor-canvas {
94
94
  flex: 1;
95
95
  min-width: 0;
96
96
  display: flex;
@@ -107,11 +107,11 @@ editor-shell pane-ui {
107
107
  flex-shrink: 0;
108
108
  }
109
109
 
110
- editor-shell pane-ui[data-left] {
110
+ editor-shell editor-sidebar[slot="leading"] > pane-ui {
111
111
  width: var(--editor-pane-width-left);
112
112
  }
113
113
 
114
- editor-shell pane-ui[data-right] {
114
+ editor-shell editor-sidebar[slot="trailing"] > pane-ui {
115
115
  width: var(--editor-pane-width-right);
116
116
  }
117
117
 
@@ -2,26 +2,27 @@ import { UIElement } from '../../../web-components/core/element.js';
2
2
 
3
3
  /**
4
4
  * <editor-shell focus-mode?>
5
- * <editor-toolbar>...</editor-toolbar> (or legacy <header>)
6
- * <editor-sidebar slot="leading"> (or legacy <pane-ui data-left>)
5
+ * <editor-toolbar>...</editor-toolbar>
6
+ * <editor-sidebar slot="leading">
7
7
  * <pane-ui resizable>...</pane-ui>
8
8
  * </editor-sidebar>
9
- * <editor-canvas>...</editor-canvas> (or legacy <div data-canvas>)
10
- * <editor-sidebar slot="trailing"> (or legacy <pane-ui data-right>)
9
+ * <editor-canvas>...</editor-canvas>
10
+ * <editor-sidebar slot="trailing">
11
11
  * <pane-ui resizable>...</pane-ui>
12
12
  * </editor-sidebar>
13
- * <editor-statusbar>...</editor-statusbar> (or legacy <footer>)
13
+ * <editor-statusbar>...</editor-statusbar>
14
14
  * </editor-shell>
15
15
  *
16
16
  * Behavior-only orchestrator for design-tool UIs:
17
17
  * topbar, navigator pane, center canvas, inspector pane, bottombar.
18
18
  *
19
- * Per ADR-0023, the bespoke shape uses cluster-namespaced custom
20
- * elements. Both legacy and bespoke shapes coexist via :is() reads
21
- * in the host. Editor cluster has the smallest bespoke family of
22
- * the three (admin, chat, editor) only 3 JS-bearing children +
23
- * 2 CSS-only structural stubs — because <pane-ui> already owns
24
- * resize and the editor doesn't need a command palette.
19
+ * **Bespoke-only since v0.4.0** (ADR-0023 Phase 3). The legacy shapes
20
+ * (<header>, <div data-editor-body>, <pane-ui data-left|data-right>,
21
+ * <div data-canvas>, <footer>) are no longer recognized. The editor
22
+ * cluster has the smallest bespoke family of the three (admin / chat /
23
+ * editor) — only 3 JS-bearing children + 2 CSS-only structural stubs —
24
+ * because <pane-ui> already owns resize and the editor doesn't need
25
+ * a command palette.
25
26
  *
26
27
  * Reflected attributes:
27
28
  * [focus-mode] — distraction-free / canvas-focus mode; consumers
@@ -48,13 +49,14 @@ class EditorShell extends UIElement {
48
49
  #onToolbarAction = null;
49
50
 
50
51
  connected() {
51
- // Per ADR-0023 read BOTH legacy + bespoke shapes
52
- this.#toolbarEl = this.querySelector('editor-toolbar')
53
- || this.querySelector('header');
54
- this.#canvasEl = this.querySelector('editor-canvas')
55
- || this.querySelector('[data-canvas]');
52
+ // **Bespoke-only since v0.4.0** (ADR-0023 Phase 3). The legacy
53
+ // shapes (<header>, <div data-canvas>, <div data-editor-body>,
54
+ // <pane-ui data-left|data-right>, <footer>) are no longer
55
+ // recognized. Consumers MUST use the bespoke vocabulary.
56
+ this.#toolbarEl = this.querySelector('editor-toolbar');
57
+ this.#canvasEl = this.querySelector('editor-canvas');
56
58
 
57
- // Wire select options (legacy concern, kept for backwards compat)
59
+ // Wire select options inside the toolbar / sidebars
58
60
  this.#wireSelects();
59
61
 
60
62
  // Listen for toolbar-action bubbling from <editor-toolbar>