@adia-ai/web-modules 0.3.3 → 0.3.5

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 (88) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/chat/chat-composer/chat-composer.a2ui.json +94 -0
  3. package/chat/chat-composer/chat-composer.examples.html +28 -0
  4. package/chat/chat-composer/chat-composer.html +43 -0
  5. package/chat/chat-composer/chat-composer.js +107 -0
  6. package/chat/chat-composer/chat-composer.test.js +112 -0
  7. package/chat/chat-composer/chat-composer.yaml +91 -0
  8. package/chat/chat-empty/chat-empty.a2ui.json +68 -0
  9. package/chat/chat-empty/chat-empty.examples.html +34 -0
  10. package/chat/chat-empty/chat-empty.html +42 -0
  11. package/chat/chat-empty/chat-empty.yaml +58 -0
  12. package/chat/chat-header/chat-header.a2ui.json +77 -0
  13. package/chat/chat-header/chat-header.examples.html +30 -0
  14. package/chat/chat-header/chat-header.html +42 -0
  15. package/chat/chat-header/chat-header.yaml +68 -0
  16. package/chat/chat-shell/chat-shell.css +1 -0
  17. package/chat/chat-shell/chat-shell.examples.html +126 -0
  18. package/chat/chat-shell/chat-shell.html +42 -0
  19. package/chat/chat-shell/chat-shell.js +35 -7
  20. package/chat/chat-shell/css/chat-shell.bespoke.css +196 -0
  21. package/chat/chat-sidebar/chat-sidebar.a2ui.json +136 -0
  22. package/chat/chat-sidebar/chat-sidebar.examples.html +36 -0
  23. package/chat/chat-sidebar/chat-sidebar.html +43 -0
  24. package/chat/chat-sidebar/chat-sidebar.js +227 -0
  25. package/chat/chat-sidebar/chat-sidebar.test.js +110 -0
  26. package/chat/chat-sidebar/chat-sidebar.yaml +140 -0
  27. package/chat/chat-status/chat-status.a2ui.json +63 -0
  28. package/chat/chat-status/chat-status.examples.html +29 -0
  29. package/chat/chat-status/chat-status.html +42 -0
  30. package/chat/chat-status/chat-status.yaml +52 -0
  31. package/chat/chat-thread/chat-thread.a2ui.json +91 -0
  32. package/chat/chat-thread/chat-thread.examples.html +36 -0
  33. package/chat/chat-thread/chat-thread.html +43 -0
  34. package/chat/chat-thread/chat-thread.js +106 -0
  35. package/chat/chat-thread/chat-thread.test.js +82 -0
  36. package/chat/chat-thread/chat-thread.yaml +89 -0
  37. package/chat/index.js +3 -0
  38. package/editor/editor-shell/editor-shell.examples.html +71 -0
  39. package/editor/editor-shell/editor-shell.html +42 -0
  40. package/package.json +1 -1
  41. package/shell/admin-command/admin-command.a2ui.json +102 -0
  42. package/shell/admin-command/admin-command.examples.html +83 -0
  43. package/shell/admin-command/admin-command.html +42 -0
  44. package/shell/admin-command/admin-command.js +161 -0
  45. package/shell/admin-command/admin-command.test.js +115 -0
  46. package/shell/admin-command/admin-command.yaml +102 -0
  47. package/shell/admin-content/admin-content.a2ui.json +73 -0
  48. package/shell/admin-content/admin-content.examples.html +33 -0
  49. package/shell/admin-content/admin-content.html +42 -0
  50. package/shell/admin-content/admin-content.yaml +63 -0
  51. package/shell/admin-page/admin-page.a2ui.json +74 -0
  52. package/shell/admin-page/admin-page.examples.html +37 -0
  53. package/shell/admin-page/admin-page.html +42 -0
  54. package/shell/admin-page/admin-page.yaml +61 -0
  55. package/shell/admin-page-body/admin-page-body.a2ui.json +62 -0
  56. package/shell/admin-page-body/admin-page-body.examples.html +34 -0
  57. package/shell/admin-page-body/admin-page-body.html +42 -0
  58. package/shell/admin-page-body/admin-page-body.yaml +49 -0
  59. package/shell/admin-page-header/admin-page-header.a2ui.json +62 -0
  60. package/shell/admin-page-header/admin-page-header.examples.html +34 -0
  61. package/shell/admin-page-header/admin-page-header.html +42 -0
  62. package/shell/admin-page-header/admin-page-header.yaml +47 -0
  63. package/shell/admin-scroll/admin-scroll.a2ui.json +62 -0
  64. package/shell/admin-scroll/admin-scroll.examples.html +31 -0
  65. package/shell/admin-scroll/admin-scroll.html +42 -0
  66. package/shell/admin-scroll/admin-scroll.yaml +51 -0
  67. package/shell/admin-shell/admin-shell.a2ui.json +0 -10
  68. package/shell/admin-shell/admin-shell.css +1 -0
  69. package/shell/admin-shell/admin-shell.examples.html +61 -5
  70. package/shell/admin-shell/admin-shell.js +165 -121
  71. package/shell/admin-shell/admin-shell.yaml +6 -6
  72. package/shell/admin-shell/css/admin-shell.bespoke.css +198 -0
  73. package/shell/admin-shell/css/admin-shell.tokens.css +10 -0
  74. package/shell/admin-sidebar/admin-sidebar.a2ui.json +138 -0
  75. package/shell/admin-sidebar/admin-sidebar.examples.html +76 -0
  76. package/shell/admin-sidebar/admin-sidebar.html +47 -0
  77. package/shell/admin-sidebar/admin-sidebar.js +227 -0
  78. package/shell/admin-sidebar/admin-sidebar.test.js +123 -0
  79. package/shell/admin-sidebar/admin-sidebar.yaml +140 -0
  80. package/shell/admin-statusbar/admin-statusbar.a2ui.json +81 -0
  81. package/shell/admin-statusbar/admin-statusbar.examples.html +29 -0
  82. package/shell/admin-statusbar/admin-statusbar.html +42 -0
  83. package/shell/admin-statusbar/admin-statusbar.yaml +68 -0
  84. package/shell/admin-topbar/admin-topbar.a2ui.json +83 -0
  85. package/shell/admin-topbar/admin-topbar.examples.html +31 -0
  86. package/shell/admin-topbar/admin-topbar.html +42 -0
  87. package/shell/admin-topbar/admin-topbar.yaml +75 -0
  88. package/shell/index.js +2 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * <admin-command shortcut="cmd+k|ctrl+k|both">
3
+ * <command-ui placeholder="Search…"></command-ui>
4
+ * </admin-command>
5
+ *
6
+ * Module-tier command palette — wraps a native <dialog> and the inner
7
+ * <command-ui>. Owns the keyboard shortcut listener, focus management,
8
+ * and dismiss handlers. Reflects [open].
9
+ *
10
+ * Reflected attributes:
11
+ * [open] — set while the dialog is showing
12
+ *
13
+ * Author-supplied attributes:
14
+ * [shortcut="cmd+k"|"ctrl+k"|"both"]
15
+ * — keyboard shortcut. Default "both"
16
+ * (responds to Cmd+K on Mac and Ctrl+K
17
+ * on other platforms).
18
+ * [no-shortcut] — opts out of the keyboard listener
19
+ * entirely. Use when the host wires
20
+ * its own shortcut handling.
21
+ *
22
+ * Public methods:
23
+ * .show() — open the palette (via showModal)
24
+ * .hide() — close
25
+ * .toggle() — flip open state
26
+ *
27
+ * Events forwarded from inner <command-ui>:
28
+ * command-select — bubbles. detail: { value, ... }
29
+ *
30
+ * Authors composing into <admin-shell> just drop this in as a child;
31
+ * the host does NOT reach inside. <admin-shell> wires
32
+ * [data-command-trigger] elements to this.show() via a lookup.
33
+ *
34
+ * Backwards compat: <admin-shell> still recognizes the legacy
35
+ * <dialog data-command> shape and wires the same shortcut. New code
36
+ * should prefer <admin-command>.
37
+ */
38
+
39
+ import { UIElement } from '../../../web-components/core/element.js';
40
+
41
+ class AdminCommand extends UIElement {
42
+ static properties = {
43
+ open: { type: Boolean, default: false, reflect: true },
44
+ shortcut: { type: String, default: 'both', reflect: true },
45
+ noShortcut: { type: Boolean, default: false, reflect: true, attribute: 'no-shortcut' },
46
+ };
47
+
48
+ static template = () => null;
49
+
50
+ #keyHandler = null;
51
+ #cmdEl = null;
52
+ #dialog = null;
53
+
54
+ connected() {
55
+ // Find or construct the dialog. If author supplies <dialog>, use it.
56
+ // Otherwise, wrap the slotted content in a fresh <dialog>.
57
+ this.#dialog = this.querySelector(':scope > dialog');
58
+ if (!this.#dialog) {
59
+ this.#dialog = document.createElement('dialog');
60
+ // Move all children into the dialog
61
+ while (this.firstChild) this.#dialog.appendChild(this.firstChild);
62
+ this.appendChild(this.#dialog);
63
+ }
64
+ this.#cmdEl = this.querySelector('command-ui');
65
+
66
+ this.#wireDialog();
67
+ this.#wireCommand();
68
+ if (!this.noShortcut) this.#wireShortcut();
69
+ }
70
+
71
+ disconnected() {
72
+ if (this.#keyHandler) {
73
+ document.removeEventListener('keydown', this.#keyHandler);
74
+ this.#keyHandler = null;
75
+ }
76
+ }
77
+
78
+ // ── Public API ──
79
+
80
+ show() {
81
+ if (!this.#dialog) return;
82
+ if (this.#dialog.open) return;
83
+ this.#dialog.showModal();
84
+ if (this.#cmdEl) {
85
+ this.#cmdEl.open = true;
86
+ this.#cmdEl.value = '';
87
+ this.#cmdEl.focus();
88
+ }
89
+ this.open = true;
90
+ }
91
+
92
+ hide() {
93
+ if (!this.#dialog) return;
94
+ if (!this.#dialog.open) return;
95
+ this.#dialog.close();
96
+ if (this.#cmdEl) this.#cmdEl.open = false;
97
+ this.open = false;
98
+ }
99
+
100
+ toggle() {
101
+ if (this.open) {
102
+ this.hide();
103
+ } else {
104
+ this.show();
105
+ }
106
+ return this.open;
107
+ }
108
+
109
+ // ── Wiring ──
110
+
111
+ #wireDialog() {
112
+ if (!this.#dialog) return;
113
+
114
+ // Backdrop click closes
115
+ this.#dialog.addEventListener('click', (e) => {
116
+ if (e.target === this.#dialog) this.hide();
117
+ });
118
+
119
+ // Native dialog close (esc key, etc.) syncs [open]
120
+ this.#dialog.addEventListener('close', () => {
121
+ if (this.#cmdEl) this.#cmdEl.open = false;
122
+ this.open = false;
123
+ });
124
+ }
125
+
126
+ #wireCommand() {
127
+ if (!this.#cmdEl) return;
128
+
129
+ this.#cmdEl.addEventListener('dismiss', () => this.hide());
130
+ this.#cmdEl.addEventListener('select', (e) => {
131
+ // Forward as command-select; let consumers decide what to do
132
+ this.dispatchEvent(new CustomEvent('command-select', {
133
+ bubbles: true,
134
+ detail: e.detail,
135
+ }));
136
+ this.hide();
137
+ });
138
+ }
139
+
140
+ #wireShortcut() {
141
+ const matches = (e) => {
142
+ const isMac = e.metaKey;
143
+ const isCtrl = e.ctrlKey;
144
+ if (e.key !== 'k') return false;
145
+ if (this.shortcut === 'cmd+k') return isMac;
146
+ if (this.shortcut === 'ctrl+k') return isCtrl;
147
+ // 'both' (default)
148
+ return isMac || isCtrl;
149
+ };
150
+
151
+ this.#keyHandler = (e) => {
152
+ if (!matches(e)) return;
153
+ e.preventDefault();
154
+ this.toggle();
155
+ };
156
+ document.addEventListener('keydown', this.#keyHandler);
157
+ }
158
+ }
159
+
160
+ customElements.define('admin-command', AdminCommand);
161
+ export { AdminCommand };
@@ -0,0 +1,115 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import '../../../web-components/core/element.js';
3
+ import './admin-command.js';
4
+
5
+ const tick = () => new Promise((r) => queueMicrotask(r));
6
+
7
+ function mount(html) {
8
+ const wrap = document.createElement('div');
9
+ wrap.innerHTML = html;
10
+ document.body.appendChild(wrap);
11
+ return wrap.firstElementChild;
12
+ }
13
+
14
+ // happy-dom's <dialog> support is partial — showModal/close need to be
15
+ // patched into noops that toggle the .open getter via a flag. The real
16
+ // browser does this natively.
17
+ function patchDialogPolyfill(dialog) {
18
+ let isOpen = false;
19
+ Object.defineProperty(dialog, 'open', {
20
+ get: () => isOpen,
21
+ set: (v) => { isOpen = !!v; },
22
+ configurable: true,
23
+ });
24
+ dialog.showModal = function () {
25
+ isOpen = true;
26
+ this.dispatchEvent(new Event('toggle'));
27
+ };
28
+ dialog.close = function () {
29
+ isOpen = false;
30
+ this.dispatchEvent(new Event('close'));
31
+ };
32
+ }
33
+
34
+ beforeEach(() => {
35
+ document.body.innerHTML = '';
36
+ });
37
+
38
+ describe('admin-command', () => {
39
+ it('registers admin-command as a custom element', () => {
40
+ expect(customElements.get('admin-command')).toBeDefined();
41
+ });
42
+
43
+ it('defaults to open=false, shortcut="both"', () => {
44
+ const cmd = mount('<admin-command></admin-command>');
45
+ expect(cmd.open).toBe(false);
46
+ expect(cmd.shortcut).toBe('both');
47
+ });
48
+
49
+ it('exposes .show() / .hide() / .toggle() public methods', () => {
50
+ const cmd = mount('<admin-command></admin-command>');
51
+ expect(typeof cmd.show).toBe('function');
52
+ expect(typeof cmd.hide).toBe('function');
53
+ expect(typeof cmd.toggle).toBe('function');
54
+ });
55
+
56
+ it('reflects [open] when .show() is called', async () => {
57
+ const cmd = mount('<admin-command></admin-command>');
58
+ const dialog = cmd.shadowRoot?.querySelector('dialog') ?? cmd.querySelector('dialog');
59
+ if (dialog) patchDialogPolyfill(dialog);
60
+ cmd.show();
61
+ await tick();
62
+ expect(cmd.open).toBe(true);
63
+ expect(cmd.hasAttribute('open')).toBe(true);
64
+ });
65
+
66
+ it('clears [open] when .hide() is called', async () => {
67
+ const cmd = mount('<admin-command></admin-command>');
68
+ const dialog = cmd.shadowRoot?.querySelector('dialog') ?? cmd.querySelector('dialog');
69
+ if (dialog) patchDialogPolyfill(dialog);
70
+ cmd.show();
71
+ await tick();
72
+ cmd.hide();
73
+ await tick();
74
+ expect(cmd.open).toBe(false);
75
+ expect(cmd.hasAttribute('open')).toBe(false);
76
+ });
77
+
78
+ it('toggle() flips open state and returns the new value', async () => {
79
+ const cmd = mount('<admin-command></admin-command>');
80
+ const dialog = cmd.shadowRoot?.querySelector('dialog') ?? cmd.querySelector('dialog');
81
+ if (dialog) patchDialogPolyfill(dialog);
82
+ const after1 = cmd.toggle();
83
+ await tick();
84
+ expect(after1).toBe(true);
85
+ const after2 = cmd.toggle();
86
+ await tick();
87
+ expect(after2).toBe(false);
88
+ });
89
+
90
+ it('removes Cmd+K listener on disconnect', () => {
91
+ const cmd = mount('<admin-command></admin-command>');
92
+ const removeSpy = vi.spyOn(document, 'removeEventListener');
93
+ cmd.remove();
94
+ const removedTypes = removeSpy.mock.calls.map((args) => args[0]);
95
+ expect(removedTypes).toContain('keydown');
96
+ });
97
+
98
+ it('honors [no-shortcut] — does not toggle on Cmd+K', async () => {
99
+ // Verify behavior, not listener registration (happy-dom timing makes
100
+ // spy-based tests unreliable for synchronous custom-element lifecycle).
101
+ const cmd = mount('<admin-command no-shortcut></admin-command>');
102
+ const dialog = cmd.querySelector(':scope > dialog');
103
+ if (dialog) patchDialogPolyfill(dialog);
104
+ const event = new KeyboardEvent('keydown', { key: 'k', metaKey: true });
105
+ document.dispatchEvent(event);
106
+ await tick();
107
+ expect(cmd.open).toBe(false);
108
+ cmd.remove();
109
+ });
110
+
111
+ it('accepts shortcut="cmd+k"', () => {
112
+ const cmd = mount('<admin-command shortcut="cmd+k"></admin-command>');
113
+ expect(cmd.shortcut).toBe('cmd+k');
114
+ });
115
+ });
@@ -0,0 +1,102 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: AdminCommand
4
+ tag: admin-command
5
+ component: AdminCommand
6
+ category: interaction
7
+ version: 1
8
+ description: |
9
+ Module-tier command palette wrapper — wraps a native <dialog> and the
10
+ inner <command-ui>. Owns the keyboard shortcut listener, focus
11
+ management, and dismiss handlers. Reflects [open].
12
+
13
+ Sits inside <admin-shell> as a direct child. The host wires
14
+ [data-command-trigger] elements to <admin-command>.show() via lookup.
15
+
16
+ This is the bespoke web-component replacement for the legacy
17
+ <dialog data-command> shape. <admin-shell> still recognizes the
18
+ legacy shape via :is() selector. New code should prefer <admin-command>.
19
+
20
+ props:
21
+ open:
22
+ description: |
23
+ Reflected — set while the dialog is showing. Synced with both
24
+ programmatic .show()/.hide() and native dialog close events
25
+ (esc key, backdrop click).
26
+ type: boolean
27
+ default: false
28
+ reflect: true
29
+
30
+ shortcut:
31
+ description: |
32
+ Keyboard shortcut binding. "cmd+k" responds only on Mac
33
+ (metaKey); "ctrl+k" responds only when ctrlKey; "both" (default)
34
+ responds to either, which is the canonical AdiaUI behavior for
35
+ cross-platform Cmd+K affordance.
36
+ type: string
37
+ default: both
38
+ enum:
39
+ - both
40
+ - cmd+k
41
+ - ctrl+k
42
+ reflect: true
43
+
44
+ no-shortcut:
45
+ description: |
46
+ Opts out of the keyboard listener entirely. Use when the host
47
+ wires its own shortcut handling, or when the palette should be
48
+ mouse-only.
49
+ type: boolean
50
+ default: false
51
+ reflect: true
52
+
53
+ events:
54
+ command-select:
55
+ description: Forwarded from the inner <command-ui> when an option
56
+ is chosen. Detail mirrors the inner event's detail.
57
+ detail:
58
+ value: string
59
+
60
+ slots:
61
+ default:
62
+ description: >-
63
+ Default slot — the inner <command-ui> (and any other content
64
+ inside the dialog). Authors typically place exactly one
65
+ <command-ui placeholder="…">.
66
+
67
+ states:
68
+ - name: idle
69
+ description: Default, palette closed.
70
+ - name: open
71
+ attribute: open
72
+ description: Dialog is showing; first input has focus.
73
+
74
+ traits: []
75
+
76
+ a2ui:
77
+ rules:
78
+ - >-
79
+ admin-command wraps a native <dialog>; the inner <command-ui>
80
+ is the actual palette. Keyboard shortcut defaults to both
81
+ Cmd+K (mac) and Ctrl+K (other) — the AdiaUI convention.
82
+ - >-
83
+ Place admin-command as a direct child of admin-shell, NOT inside
84
+ a sidebar or main column. The host coordinates triggers
85
+ ([data-command-trigger]) by reaching across siblings.
86
+
87
+ keywords:
88
+ - admin-command
89
+ - command-palette
90
+ - palette
91
+ - cmd-k
92
+ - keyboard-shortcut
93
+ - quickaction
94
+
95
+ synonyms:
96
+ command-palette: [palette, quick-action, omnibox]
97
+ cmd-k: [ctrl-k, command-shortcut]
98
+
99
+ related:
100
+ - AdminShell
101
+ - AdminSidebar
102
+ - Command
@@ -0,0 +1,73 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/AdminContent.json",
4
+ "title": "AdminContent",
5
+ "description": "Module-tier shell main-column container. CSS-only — no behavior, no\nJS. Sits inside <admin-shell> as the center column between leading\nand trailing sidebars. Authors compose chrome bars + scroll surface\nvia slot vocabulary.\n\nThis is the bespoke replacement for the legacy raw <main> element\ninside admin-shell. Both shapes still render correctly per ADR-0023\nPhase 1 backwards-compat; new code should prefer <admin-content>.\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": "AdminContent"
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
+ "admin-content",
31
+ "main",
32
+ "center-column",
33
+ "workspace"
34
+ ],
35
+ "name": "AdminContent",
36
+ "related": [
37
+ "AdminShell",
38
+ "AdminSidebar",
39
+ "AdminTopbar",
40
+ "AdminStatusbar",
41
+ "AdminScroll",
42
+ "AdminPage"
43
+ ],
44
+ "slots": {
45
+ "default": {
46
+ "description": "Default content — typically <admin-topbar slot=\"header\">, an <admin-scroll> wrapping content, and an optional <admin-statusbar slot=\"footer\">."
47
+ },
48
+ "footer": {
49
+ "description": "Bottom chrome bar — typically <admin-statusbar>."
50
+ },
51
+ "header": {
52
+ "description": "Top chrome bar — typically <admin-topbar>."
53
+ }
54
+ },
55
+ "states": [
56
+ {
57
+ "description": "Default, the only state.",
58
+ "name": "idle"
59
+ }
60
+ ],
61
+ "synonyms": {
62
+ "main": [
63
+ "content",
64
+ "center",
65
+ "workspace"
66
+ ]
67
+ },
68
+ "tag": "admin-content",
69
+ "tokens": {},
70
+ "traits": [],
71
+ "version": 1
72
+ }
73
+ }
@@ -0,0 +1,33 @@
1
+ <header>
2
+ <div>
3
+ <h1>Admin Content</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">admin-content</tag-ui>
6
+ <tag-ui size="sm" variant="ghost">CSS-only</tag-ui>
7
+ </div>
8
+ </div>
9
+ <p>Module-tier shell main-column container. CSS-only. Sits inside <admin-shell> as the center column between leading and trailing sidebars.</p>
10
+ </header>
11
+
12
+ <section data-section>
13
+ <h2 variant="section">Role</h2>
14
+ <p>This is a CSS-only structural stub — no JavaScript, no behavior. The shell host (<code>&lt;admin-shell&gt;</code>) styles it via tag-presence. Authors compose it with sibling bespoke children to express semantic shell-tier structure.</p>
15
+ </section>
16
+
17
+ <section data-section>
18
+ <h2 variant="section">Composition</h2>
19
+ <p>Typical placement inside <code>&lt;admin-shell&gt;</code>:</p>
20
+ <code-ui language="html">&lt;admin-shell&gt;
21
+ &lt;admin-sidebar slot="leading"&gt;…&lt;/admin-sidebar&gt;
22
+ &lt;admin-content&gt;
23
+ &lt;admin-topbar slot="header"&gt;…&lt;/admin-topbar&gt;
24
+ &lt;admin-scroll&gt;…&lt;/admin-scroll&gt;
25
+ &lt;admin-statusbar slot="footer"&gt;…&lt;/admin-statusbar&gt;
26
+ &lt;/admin-content&gt;
27
+ &lt;/admin-shell&gt;</code-ui>
28
+ </section>
29
+
30
+ <section data-section>
31
+ <h2 variant="section">Slot vocabulary</h2>
32
+ <p>See the <a href="../admin-shell/admin-shell.html"><code>admin-shell</code></a> demo for the full composition pattern. CSS-only stubs declare slot intent; the parent shell handles layout.</p>
33
+ </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>Admin Content — 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="../admin-shell/admin-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="../admin-shell/admin-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('./admin-content.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 admin-content.examples.html — ${err.message}</p>`;
37
+ console.error('[admin-content.html]', err);
38
+ }
39
+ </script>
40
+
41
+ </body>
42
+ </html>
@@ -0,0 +1,63 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
3
+ name: AdminContent
4
+ tag: admin-content
5
+ component: AdminContent
6
+ category: layout
7
+ version: 1
8
+ description: |
9
+ Module-tier shell main-column container. CSS-only — no behavior, no
10
+ JS. Sits inside <admin-shell> as the center column between leading
11
+ and trailing sidebars. Authors compose chrome bars + scroll surface
12
+ via slot vocabulary.
13
+
14
+ This is the bespoke replacement for the legacy raw <main> element
15
+ inside admin-shell. Both shapes still render correctly per ADR-0023
16
+ Phase 1 backwards-compat; new code should prefer <admin-content>.
17
+
18
+ props: {}
19
+
20
+ events: {}
21
+
22
+ slots:
23
+ default:
24
+ description: >-
25
+ Default content — typically <admin-topbar slot="header">, an
26
+ <admin-scroll> wrapping content, and an optional
27
+ <admin-statusbar slot="footer">.
28
+ header:
29
+ description: >-
30
+ Top chrome bar — typically <admin-topbar>.
31
+ footer:
32
+ description: >-
33
+ Bottom chrome bar — typically <admin-statusbar>.
34
+
35
+ states:
36
+ - name: idle
37
+ description: Default, the only state.
38
+
39
+ traits: []
40
+
41
+ a2ui:
42
+ rules:
43
+ - >-
44
+ admin-content is the bespoke replacement for raw <main> inside
45
+ admin-shell. CSS-only; the shell's css/main.css selectors target
46
+ both shapes via :is(main, admin-content).
47
+
48
+ keywords:
49
+ - admin-content
50
+ - main
51
+ - center-column
52
+ - workspace
53
+
54
+ synonyms:
55
+ main: [content, center, workspace]
56
+
57
+ related:
58
+ - AdminShell
59
+ - AdminSidebar
60
+ - AdminTopbar
61
+ - AdminStatusbar
62
+ - AdminScroll
63
+ - AdminPage
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/AdminPage.json",
4
+ "title": "AdminPage",
5
+ "description": "Module-tier page wrapper. CSS-only — no behavior, no JS. Provides\nthe page-content-root container query (named `page-content`) so\ndescendants can adapt to available content width (sidebars expanded\nvs collapsed) instead of viewport width. Stamps the sticky-band\nlayout: <admin-page-header> + <admin-page-body> + optional footer.\n\nReplaces the legacy <article data-content-root> shape 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": "AdminPage"
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
+ "admin-page",
31
+ "page-content",
32
+ "container-query-host"
33
+ ],
34
+ "name": "AdminPage",
35
+ "related": [
36
+ "AdminShell",
37
+ "AdminContent",
38
+ "AdminScroll",
39
+ "AdminPageHeader",
40
+ "AdminPageBody"
41
+ ],
42
+ "slots": {
43
+ "default": {
44
+ "description": "Default — typically <admin-page-header> + <admin-page-body>."
45
+ },
46
+ "body": {
47
+ "description": "Centered reading column (alternate slot for the body band)."
48
+ },
49
+ "footer": {
50
+ "description": "Sticky bottom band."
51
+ },
52
+ "header": {
53
+ "description": "Sticky top band (alternate slot for the header band)."
54
+ }
55
+ },
56
+ "states": [
57
+ {
58
+ "description": "Default, the only state.",
59
+ "name": "idle"
60
+ }
61
+ ],
62
+ "synonyms": {
63
+ "page-content": [
64
+ "content-area",
65
+ "content-root",
66
+ "document-region"
67
+ ]
68
+ },
69
+ "tag": "admin-page",
70
+ "tokens": {},
71
+ "traits": [],
72
+ "version": 1
73
+ }
74
+ }