@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.58 → 2.0.0-next.60
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/bundle/openbridge-webcomponents.bundle.js +8144 -5241
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +1937 -78
- package/dist/alert-severity.d.ts +38 -0
- package/dist/alert-severity.d.ts.map +1 -0
- package/dist/alert-severity.js +176 -0
- package/dist/alert-severity.js.map +1 -0
- package/dist/ar/building-blocks/poi-header/poi-header.css.js +38 -7
- package/dist/ar/building-blocks/poi-header/poi-header.css.js.map +1 -1
- package/dist/ar/building-blocks/poi-header/poi-header.d.ts +7 -2
- package/dist/ar/building-blocks/poi-header/poi-header.d.ts.map +1 -1
- package/dist/ar/building-blocks/poi-header/poi-header.js +5 -0
- package/dist/ar/building-blocks/poi-header/poi-header.js.map +1 -1
- package/dist/ar/poi-button/poi-button.css.js +110 -32
- package/dist/ar/poi-button/poi-button.css.js.map +1 -1
- package/dist/ar/poi-button/poi-button.d.ts +7 -2
- package/dist/ar/poi-button/poi-button.d.ts.map +1 -1
- package/dist/ar/poi-button/poi-button.js +15 -0
- package/dist/ar/poi-button/poi-button.js.map +1 -1
- package/dist/ar/types.d.ts +6 -1
- package/dist/ar/types.d.ts.map +1 -1
- package/dist/ar/types.js +5 -0
- package/dist/ar/types.js.map +1 -1
- package/dist/automation/automation-badge/automation-badge.d.ts +9 -1
- package/dist/automation/automation-badge/automation-badge.d.ts.map +1 -1
- package/dist/automation/automation-badge/automation-badge.js +119 -12
- package/dist/automation/automation-badge/automation-badge.js.map +1 -1
- package/dist/automation/automation-button/abstract-automation-button-storybook-helpers.d.ts +25 -1
- package/dist/automation/automation-button/abstract-automation-button-storybook-helpers.d.ts.map +1 -1
- package/dist/automation/automation-button/abstract-automation-button-storybook-helpers.js +7 -2
- package/dist/automation/automation-button/abstract-automation-button-storybook-helpers.js.map +1 -1
- package/dist/automation/automation-button/abstract-automation-button.d.ts +10 -3
- package/dist/automation/automation-button/abstract-automation-button.d.ts.map +1 -1
- package/dist/automation/automation-button/abstract-automation-button.js +23 -2
- package/dist/automation/automation-button/abstract-automation-button.js.map +1 -1
- package/dist/automation/automation-button/automation-button.css.js +9 -4
- package/dist/automation/automation-button/automation-button.css.js.map +1 -1
- package/dist/automation/automation-button/automation-button.d.ts +4 -2
- package/dist/automation/automation-button/automation-button.d.ts.map +1 -1
- package/dist/automation/automation-button/automation-button.js +24 -6
- package/dist/automation/automation-button/automation-button.js.map +1 -1
- package/dist/automation/automation-tank/automation-tank.d.ts +3 -2
- package/dist/automation/automation-tank/automation-tank.d.ts.map +1 -1
- package/dist/automation/automation-tank/automation-tank.js +13 -2
- package/dist/automation/automation-tank/automation-tank.js.map +1 -1
- package/dist/components/accordion-card/accordion-card.css.js +34 -0
- package/dist/components/accordion-card/accordion-card.css.js.map +1 -1
- package/dist/components/accordion-card/accordion-card.d.ts +3 -2
- package/dist/components/accordion-card/accordion-card.d.ts.map +1 -1
- package/dist/components/accordion-card/accordion-card.js +4 -3
- package/dist/components/accordion-card/accordion-card.js.map +1 -1
- package/dist/components/alert-button/alert-button.css.js +744 -7
- package/dist/components/alert-button/alert-button.css.js.map +1 -1
- package/dist/components/alert-button/alert-button.d.ts +3 -1
- package/dist/components/alert-button/alert-button.d.ts.map +1 -1
- package/dist/components/alert-button/alert-button.js +33 -31
- package/dist/components/alert-button/alert-button.js.map +1 -1
- package/dist/components/alert-frame/alert-frame.css.js +116 -29
- package/dist/components/alert-frame/alert-frame.css.js.map +1 -1
- package/dist/components/alert-frame/alert-frame.d.ts +42 -15
- package/dist/components/alert-frame/alert-frame.d.ts.map +1 -1
- package/dist/components/alert-frame/alert-frame.js +68 -17
- package/dist/components/alert-frame/alert-frame.js.map +1 -1
- package/dist/components/alert-frame/critical-badge.d.ts +12 -0
- package/dist/components/alert-frame/critical-badge.d.ts.map +1 -0
- package/dist/components/alert-frame/critical-badge.js +47 -0
- package/dist/components/alert-frame/critical-badge.js.map +1 -0
- package/dist/components/alert-frame/diagnostic-badge.d.ts +12 -0
- package/dist/components/alert-frame/diagnostic-badge.d.ts.map +1 -0
- package/dist/components/alert-frame/diagnostic-badge.js +60 -0
- package/dist/components/alert-frame/diagnostic-badge.js.map +1 -0
- package/dist/components/alert-icon/alert-icon.d.ts +6 -1
- package/dist/components/alert-icon/alert-icon.d.ts.map +1 -1
- package/dist/components/alert-icon/alert-icon.js +96 -38
- package/dist/components/alert-icon/alert-icon.js.map +1 -1
- package/dist/components/alert-icon/icons/icon-critical.d.ts +3 -0
- package/dist/components/alert-icon/icons/icon-critical.d.ts.map +1 -0
- package/dist/components/alert-icon/icons/icon-critical.js +26 -0
- package/dist/components/alert-icon/icons/icon-critical.js.map +1 -0
- package/dist/components/alert-list-details/alert-list-details.d.ts.map +1 -1
- package/dist/components/alert-list-details/alert-list-details.js +6 -7
- package/dist/components/alert-list-details/alert-list-details.js.map +1 -1
- package/dist/components/badge/badge.css.js +50 -2
- package/dist/components/badge/badge.css.js.map +1 -1
- package/dist/components/badge/badge.d.ts +13 -2
- package/dist/components/badge/badge.d.ts.map +1 -1
- package/dist/components/badge/badge.js +54 -0
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/navigation-item/navigation-item.css.js +5 -0
- package/dist/components/navigation-item/navigation-item.css.js.map +1 -1
- package/dist/components/navigation-item/navigation-item.d.ts +18 -0
- package/dist/components/navigation-item/navigation-item.d.ts.map +1 -1
- package/dist/components/navigation-item/navigation-item.js +49 -1
- package/dist/components/navigation-item/navigation-item.js.map +1 -1
- package/dist/components/navigation-item-group/navigation-item-group.css.js +8 -0
- package/dist/components/navigation-item-group/navigation-item-group.css.js.map +1 -1
- package/dist/components/navigation-item-group/navigation-item-group.d.ts +22 -0
- package/dist/components/navigation-item-group/navigation-item-group.d.ts.map +1 -1
- package/dist/components/navigation-item-group/navigation-item-group.js +63 -1
- package/dist/components/navigation-item-group/navigation-item-group.js.map +1 -1
- package/dist/components/navigation-menu/navigation-menu.d.ts +29 -1
- package/dist/components/navigation-menu/navigation-menu.d.ts.map +1 -1
- package/dist/components/navigation-menu/navigation-menu.js +105 -0
- package/dist/components/navigation-menu/navigation-menu.js.map +1 -1
- package/dist/components/tree-navigation/tree-navigation.css.js +18 -0
- package/dist/components/tree-navigation/tree-navigation.css.js.map +1 -0
- package/dist/components/tree-navigation/tree-navigation.d.ts +74 -0
- package/dist/components/tree-navigation/tree-navigation.d.ts.map +1 -0
- package/dist/components/tree-navigation/tree-navigation.js +120 -0
- package/dist/components/tree-navigation/tree-navigation.js.map +1 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.css.js +22 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.css.js.map +1 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.d.ts +94 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.d.ts.map +1 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.js +116 -0
- package/dist/components/tree-navigation-group/tree-navigation-group.js.map +1 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.css.js +429 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.css.js.map +1 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.d.ts +160 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.d.ts.map +1 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.js +208 -0
- package/dist/components/tree-navigation-item/tree-navigation-item.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/internal/tree-roving-navigator.d.ts +71 -0
- package/dist/internal/tree-roving-navigator.d.ts.map +1 -0
- package/dist/internal/tree-roving-navigator.js +172 -0
- package/dist/internal/tree-roving-navigator.js.map +1 -0
- package/dist/manual-icon/icon-alerts-critical-twotone.d.ts +30 -0
- package/dist/manual-icon/icon-alerts-critical-twotone.d.ts.map +1 -0
- package/dist/manual-icon/icon-alerts-critical-twotone.js +55 -0
- package/dist/manual-icon/icon-alerts-critical-twotone.js.map +1 -0
- package/dist/manual-icon/icon-alerts-diagnostic-twotone.d.ts +30 -0
- package/dist/manual-icon/icon-alerts-diagnostic-twotone.d.ts.map +1 -0
- package/dist/manual-icon/icon-alerts-diagnostic-twotone.js +55 -0
- package/dist/manual-icon/icon-alerts-diagnostic-twotone.js.map +1 -0
- package/dist/navigation-instruments/readout/readout.css.js +3 -18
- package/dist/navigation-instruments/readout/readout.css.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.d.ts +6 -7
- package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout.js +54 -52
- package/dist/navigation-instruments/readout/readout.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js +9 -36
- package/dist/navigation-instruments/readout-list-item/readout-list-item.css.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +8 -8
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js +49 -42
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/dist/openbridge.css +155 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +18 -7
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/alert-severity.ts +225 -0
- package/src/ar/building-blocks/poi-header/poi-header.css +38 -7
- package/src/ar/building-blocks/poi-header/poi-header.ts +6 -1
- package/src/ar/poi-button/poi-button.css +126 -32
- package/src/ar/poi-button/poi-button.ts +16 -1
- package/src/ar/types.ts +5 -0
- package/src/automation/automation-badge/automation-badge.ts +124 -17
- package/src/automation/automation-button/abstract-automation-button-storybook-helpers.ts +5 -0
- package/src/automation/automation-button/abstract-automation-button.ts +21 -3
- package/src/automation/automation-button/automation-button.css +9 -4
- package/src/automation/automation-button/automation-button.ts +25 -7
- package/src/automation/automation-tank/automation-tank.stories.ts +22 -0
- package/src/automation/automation-tank/automation-tank.ts +12 -3
- package/src/components/accordion-card/accordion-card.css +33 -0
- package/src/components/accordion-card/accordion-card.stories.ts +2 -1
- package/src/components/accordion-card/accordion-card.ts +3 -4
- package/src/components/alert-button/alert-button.css +89 -5
- package/src/components/alert-button/alert-button.stories.ts +43 -0
- package/src/components/alert-button/alert-button.ts +43 -32
- package/src/components/alert-frame/alert-frame.css +116 -29
- package/src/components/alert-frame/alert-frame.stories.ts +63 -3
- package/src/components/alert-frame/alert-frame.ts +114 -23
- package/src/components/alert-frame/critical-badge.ts +39 -0
- package/src/components/alert-frame/diagnostic-badge.ts +52 -0
- package/src/components/alert-icon/alert-icon.stories.ts +41 -0
- package/src/components/alert-icon/alert-icon.ts +101 -38
- package/src/components/alert-icon/icons/icon-critical.ts +23 -0
- package/src/components/alert-list-details/alert-list-details.stories.ts +67 -0
- package/src/components/alert-list-details/alert-list-details.ts +11 -10
- package/src/components/badge/badge.css +52 -2
- package/src/components/badge/badge.stories.ts +75 -0
- package/src/components/badge/badge.ts +70 -2
- package/src/components/navigation-item/navigation-item.css +5 -0
- package/src/components/navigation-item/navigation-item.ts +56 -1
- package/src/components/navigation-item-group/navigation-item-group.css +8 -0
- package/src/components/navigation-item-group/navigation-item-group.ts +71 -1
- package/src/components/navigation-menu/navigation-menu.stories.ts +54 -0
- package/src/components/navigation-menu/navigation-menu.ts +151 -0
- package/src/components/tree-navigation/tree-navigation.css +7 -0
- package/src/components/tree-navigation/tree-navigation.stories.ts +162 -0
- package/src/components/tree-navigation/tree-navigation.ts +188 -0
- package/src/components/tree-navigation-group/tree-navigation-group.css +11 -0
- package/src/components/tree-navigation-group/tree-navigation-group.ts +157 -0
- package/src/components/tree-navigation-item/tree-navigation-item.css +258 -0
- package/src/components/tree-navigation-item/tree-navigation-item.stories.ts +119 -0
- package/src/components/tree-navigation-item/tree-navigation-item.ts +307 -0
- package/src/internal/tree-roving-navigator.ts +231 -0
- package/src/main.css +1 -0
- package/src/manual-icon/icon-alerts-critical-twotone.ts +60 -0
- package/src/manual-icon/icon-alerts-diagnostic-twotone.ts +60 -0
- package/src/mixins/alert.css +29 -0
- package/src/navigation-instruments/readout/readout.css +3 -24
- package/src/navigation-instruments/readout/readout.stories.ts +57 -4
- package/src/navigation-instruments/readout/readout.ts +69 -63
- package/src/navigation-instruments/readout-list-item/readout-list-item.css +9 -42
- package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +57 -14
- package/src/navigation-instruments/readout-list-item/readout-list-item.ts +54 -44
- package/src/palettes/critical.md +95 -0
- package/src/palettes/manual.css +165 -0
- package/src/types.ts +20 -3
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import {LitElement, html, unsafeCSS} from 'lit';
|
|
2
|
+
import componentStyle from './tree-navigation.css?inline';
|
|
3
|
+
import {customElement} from '../../decorator.js';
|
|
4
|
+
import {
|
|
5
|
+
ObcTreeNavigationItem,
|
|
6
|
+
TreeBranchType,
|
|
7
|
+
} from '../tree-navigation-item/tree-navigation-item.js';
|
|
8
|
+
import {ObcTreeNavigationGroup} from '../tree-navigation-group/tree-navigation-group.js';
|
|
9
|
+
import '../tree-navigation-group/tree-navigation-group.js';
|
|
10
|
+
import {
|
|
11
|
+
TreeRovingNavigator,
|
|
12
|
+
TreeRovingAdapter,
|
|
13
|
+
} from '../../internal/tree-roving-navigator.js';
|
|
14
|
+
|
|
15
|
+
/** A tree row is either a leaf item or an expandable group. */
|
|
16
|
+
type TreeRow = ObcTreeNavigationItem | ObcTreeNavigationGroup;
|
|
17
|
+
|
|
18
|
+
const ITEM_TAG = 'obc-tree-navigation-item';
|
|
19
|
+
const GROUP_TAG = 'obc-tree-navigation-group';
|
|
20
|
+
|
|
21
|
+
function isGroup(el: Element): el is ObcTreeNavigationGroup {
|
|
22
|
+
return el.tagName.toLowerCase() === GROUP_TAG;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isRow(el: Element): el is TreeRow {
|
|
26
|
+
const tag = el.tagName.toLowerCase();
|
|
27
|
+
return tag === ITEM_TAG || tag === GROUP_TAG;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* `<obc-tree-navigation>` – The container for a tree- or file-explorer-style
|
|
32
|
+
* navigation list. Holds nested `<obc-tree-navigation-group>` and
|
|
33
|
+
* `<obc-tree-navigation-item>` rows and computes each row's indentation guide
|
|
34
|
+
* lines automatically from its position in the hierarchy.
|
|
35
|
+
*
|
|
36
|
+
* Consumers write the tree as plain nested markup; the container assigns every
|
|
37
|
+
* row's `branches` array so the guide lines (pass-through verticals, elbows, and
|
|
38
|
+
* the last-child corner) connect correctly — there is no need to compute depth or
|
|
39
|
+
* branch types by hand. It re-derives the guides whenever rows are added, removed,
|
|
40
|
+
* or groups expand and collapse.
|
|
41
|
+
*
|
|
42
|
+
* ## Features
|
|
43
|
+
* - **Automatic guide lines:** Each row receives a `branches` array derived from
|
|
44
|
+
* its depth and whether each ancestor still has siblings below it. Last children
|
|
45
|
+
* get a corner (`└`); rows with siblings below get an intersection (`├`); and
|
|
46
|
+
* ancestor columns become a pass-through (`│`) or blank as appropriate.
|
|
47
|
+
* - **Live updates:** Reacts to slotted content changes and to group expand state,
|
|
48
|
+
* recomputing the guides so they always match the visible structure.
|
|
49
|
+
* - **Composable:** Works with any nesting depth of groups and items.
|
|
50
|
+
*
|
|
51
|
+
* ## Usage Guidelines
|
|
52
|
+
* - Use as the root of a hierarchical navigation list. For flat navigation, use
|
|
53
|
+
* `obc-navigation-menu` instead.
|
|
54
|
+
* - Place `<obc-tree-navigation-group>` for expandable parents and
|
|
55
|
+
* `<obc-tree-navigation-item>` for leaves; nest groups to any depth.
|
|
56
|
+
* - Do not set each row's `branches` manually — the container manages them.
|
|
57
|
+
*
|
|
58
|
+
* ## Slots
|
|
59
|
+
*
|
|
60
|
+
* | Slot Name | Renders When... | Purpose |
|
|
61
|
+
* |-----------|-----------------|----------------------------------------------------|
|
|
62
|
+
* | (default) | Always | Top-level rows (`obc-tree-navigation-group`/`-item`). |
|
|
63
|
+
*
|
|
64
|
+
* @slot - Top-level tree rows (groups and items).
|
|
65
|
+
*/
|
|
66
|
+
@customElement('obc-tree-navigation')
|
|
67
|
+
export class ObcTreeNavigation extends LitElement {
|
|
68
|
+
private mutationObserver?: MutationObserver;
|
|
69
|
+
|
|
70
|
+
/** The focusable header item for a row: a leaf is itself; a group's is its shadow header. */
|
|
71
|
+
private innerItem(row: TreeRow): ObcTreeNavigationItem | null {
|
|
72
|
+
return isGroup(row)
|
|
73
|
+
? (row.shadowRoot?.querySelector<ObcTreeNavigationItem>(ITEM_TAG) ?? null)
|
|
74
|
+
: row;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private readonly navigator = new TreeRovingNavigator<TreeRow>(this, {
|
|
78
|
+
getRows: () => this.childRows(this),
|
|
79
|
+
childRows: (row) => this.childRows(row),
|
|
80
|
+
isGroup: (row) => isGroup(row),
|
|
81
|
+
isExpanded: (row) => isGroup(row) && row.hasAttribute('expanded'),
|
|
82
|
+
setExpanded: (row, expanded) => {
|
|
83
|
+
if (isGroup(row)) row.expanded = expanded;
|
|
84
|
+
},
|
|
85
|
+
innerItem: (row) => this.innerItem(row),
|
|
86
|
+
isDisabled: (row) => this.innerItem(row)?.hasAttribute('disabled') ?? false,
|
|
87
|
+
} satisfies TreeRovingAdapter<TreeRow>);
|
|
88
|
+
|
|
89
|
+
override connectedCallback(): void {
|
|
90
|
+
super.connectedCallback();
|
|
91
|
+
// Recompute guides on any structural change: rows added/removed, or a group's
|
|
92
|
+
// `expanded` attribute toggled anywhere in the subtree.
|
|
93
|
+
this.mutationObserver = new MutationObserver(() => this.updateBranches());
|
|
94
|
+
this.mutationObserver.observe(this, {
|
|
95
|
+
childList: true,
|
|
96
|
+
subtree: true,
|
|
97
|
+
attributes: true,
|
|
98
|
+
attributeFilter: ['expanded'],
|
|
99
|
+
});
|
|
100
|
+
this.addEventListener('expand-toggle', this.onExpandToggle);
|
|
101
|
+
this.addEventListener('keydown', this.onKeydown);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private onKeydown = (event: KeyboardEvent): void => {
|
|
105
|
+
if (this.navigator.handleKeydown(event)) event.preventDefault();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
override disconnectedCallback(): void {
|
|
109
|
+
super.disconnectedCallback();
|
|
110
|
+
this.mutationObserver?.disconnect();
|
|
111
|
+
this.mutationObserver = undefined;
|
|
112
|
+
this.removeEventListener('expand-toggle', this.onExpandToggle);
|
|
113
|
+
this.removeEventListener('keydown', this.onKeydown);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private onExpandToggle = () => {
|
|
117
|
+
// Defer so the group's `expanded` attribute and slotted children reflect the
|
|
118
|
+
// new state before guides are recomputed.
|
|
119
|
+
queueMicrotask(() => this.updateBranches());
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
override firstUpdated(): void {
|
|
123
|
+
this.updateBranches();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Direct tree-row children of an element, in document order. */
|
|
127
|
+
private childRows(el: Element): TreeRow[] {
|
|
128
|
+
return Array.from(el.children).filter(isRow);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Walk the row tree and assign each row's `branches`. Mirrors the guide-line
|
|
133
|
+
* model: a row gets one column per ancestor (pass-through `straight` if that
|
|
134
|
+
* ancestor still has siblings below, else `blank`) followed by its own elbow
|
|
135
|
+
* (`corner` if it is the last child, else `intersection`). Top-level rows draw
|
|
136
|
+
* no columns at all.
|
|
137
|
+
*
|
|
138
|
+
* @param rows - sibling rows at this level, in order
|
|
139
|
+
* @param ancestorHasNextSibling - one flag per ancestor *below the root*: true
|
|
140
|
+
* if that ancestor has a sibling still below it (so its column is a
|
|
141
|
+
* pass-through), false if its subtree has ended (a blank column)
|
|
142
|
+
* @param depth - nesting depth; 0 for top-level rows (which draw no columns)
|
|
143
|
+
*/
|
|
144
|
+
private assignBranches(
|
|
145
|
+
rows: TreeRow[],
|
|
146
|
+
ancestorHasNextSibling: boolean[],
|
|
147
|
+
depth: number
|
|
148
|
+
): void {
|
|
149
|
+
rows.forEach((row, index) => {
|
|
150
|
+
const isLast = index === rows.length - 1;
|
|
151
|
+
row.branches =
|
|
152
|
+
depth === 0
|
|
153
|
+
? []
|
|
154
|
+
: [
|
|
155
|
+
...ancestorHasNextSibling.map((hasNext) =>
|
|
156
|
+
hasNext ? TreeBranchType.straight : TreeBranchType.blank
|
|
157
|
+
),
|
|
158
|
+
isLast ? TreeBranchType.corner : TreeBranchType.intersection,
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
if (isGroup(row)) {
|
|
162
|
+
const childAncestry =
|
|
163
|
+
depth === 0 ? [] : [...ancestorHasNextSibling, !isLast];
|
|
164
|
+
this.assignBranches(this.childRows(row), childAncestry, depth + 1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private updateBranches(): void {
|
|
170
|
+
this.assignBranches(this.childRows(this), [], 0);
|
|
171
|
+
// Keep the roving tabindex in lockstep with the visible structure.
|
|
172
|
+
this.navigator.refresh();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
override render() {
|
|
176
|
+
return html`<div role="tree">
|
|
177
|
+
<slot @slotchange=${() => this.updateBranches()}></slot>
|
|
178
|
+
</div>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static override styles = unsafeCSS(componentStyle);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
declare global {
|
|
185
|
+
interface HTMLElementTagNameMap {
|
|
186
|
+
'obc-tree-navigation': ObcTreeNavigation;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {LitElement, html, nothing, unsafeCSS} from 'lit';
|
|
2
|
+
import {property, query} from 'lit/decorators.js';
|
|
3
|
+
import componentStyle from './tree-navigation-group.css?inline';
|
|
4
|
+
import {customElement} from '../../decorator.js';
|
|
5
|
+
import {
|
|
6
|
+
ObcTreeNavigationItem,
|
|
7
|
+
TreeBranchType,
|
|
8
|
+
TreeTerminalType,
|
|
9
|
+
} from '../tree-navigation-item/tree-navigation-item.js';
|
|
10
|
+
import '../tree-navigation-item/tree-navigation-item.js';
|
|
11
|
+
import {BadgeType} from '../badge/badge.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `<obc-tree-navigation-group>` – An expandable parent row in a tree-navigation
|
|
15
|
+
* structure: a header row with an expand/collapse chevron, plus a slot for the
|
|
16
|
+
* child rows it discloses.
|
|
17
|
+
*
|
|
18
|
+
* A group renders an `<obc-tree-navigation-item>` header (carrying its own label,
|
|
19
|
+
* icon, terminal type, and alert badge) followed by its slotted children. When
|
|
20
|
+
* placed inside `<obc-tree-navigation>`, the container computes and assigns the
|
|
21
|
+
* `branches` guide lines for every row automatically from each row's position —
|
|
22
|
+
* a group does not need its depth configured by hand.
|
|
23
|
+
*
|
|
24
|
+
* The group manages only its own open/closed state and forwards header presentation
|
|
25
|
+
* to its internal header item. It does not draw guide lines itself; that is the
|
|
26
|
+
* container's responsibility (see `<obc-tree-navigation>`).
|
|
27
|
+
*
|
|
28
|
+
* ## Features
|
|
29
|
+
* - **Disclosure:** A chevron in the header toggles the slotted children. The open
|
|
30
|
+
* state is held in `expanded` and reflected so the container and CSS can react.
|
|
31
|
+
* - **Header presentation:** `label`, the `icon` slot, `terminalType`, and the
|
|
32
|
+
* alert badge (`hasAlertBadge`, `alertCount`, `alertType`) are forwarded to the
|
|
33
|
+
* header row.
|
|
34
|
+
* - **Selection:** `checked` marks the group's header as the current item.
|
|
35
|
+
* - **Automatic guides:** Inside `<obc-tree-navigation>`, the header's `branches`
|
|
36
|
+
* are assigned by the container; nested groups continue the guide columns down.
|
|
37
|
+
*
|
|
38
|
+
* ## Usage Guidelines
|
|
39
|
+
* - Nest `<obc-tree-navigation-item>` (leaves) and further `<obc-tree-navigation-group>`
|
|
40
|
+
* elements as children to build the hierarchy.
|
|
41
|
+
* - Always place groups and items inside an `<obc-tree-navigation>` container so the
|
|
42
|
+
* guide lines are computed; using a group standalone draws a header with no guides.
|
|
43
|
+
* - Provide a header icon via the `icon` slot (forwarded to the header row).
|
|
44
|
+
*
|
|
45
|
+
* ## Slots
|
|
46
|
+
*
|
|
47
|
+
* | Slot Name | Renders When... | Purpose |
|
|
48
|
+
* |-----------|--------------------------|--------------------------------------------------------------|
|
|
49
|
+
* | icon | `hasIcon` is true | Leading icon for the group header row. |
|
|
50
|
+
* | (default) | Always | Child rows (`obc-tree-navigation-item` / `-group`). |
|
|
51
|
+
*
|
|
52
|
+
* @slot icon - Leading icon for the group header (shown when `hasIcon` is true).
|
|
53
|
+
* @slot - Child rows disclosed when the group is expanded.
|
|
54
|
+
* @fires expand-toggle {CustomEvent<boolean>} Fired when the header is activated; detail is the next `expanded` value.
|
|
55
|
+
*/
|
|
56
|
+
@customElement('obc-tree-navigation-group')
|
|
57
|
+
export class ObcTreeNavigationGroup extends LitElement {
|
|
58
|
+
/** The text label displayed for the group header row. */
|
|
59
|
+
@property({type: String}) label = 'Group';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Guide line to draw for each ancestor level of the header row. Normally set by
|
|
63
|
+
* the parent `<obc-tree-navigation>` container from the group's position; only
|
|
64
|
+
* set it manually when using a group outside the container.
|
|
65
|
+
*/
|
|
66
|
+
@property({type: Array}) branches: TreeBranchType[] = [];
|
|
67
|
+
|
|
68
|
+
/** Whether the group is expanded, disclosing its children. Rotates the chevron. */
|
|
69
|
+
@property({type: Boolean, reflect: true}) expanded = false;
|
|
70
|
+
|
|
71
|
+
/** Whether the group header is the current selection. */
|
|
72
|
+
@property({type: Boolean, reflect: true}) checked = false;
|
|
73
|
+
|
|
74
|
+
/** Disables the group header, removing it from the tab order and dimming it. */
|
|
75
|
+
@property({type: Boolean, reflect: true}) disabled = false;
|
|
76
|
+
|
|
77
|
+
/** Whether the group header shows a leading icon (provided via the `icon` slot). */
|
|
78
|
+
@property({type: Boolean, attribute: false}) hasIcon = true;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Terminal type for the header row, controlling the alert-header marker shown in
|
|
82
|
+
* the terminal. One of `regular` (default), `aggregated-header`, or `group-header`.
|
|
83
|
+
*/
|
|
84
|
+
@property({type: String}) terminalType: string = TreeTerminalType.regular;
|
|
85
|
+
|
|
86
|
+
/** Whether a trailing alert counter badge is shown on the header row. */
|
|
87
|
+
@property({type: Boolean}) hasAlertBadge = false;
|
|
88
|
+
|
|
89
|
+
/** The number shown in the header's alert badge when `hasAlertBadge` is true. */
|
|
90
|
+
@property({type: Number}) alertCount = 0;
|
|
91
|
+
|
|
92
|
+
/** The severity/type of the header's alert badge. One of the `obc-badge` types (default `alarm`). */
|
|
93
|
+
@property({type: String}) alertType: string = BadgeType.alarm;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The URL to navigate to when the header is activated. If set, the header row
|
|
97
|
+
* renders as a link; otherwise it acts as a button.
|
|
98
|
+
*/
|
|
99
|
+
@property({type: String}) href: string | undefined;
|
|
100
|
+
|
|
101
|
+
@query('obc-tree-navigation-item') private headerItem?: ObcTreeNavigationItem;
|
|
102
|
+
|
|
103
|
+
private onHeaderToggle(event: CustomEvent<boolean>) {
|
|
104
|
+
this.expanded = event.detail;
|
|
105
|
+
this.dispatchEvent(
|
|
106
|
+
new CustomEvent<boolean>('expand-toggle', {detail: this.expanded})
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Closes the group (and, recursively, any nested groups inside it). */
|
|
111
|
+
close() {
|
|
112
|
+
this.expanded = false;
|
|
113
|
+
this.querySelectorAll('obc-tree-navigation-group').forEach((group) =>
|
|
114
|
+
group.close()
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public override focus(options?: FocusOptions): void {
|
|
119
|
+
this.headerItem?.focus(options);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override render() {
|
|
123
|
+
return html`
|
|
124
|
+
<obc-tree-navigation-item
|
|
125
|
+
part="header"
|
|
126
|
+
.label=${this.label}
|
|
127
|
+
.branches=${this.branches}
|
|
128
|
+
expandable
|
|
129
|
+
?expanded=${this.expanded}
|
|
130
|
+
?checked=${this.checked}
|
|
131
|
+
?disabled=${this.disabled}
|
|
132
|
+
.hasLeadingIcon=${this.hasIcon}
|
|
133
|
+
.terminalType=${this.terminalType}
|
|
134
|
+
?hasAlertBadge=${this.hasAlertBadge}
|
|
135
|
+
.alertCount=${this.alertCount}
|
|
136
|
+
.alertType=${this.alertType}
|
|
137
|
+
.href=${this.href}
|
|
138
|
+
@expand-toggle=${this.onHeaderToggle}
|
|
139
|
+
>
|
|
140
|
+
${this.hasIcon ? html`<slot name="icon" slot="icon"></slot>` : nothing}
|
|
141
|
+
</obc-tree-navigation-item>
|
|
142
|
+
<div part="children" role="group" ?hidden=${!this.expanded}>
|
|
143
|
+
<slot></slot>
|
|
144
|
+
</div>
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static override styles = unsafeCSS(componentStyle);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type ObcTreeNavigationGroupExpandToggleEvent = CustomEvent<boolean>;
|
|
152
|
+
|
|
153
|
+
declare global {
|
|
154
|
+
interface HTMLElementTagNameMap {
|
|
155
|
+
'obc-tree-navigation-group': ObcTreeNavigationGroup;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
display: block;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.wrapper {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: var(--menu-navigation-components-tree-navigation-item-touch-target);
|
|
14
|
+
user-select: none;
|
|
15
|
+
|
|
16
|
+
@mixin outline-inward;
|
|
17
|
+
@mixin style style=flat visibleWrapperClass=.visible-wrapper;
|
|
18
|
+
@mixin font-body;
|
|
19
|
+
color: var(--on-flat-active-color);
|
|
20
|
+
|
|
21
|
+
.visible-wrapper {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
border-radius: var(--global-border-radius-border-radius-base);
|
|
27
|
+
padding: 0
|
|
28
|
+
var(--menu-navigation-components-tree-navigation-item-padding-horizontal);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* A checked row is not re-selectable, so it stays on the amplified enabled
|
|
33
|
+
* style with no hover/pressed feedback.
|
|
34
|
+
*/
|
|
35
|
+
&.checked {
|
|
36
|
+
@mixin style style=amplified visibleWrapperClass=.visible-wrapper;
|
|
37
|
+
cursor: default;
|
|
38
|
+
|
|
39
|
+
& .visible-wrapper,
|
|
40
|
+
&:hover .visible-wrapper,
|
|
41
|
+
&:active .visible-wrapper {
|
|
42
|
+
background-color: var(--amplified-enabled-background-color);
|
|
43
|
+
border-color: var(--amplified-enabled-border-color);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
& .label {
|
|
47
|
+
@mixin font-body-active;
|
|
48
|
+
color: var(--on-flat-active-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
& .leading-icon {
|
|
52
|
+
color: var(--on-amplified-active-color);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Guide lines are tree structure, not row state, so they do not dim here. */
|
|
57
|
+
&.disabled {
|
|
58
|
+
color: var(--on-flat-disabled-color);
|
|
59
|
+
|
|
60
|
+
& .leading-icon {
|
|
61
|
+
color: var(--on-flat-disabled-color);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.tree-node-row {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
height: 100%;
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.branch {
|
|
74
|
+
position: relative;
|
|
75
|
+
height: 100%;
|
|
76
|
+
width: var(--menu-navigation-components-branch-width);
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Guide lines all run on a rail at 75% of each 32px column and share the faint
|
|
82
|
+
* outline color. Verticals and the dropdown bleed 1px past the row edges so they
|
|
83
|
+
* cross the visible-wrapper's 1px transparent flat border and meet the adjacent
|
|
84
|
+
* row's line with no seam gap.
|
|
85
|
+
*/
|
|
86
|
+
.branch-vertical {
|
|
87
|
+
position: absolute;
|
|
88
|
+
top: -1px;
|
|
89
|
+
bottom: -1px;
|
|
90
|
+
left: 75%;
|
|
91
|
+
width: 1px;
|
|
92
|
+
transform: translateX(-0.5px);
|
|
93
|
+
background: var(--border-outline-color);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.branch-horizontal {
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 50%;
|
|
99
|
+
transform: translateY(-0.5px);
|
|
100
|
+
left: 75%;
|
|
101
|
+
right: 0;
|
|
102
|
+
height: 1px;
|
|
103
|
+
background: var(--border-outline-color);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* Corner (└, last child): a single bordered box replaces the straight rects so
|
|
108
|
+
* the bend can be rounded. The box bleeds 1px past the column's right edge so its
|
|
109
|
+
* bottom border overlaps the terminal connector with no break, and translateY
|
|
110
|
+
* drops it 0.5px so that border lands on the connector's pixel row (else the join
|
|
111
|
+
* reads as a `---___` step). The radius stays tight — the stub is only 8px, so a
|
|
112
|
+
* larger fillet would consume the whole flat run.
|
|
113
|
+
*/
|
|
114
|
+
.branch-corner .branch-vertical,
|
|
115
|
+
.branch-corner .branch-horizontal {
|
|
116
|
+
display: none;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.branch-corner .branch-elbow {
|
|
120
|
+
position: absolute;
|
|
121
|
+
top: -1px;
|
|
122
|
+
bottom: 50%;
|
|
123
|
+
left: 75%;
|
|
124
|
+
right: -1px;
|
|
125
|
+
transform: translate(-0.5px, 0.5px);
|
|
126
|
+
border-left: 1px solid var(--border-outline-color);
|
|
127
|
+
border-bottom: 1px solid var(--border-outline-color);
|
|
128
|
+
border-bottom-left-radius: var(
|
|
129
|
+
--menu-navigation-components-branch-corner-radius,
|
|
130
|
+
2px
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.terminal {
|
|
135
|
+
position: relative;
|
|
136
|
+
height: 100%;
|
|
137
|
+
width: var(--global-size-spacing-touch-target-min);
|
|
138
|
+
flex-shrink: 0;
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
justify-content: center;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Stub entering the terminal, continuing the guide line up to the chevron gap. */
|
|
145
|
+
.terminal-connector {
|
|
146
|
+
position: absolute;
|
|
147
|
+
top: 50%;
|
|
148
|
+
transform: translateY(-0.5px);
|
|
149
|
+
left: 0;
|
|
150
|
+
width: 25%;
|
|
151
|
+
height: 1px;
|
|
152
|
+
background: var(--border-outline-color);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* On a leaf (no chevron) the stub runs further, stopping ~13px before the icon. */
|
|
156
|
+
.terminal:not(:has(.chevron)) .terminal-connector {
|
|
157
|
+
width: calc(100% - 13px);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Descends from below the chevron to connect an expanded node to its children. */
|
|
161
|
+
.terminal-dropdown {
|
|
162
|
+
position: absolute;
|
|
163
|
+
left: 50%;
|
|
164
|
+
transform: translateX(-0.5px);
|
|
165
|
+
top: 75%;
|
|
166
|
+
bottom: -1px;
|
|
167
|
+
width: 1px;
|
|
168
|
+
background: var(--border-outline-color);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Visual expand/collapse indicator only — not a separate control. */
|
|
172
|
+
.chevron {
|
|
173
|
+
position: relative;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: center;
|
|
177
|
+
width: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
178
|
+
height: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
179
|
+
color: var(--element-neutral-color);
|
|
180
|
+
transition: transform 100ms ease-in-out;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@media (prefers-reduced-motion: reduce) {
|
|
184
|
+
.chevron {
|
|
185
|
+
transition: none;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.wrapper.disabled .chevron {
|
|
190
|
+
color: var(--on-flat-disabled-color);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
:host([expanded]) .chevron {
|
|
194
|
+
transform: rotate(90deg);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Alert-header marker for non-regular terminal types, at the terminal's top-right. */
|
|
198
|
+
.terminal-header {
|
|
199
|
+
position: absolute;
|
|
200
|
+
inset: 0;
|
|
201
|
+
display: flex;
|
|
202
|
+
justify-content: flex-end;
|
|
203
|
+
align-items: flex-start;
|
|
204
|
+
padding: var(--menu-navigation-components-terminal-padding-aggregated-icon);
|
|
205
|
+
color: var(--element-neutral-color);
|
|
206
|
+
pointer-events: none;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.terminal-header > * {
|
|
210
|
+
width: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
211
|
+
height: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.wrapper.disabled .terminal-header {
|
|
215
|
+
color: var(--on-flat-disabled-color);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.label-container {
|
|
219
|
+
display: flex;
|
|
220
|
+
flex: 1;
|
|
221
|
+
gap: var(
|
|
222
|
+
--menu-navigation-components-tree-navigation-item-padding-horizontal
|
|
223
|
+
);
|
|
224
|
+
align-items: center;
|
|
225
|
+
min-width: 0;
|
|
226
|
+
padding-right: var(
|
|
227
|
+
--menu-navigation-components-tree-navigation-item-padding-horizontal
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.leading-icon {
|
|
232
|
+
position: relative;
|
|
233
|
+
flex-shrink: 0;
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
width: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
238
|
+
height: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
239
|
+
color: var(--on-flat-neutral-color);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
::slotted([slot="icon"]) {
|
|
243
|
+
display: block;
|
|
244
|
+
width: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
245
|
+
height: var(--menu-navigation-components-tree-navigation-item-icon-size);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.label {
|
|
249
|
+
flex: 1;
|
|
250
|
+
overflow: hidden;
|
|
251
|
+
text-overflow: ellipsis;
|
|
252
|
+
white-space: nowrap;
|
|
253
|
+
min-width: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.alert-badge {
|
|
257
|
+
flex-shrink: 0;
|
|
258
|
+
}
|