@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.
- package/CHANGELOG.md +60 -0
- package/chat/chat-composer/chat-composer.a2ui.json +94 -0
- package/chat/chat-composer/chat-composer.examples.html +28 -0
- package/chat/chat-composer/chat-composer.html +43 -0
- package/chat/chat-composer/chat-composer.js +107 -0
- package/chat/chat-composer/chat-composer.test.js +112 -0
- package/chat/chat-composer/chat-composer.yaml +91 -0
- package/chat/chat-empty/chat-empty.a2ui.json +68 -0
- package/chat/chat-empty/chat-empty.examples.html +34 -0
- package/chat/chat-empty/chat-empty.html +42 -0
- package/chat/chat-empty/chat-empty.yaml +58 -0
- package/chat/chat-header/chat-header.a2ui.json +77 -0
- package/chat/chat-header/chat-header.examples.html +30 -0
- package/chat/chat-header/chat-header.html +42 -0
- package/chat/chat-header/chat-header.yaml +68 -0
- package/chat/chat-shell/chat-shell.css +1 -0
- package/chat/chat-shell/chat-shell.examples.html +126 -0
- package/chat/chat-shell/chat-shell.html +42 -0
- package/chat/chat-shell/chat-shell.js +35 -7
- package/chat/chat-shell/css/chat-shell.bespoke.css +196 -0
- package/chat/chat-sidebar/chat-sidebar.a2ui.json +136 -0
- package/chat/chat-sidebar/chat-sidebar.examples.html +36 -0
- package/chat/chat-sidebar/chat-sidebar.html +43 -0
- package/chat/chat-sidebar/chat-sidebar.js +227 -0
- package/chat/chat-sidebar/chat-sidebar.test.js +110 -0
- package/chat/chat-sidebar/chat-sidebar.yaml +140 -0
- package/chat/chat-status/chat-status.a2ui.json +63 -0
- package/chat/chat-status/chat-status.examples.html +29 -0
- package/chat/chat-status/chat-status.html +42 -0
- package/chat/chat-status/chat-status.yaml +52 -0
- package/chat/chat-thread/chat-thread.a2ui.json +91 -0
- package/chat/chat-thread/chat-thread.examples.html +36 -0
- package/chat/chat-thread/chat-thread.html +43 -0
- package/chat/chat-thread/chat-thread.js +106 -0
- package/chat/chat-thread/chat-thread.test.js +82 -0
- package/chat/chat-thread/chat-thread.yaml +89 -0
- package/chat/index.js +3 -0
- package/editor/editor-shell/editor-shell.examples.html +71 -0
- package/editor/editor-shell/editor-shell.html +42 -0
- package/package.json +1 -1
- package/shell/admin-command/admin-command.a2ui.json +102 -0
- package/shell/admin-command/admin-command.examples.html +83 -0
- package/shell/admin-command/admin-command.html +42 -0
- package/shell/admin-command/admin-command.js +161 -0
- package/shell/admin-command/admin-command.test.js +115 -0
- package/shell/admin-command/admin-command.yaml +102 -0
- package/shell/admin-content/admin-content.a2ui.json +73 -0
- package/shell/admin-content/admin-content.examples.html +33 -0
- package/shell/admin-content/admin-content.html +42 -0
- package/shell/admin-content/admin-content.yaml +63 -0
- package/shell/admin-page/admin-page.a2ui.json +74 -0
- package/shell/admin-page/admin-page.examples.html +37 -0
- package/shell/admin-page/admin-page.html +42 -0
- package/shell/admin-page/admin-page.yaml +61 -0
- package/shell/admin-page-body/admin-page-body.a2ui.json +62 -0
- package/shell/admin-page-body/admin-page-body.examples.html +34 -0
- package/shell/admin-page-body/admin-page-body.html +42 -0
- package/shell/admin-page-body/admin-page-body.yaml +49 -0
- package/shell/admin-page-header/admin-page-header.a2ui.json +62 -0
- package/shell/admin-page-header/admin-page-header.examples.html +34 -0
- package/shell/admin-page-header/admin-page-header.html +42 -0
- package/shell/admin-page-header/admin-page-header.yaml +47 -0
- package/shell/admin-scroll/admin-scroll.a2ui.json +62 -0
- package/shell/admin-scroll/admin-scroll.examples.html +31 -0
- package/shell/admin-scroll/admin-scroll.html +42 -0
- package/shell/admin-scroll/admin-scroll.yaml +51 -0
- package/shell/admin-shell/admin-shell.a2ui.json +0 -10
- package/shell/admin-shell/admin-shell.css +1 -0
- package/shell/admin-shell/admin-shell.examples.html +61 -5
- package/shell/admin-shell/admin-shell.js +165 -121
- package/shell/admin-shell/admin-shell.yaml +6 -6
- package/shell/admin-shell/css/admin-shell.bespoke.css +198 -0
- package/shell/admin-shell/css/admin-shell.tokens.css +10 -0
- package/shell/admin-sidebar/admin-sidebar.a2ui.json +138 -0
- package/shell/admin-sidebar/admin-sidebar.examples.html +76 -0
- package/shell/admin-sidebar/admin-sidebar.html +47 -0
- package/shell/admin-sidebar/admin-sidebar.js +227 -0
- package/shell/admin-sidebar/admin-sidebar.test.js +123 -0
- package/shell/admin-sidebar/admin-sidebar.yaml +140 -0
- package/shell/admin-statusbar/admin-statusbar.a2ui.json +81 -0
- package/shell/admin-statusbar/admin-statusbar.examples.html +29 -0
- package/shell/admin-statusbar/admin-statusbar.html +42 -0
- package/shell/admin-statusbar/admin-statusbar.yaml +68 -0
- package/shell/admin-topbar/admin-topbar.a2ui.json +83 -0
- package/shell/admin-topbar/admin-topbar.examples.html +31 -0
- package/shell/admin-topbar/admin-topbar.html +42 -0
- package/shell/admin-topbar/admin-topbar.yaml +75 -0
- package/shell/index.js +2 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import '../../../web-components/core/element.js';
|
|
3
|
+
import './chat-sidebar.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
|
+
let originalRect;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
document.body.innerHTML = '';
|
|
17
|
+
try { localStorage.clear(); } catch {}
|
|
18
|
+
globalThis.ResizeObserver = class {
|
|
19
|
+
observe() {} unobserve() {} disconnect() {}
|
|
20
|
+
};
|
|
21
|
+
originalRect = HTMLElement.prototype.getBoundingClientRect;
|
|
22
|
+
HTMLElement.prototype.getBoundingClientRect = function () {
|
|
23
|
+
const inline = this.style?.width || '';
|
|
24
|
+
const w = parseFloat(inline) || 240;
|
|
25
|
+
return { width: w, height: 600, top: 0, left: 0, right: w, bottom: 600, x: 0, y: 0 };
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
if (originalRect) HTMLElement.prototype.getBoundingClientRect = originalRect;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('chat-sidebar', () => {
|
|
34
|
+
it('registers chat-sidebar as a custom element', () => {
|
|
35
|
+
expect(customElements.get('chat-sidebar')).toBeDefined();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('defaults to collapsed=false on connect', () => {
|
|
39
|
+
const sb = mount('<chat-sidebar slot="leading"></chat-sidebar>');
|
|
40
|
+
expect(sb.collapsed).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('reflects [collapsed] via property assignment', async () => {
|
|
44
|
+
const sb = mount('<chat-sidebar slot="leading"></chat-sidebar>');
|
|
45
|
+
sb.collapsed = true;
|
|
46
|
+
await tick();
|
|
47
|
+
expect(sb.hasAttribute('collapsed')).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('reflects [resizing] via property assignment', async () => {
|
|
51
|
+
const sb = mount('<chat-sidebar slot="leading"></chat-sidebar>');
|
|
52
|
+
sb.resizing = true;
|
|
53
|
+
await tick();
|
|
54
|
+
expect(sb.hasAttribute('resizing')).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('exposes .toggle() / .collapse() / .expand() public methods', () => {
|
|
58
|
+
const sb = mount('<chat-sidebar slot="leading" collapsible></chat-sidebar>');
|
|
59
|
+
expect(typeof sb.toggle).toBe('function');
|
|
60
|
+
expect(typeof sb.collapse).toBe('function');
|
|
61
|
+
expect(typeof sb.expand).toBe('function');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('persists width to chat-namespaced localStorage key (not collide with admin)', async () => {
|
|
65
|
+
const sb = mount('<chat-sidebar slot="leading" collapsible></chat-sidebar>');
|
|
66
|
+
sb.style.width = '240px';
|
|
67
|
+
sb.collapse();
|
|
68
|
+
expect(sb.collapsed).toBe(true);
|
|
69
|
+
// localStorage key should be chat-namespaced
|
|
70
|
+
expect(localStorage.getItem('adia-chat-sidebar-leading')).not.toBeNull();
|
|
71
|
+
// Should NOT have written to the admin namespace
|
|
72
|
+
expect(localStorage.getItem('adia-sidebar-leading')).toBeNull();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('uses [name] override for the localStorage key', () => {
|
|
76
|
+
const sb = mount('<chat-sidebar slot="leading" name="conversations" collapsible></chat-sidebar>');
|
|
77
|
+
sb.style.width = '200px';
|
|
78
|
+
sb.collapse();
|
|
79
|
+
expect(localStorage.getItem('adia-chat-sidebar-conversations')).not.toBeNull();
|
|
80
|
+
expect(localStorage.getItem('adia-chat-sidebar-leading')).toBeNull();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('toggle() returns the new collapsed value', () => {
|
|
84
|
+
const sb = mount('<chat-sidebar slot="leading" collapsible></chat-sidebar>');
|
|
85
|
+
sb.style.width = '200px';
|
|
86
|
+
const result = sb.toggle();
|
|
87
|
+
expect(result).toBe(sb.collapsed);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('dispatches sidebar-toggle event on toggle()', () => {
|
|
91
|
+
const sb = mount('<chat-sidebar slot="leading" collapsible></chat-sidebar>');
|
|
92
|
+
sb.style.width = '200px';
|
|
93
|
+
const onToggle = vi.fn();
|
|
94
|
+
sb.addEventListener('sidebar-toggle', onToggle);
|
|
95
|
+
sb.toggle();
|
|
96
|
+
expect(onToggle).toHaveBeenCalledTimes(1);
|
|
97
|
+
expect(onToggle.mock.calls[0][0].detail).toEqual(
|
|
98
|
+
expect.objectContaining({ name: expect.any(String), expanded: expect.any(Boolean) })
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('cleans up resize handlers on disconnect', () => {
|
|
103
|
+
const sb = mount('<chat-sidebar slot="leading" resizable><div data-resize></div></chat-sidebar>');
|
|
104
|
+
const handle = sb.querySelector('[data-resize]');
|
|
105
|
+
const removeSpy = vi.spyOn(handle, 'removeEventListener');
|
|
106
|
+
sb.remove();
|
|
107
|
+
const removedTypes = removeSpy.mock.calls.map((args) => args[0]);
|
|
108
|
+
expect(removedTypes).toContain('pointerdown');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Edit this file; run `npm run build:components` to regenerate a2ui.json.
|
|
2
|
+
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
3
|
+
name: ChatSidebar
|
|
4
|
+
tag: chat-sidebar
|
|
5
|
+
component: ChatSidebar
|
|
6
|
+
category: layout
|
|
7
|
+
version: 1
|
|
8
|
+
description: |
|
|
9
|
+
Module-tier chat-cluster sidebar — owns resize, snap-to-collapsed,
|
|
10
|
+
persistence, and the [collapsed] reflected attribute. Sits inside
|
|
11
|
+
<chat-shell> as slot="leading" (conversation history rail) or
|
|
12
|
+
slot="trailing" (artifacts/citations panel). Mirrors the admin-sidebar
|
|
13
|
+
shape — same 4 concerns, cluster-namespaced for the chat family.
|
|
14
|
+
|
|
15
|
+
This is the chat-cluster equivalent of <admin-sidebar> per ADR-0023.
|
|
16
|
+
<chat-shell> doesn't currently have a legacy sidebar shape (chat is
|
|
17
|
+
typically a single-pane experience), so <chat-sidebar> is purely
|
|
18
|
+
forward-looking — for chat apps that want conversation-history or
|
|
19
|
+
inspector rails.
|
|
20
|
+
|
|
21
|
+
props:
|
|
22
|
+
collapsed:
|
|
23
|
+
description: |
|
|
24
|
+
Reflected — set when the sidebar's measured width is at or below
|
|
25
|
+
96px. Consumers query this to style "collapsed mode" without
|
|
26
|
+
duplicating threshold math.
|
|
27
|
+
type: boolean
|
|
28
|
+
default: false
|
|
29
|
+
reflect: true
|
|
30
|
+
|
|
31
|
+
resizing:
|
|
32
|
+
description: |
|
|
33
|
+
Reflected — set during an active pointer-drag on the resize handle.
|
|
34
|
+
Useful for suppressing transitions while dragging.
|
|
35
|
+
type: boolean
|
|
36
|
+
default: false
|
|
37
|
+
reflect: true
|
|
38
|
+
|
|
39
|
+
resizable:
|
|
40
|
+
description: |
|
|
41
|
+
Opts in to drag-to-resize behavior. Author supplies a child
|
|
42
|
+
[data-resize] element as the drag handle.
|
|
43
|
+
type: boolean
|
|
44
|
+
default: false
|
|
45
|
+
reflect: true
|
|
46
|
+
|
|
47
|
+
collapsible:
|
|
48
|
+
description: |
|
|
49
|
+
Opts in to programmatic collapse — toggle button wiring + the
|
|
50
|
+
.toggle() / .collapse() / .expand() public methods.
|
|
51
|
+
type: boolean
|
|
52
|
+
default: false
|
|
53
|
+
reflect: true
|
|
54
|
+
|
|
55
|
+
name:
|
|
56
|
+
description: |
|
|
57
|
+
Identifier for localStorage namespacing. Defaults to slot value
|
|
58
|
+
("leading" or "trailing"). Override when running multiple sidebars
|
|
59
|
+
with the same slot.
|
|
60
|
+
type: string
|
|
61
|
+
default: ""
|
|
62
|
+
reflect: true
|
|
63
|
+
|
|
64
|
+
min-width:
|
|
65
|
+
description: |
|
|
66
|
+
Optional override for the snap-floor width. Defaults to reading
|
|
67
|
+
CSS min-width via getComputedStyle.
|
|
68
|
+
type: string
|
|
69
|
+
default: ""
|
|
70
|
+
reflect: true
|
|
71
|
+
|
|
72
|
+
events:
|
|
73
|
+
sidebar-toggle:
|
|
74
|
+
description: Bubbles when sidebar collapses or expands.
|
|
75
|
+
detail:
|
|
76
|
+
name: string
|
|
77
|
+
expanded: boolean
|
|
78
|
+
sidebar-resize:
|
|
79
|
+
description: Bubbles when an active pointer-drag releases.
|
|
80
|
+
detail:
|
|
81
|
+
name: string
|
|
82
|
+
width: number
|
|
83
|
+
|
|
84
|
+
slots:
|
|
85
|
+
default:
|
|
86
|
+
description: >-
|
|
87
|
+
Default content — typically a <nav-ui> for navigation, or a list
|
|
88
|
+
/ tree for the trailing inspector pattern.
|
|
89
|
+
header:
|
|
90
|
+
description: >-
|
|
91
|
+
Top chrome bar (workspace select, breadcrumb, etc.).
|
|
92
|
+
footer:
|
|
93
|
+
description: >-
|
|
94
|
+
Bottom chrome bar (user select, status indicator, etc.).
|
|
95
|
+
|
|
96
|
+
states:
|
|
97
|
+
- name: idle
|
|
98
|
+
description: Default, expanded.
|
|
99
|
+
- name: collapsed
|
|
100
|
+
attribute: collapsed
|
|
101
|
+
description: Sidebar width is at or below the snap threshold; CSS
|
|
102
|
+
container queries flip child layout to icon-only mode.
|
|
103
|
+
- name: resizing
|
|
104
|
+
attribute: resizing
|
|
105
|
+
description: Active pointer-drag in progress.
|
|
106
|
+
|
|
107
|
+
traits: []
|
|
108
|
+
|
|
109
|
+
a2ui:
|
|
110
|
+
rules:
|
|
111
|
+
- >-
|
|
112
|
+
chat-sidebar is the bespoke replacement for legacy
|
|
113
|
+
<aside data-sidebar>. Use slot="leading" or slot="trailing"
|
|
114
|
+
to position. Add resizable + collapsible attributes to opt in
|
|
115
|
+
to interactive behaviors.
|
|
116
|
+
- >-
|
|
117
|
+
For chrome bars inside the sidebar, prefer <admin-topbar
|
|
118
|
+
slot="header"> and <admin-statusbar slot="footer"> over raw
|
|
119
|
+
<header-ui> / <footer-ui> when authoring shell-tier markup.
|
|
120
|
+
|
|
121
|
+
keywords:
|
|
122
|
+
- chat-sidebar
|
|
123
|
+
- chat-sidebar
|
|
124
|
+
- conversation-history
|
|
125
|
+
- chat-rail
|
|
126
|
+
- sidebar
|
|
127
|
+
- leading
|
|
128
|
+
- trailing
|
|
129
|
+
- inspector
|
|
130
|
+
|
|
131
|
+
synonyms:
|
|
132
|
+
sidebar: [aside, rail, panel]
|
|
133
|
+
collapsed: [minimized, narrow, icon-only]
|
|
134
|
+
|
|
135
|
+
related:
|
|
136
|
+
- ChatShell
|
|
137
|
+
- ChatComposer
|
|
138
|
+
- ChatHeader
|
|
139
|
+
- List
|
|
140
|
+
- Nav
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://adiaui.dev/a2ui/v0_9/components/ChatStatus.json",
|
|
4
|
+
"title": "ChatStatus",
|
|
5
|
+
"description": "Module-tier chat status indicator. CSS-only — no behavior, no JS.\nConveys connection / streaming state via inline content. Typically\nslotted into <chat-header slot=\"status\"> or used inline.\n\nReplaces the legacy <span data-chat-status> 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": "ChatStatus"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"required": [
|
|
21
|
+
"component"
|
|
22
|
+
],
|
|
23
|
+
"unevaluatedProperties": false,
|
|
24
|
+
"x-adiaui": {
|
|
25
|
+
"anti_patterns": [],
|
|
26
|
+
"category": "feedback",
|
|
27
|
+
"events": {},
|
|
28
|
+
"examples": [],
|
|
29
|
+
"keywords": [
|
|
30
|
+
"chat-status",
|
|
31
|
+
"status-indicator",
|
|
32
|
+
"connection-status",
|
|
33
|
+
"streaming-indicator"
|
|
34
|
+
],
|
|
35
|
+
"name": "ChatStatus",
|
|
36
|
+
"related": [
|
|
37
|
+
"ChatShell",
|
|
38
|
+
"ChatHeader",
|
|
39
|
+
"ChatThread"
|
|
40
|
+
],
|
|
41
|
+
"slots": {
|
|
42
|
+
"default": {
|
|
43
|
+
"description": "Status content — text, icon, dot indicator, etc. Authors set content directly; the host (chat-shell) updates innerText during streaming via legacy [data-chat-status] selector OR via querySelector('chat-status') for the bespoke shape."
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"states": [
|
|
47
|
+
{
|
|
48
|
+
"description": "Default, the only state.",
|
|
49
|
+
"name": "idle"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"synonyms": {
|
|
53
|
+
"chat-status": [
|
|
54
|
+
"connection-indicator",
|
|
55
|
+
"streaming-status"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"tag": "chat-status",
|
|
59
|
+
"tokens": {},
|
|
60
|
+
"traits": [],
|
|
61
|
+
"version": 1
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<header>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>Chat Status</h1>
|
|
4
|
+
<div data-actions>
|
|
5
|
+
<tag-ui size="sm">chat-status</tag-ui>
|
|
6
|
+
<tag-ui size="sm" variant="ghost">CSS-only</tag-ui>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
<p>Module-tier chat status indicator. CSS-only. Inline content for connection/streaming state.</p>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<section data-section>
|
|
13
|
+
<h2 variant="section">Role</h2>
|
|
14
|
+
<p>Inline status indicator. Pure CSS-only stub. Authors set content directly; the host's streaming pipeline updates innerText.</p>
|
|
15
|
+
</section>
|
|
16
|
+
|
|
17
|
+
<section data-section>
|
|
18
|
+
<h2 variant="section">Composition</h2>
|
|
19
|
+
<p>Typical placement inside <code><chat-shell></code>:</p>
|
|
20
|
+
<code-ui language="html"><chat-status>
|
|
21
|
+
<icon-ui name="circle-fill" style="color: var(--a-success)"></icon-ui>
|
|
22
|
+
<span>Connected</span>
|
|
23
|
+
</chat-status></code-ui>
|
|
24
|
+
</section>
|
|
25
|
+
|
|
26
|
+
<section data-section>
|
|
27
|
+
<h2 variant="section">Family</h2>
|
|
28
|
+
<p>Per <a href="../../../../.brain/adrs/0023-bespoke-shell-tier-children.md">ADR-0023</a>, the chat cluster's bespoke family — <code><chat-shell></code> (host), <code><chat-thread></code>, <code><chat-composer></code>, <code><chat-sidebar></code> (JS-bearing) + <code><chat-header></code>, <code><chat-status></code>, <code><chat-empty></code> (CSS-only). Mirrors the admin cluster's pattern.</p>
|
|
29
|
+
</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>Chat Status — 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="../chat-shell/chat-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="../chat-shell/chat-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('./chat-status.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 chat-status.examples.html — ${err.message}</p>`;
|
|
37
|
+
console.error('[chat-status.html]', err);
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Edit this file; run `npm run build:components` to regenerate a2ui.json.
|
|
2
|
+
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
3
|
+
name: ChatStatus
|
|
4
|
+
tag: chat-status
|
|
5
|
+
component: ChatStatus
|
|
6
|
+
category: feedback
|
|
7
|
+
version: 1
|
|
8
|
+
description: |
|
|
9
|
+
Module-tier chat status indicator. CSS-only — no behavior, no JS.
|
|
10
|
+
Conveys connection / streaming state via inline content. Typically
|
|
11
|
+
slotted into <chat-header slot="status"> or used inline.
|
|
12
|
+
|
|
13
|
+
Replaces the legacy <span data-chat-status> shape per ADR-0023.
|
|
14
|
+
|
|
15
|
+
props: {}
|
|
16
|
+
|
|
17
|
+
events: {}
|
|
18
|
+
|
|
19
|
+
slots:
|
|
20
|
+
default:
|
|
21
|
+
description: >-
|
|
22
|
+
Status content — text, icon, dot indicator, etc. Authors set
|
|
23
|
+
content directly; the host (chat-shell) updates innerText
|
|
24
|
+
during streaming via legacy [data-chat-status] selector OR
|
|
25
|
+
via querySelector('chat-status') for the bespoke shape.
|
|
26
|
+
|
|
27
|
+
states:
|
|
28
|
+
- name: idle
|
|
29
|
+
description: Default, the only state.
|
|
30
|
+
|
|
31
|
+
traits: []
|
|
32
|
+
|
|
33
|
+
a2ui:
|
|
34
|
+
rules:
|
|
35
|
+
- >-
|
|
36
|
+
chat-status replaces legacy <span data-chat-status> for the
|
|
37
|
+
streaming/connection indicator. Place inside <chat-header
|
|
38
|
+
slot="status">.
|
|
39
|
+
|
|
40
|
+
keywords:
|
|
41
|
+
- chat-status
|
|
42
|
+
- status-indicator
|
|
43
|
+
- connection-status
|
|
44
|
+
- streaming-indicator
|
|
45
|
+
|
|
46
|
+
synonyms:
|
|
47
|
+
chat-status: [connection-indicator, streaming-status]
|
|
48
|
+
|
|
49
|
+
related:
|
|
50
|
+
- ChatShell
|
|
51
|
+
- ChatHeader
|
|
52
|
+
- ChatThread
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://adiaui.dev/a2ui/v0_9/components/ChatThread.json",
|
|
4
|
+
"title": "ChatThread",
|
|
5
|
+
"description": "Module-tier chat message thread container — replaces legacy\n<section data-chat-messages> per ADR-0023. Owns scroll-to-bottom\non new message (with user-scroll-up suspension), [streaming] and\n[empty] reflected attributes, and a stable target for the host's\nmessage rendering pipeline.\n\nSits inside <chat-shell> as the central scroll surface. Authors\ncompose <chat-empty> as an optional first child for the empty\nstate; message children are appended dynamically by the host.\n\nBackwards compat — <chat-shell> still recognizes the legacy\n<section data-chat-messages> shape via :is() selector. New code\nshould prefer <chat-thread>.\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": "ChatThread"
|
|
18
|
+
},
|
|
19
|
+
"empty": {
|
|
20
|
+
"description": "Reflected — set when zero message children. Drives the\n<chat-empty> visibility via CSS — no JS toggling needed.\n",
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"default": true
|
|
23
|
+
},
|
|
24
|
+
"streaming": {
|
|
25
|
+
"description": "Reflected — set by the host while an LLM response is streaming.\nConsumers can style streaming-mode (e.g. cursor blink) via\n:has(chat-thread[streaming]) or attribute selectors.\n",
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"default": false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"required": [
|
|
31
|
+
"component"
|
|
32
|
+
],
|
|
33
|
+
"unevaluatedProperties": false,
|
|
34
|
+
"x-adiaui": {
|
|
35
|
+
"anti_patterns": [],
|
|
36
|
+
"category": "container",
|
|
37
|
+
"events": {},
|
|
38
|
+
"examples": [],
|
|
39
|
+
"keywords": [
|
|
40
|
+
"chat-thread",
|
|
41
|
+
"message-list",
|
|
42
|
+
"conversation",
|
|
43
|
+
"thread",
|
|
44
|
+
"scroll-surface"
|
|
45
|
+
],
|
|
46
|
+
"name": "ChatThread",
|
|
47
|
+
"related": [
|
|
48
|
+
"ChatShell",
|
|
49
|
+
"ChatEmpty",
|
|
50
|
+
"ChatComposer",
|
|
51
|
+
"ChatSidebar"
|
|
52
|
+
],
|
|
53
|
+
"slots": {
|
|
54
|
+
"default": {
|
|
55
|
+
"description": "Default — message children (typically appended dynamically by <chat-shell>'s rendering pipeline) plus an optional first <chat-empty> sibling for the empty state."
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"states": [
|
|
59
|
+
{
|
|
60
|
+
"description": "Default, no streaming.",
|
|
61
|
+
"name": "idle"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"description": "Host is actively streaming an LLM response.",
|
|
65
|
+
"attribute": "streaming",
|
|
66
|
+
"name": "streaming"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"description": "Zero message children — empty state visible.",
|
|
70
|
+
"attribute": "empty",
|
|
71
|
+
"name": "empty"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"synonyms": {
|
|
75
|
+
"message-list": [
|
|
76
|
+
"messages",
|
|
77
|
+
"message-stream"
|
|
78
|
+
],
|
|
79
|
+
"thread": [
|
|
80
|
+
"conversation",
|
|
81
|
+
"dialogue",
|
|
82
|
+
"chat-log",
|
|
83
|
+
"transcript"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"tag": "chat-thread",
|
|
87
|
+
"tokens": {},
|
|
88
|
+
"traits": [],
|
|
89
|
+
"version": 1
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<header>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>Chat Thread</h1>
|
|
4
|
+
<div data-actions>
|
|
5
|
+
<tag-ui size="sm">chat-thread</tag-ui>
|
|
6
|
+
<tag-ui size="sm" variant="ghost">JS-bearing</tag-ui>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
<p>Module-tier chat message thread container — owns scroll-to-bottom, [streaming] and [empty] reflected attributes.</p>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<section data-section>
|
|
13
|
+
<h2 variant="section">Role</h2>
|
|
14
|
+
<p>Owns scroll-to-bottom on new message (with user-scroll-up suspension), [streaming] and [empty] reflected attributes, and a stable target for the host's message rendering pipeline. JS-bearing.</p>
|
|
15
|
+
</section>
|
|
16
|
+
|
|
17
|
+
<section data-section>
|
|
18
|
+
<h2 variant="section">Composition</h2>
|
|
19
|
+
<p>Typical placement inside <code><chat-shell></code>:</p>
|
|
20
|
+
<code-ui language="html"><chat-shell>
|
|
21
|
+
<chat-header>…</chat-header>
|
|
22
|
+
<chat-thread>
|
|
23
|
+
<chat-empty>
|
|
24
|
+
<empty-state-ui icon="chat-circle" heading="Hello!" description="Ask me anything."></empty-state-ui>
|
|
25
|
+
</chat-empty>
|
|
26
|
+
</chat-thread>
|
|
27
|
+
<chat-composer>
|
|
28
|
+
<chat-input-ui placeholder="Message…"></chat-input-ui>
|
|
29
|
+
</chat-composer>
|
|
30
|
+
</chat-shell></code-ui>
|
|
31
|
+
</section>
|
|
32
|
+
|
|
33
|
+
<section data-section>
|
|
34
|
+
<h2 variant="section">Family</h2>
|
|
35
|
+
<p>Per <a href="../../../../.brain/adrs/0023-bespoke-shell-tier-children.md">ADR-0023</a>, the chat cluster's bespoke family — <code><chat-shell></code> (host), <code><chat-thread></code>, <code><chat-composer></code>, <code><chat-sidebar></code> (JS-bearing) + <code><chat-header></code>, <code><chat-status></code>, <code><chat-empty></code> (CSS-only). Mirrors the admin cluster's pattern.</p>
|
|
36
|
+
</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>Chat Thread — 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="../chat-shell/chat-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="../chat-shell/chat-shell.js"></script>
|
|
15
|
+
<script type="module" src="./chat-thread.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('./chat-thread.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 chat-thread.examples.html — ${err.message}</p>`;
|
|
38
|
+
console.error('[chat-thread.html]', err);
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|