@adia-ai/web-components 0.0.29 → 0.0.34
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/components/accordion/accordion.a2ui.json +1 -1
- package/components/accordion/accordion.js +6 -6
- package/components/accordion/accordion.yaml +1 -1
- package/components/action-list/action-list.a2ui.json +1 -1
- package/components/action-list/action-list.js +6 -6
- package/components/action-list/action-list.yaml +1 -1
- package/components/agent-artifact/agent-artifact.a2ui.json +1 -1
- package/components/agent-artifact/agent-artifact.js +4 -4
- package/components/agent-artifact/agent-artifact.yaml +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.js +4 -4
- package/components/agent-feedback-bar/agent-feedback-bar.yaml +1 -1
- package/components/agent-questions/agent-questions.a2ui.json +1 -1
- package/components/agent-questions/agent-questions.js +4 -4
- package/components/agent-questions/agent-questions.yaml +1 -1
- package/components/agent-reasoning/agent-reasoning.a2ui.json +3 -3
- package/components/agent-reasoning/agent-reasoning.js +4 -4
- package/components/agent-reasoning/agent-reasoning.yaml +3 -3
- package/components/agent-suggestions/agent-suggestions.a2ui.json +1 -1
- package/components/agent-suggestions/agent-suggestions.js +4 -4
- package/components/agent-suggestions/agent-suggestions.yaml +1 -1
- package/components/agent-trace/agent-trace.a2ui.json +1 -1
- package/components/agent-trace/agent-trace.js +4 -4
- package/components/agent-trace/agent-trace.yaml +1 -1
- package/components/alert/alert.a2ui.json +1 -1
- package/components/alert/alert.js +4 -4
- package/components/alert/alert.yaml +1 -1
- package/components/aside/aside.a2ui.json +1 -1
- package/components/aside/aside.yaml +1 -1
- package/components/avatar/avatar.a2ui.json +1 -1
- package/components/avatar/avatar.js +8 -8
- package/components/avatar/avatar.yaml +1 -1
- package/components/badge/badge.a2ui.json +1 -1
- package/components/badge/badge.js +4 -4
- package/components/badge/badge.yaml +1 -1
- package/components/block/block.a2ui.json +1 -1
- package/components/block/block.js +4 -4
- package/components/block/block.yaml +1 -1
- package/components/breadcrumb/breadcrumb.a2ui.json +1 -1
- package/components/breadcrumb/breadcrumb.js +4 -4
- package/components/breadcrumb/breadcrumb.yaml +1 -1
- package/components/button/button.a2ui.json +1 -1
- package/components/button/button.js +4 -4
- package/components/button/button.yaml +1 -1
- package/components/calendar-picker/calendar-picker.a2ui.json +1 -1
- package/components/calendar-picker/calendar-picker.js +6 -6
- package/components/calendar-picker/calendar-picker.yaml +1 -1
- package/components/canvas/canvas.a2ui.json +1 -1
- package/components/canvas/canvas.js +4 -4
- package/components/canvas/canvas.yaml +1 -1
- package/components/card/card.a2ui.json +1 -1
- package/components/card/card.js +4 -4
- package/components/card/card.yaml +1 -1
- package/components/chart/chart.a2ui.json +1 -1
- package/components/chart/chart.js +5 -5
- package/components/chart/chart.yaml +1 -1
- package/components/chart-legend/chart-legend.a2ui.json +1 -1
- package/components/chart-legend/chart-legend.js +7 -7
- package/components/chart-legend/chart-legend.yaml +1 -1
- package/components/{chat → chat-thread}/chat-input.js +5 -5
- package/components/{chat/chat.a2ui.json → chat-thread/chat-thread.a2ui.json} +6 -6
- package/components/{chat/chat.css → chat-thread/chat-thread.css} +2 -2
- package/components/{chat/chat.js → chat-thread/chat-thread.js} +7 -7
- package/components/{chat/chat.yaml → chat-thread/chat-thread.yaml} +4 -4
- package/components/check/check.a2ui.json +1 -1
- package/components/check/check.js +5 -5
- package/components/check/check.yaml +1 -1
- package/components/code/code.a2ui.json +1 -1
- package/components/code/code.js +4 -4
- package/components/code/code.yaml +1 -1
- package/components/col/col.a2ui.json +1 -1
- package/components/col/col.js +4 -4
- package/components/col/col.yaml +1 -1
- package/components/color-picker/color-picker.a2ui.json +1 -1
- package/components/color-picker/color-picker.js +6 -6
- package/components/color-picker/color-picker.yaml +1 -1
- package/components/command/command.a2ui.json +1 -1
- package/components/command/command.js +5 -5
- package/components/command/command.yaml +1 -1
- package/components/description-list/description-list.a2ui.json +1 -1
- package/components/description-list/description-list.js +4 -4
- package/components/description-list/description-list.yaml +1 -1
- package/components/divider/divider.a2ui.json +1 -1
- package/components/divider/divider.js +4 -4
- package/components/divider/divider.yaml +1 -1
- package/components/drawer/drawer.a2ui.json +1 -1
- package/components/drawer/drawer.js +4 -4
- package/components/drawer/drawer.yaml +1 -1
- package/components/embed/embed.a2ui.json +1 -1
- package/components/embed/embed.js +4 -4
- package/components/embed/embed.yaml +1 -1
- package/components/empty-state/empty-state.a2ui.json +1 -1
- package/components/empty-state/empty-state.js +4 -4
- package/components/empty-state/empty-state.yaml +1 -1
- package/components/feed/feed-item.yaml +2 -2
- package/components/feed/feed.a2ui.json +2 -2
- package/components/feed/feed.css +12 -3
- package/components/feed/feed.js +22 -22
- package/components/feed/feed.yaml +2 -2
- package/components/field/field.a2ui.json +1 -1
- package/components/field/field.js +10 -10
- package/components/field/field.yaml +2 -2
- package/components/footer/footer.a2ui.json +1 -1
- package/components/footer/footer.yaml +1 -1
- package/components/grid/grid.a2ui.json +1 -1
- package/components/grid/grid.js +4 -4
- package/components/grid/grid.yaml +1 -1
- package/components/header/header.a2ui.json +1 -1
- package/components/header/header.yaml +1 -1
- package/components/heatmap/heatmap.a2ui.json +1 -1
- package/components/heatmap/heatmap.js +4 -4
- package/components/heatmap/heatmap.yaml +1 -1
- package/components/icon/icon.a2ui.json +1 -1
- package/components/icon/icon.js +4 -4
- package/components/icon/icon.yaml +1 -1
- package/components/image/image.a2ui.json +1 -1
- package/components/image/image.js +4 -4
- package/components/image/image.yaml +1 -1
- package/components/index.js +89 -85
- package/components/input/input.a2ui.json +1 -1
- package/components/input/input.js +7 -7
- package/components/input/input.yaml +1 -1
- package/components/inspector/inspector.a2ui.json +1 -1
- package/components/inspector/inspector.js +4 -4
- package/components/inspector/inspector.yaml +1 -1
- package/components/kbd/kbd.a2ui.json +1 -1
- package/components/kbd/kbd.js +4 -4
- package/components/kbd/kbd.yaml +1 -1
- package/components/list/list.a2ui.json +1 -1
- package/components/list/list.js +6 -6
- package/components/list/list.yaml +1 -1
- package/components/menu/menu.a2ui.json +1 -1
- package/components/menu/menu.js +8 -8
- package/components/menu/menu.yaml +1 -1
- package/components/modal/modal.a2ui.json +1 -1
- package/components/modal/modal.js +4 -4
- package/components/modal/modal.yaml +1 -1
- package/components/nav/nav.a2ui.json +98 -0
- package/components/nav/nav.css +133 -0
- package/components/nav/nav.js +140 -0
- package/components/nav/nav.test.js +428 -0
- package/components/nav/nav.yaml +114 -0
- package/components/nav-group/nav-group.a2ui.json +100 -0
- package/components/nav-group/nav-group.css +317 -0
- package/components/nav-group/nav-group.js +142 -0
- package/components/nav-group/nav-group.yaml +69 -0
- package/components/nav-item/nav-item.a2ui.json +106 -0
- package/components/nav-item/nav-item.css +194 -0
- package/components/nav-item/nav-item.js +76 -0
- package/components/nav-item/nav-item.yaml +73 -0
- package/components/noodles/noodles.a2ui.json +1 -1
- package/components/noodles/noodles.js +4 -4
- package/components/noodles/noodles.yaml +1 -1
- package/components/option-card/option-card.a2ui.json +1 -1
- package/components/option-card/option-card.js +6 -6
- package/components/option-card/option-card.yaml +1 -1
- package/components/otp-input/otp-input.a2ui.json +1 -1
- package/components/otp-input/otp-input.js +5 -5
- package/components/otp-input/otp-input.yaml +1 -1
- package/components/page/page.a2ui.json +3 -3
- package/components/page/page.js +4 -4
- package/components/page/page.yaml +3 -3
- package/components/pagination/pagination.a2ui.json +1 -1
- package/components/pagination/pagination.js +4 -4
- package/components/pagination/pagination.yaml +1 -1
- package/components/pane/pane.a2ui.json +1 -1
- package/components/pane/pane.js +4 -4
- package/components/pane/pane.yaml +1 -1
- package/components/pipeline-status/pipeline-status.a2ui.json +1 -1
- package/components/pipeline-status/pipeline-status.js +4 -4
- package/components/pipeline-status/pipeline-status.yaml +1 -1
- package/components/popover/popover.a2ui.json +1 -1
- package/components/popover/popover.js +4 -4
- package/components/popover/popover.yaml +1 -1
- package/components/progress/progress.a2ui.json +1 -1
- package/components/progress/progress.js +4 -4
- package/components/progress/progress.yaml +1 -1
- package/components/progress-row/progress-row.a2ui.json +1 -1
- package/components/progress-row/progress-row.js +4 -4
- package/components/progress-row/progress-row.yaml +1 -1
- package/components/radio/radio.a2ui.json +1 -1
- package/components/radio/radio.js +5 -5
- package/components/radio/radio.yaml +1 -1
- package/components/range/range.a2ui.json +1 -1
- package/components/range/range.js +7 -7
- package/components/range/range.yaml +1 -1
- package/components/rating/rating.a2ui.json +1 -1
- package/components/rating/rating.js +6 -6
- package/components/rating/rating.yaml +1 -1
- package/components/richtext/richtext.a2ui.json +1 -1
- package/components/richtext/richtext.js +4 -4
- package/components/richtext/richtext.yaml +1 -1
- package/components/row/row.a2ui.json +1 -1
- package/components/row/row.js +4 -4
- package/components/row/row.yaml +1 -1
- package/components/search/search.a2ui.json +1 -1
- package/components/search/search.js +5 -5
- package/components/search/search.yaml +1 -1
- package/components/section/section.a2ui.json +1 -1
- package/components/section/section.yaml +1 -1
- package/components/segment/segment.a2ui.json +1 -1
- package/components/segment/segment.js +4 -4
- package/components/segment/segment.yaml +1 -1
- package/components/segmented/segmented.a2ui.json +1 -1
- package/components/segmented/segmented.css +6 -0
- package/components/segmented/segmented.js +7 -7
- package/components/segmented/segmented.yaml +1 -1
- package/components/select/select.a2ui.json +1 -1
- package/components/select/select.js +5 -5
- package/components/select/select.yaml +1 -1
- package/components/skeleton/skeleton.a2ui.json +1 -1
- package/components/skeleton/skeleton.js +4 -4
- package/components/skeleton/skeleton.yaml +1 -1
- package/components/slider/slider.a2ui.json +1 -1
- package/components/slider/slider.js +7 -7
- package/components/slider/slider.yaml +1 -1
- package/components/stack/stack.a2ui.json +1 -1
- package/components/stack/stack.js +4 -4
- package/components/stack/stack.yaml +1 -1
- package/components/stat/stat.a2ui.json +1 -1
- package/components/stat/stat.js +4 -4
- package/components/stat/stat.yaml +1 -1
- package/components/step-progress/step-progress.a2ui.json +111 -0
- package/components/step-progress/step-progress.css +61 -0
- package/components/step-progress/step-progress.js +88 -0
- package/components/step-progress/step-progress.test.js +118 -0
- package/components/step-progress/step-progress.yaml +93 -0
- package/components/stepper/stepper.a2ui.json +1 -1
- package/components/stepper/stepper.js +6 -6
- package/components/stepper/stepper.yaml +1 -1
- package/components/stream/stream.a2ui.json +1 -1
- package/components/stream/stream.js +4 -4
- package/components/stream/stream.yaml +1 -1
- package/components/swatch/swatch.a2ui.json +1 -1
- package/components/swatch/swatch.js +4 -4
- package/components/swatch/swatch.yaml +1 -1
- package/components/swiper/swiper.a2ui.json +1 -1
- package/components/swiper/swiper.js +4 -4
- package/components/swiper/swiper.yaml +1 -1
- package/components/switch/switch.a2ui.json +1 -1
- package/components/switch/switch.js +5 -5
- package/components/switch/switch.yaml +1 -1
- package/components/table/table.a2ui.json +1 -1
- package/components/table/table.js +4 -4
- package/components/table/table.yaml +1 -1
- package/components/table-toolbar/table-toolbar.a2ui.json +1 -1
- package/components/table-toolbar/table-toolbar.js +4 -4
- package/components/table-toolbar/table-toolbar.yaml +1 -1
- package/components/tabs/tab.js +4 -4
- package/components/tabs/tabs.a2ui.json +1 -1
- package/components/tabs/tabs.js +5 -5
- package/components/tabs/tabs.yaml +1 -1
- package/components/tag/tag.a2ui.json +1 -1
- package/components/tag/tag.js +4 -4
- package/components/tag/tag.yaml +1 -1
- package/components/text/text.a2ui.json +1 -1
- package/components/text/text.js +4 -4
- package/components/text/text.yaml +1 -1
- package/components/textarea/textarea.a2ui.json +1 -1
- package/components/textarea/textarea.js +5 -5
- package/components/textarea/textarea.yaml +1 -1
- package/components/timeline/timeline.a2ui.json +1 -1
- package/components/timeline/timeline.js +6 -6
- package/components/timeline/timeline.yaml +1 -1
- package/components/toast/toast.a2ui.json +1 -1
- package/components/toast/toast.js +18 -18
- package/components/toast/toast.yaml +1 -1
- package/components/toggle-group/toggle-group.a2ui.json +1 -1
- package/components/toggle-group/toggle-group.js +6 -6
- package/components/toggle-group/toggle-group.yaml +1 -1
- package/components/toolbar/toolbar.a2ui.json +1 -1
- package/components/toolbar/toolbar.js +6 -6
- package/components/toolbar/toolbar.yaml +1 -1
- package/components/tooltip/tooltip.a2ui.json +1 -1
- package/components/tooltip/tooltip.js +7 -7
- package/components/tooltip/tooltip.yaml +1 -1
- package/components/tree/tree.a2ui.json +1 -1
- package/components/tree/tree.js +6 -6
- package/components/tree/tree.yaml +1 -1
- package/components/upload/upload.a2ui.json +1 -1
- package/components/upload/upload.js +6 -6
- package/components/upload/upload.yaml +1 -1
- package/core/element.js +4 -4
- package/core/element.test.js +18 -18
- package/core/form.js +9 -9
- package/core/index.js +2 -2
- package/core/provider.js +7 -7
- package/core/template.js +1 -1
- package/index.css +1 -1
- package/index.js +10 -8
- package/package.json +1 -1
- package/styles/components.css +11 -6
- package/styles/resets.css +1 -1
- package/traits/define.js +2 -2
- /package/components/{chat → chat-thread}/chat-input.css +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://adiaui.dev/a2ui/v0_9/components/Nav.json",
|
|
4
|
+
"title": "Nav",
|
|
5
|
+
"description": "Navigation rail. Consolidates the prior `app-nav-ui` + `section-nav-ui`\npair per ADR-0015 § Nav consolidation. [variant] drives visual\ntreatment; behavior is unified.\n\nDefault variant (\"primary\") is the app-sidebar nav: ResizeObserver\ncollapses to icon-only below 96px, groups open a popover when\ncollapsed. [variant=\"section\"] is a subnav rail with quieter chrome\nand a [heading] kicker rendered via CSS.\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
|
+
"collapsed": {
|
|
17
|
+
"description": "Primary-variant only. Force icon-only collapse regardless of viewport width.",
|
|
18
|
+
"type": "boolean",
|
|
19
|
+
"default": false
|
|
20
|
+
},
|
|
21
|
+
"component": {
|
|
22
|
+
"const": "Nav"
|
|
23
|
+
},
|
|
24
|
+
"divider": {
|
|
25
|
+
"description": "Auto-place dividers between adjacent groups + items.",
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"default": false
|
|
28
|
+
},
|
|
29
|
+
"heading": {
|
|
30
|
+
"description": "Optional kicker label. Section variant renders it via ::before; primary uses it as aria-label only.",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"default": ""
|
|
33
|
+
},
|
|
34
|
+
"variant": {
|
|
35
|
+
"description": "Visual treatment. primary = app sidebar; section = subnav rail.",
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": [
|
|
38
|
+
"primary",
|
|
39
|
+
"section"
|
|
40
|
+
],
|
|
41
|
+
"default": "primary"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"required": [
|
|
45
|
+
"component"
|
|
46
|
+
],
|
|
47
|
+
"unevaluatedProperties": false,
|
|
48
|
+
"x-adiaui": {
|
|
49
|
+
"anti_patterns": [],
|
|
50
|
+
"category": "layout",
|
|
51
|
+
"events": {
|
|
52
|
+
"nav-select": {
|
|
53
|
+
"description": "Bubbles from <nav-item-ui> children when one is selected. Detail: { item, text, value }."
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"examples": [
|
|
57
|
+
{
|
|
58
|
+
"description": "App sidebar nav with groups + items.",
|
|
59
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Nav\",\n \"children\": [\"g1\", \"i1\"]\n },\n {\n \"id\": \"g1\",\n \"component\": \"NavGroup\",\n \"text\": \"Settings\",\n \"icon\": \"gear\",\n \"children\": [\"g1i1\"]\n },\n {\n \"id\": \"g1i1\",\n \"component\": \"NavItem\",\n \"text\": \"General\",\n \"value\": \"/settings/general\"\n },\n {\n \"id\": \"i1\",\n \"component\": \"NavItem\",\n \"text\": \"Profile\",\n \"icon\": \"user\",\n \"value\": \"/profile\"\n }\n]",
|
|
60
|
+
"name": "primary"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Subnav rail with heading.",
|
|
64
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Nav\",\n \"variant\": \"section\",\n \"heading\": \"On this page\",\n \"children\": [\"i1\", \"i2\"]\n },\n {\n \"id\": \"i1\",\n \"component\": \"NavItem\",\n \"text\": \"Overview\",\n \"value\": \"#overview\"\n },\n {\n \"id\": \"i2\",\n \"component\": \"NavItem\",\n \"text\": \"API\",\n \"value\": \"#api\"\n }\n]",
|
|
65
|
+
"name": "section"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"keywords": [
|
|
69
|
+
"nav",
|
|
70
|
+
"navigation",
|
|
71
|
+
"sidebar",
|
|
72
|
+
"menu",
|
|
73
|
+
"links"
|
|
74
|
+
],
|
|
75
|
+
"name": "UINav",
|
|
76
|
+
"related": [],
|
|
77
|
+
"slots": {
|
|
78
|
+
"default": {
|
|
79
|
+
"description": "Primary slot — accepts <nav-group-ui> + <nav-item-ui> children, plus <hr data-nav-divider> for hand-placed dividers."
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"states": [
|
|
83
|
+
{
|
|
84
|
+
"description": "Default, not collapsed.",
|
|
85
|
+
"name": "idle"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"description": "Primary variant when [collapsed] or container width <= 96px.",
|
|
89
|
+
"name": "collapsed"
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"synonyms": {},
|
|
93
|
+
"tag": "nav-ui",
|
|
94
|
+
"tokens": {},
|
|
95
|
+
"traits": [],
|
|
96
|
+
"version": 1
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* ═══════════════════════════════════════════
|
|
2
|
+
nav-ui — Consolidated navigation rail
|
|
3
|
+
Variants: primary (default, app sidebar) / section (subnav rail)
|
|
4
|
+
═══════════════════════════════════════════ */
|
|
5
|
+
|
|
6
|
+
@scope (nav-ui) {
|
|
7
|
+
:where(:scope) {
|
|
8
|
+
/* Shared */
|
|
9
|
+
--nav-gap: var(--a-space-1);
|
|
10
|
+
--nav-px: var(--a-space-2);
|
|
11
|
+
--nav-py: var(--a-space-2);
|
|
12
|
+
--nav-font-size: var(--a-ui-size);
|
|
13
|
+
--nav-bg: transparent;
|
|
14
|
+
--nav-divider-bg: var(--a-border-subtle);
|
|
15
|
+
--nav-divider-my: var(--a-space-1);
|
|
16
|
+
|
|
17
|
+
/* Primary-variant collapse */
|
|
18
|
+
--nav-width: auto;
|
|
19
|
+
--nav-width-collapsed: 48px;
|
|
20
|
+
--nav-duration: var(--a-duration-base, 200ms);
|
|
21
|
+
--nav-easing: var(--a-easing, ease);
|
|
22
|
+
|
|
23
|
+
/* Group-heading kicker */
|
|
24
|
+
--nav-label-fg: var(--a-fg-muted);
|
|
25
|
+
--nav-label-font-size: var(--a-kicker-sm);
|
|
26
|
+
--nav-label-weight: var(--a-weight-medium);
|
|
27
|
+
--nav-label-px: var(--a-space-2);
|
|
28
|
+
--nav-label-py: var(--a-space-3) var(--a-space-1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:scope {
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: var(--nav-gap);
|
|
36
|
+
padding: var(--nav-py) var(--nav-px);
|
|
37
|
+
background: var(--nav-bg);
|
|
38
|
+
font-size: var(--nav-font-size);
|
|
39
|
+
min-width: 0;
|
|
40
|
+
overflow-y: auto;
|
|
41
|
+
overflow-x: hidden;
|
|
42
|
+
scrollbar-width: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
:scope::-webkit-scrollbar { display: none; }
|
|
46
|
+
|
|
47
|
+
/* ── Primary variant (default) ── */
|
|
48
|
+
|
|
49
|
+
:scope:not([variant="section"]) {
|
|
50
|
+
width: var(--nav-width);
|
|
51
|
+
transition: width var(--nav-duration) var(--nav-easing);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:scope:not([variant="section"])[collapsed] {
|
|
55
|
+
width: var(--nav-width-collapsed);
|
|
56
|
+
--nav-px: var(--a-space-1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Container-query collapse — when nav lives in a sidebar that goes
|
|
60
|
+
narrow, behave as if [collapsed] regardless of attribute. */
|
|
61
|
+
@container sidebar (max-width: 96px) {
|
|
62
|
+
:scope:not([variant="section"]) {
|
|
63
|
+
--nav-px: var(--a-space-1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Group label kicker (group header text inside nav-group) */
|
|
68
|
+
[data-nav-label] {
|
|
69
|
+
display: block;
|
|
70
|
+
padding: var(--nav-label-py) var(--nav-label-px);
|
|
71
|
+
font-size: var(--nav-label-font-size);
|
|
72
|
+
font-weight: var(--nav-label-weight);
|
|
73
|
+
color: var(--nav-label-fg);
|
|
74
|
+
text-transform: uppercase;
|
|
75
|
+
letter-spacing: 0.06em;
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Hand-placed dividers */
|
|
81
|
+
[data-nav-divider] {
|
|
82
|
+
border: none;
|
|
83
|
+
height: 1px;
|
|
84
|
+
background: var(--nav-divider-bg);
|
|
85
|
+
margin: var(--nav-divider-my) 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Auto-dividers between groups when [divider] set */
|
|
89
|
+
:scope[divider] > nav-group-ui + nav-group-ui,
|
|
90
|
+
:scope[divider] > nav-item-ui + nav-group-ui,
|
|
91
|
+
:scope[divider] > nav-group-ui + nav-item-ui {
|
|
92
|
+
border-top: 1px solid var(--nav-divider-bg);
|
|
93
|
+
margin-top: var(--nav-divider-my);
|
|
94
|
+
padding-top: var(--nav-divider-my);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Spacer — pushes items below to bottom */
|
|
98
|
+
[data-nav-spacer] { flex: 1; }
|
|
99
|
+
|
|
100
|
+
/* Collapsed (primary): hide labels + dividers */
|
|
101
|
+
:scope:not([variant="section"])[collapsed] [data-nav-label],
|
|
102
|
+
:scope:not([variant="section"])[collapsed] [data-nav-divider] {
|
|
103
|
+
display: none;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@container sidebar (max-width: 96px) {
|
|
107
|
+
:scope:not([variant="section"]) [data-nav-label],
|
|
108
|
+
:scope:not([variant="section"]) [data-nav-divider] {
|
|
109
|
+
display: none;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ── Section variant ── */
|
|
114
|
+
|
|
115
|
+
:scope[variant="section"] {
|
|
116
|
+
--nav-px: 0;
|
|
117
|
+
--nav-py: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Heading rendered from [heading] attribute on section variant. */
|
|
121
|
+
:scope[variant="section"][heading]:not([heading=""])::before {
|
|
122
|
+
content: attr(heading);
|
|
123
|
+
display: block;
|
|
124
|
+
padding: var(--nav-label-py) var(--nav-label-px);
|
|
125
|
+
font-size: var(--nav-label-font-size);
|
|
126
|
+
font-weight: var(--nav-label-weight);
|
|
127
|
+
color: var(--nav-label-fg);
|
|
128
|
+
text-transform: uppercase;
|
|
129
|
+
letter-spacing: 0.06em;
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <nav-ui> — Navigation rail (consolidated primary + section variants).
|
|
3
|
+
*
|
|
4
|
+
* Consolidates the prior `app-nav-ui` + `section-nav-ui` dual-family
|
|
5
|
+
* per ADR-0015 § Nav consolidation. Variant drives visual treatment;
|
|
6
|
+
* behavior is unified.
|
|
7
|
+
*
|
|
8
|
+
* Variants:
|
|
9
|
+
* primary — default. App sidebar. ResizeObserver collapses to icon-only
|
|
10
|
+
* below 96px container width or when [collapsed] set; groups
|
|
11
|
+
* open a popover with their children when collapsed.
|
|
12
|
+
* section — subnav rail. Quieter chrome; no collapse behavior.
|
|
13
|
+
* Optional [heading] attribute renders an uppercase label
|
|
14
|
+
* via ::before pseudo (CSS-only).
|
|
15
|
+
*
|
|
16
|
+
* Structure:
|
|
17
|
+
* <nav-ui>
|
|
18
|
+
* <nav-group-ui icon="gear" text="Settings" badge="3">
|
|
19
|
+
* <nav-item-ui text="General" value="/settings/general"></nav-item-ui>
|
|
20
|
+
* </nav-group-ui>
|
|
21
|
+
* <nav-item-ui icon="user" text="Profile" value="/profile"></nav-item-ui>
|
|
22
|
+
* </nav-ui>
|
|
23
|
+
*
|
|
24
|
+
* <nav-ui variant="section" heading="On this page">
|
|
25
|
+
* <nav-item-ui text="Overview" value="#overview"></nav-item-ui>
|
|
26
|
+
* </nav-ui>
|
|
27
|
+
*
|
|
28
|
+
* Event: nav-select (bubbles from nav-item-ui). detail: { item, text, value }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { UIElement } from '../../core/element.js';
|
|
32
|
+
|
|
33
|
+
class UINav extends UIElement {
|
|
34
|
+
static properties = {
|
|
35
|
+
variant: { type: String, default: 'primary', reflect: true },
|
|
36
|
+
collapsed: { type: Boolean, default: false, reflect: true },
|
|
37
|
+
divider: { type: Boolean, default: false, reflect: true },
|
|
38
|
+
heading: { type: String, default: '', reflect: true },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
static template = () => null;
|
|
42
|
+
|
|
43
|
+
#ro = null;
|
|
44
|
+
|
|
45
|
+
connected() {
|
|
46
|
+
this.setAttribute('role', 'navigation');
|
|
47
|
+
if (this.heading) this.setAttribute('aria-label', this.heading);
|
|
48
|
+
this.addEventListener('click', this.#onClick);
|
|
49
|
+
|
|
50
|
+
// ResizeObserver only meaningful for primary variant — section is static.
|
|
51
|
+
if (this.variant !== 'section') {
|
|
52
|
+
this.#ro = new ResizeObserver(() => this.#updateTooltips());
|
|
53
|
+
this.#ro.observe(this);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
render() {
|
|
58
|
+
if (this.heading) this.setAttribute('aria-label', this.heading);
|
|
59
|
+
else this.removeAttribute('aria-label');
|
|
60
|
+
if (this.variant !== 'section') this.#updateTooltips();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#updateTooltips() {
|
|
64
|
+
const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
|
|
65
|
+
for (const group of this.querySelectorAll(':scope > nav-group-ui')) {
|
|
66
|
+
const header = group.querySelector(':scope > [slot="header"]');
|
|
67
|
+
if (header) header.title = isCollapsed ? group.text : '';
|
|
68
|
+
}
|
|
69
|
+
for (const item of this.querySelectorAll(':scope > nav-item-ui')) {
|
|
70
|
+
item.title = isCollapsed ? item.text : '';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get selectedItem() {
|
|
75
|
+
return this.querySelector('nav-item-ui[selected]');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
select(item) {
|
|
79
|
+
const prev = this.selectedItem;
|
|
80
|
+
if (prev && prev !== item) prev.removeAttribute('selected');
|
|
81
|
+
if (item) {
|
|
82
|
+
item.setAttribute('selected', '');
|
|
83
|
+
this.dispatchEvent(new CustomEvent('nav-select', {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
detail: { item, text: item.text, value: item.value },
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
toggle() {
|
|
91
|
+
if (this.variant === 'section') return; // no-op for section variant
|
|
92
|
+
this.collapsed = !this.collapsed;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#onClick = (e) => {
|
|
96
|
+
const item = e.target.closest('nav-item-ui');
|
|
97
|
+
if (item && this.contains(item)) {
|
|
98
|
+
if (item.disabled) return;
|
|
99
|
+
this.select(item);
|
|
100
|
+
this.#flushHoverState();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Group expand/popover — primary variant only.
|
|
105
|
+
if (this.variant === 'section') return;
|
|
106
|
+
|
|
107
|
+
const group = e.target.closest('nav-group-ui');
|
|
108
|
+
if (group && this.contains(group)) {
|
|
109
|
+
const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
|
|
110
|
+
if (isCollapsed) {
|
|
111
|
+
group.showPopover?.();
|
|
112
|
+
} else {
|
|
113
|
+
const header = group.querySelector(':scope > [slot="header"]');
|
|
114
|
+
if (header && (e.target === header || header.contains(e.target))) {
|
|
115
|
+
group.open = !group.open;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Safari macOS leaves :hover stuck on items the cursor passed through
|
|
122
|
+
// when the DOM mutates during click+route navigation. Toggling pointer-
|
|
123
|
+
// events forces re-evaluation of hover state on next paint.
|
|
124
|
+
// See docs/BROWSER-COMPAT.md §3a.
|
|
125
|
+
#flushHoverState() {
|
|
126
|
+
this.style.pointerEvents = 'none';
|
|
127
|
+
requestAnimationFrame(() => {
|
|
128
|
+
this.style.pointerEvents = '';
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
disconnected() {
|
|
133
|
+
this.removeEventListener('click', this.#onClick);
|
|
134
|
+
this.#ro?.disconnect();
|
|
135
|
+
this.#ro = null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
customElements.define('nav-ui', UINav);
|
|
140
|
+
export { UINav };
|