@adia-ai/web-components 0.0.28 → 0.0.29

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 (69) hide show
  1. package/README.md +4 -8
  2. package/a2ui/index.js +1 -1
  3. package/components/canvas/canvas.js +1 -1
  4. package/components/feed/feed.css +9 -0
  5. package/components/feed/feed.js +118 -9
  6. package/components/toast/toast.js +48 -178
  7. package/index.css +3 -2
  8. package/index.js +15 -7
  9. package/package.json +1 -5
  10. package/patterns/a2ui-root/a2ui-root.a2ui.json +0 -125
  11. package/patterns/a2ui-root/a2ui-root.js +0 -191
  12. package/patterns/a2ui-root/a2ui-root.yaml +0 -87
  13. package/patterns/adia-chat/adia-chat.a2ui.json +0 -149
  14. package/patterns/adia-chat/adia-chat.css +0 -10
  15. package/patterns/adia-chat/adia-chat.js +0 -297
  16. package/patterns/adia-chat/adia-chat.yaml +0 -118
  17. package/patterns/adia-chat/css/adia-chat.empty.css +0 -12
  18. package/patterns/adia-chat/css/adia-chat.layout.css +0 -60
  19. package/patterns/adia-chat/css/adia-chat.markdown.css +0 -74
  20. package/patterns/adia-chat/css/adia-chat.messages.css +0 -87
  21. package/patterns/adia-chat/css/adia-chat.streaming.css +0 -30
  22. package/patterns/adia-chat/css/adia-chat.tokens.css +0 -95
  23. package/patterns/adia-editor/adia-editor.a2ui.json +0 -73
  24. package/patterns/adia-editor/adia-editor.css +0 -6
  25. package/patterns/adia-editor/adia-editor.js +0 -56
  26. package/patterns/adia-editor/adia-editor.yaml +0 -59
  27. package/patterns/adia-editor/css/adia-editor.layout.css +0 -171
  28. package/patterns/adia-editor/css/adia-editor.tokens.css +0 -28
  29. package/patterns/app-nav/app-nav.a2ui.json +0 -89
  30. package/patterns/app-nav/app-nav.css +0 -92
  31. package/patterns/app-nav/app-nav.js +0 -112
  32. package/patterns/app-nav/app-nav.yaml +0 -54
  33. package/patterns/app-nav-group/app-nav-group.a2ui.json +0 -82
  34. package/patterns/app-nav-group/app-nav-group.css +0 -264
  35. package/patterns/app-nav-group/app-nav-group.js +0 -116
  36. package/patterns/app-nav-group/app-nav-group.yaml +0 -59
  37. package/patterns/app-nav-item/app-nav-item.a2ui.json +0 -83
  38. package/patterns/app-nav-item/app-nav-item.css +0 -162
  39. package/patterns/app-nav-item/app-nav-item.js +0 -42
  40. package/patterns/app-nav-item/app-nav-item.yaml +0 -62
  41. package/patterns/app-shell/app-shell.a2ui.json +0 -129
  42. package/patterns/app-shell/app-shell.css +0 -14
  43. package/patterns/app-shell/app-shell.js +0 -251
  44. package/patterns/app-shell/app-shell.yaml +0 -89
  45. package/patterns/app-shell/css/app-shell.collapsed.css +0 -86
  46. package/patterns/app-shell/css/app-shell.helpers.css +0 -42
  47. package/patterns/app-shell/css/app-shell.main.css +0 -172
  48. package/patterns/app-shell/css/app-shell.shell.css +0 -44
  49. package/patterns/app-shell/css/app-shell.sidebar.css +0 -161
  50. package/patterns/app-shell/css/app-shell.templates.css +0 -214
  51. package/patterns/app-shell/css/app-shell.tokens.css +0 -119
  52. package/patterns/gen-ui/gen-ui.a2ui.json +0 -72
  53. package/patterns/gen-ui/gen-ui.css +0 -83
  54. package/patterns/gen-ui/gen-ui.js +0 -136
  55. package/patterns/gen-ui/gen-ui.yaml +0 -43
  56. package/patterns/index.js +0 -11
  57. package/patterns/section-nav/section-nav.a2ui.json +0 -91
  58. package/patterns/section-nav/section-nav.css +0 -60
  59. package/patterns/section-nav/section-nav.js +0 -42
  60. package/patterns/section-nav/section-nav.yaml +0 -58
  61. package/patterns/section-nav-group/section-nav-group.a2ui.json +0 -95
  62. package/patterns/section-nav-group/section-nav-group.css +0 -74
  63. package/patterns/section-nav-group/section-nav-group.js +0 -84
  64. package/patterns/section-nav-group/section-nav-group.yaml +0 -66
  65. package/patterns/section-nav-item/section-nav-item.a2ui.json +0 -97
  66. package/patterns/section-nav-item/section-nav-item.css +0 -106
  67. package/patterns/section-nav-item/section-nav-item.js +0 -66
  68. package/patterns/section-nav-item/section-nav-item.yaml +0 -70
  69. package/styles/layouts/admin.css +0 -7
@@ -1,112 +0,0 @@
1
- /**
2
- * <app-nav-ui> — Collapsible navigation sidebar.
3
- *
4
- * Structure:
5
- * <app-nav-ui>
6
- * <app-nav-group-ui icon="gear" text="Settings" badge="3">
7
- * <app-nav-item-ui text="General" value="/settings/general"></app-nav-item-ui>
8
- * </app-nav-group-ui>
9
- * <app-nav-item-ui icon="user" text="Profile" value="/profile"></app-nav-item-ui>
10
- * </app-nav-ui>
11
- *
12
- * When [collapsed], labels and badges hide; groups open a popover with their
13
- * children instead of expanding inline.
14
- *
15
- * Event: nav-select (detail: { item, text, value })
16
- */
17
-
18
- import { AdiaElement } from '../../core/element.js';
19
-
20
- class AdiaAppNav extends AdiaElement {
21
- static properties = {
22
- collapsed: { type: Boolean, default: false, reflect: true },
23
- divider: { type: Boolean, default: false, reflect: true },
24
- };
25
-
26
- static template = () => null;
27
-
28
- #ro = null;
29
-
30
- connected() {
31
- this.setAttribute('role', 'navigation');
32
- this.addEventListener('click', this.#onClick);
33
- this.#ro = new ResizeObserver(() => this.#updateTooltips());
34
- this.#ro.observe(this);
35
- }
36
-
37
- render() {
38
- this.#updateTooltips();
39
- }
40
-
41
- #updateTooltips() {
42
- const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
43
- for (const group of this.querySelectorAll(':scope > app-nav-group-ui')) {
44
- const header = group.querySelector(':scope > [slot="header"]');
45
- if (header) header.title = isCollapsed ? group.text : '';
46
- }
47
- for (const item of this.querySelectorAll(':scope > app-nav-item-ui')) {
48
- item.title = isCollapsed ? item.text : '';
49
- }
50
- }
51
-
52
- get selectedItem() {
53
- return this.querySelector('app-nav-item-ui[selected]');
54
- }
55
-
56
- select(item) {
57
- const prev = this.selectedItem;
58
- if (prev && prev !== item) prev.removeAttribute('selected');
59
- item.setAttribute('selected', '');
60
- this.dispatchEvent(new CustomEvent('nav-select', {
61
- bubbles: true,
62
- detail: { item, text: item.text, value: item.value },
63
- }));
64
- }
65
-
66
- toggle() {
67
- this.collapsed = !this.collapsed;
68
- }
69
-
70
- #onClick = (e) => {
71
- const item = e.target.closest('app-nav-item-ui');
72
- if (item && this.contains(item)) {
73
- this.select(item);
74
- this.#flushHoverState();
75
- return;
76
- }
77
-
78
- const group = e.target.closest('app-nav-group-ui');
79
- if (group && this.contains(group)) {
80
- const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
81
- if (isCollapsed) {
82
- group.showPopover();
83
- } else {
84
- const header = group.querySelector(':scope > [slot="header"]');
85
- if (header && (e.target === header || header.contains(e.target))) {
86
- group.open = !group.open;
87
- }
88
- }
89
- }
90
- };
91
-
92
- // Safari macOS leaves `:hover` stuck on items the cursor passed through
93
- // when the DOM mutates during click+route navigation (no `mouseleave`
94
- // fires). Toggling pointer-events on the container forces Safari to
95
- // re-evaluate hover state on next paint without flickering layout.
96
- // Documented in docs/BROWSER-COMPAT.md §3a.
97
- #flushHoverState() {
98
- this.style.pointerEvents = 'none';
99
- requestAnimationFrame(() => {
100
- this.style.pointerEvents = '';
101
- });
102
- }
103
-
104
- disconnected() {
105
- this.removeEventListener('click', this.#onClick);
106
- this.#ro?.disconnect();
107
- this.#ro = null;
108
- }
109
- }
110
- customElements.define('app-nav-ui', AdiaAppNav);
111
-
112
- export { AdiaAppNav };
@@ -1,54 +0,0 @@
1
- $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
- name: AdiaAppNav
3
- tag: app-nav-ui
4
- component: AppNav
5
- category: nav
6
- version: 1
7
- description: |
8
- Collapsible navigation sidebar. Manages selection state across
9
- app-nav-item-ui children and opens popover menus for app-nav-group-ui
10
- children when collapsed.
11
-
12
- props:
13
- collapsed:
14
- type: boolean
15
- default: false
16
- reflect: true
17
- description: When true, labels and badges hide; only icons show. Groups use popovers instead of inline expansion.
18
-
19
- divider:
20
- type: boolean
21
- default: false
22
- reflect: true
23
- description: Render auto-dividers between groups.
24
-
25
- events:
26
- nav-select:
27
- description: Fired when a child app-nav-item-ui is selected (via click or the .select() method).
28
- detail:
29
- item: HTMLElement
30
- text: string
31
- value: string
32
-
33
- slots:
34
- default:
35
- description: app-nav-group-ui and app-nav-item-ui children.
36
-
37
- states:
38
- - name: idle
39
- description: Default, interactive.
40
- - name: collapsed
41
- attribute: collapsed
42
- description: Narrow-width mode; groups open popovers instead of expanding.
43
-
44
- traits: []
45
-
46
- a2ui:
47
- rules:
48
- - app-nav-ui is the only valid parent of app-nav-group-ui.
49
- - app-nav-item-ui may be a direct child of app-nav-ui OR nested inside app-nav-group-ui.
50
-
51
- keywords: [app-nav, sidebar, navigation, nav, menu]
52
- synonyms:
53
- sidebar: [app-nav, nav, navigation]
54
- related: [AppShell, AppNavGroup, AppNavItem]
@@ -1,82 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://adiaui.dev/a2ui/v0_9/components/AppNavGroup.json",
4
- "title": "AppNavGroup",
5
- "description": "Collapsible group inside app-nav-ui. Has icon, label, optional badge, and\na caret indicating open/closed. When the parent app-nav-ui is collapsed,\nclicking the group opens a popover with its children instead of toggling\ninline expansion.\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
- "badge": {
17
- "description": "Optional badge text (e.g. unread count).",
18
- "type": "string",
19
- "default": ""
20
- },
21
- "component": {
22
- "const": "AppNavGroup"
23
- },
24
- "icon": {
25
- "description": "Phosphor icon name rendered in the group header.",
26
- "type": "string",
27
- "default": ""
28
- },
29
- "open": {
30
- "description": "Expanded state. Toggled by header click; ignored when parent nav is collapsed (popover used instead).",
31
- "type": "boolean",
32
- "default": false
33
- },
34
- "text": {
35
- "description": "Group label text.",
36
- "type": "string",
37
- "default": ""
38
- }
39
- },
40
- "required": [
41
- "component"
42
- ],
43
- "unevaluatedProperties": false,
44
- "x-adiaui": {
45
- "anti_patterns": [],
46
- "category": "nav",
47
- "events": {},
48
- "examples": [],
49
- "keywords": [
50
- "app-nav-group",
51
- "nav",
52
- "group",
53
- "menu-section"
54
- ],
55
- "name": "AdiaAppNavGroup",
56
- "related": [
57
- "AppNav",
58
- "AppNavItem"
59
- ],
60
- "slots": {
61
- "default": {
62
- "description": "app-nav-item-ui children rendered beneath the group header."
63
- }
64
- },
65
- "states": [
66
- {
67
- "description": "Default, collapsed or open based on [open].",
68
- "name": "idle"
69
- },
70
- {
71
- "description": "Group is expanded; children visible.",
72
- "attribute": "open",
73
- "name": "open"
74
- }
75
- ],
76
- "synonyms": {},
77
- "tag": "app-nav-group-ui",
78
- "tokens": {},
79
- "traits": [],
80
- "version": 1
81
- }
82
- }
@@ -1,264 +0,0 @@
1
- @scope (app-nav-group-ui) {
2
- :where(:scope) {
3
- --nav-group-row-height: var(--a-size);
4
- --nav-group-row-height-sm: var(--a-size-sm);
5
- --nav-group-row-height-lg: var(--a-size-lg);
6
- --nav-group-row-px: var(--a-ui-px);
7
- --nav-group-row-gap: var(--a-space-1);
8
- --nav-group-row-radius: var(--a-radius-md);
9
- --nav-group-font-size: var(--a-ui-size);
10
- --nav-group-font-size-sm: var(--a-ui-sm);
11
- --nav-group-font-size-lg: var(--a-ui-lg);
12
- --nav-group-fg: var(--a-fg);
13
- --nav-group-fg-hover: var(--a-fg-strong);
14
- --nav-group-fg-muted: var(--a-fg-muted);
15
- --nav-group-fg-selected: var(--a-fg-strong);
16
- --nav-group-bg-hover: var(--a-bg-muted);
17
- --nav-group-icon-size: calc(var(--nav-group-row-height) - var(--a-space-2));
18
- --nav-group-badge-size: var(--a-ui-sm);
19
-
20
- --nav-item-child-height: var(--a-size-sm);
21
- --nav-item-child-font: var(--nav-group-font-size);
22
- }
23
-
24
- :scope {
25
- box-sizing: border-box;
26
- display: flex;
27
- flex-direction: column;
28
- gap: var(--nav-gap);
29
- position: relative;
30
- }
31
-
32
- /* Continuous indent rail */
33
- :scope[open]::after {
34
- content: '';
35
- position: absolute;
36
- left: calc(var(--nav-group-row-px) + var(--nav-group-icon-size) / 2);
37
- transform: translateX(-50%);
38
- top: var(--nav-group-row-height);
39
- bottom: calc(var(--nav-group-row-height) / 2);
40
- width: 1px;
41
- background: var(--nav-group-indent-rail-bg);
42
- pointer-events: none;
43
- }
44
- :scope[open] > [slot="header"],
45
- :scope[open] > [slot="header"] [slot="icon"] {
46
- color: var(--nav-group-fg-selected);
47
- }
48
-
49
- /* Header row */
50
- [slot="header"] {
51
- display: flex;
52
- align-items: center;
53
- gap: var(--nav-group-row-gap);
54
- height: var(--nav-group-row-height);
55
- padding: 0 var(--nav-group-row-px);
56
- border-radius: var(--nav-group-row-radius);
57
- font-size: var(--nav-group-font-size);
58
- color: var(--nav-group-fg);
59
- cursor: pointer;
60
- user-select: none;
61
- white-space: nowrap;
62
- transition:
63
- background var(--nav-duration-fast) var(--nav-easing),
64
- color var(--nav-duration-fast) var(--nav-easing);
65
- outline: none;
66
- }
67
-
68
- [slot="header"]:hover {
69
- background: var(--nav-group-bg-hover);
70
- color: var(--nav-group-fg-hover);
71
- }
72
-
73
- [slot="header"]:hover [slot="icon"] {
74
- color: var(--nav-group-fg-hover);
75
- }
76
-
77
- [slot="header"]:focus-visible {
78
- background: var(--nav-group-bg-hover);
79
- color: var(--nav-group-fg-hover);
80
- outline: none;
81
- }
82
-
83
- [slot="header"] [slot="icon"] {
84
- width: var(--nav-group-icon-size);
85
- height: var(--nav-group-icon-size);
86
- flex-shrink: 0;
87
- color: var(--nav-group-fg-muted);
88
- transition: color var(--nav-duration-fast) var(--nav-easing);
89
- display: flex;
90
- align-items: center;
91
- justify-content: center;
92
- }
93
-
94
- [slot="header"] [slot="icon"] icon-ui {
95
- --a-icon-size: calc(var(--nav-group-icon-font-size) + 2px);
96
- }
97
-
98
- [slot="header"] [slot="text"] {
99
- flex: 1;
100
- min-width: 0;
101
- overflow: hidden;
102
- text-overflow: ellipsis;
103
- font-weight: var(--nav-group-text-weight);
104
- }
105
-
106
- [slot="header"] [slot="badge"] {
107
- font-size: var(--nav-group-badge-size);
108
- color: var(--nav-group-fg-muted);
109
- background: var(--nav-group-badge-bg);
110
- padding: 1px var(--nav-group-badge-px);
111
- border-radius: var(--nav-group-badge-radius);
112
- line-height: 1.4;
113
- }
114
-
115
- [slot="header"] [slot="caret"] {
116
- /*--a-icon-size: 0.5rem;*/
117
- color: var(--nav-group-fg-muted);
118
- transition:
119
- transform var(--nav-duration-fast) var(--nav-easing),
120
- color var(--nav-duration-fast) var(--nav-easing);
121
- transform: rotate(90deg);
122
- flex-shrink: 0;
123
-
124
- --a-icon-size: var(--a-caret-size);
125
- }
126
-
127
- [slot="header"]:hover [slot="caret"] {
128
- color: var(--nav-group-fg-hover);
129
- }
130
-
131
- :scope:not([open]) > [slot="header"] [slot="caret"] {
132
- transform: rotate(0deg);
133
- }
134
-
135
- /* Children — hidden when collapsed */
136
- :scope:not([open]) > app-nav-item-ui {
137
- display: none;
138
- }
139
-
140
- /* Child items default to sm for visual hierarchy */
141
- :scope > app-nav-item-ui:not([size]) {
142
- height: var(--nav-item-child-height);
143
- font-size: var(--nav-item-child-font);
144
- }
145
-
146
- /* ── Collapsed nav: hide text, badge, caret ── */
147
- app-nav-ui[collapsed] & [slot="text"],
148
- app-nav-ui[collapsed] & [slot="badge"],
149
- app-nav-ui[collapsed] & [slot="caret"] {
150
- display: none;
151
- }
152
-
153
- app-nav-ui[collapsed] & [slot="header"] {
154
- justify-content: center;
155
- padding: 0;
156
- }
157
-
158
- app-nav-ui[collapsed] & {
159
- align-self: stretch;
160
- }
161
-
162
- app-nav-ui[collapsed] &::after {
163
- display: none;
164
- }
165
-
166
- @container sidebar (max-width: 96px) {
167
- [slot="text"], [slot="badge"], [slot="caret"] {
168
- display: none !important;
169
- }
170
- app-nav-item-ui {
171
- display: none !important;
172
- }
173
- [slot="header"] {
174
- justify-content: center;
175
- padding: 0;
176
- }
177
- [slot="icon"] icon-ui {
178
- --a-icon-size: --a-icon-size;
179
- }
180
- [slot="caret"] icon-ui {
181
- --a-icon-size: --a-caret-size;
182
- }
183
- :scope {
184
- align-self: stretch;
185
- }
186
- :scope::after {
187
- display: none;
188
- }
189
- }
190
-
191
- /* ── Size variants ── */
192
- :scope[size="sm"] {
193
- --nav-group-row-height: var(--nav-group-row-height-sm);
194
- --nav-group-font-size: var(--nav-group-font-size-sm);
195
- }
196
-
197
- :scope[size="lg"] {
198
- --nav-group-row-height: var(--nav-group-row-height-lg);
199
- --nav-group-font-size: var(--nav-group-font-size-lg);
200
- }
201
- }
202
-
203
- /* Nav-group popover (outside @scope — lives in top layer)
204
- Popovers are promoted to the top layer and cannot inherit
205
- pattern-level custom properties, so raw --a-* tokens are
206
- used intentionally here. */
207
- app-nav-group-ui [slot="popover"] {
208
- margin: 0;
209
- padding: var(--a-space-1);
210
- border: 1px solid var(--a-border-subtle);
211
- border-radius: var(--a-radius);
212
- background: var(--a-bg-subtle);
213
- box-shadow: var(--a-shadow-lg);
214
- min-width: 160px;
215
- max-height: calc(100vh - 3rem);
216
- overflow-y: auto;
217
- font-size: var(--a-ui-size);
218
- }
219
-
220
- app-nav-group-ui [slot="popover-label"] {
221
- padding: var(--a-space-1) var(--a-space-2);
222
- font-weight: var(--a-weight-medium);
223
- color: var(--a-fg-muted);
224
- font-size: var(--a-ui-tiny);
225
- text-transform: uppercase;
226
- letter-spacing: 0.06em;
227
- }
228
-
229
- app-nav-group-ui [slot="popover"] [role="option"] {
230
- padding: var(--a-space-1) var(--a-space-2);
231
- border-radius: var(--a-radius);
232
- color: var(--a-fg-subtle);
233
- cursor: pointer;
234
- white-space: nowrap;
235
- transition:
236
- background var(--a-duration-fast) var(--a-easing),
237
- color var(--a-duration-fast) var(--a-easing);
238
- }
239
-
240
- app-nav-group-ui [slot="popover"] [role="option"]:hover {
241
- background: var(--a-bg-hover);
242
- color: var(--a-fg-strong);
243
- }
244
-
245
- /* Selected / current option — mirrors the main rail's nav-item selection:
246
- muted fill + leading 2px accent bar. */
247
- app-nav-group-ui [slot="popover"] [role="option"][aria-current="page"],
248
- app-nav-group-ui [slot="popover"] [role="option"][aria-selected="true"] {
249
- position: relative;
250
- background: var(--a-bg-hover);
251
- color: var(--a-fg-strong);
252
- font-weight: var(--a-weight-medium);
253
- }
254
-
255
- app-nav-group-ui [slot="popover"] [role="option"][aria-current="page"]::before,
256
- app-nav-group-ui [slot="popover"] [role="option"][aria-selected="true"]::before {
257
- content: '';
258
- position: absolute;
259
- inset-inline-start: calc(var(--a-space-2) * -0.5);
260
- inset-block: 25%;
261
- width: 2px;
262
- border-radius: 1px;
263
- background: var(--a-accent);
264
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * <app-nav-group-ui> — Collapsible group of nav items inside app-nav-ui.
3
- *
4
- * Has icon, label, optional badge, and a caret indicating open/closed.
5
- * When the parent app-nav-ui is collapsed, clicking the group opens a
6
- * popover with its children instead of toggling inline expansion.
7
- */
8
-
9
- import { AdiaElement } from '../../core/element.js';
10
- import { anchorPopover } from '../../core/anchor.js';
11
-
12
- class AdiaAppNavGroup extends AdiaElement {
13
- static properties = {
14
- text: { type: String, default: '', reflect: true },
15
- icon: { type: String, default: '', reflect: true },
16
- badge: { type: String, default: '', reflect: true },
17
- open: { type: Boolean, default: false, reflect: true },
18
- };
19
-
20
- static template = () => null;
21
-
22
- #popover = null;
23
- #anchorCleanup = null;
24
-
25
- connected() {
26
- this.setAttribute('role', 'group');
27
-
28
- if (!this.querySelector(':scope > [slot="header"]')) {
29
- const header = document.createElement('div');
30
- header.setAttribute('slot', 'header');
31
- header.setAttribute('tabindex', '0');
32
- header.innerHTML = `
33
- <span slot="icon">${this.icon ? `<icon-ui name="${this.icon}"></icon-ui>` : ''}</span>
34
- <span slot="text">${this.text}</span>
35
- ${this.badge ? `<span slot="badge">${this.badge}</span>` : ''}
36
- <icon-ui slot="caret" name="caret-right"></icon-ui>
37
- `;
38
- this.prepend(header);
39
- }
40
- }
41
-
42
- render() {
43
- const textEl = this.querySelector('[slot="header"] [slot="text"]');
44
- if (textEl) textEl.textContent = this.text;
45
-
46
- const badgeEl = this.querySelector('[slot="header"] [slot="badge"]');
47
- if (badgeEl) badgeEl.textContent = this.badge;
48
-
49
- this.setAttribute('aria-expanded', String(this.open));
50
- }
51
-
52
- showPopover() {
53
- if (!this.#popover) {
54
- this.#popover = document.createElement('div');
55
- this.#popover.setAttribute('slot', 'popover');
56
- this.#popover.setAttribute('popover', 'auto');
57
-
58
- const label = document.createElement('div');
59
- label.setAttribute('slot', 'popover-label');
60
- label.textContent = this.text;
61
- this.#popover.appendChild(label);
62
-
63
- for (const child of this.querySelectorAll(':scope > app-nav-item-ui')) {
64
- const clone = document.createElement('div');
65
- clone.setAttribute('role', 'option');
66
- clone.dataset.sourceValue = child.getAttribute('value') || '';
67
- clone.textContent = child.text;
68
- clone.addEventListener('click', () => {
69
- const nav = this.closest('app-nav-ui');
70
- if (nav) nav.select(child);
71
- this.#popover.hidePopover();
72
- });
73
- this.#popover.appendChild(clone);
74
- }
75
-
76
- this.appendChild(this.#popover);
77
-
78
- this.#popover.addEventListener('toggle', (e) => {
79
- if (e.newState === 'closed') {
80
- this.#anchorCleanup?.();
81
- this.#anchorCleanup = null;
82
- }
83
- });
84
- }
85
-
86
- for (const opt of this.#popover.querySelectorAll('[role="option"]')) {
87
- const srcValue = opt.dataset.sourceValue;
88
- const src = srcValue
89
- ? this.querySelector(`:scope > app-nav-item-ui[value="${srcValue}"]`)
90
- : null;
91
- if (src?.hasAttribute('selected')) {
92
- opt.setAttribute('aria-current', 'page');
93
- opt.setAttribute('aria-selected', 'true');
94
- } else {
95
- opt.removeAttribute('aria-current');
96
- opt.removeAttribute('aria-selected');
97
- }
98
- }
99
-
100
- this.#popover.showPopover();
101
-
102
- this.#anchorCleanup?.();
103
- this.#anchorCleanup = anchorPopover(this, this.#popover, {
104
- placement: 'right', gap: 4,
105
- });
106
- }
107
-
108
- disconnected() {
109
- this.#anchorCleanup?.();
110
- this.#anchorCleanup = null;
111
- this.#popover?.hidePopover?.();
112
- }
113
- }
114
- customElements.define('app-nav-group-ui', AdiaAppNavGroup);
115
-
116
- export { AdiaAppNavGroup };
@@ -1,59 +0,0 @@
1
- $schema: ../../../../scripts/schemas/component.yaml.schema.json
2
- name: AdiaAppNavGroup
3
- tag: app-nav-group-ui
4
- component: AppNavGroup
5
- category: nav
6
- version: 1
7
- description: |
8
- Collapsible group inside app-nav-ui. Has icon, label, optional badge, and
9
- a caret indicating open/closed. When the parent app-nav-ui is collapsed,
10
- clicking the group opens a popover with its children instead of toggling
11
- inline expansion.
12
-
13
- props:
14
- text:
15
- type: string
16
- default: ""
17
- reflect: true
18
- description: Group label text.
19
-
20
- icon:
21
- type: string
22
- default: ""
23
- reflect: true
24
- description: Phosphor icon name rendered in the group header.
25
-
26
- badge:
27
- type: string
28
- default: ""
29
- reflect: true
30
- description: Optional badge text (e.g. unread count).
31
-
32
- open:
33
- type: boolean
34
- default: false
35
- reflect: true
36
- description: Expanded state. Toggled by header click; ignored when parent nav is collapsed (popover used instead).
37
-
38
- events: {}
39
-
40
- slots:
41
- default:
42
- description: app-nav-item-ui children rendered beneath the group header.
43
-
44
- states:
45
- - name: idle
46
- description: Default, collapsed or open based on [open].
47
- - name: open
48
- attribute: open
49
- description: Group is expanded; children visible.
50
-
51
- traits: []
52
-
53
- a2ui:
54
- rules:
55
- - Must be a direct child of app-nav-ui.
56
- - Children must be app-nav-item-ui, not arbitrary components.
57
-
58
- keywords: [app-nav-group, nav, group, menu-section]
59
- related: [AppNav, AppNavItem]