@adia-ai/web-modules 0.3.5 → 0.4.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/chat/chat-shell/chat-shell.js +28 -40
  3. package/chat/chat-shell/css/chat-shell.empty.css +3 -3
  4. package/chat/chat-shell/css/chat-shell.layout.css +2 -2
  5. package/editor/editor-canvas/editor-canvas.a2ui.json +87 -0
  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/editor-canvas.js +103 -0
  9. package/editor/editor-canvas/editor-canvas.test.js +100 -0
  10. package/editor/editor-canvas/editor-canvas.yaml +88 -0
  11. package/editor/editor-canvas-empty/editor-canvas-empty.a2ui.json +69 -0
  12. package/editor/editor-canvas-empty/editor-canvas-empty.examples.html +65 -0
  13. package/editor/editor-canvas-empty/editor-canvas-empty.html +42 -0
  14. package/editor/editor-canvas-empty/editor-canvas-empty.yaml +56 -0
  15. package/editor/editor-shell/css/editor-shell.bespoke.css +237 -0
  16. package/editor/editor-shell/css/editor-shell.layout.css +6 -6
  17. package/editor/editor-shell/editor-shell.css +1 -0
  18. package/editor/editor-shell/editor-shell.js +87 -30
  19. package/editor/editor-sidebar/editor-sidebar.a2ui.json +93 -0
  20. package/editor/editor-sidebar/editor-sidebar.examples.html +65 -0
  21. package/editor/editor-sidebar/editor-sidebar.html +43 -0
  22. package/editor/editor-sidebar/editor-sidebar.js +197 -0
  23. package/editor/editor-sidebar/editor-sidebar.test.js +145 -0
  24. package/editor/editor-sidebar/editor-sidebar.yaml +91 -0
  25. package/editor/editor-statusbar/editor-statusbar.a2ui.json +76 -0
  26. package/editor/editor-statusbar/editor-statusbar.examples.html +65 -0
  27. package/editor/editor-statusbar/editor-statusbar.html +42 -0
  28. package/editor/editor-statusbar/editor-statusbar.yaml +57 -0
  29. package/editor/editor-toolbar/editor-toolbar.a2ui.json +96 -0
  30. package/editor/editor-toolbar/editor-toolbar.examples.html +65 -0
  31. package/editor/editor-toolbar/editor-toolbar.html +43 -0
  32. package/editor/editor-toolbar/editor-toolbar.js +58 -0
  33. package/editor/editor-toolbar/editor-toolbar.test.js +99 -0
  34. package/editor/editor-toolbar/editor-toolbar.yaml +81 -0
  35. package/editor/index.js +3 -0
  36. package/package.json +4 -4
  37. package/shell/admin-shell/admin-shell.js +27 -243
  38. package/shell/admin-shell/css/admin-shell.bespoke.css +22 -26
  39. package/shell/admin-shell/css/admin-shell.main.css +2 -2
  40. package/shell/admin-shell/css/admin-shell.shell.css +2 -2
  41. package/shell/admin-shell/css/admin-shell.sidebar.css +35 -33
@@ -0,0 +1,91 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: EditorSidebar
4
+ tag: editor-sidebar
5
+ component: EditorSidebar
6
+ category: layout
7
+ version: 1
8
+ description: |
9
+ Module-tier editor-cluster sidebar — wraps <pane-ui resizable>
10
+ (the primitive that owns drag) and adds [collapsed] reflected
11
+ state, localStorage persistence (adia-editor-sidebar-{name}),
12
+ and .toggle() / .collapse() / .expand() public API.
13
+
14
+ Sits inside <editor-shell> as slot="leading" (navigator pane) or
15
+ slot="trailing" (inspector pane). Mirrors the cluster-namespace
16
+ shape from <admin-sidebar> and <chat-sidebar>, but DELEGATES to
17
+ <pane-ui> for resize rather than reimplementing it (per
18
+ bespoke-shell-children skill §When NOT to promote — pane primitive
19
+ already owns this concern).
20
+
21
+ This is the FIRST bespoke shell child that delegates rather than
22
+ duplicates a primitive's behavior. Pattern is: cluster-namespace +
23
+ state-as-attribute + persistence at the bespoke tier; physical
24
+ drag at the primitive tier.
25
+
26
+ props:
27
+ collapsed:
28
+ description: Reflected — set when inner <pane-ui> width is at or below 96px snap threshold.
29
+ type: boolean
30
+ default: false
31
+ reflect: true
32
+ resizing:
33
+ description: |
34
+ Reflected — set during an active pointer-drag of the pane's
35
+ resize handle. Used to disable transitions and visual treatments
36
+ that would feel laggy during drag.
37
+ type: boolean
38
+ default: false
39
+ reflect: true
40
+
41
+ events:
42
+ sidebar-toggle:
43
+ description: Bubbles when .toggle() / .collapse() / .expand() is called.
44
+ detail:
45
+ name: string
46
+ expanded: boolean
47
+
48
+ slots:
49
+ default:
50
+ description: >-
51
+ Default — the inner <pane-ui resizable> wrapper. Authors compose
52
+ header / section / footer inside the pane as usual.
53
+
54
+ states:
55
+ - name: idle
56
+ description: Default expanded state.
57
+ - name: collapsed
58
+ attribute: collapsed
59
+ description: Inner pane is at or below the snap threshold.
60
+
61
+ traits: []
62
+
63
+ a2ui:
64
+ rules:
65
+ - >-
66
+ editor-sidebar wraps <pane-ui resizable> rather than implementing
67
+ drag itself. Place a <pane-ui resizable> as the only structural
68
+ child; fill the pane with header / section / footer slots.
69
+ - >-
70
+ The cluster-distinct localStorage prefix (adia-editor-sidebar-*)
71
+ keeps editor sidebars from colliding with admin (adia-sidebar-*)
72
+ and chat (adia-chat-sidebar-*) sidebars on the same domain.
73
+
74
+ keywords:
75
+ - editor-sidebar
76
+ - navigator-pane
77
+ - inspector-pane
78
+ - editor-rail
79
+ - sidebar
80
+ - leading
81
+ - trailing
82
+
83
+ synonyms:
84
+ editor-sidebar: [navigator, inspector, editor-rail, side-panel]
85
+
86
+ related:
87
+ - EditorShell
88
+ - EditorCanvas
89
+ - Pane
90
+ - AdminSidebar
91
+ - ChatSidebar
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/EditorStatusbar.json",
4
+ "title": "EditorStatusbar",
5
+ "description": "Module-tier editor statusbar — bottom chrome bar inside\n<editor-shell>. CSS-only, no behavior, no JS. Holds save/sync\nstate, zoom indicator, cursor position, and tertiary actions\nvia slot vocabulary.\n\nReplaces the legacy <footer> with positional content per ADR-0023.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "component": {
17
+ "const": "EditorStatusbar"
18
+ }
19
+ },
20
+ "required": [
21
+ "component"
22
+ ],
23
+ "unevaluatedProperties": false,
24
+ "x-adiaui": {
25
+ "anti_patterns": [],
26
+ "category": "layout",
27
+ "events": {},
28
+ "examples": [],
29
+ "keywords": [
30
+ "editor-statusbar",
31
+ "statusbar",
32
+ "bottom-bar",
33
+ "editor-footer"
34
+ ],
35
+ "name": "EditorStatusbar",
36
+ "related": [
37
+ "EditorShell",
38
+ "EditorToolbar",
39
+ "EditorCanvas"
40
+ ],
41
+ "slots": {
42
+ "default": {
43
+ "description": "Default — ad-hoc inline content (legacy positional layout)."
44
+ },
45
+ "action": {
46
+ "description": "Trailing action cluster (e.g., toggle full-screen)."
47
+ },
48
+ "cursor": {
49
+ "description": "Cursor position / selection indicator."
50
+ },
51
+ "status": {
52
+ "description": "Save/sync state indicator."
53
+ },
54
+ "zoom": {
55
+ "description": "Zoom level indicator."
56
+ }
57
+ },
58
+ "states": [
59
+ {
60
+ "description": "Default, the only state.",
61
+ "name": "idle"
62
+ }
63
+ ],
64
+ "synonyms": {
65
+ "editor-statusbar": [
66
+ "statusbar",
67
+ "footer-bar",
68
+ "bottom-bar"
69
+ ]
70
+ },
71
+ "tag": "editor-statusbar",
72
+ "tokens": {},
73
+ "traits": [],
74
+ "version": 1
75
+ }
76
+ }
@@ -0,0 +1,65 @@
1
+ <header>
2
+ <div>
3
+ <h1>Editor Statusbar</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">editor-statusbar</tag-ui>
6
+ <tag-ui size="sm" variant="ghost">CSS-only</tag-ui>
7
+ </div>
8
+ </div>
9
+ <p>Module-tier editor statusbar — bottom chrome bar. CSS-only.</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 Statusbar — 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-statusbar.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-statusbar.examples.html — ${err.message}</p>`;
37
+ console.error('[editor-statusbar.html]', err);
38
+ }
39
+ </script>
40
+
41
+ </body>
42
+ </html>
@@ -0,0 +1,57 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: EditorStatusbar
4
+ tag: editor-statusbar
5
+ component: EditorStatusbar
6
+ category: layout
7
+ version: 1
8
+ description: |
9
+ Module-tier editor statusbar — bottom chrome bar inside
10
+ <editor-shell>. CSS-only, no behavior, no JS. Holds save/sync
11
+ state, zoom indicator, cursor position, and tertiary actions
12
+ via slot vocabulary.
13
+
14
+ Replaces the legacy <footer> with positional content per ADR-0023.
15
+
16
+ props: {}
17
+
18
+ events: {}
19
+
20
+ slots:
21
+ default:
22
+ description: Default — ad-hoc inline content (legacy positional layout).
23
+ status:
24
+ description: Save/sync state indicator.
25
+ cursor:
26
+ description: Cursor position / selection indicator.
27
+ zoom:
28
+ description: Zoom level indicator.
29
+ action:
30
+ description: Trailing action cluster (e.g., toggle full-screen).
31
+
32
+ states:
33
+ - name: idle
34
+ description: Default, the only state.
35
+
36
+ traits: []
37
+
38
+ a2ui:
39
+ rules:
40
+ - >-
41
+ editor-statusbar replaces legacy <footer> chrome bar inside
42
+ <editor-shell>. Use named slots for canonical clusters; ad-hoc
43
+ content goes in the default slot.
44
+
45
+ keywords:
46
+ - editor-statusbar
47
+ - statusbar
48
+ - bottom-bar
49
+ - editor-footer
50
+
51
+ synonyms:
52
+ editor-statusbar: [statusbar, footer-bar, bottom-bar]
53
+
54
+ related:
55
+ - EditorShell
56
+ - EditorToolbar
57
+ - EditorCanvas
@@ -0,0 +1,96 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/EditorToolbar.json",
4
+ "title": "EditorToolbar",
5
+ "description": "Module-tier editor toolbar — replaces legacy <header> chrome bar\ninside <editor-shell> per ADR-0023. Owns the [full-screen] reflected\nattribute (set when host enters focus mode), click-bubble for\n[data-toolbar-action] buttons, and slot vocabulary routing.\n\nSits at the top of <editor-shell>. Authors compose actions + status\nvia slot vocabulary. The host (<editor-shell>) reads either\n<editor-toolbar> or <header> via :is() selector for backwards compat.\n",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "component": {
17
+ "const": "EditorToolbar"
18
+ },
19
+ "fullScreen": {
20
+ "description": "Reflected — set when editor is in distraction-free / focus mode.",
21
+ "type": "boolean",
22
+ "default": false
23
+ }
24
+ },
25
+ "required": [
26
+ "component"
27
+ ],
28
+ "unevaluatedProperties": false,
29
+ "x-adiaui": {
30
+ "anti_patterns": [],
31
+ "category": "layout",
32
+ "events": {
33
+ "toolbar-action": {
34
+ "description": "Bubbles when a child element with [data-toolbar-action] is clicked. Detail carries the action name from the clicked element's attribute.",
35
+ "detail": {
36
+ "name": "string"
37
+ }
38
+ }
39
+ },
40
+ "examples": [],
41
+ "keywords": [
42
+ "editor-toolbar",
43
+ "editor-titlebar",
44
+ "editor-chrome",
45
+ "app-header",
46
+ "editor-actions"
47
+ ],
48
+ "name": "EditorToolbar",
49
+ "related": [
50
+ "EditorShell",
51
+ "EditorCanvas",
52
+ "EditorSidebar",
53
+ "EditorStatusbar"
54
+ ],
55
+ "slots": {
56
+ "title": {
57
+ "description": "Editor / document title cluster."
58
+ },
59
+ "default": {
60
+ "description": "Default — ad-hoc inline content (legacy positional layout)."
61
+ },
62
+ "action": {
63
+ "description": "Trailing action cluster (settings, share, more)."
64
+ },
65
+ "action-leading": {
66
+ "description": "Leading action cluster (back, switcher, undo/redo)."
67
+ },
68
+ "status": {
69
+ "description": "Status indicator (saving, dirty, synced, etc.)."
70
+ }
71
+ },
72
+ "states": [
73
+ {
74
+ "description": "Default editor mode.",
75
+ "name": "idle"
76
+ },
77
+ {
78
+ "description": "Distraction-free / focus mode active.",
79
+ "attribute": "full-screen",
80
+ "name": "full-screen"
81
+ }
82
+ ],
83
+ "synonyms": {
84
+ "editor-toolbar": [
85
+ "editor-header",
86
+ "app-header",
87
+ "navbar",
88
+ "titlebar"
89
+ ]
90
+ },
91
+ "tag": "editor-toolbar",
92
+ "tokens": {},
93
+ "traits": [],
94
+ "version": 1
95
+ }
96
+ }
@@ -0,0 +1,65 @@
1
+ <header>
2
+ <div>
3
+ <h1>Editor Toolbar</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">editor-toolbar</tag-ui>
6
+ <tag-ui size="sm" variant="ghost">JS-bearing</tag-ui>
7
+ </div>
8
+ </div>
9
+ <p>Module-tier editor toolbar — replaces legacy <header> chrome bar. Click-bubble for [data-toolbar-action] buttons + [full-screen] reflected attribute.</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 Toolbar — 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-toolbar.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-toolbar.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-toolbar.examples.html — ${err.message}</p>`;
38
+ console.error('[editor-toolbar.html]', err);
39
+ }
40
+ </script>
41
+
42
+ </body>
43
+ </html>
@@ -0,0 +1,58 @@
1
+ /**
2
+ * <editor-toolbar full-screen?>
3
+ * <span slot="title">Editor</span>
4
+ * <button-ui slot="action" icon="gear"></button-ui>
5
+ * </editor-toolbar>
6
+ *
7
+ * Module-tier editor toolbar — replaces legacy <header> with [data-title]
8
+ * + [data-spacer] + ad-hoc action children inside <editor-shell>. Owns:
9
+ *
10
+ * - [full-screen] reflected attribute (set when host enters focus mode)
11
+ * - Slot vocabulary routing (title / status / action / action-leading)
12
+ * - Click-bubble for [data-toolbar-action="<name>"] buttons → fires
13
+ * 'toolbar-action' event with the action name
14
+ *
15
+ * Reflected attributes:
16
+ * [full-screen] — true when editor is in distraction-free / focus mode
17
+ *
18
+ * Events:
19
+ * toolbar-action — bubbles. detail: { name } from clicked button's
20
+ * [data-toolbar-action] attribute
21
+ *
22
+ * The host (<editor-shell>) reads either <editor-toolbar> or <header>
23
+ * via :is() selector for backwards compat. Default-slot children fall
24
+ * back to legacy positional layout if no named slots are used.
25
+ */
26
+
27
+ import { UIElement } from '../../../web-components/core/element.js';
28
+
29
+ class EditorToolbar extends UIElement {
30
+ static properties = {
31
+ fullScreen: { type: Boolean, default: false, reflect: true, attribute: 'full-screen' },
32
+ };
33
+
34
+ static template = () => null;
35
+
36
+ #onClick = null;
37
+
38
+ connected() {
39
+ this.#onClick = (e) => {
40
+ const btn = e.target.closest('[data-toolbar-action]');
41
+ if (!btn || !this.contains(btn)) return;
42
+ const name = btn.getAttribute('data-toolbar-action');
43
+ this.dispatchEvent(new CustomEvent('toolbar-action', {
44
+ bubbles: true,
45
+ detail: { name },
46
+ }));
47
+ };
48
+ this.addEventListener('click', this.#onClick);
49
+ }
50
+
51
+ disconnected() {
52
+ if (this.#onClick) this.removeEventListener('click', this.#onClick);
53
+ this.#onClick = null;
54
+ }
55
+ }
56
+
57
+ customElements.define('editor-toolbar', EditorToolbar);
58
+ export { EditorToolbar };