@camunda/camunda-composite-components 0.23.0 → 0.23.2
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/lib/esm/package.json +1 -1
- package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +11 -7
- package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.js +8 -4
- package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-container.d.ts +1 -1
- package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-container.js +16 -11
- package/lib/esm/src/components/c3-navigation-v2/c3-breadcrumb-bar.js +10 -10
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.js +10 -6
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.types.d.ts +5 -1
- package/lib/esm/src/components/c3-navigation-v2/c3-sidebar.js +62 -25
- package/lib/esm/src/components/c3-navigation-v2/c3-tools-area.js +8 -2
- package/lib/esm/src/components/c3-navigation-v2/index.d.ts +2 -0
- package/lib/esm/src/components/c3-navigation-v2/index.js +1 -0
- package/lib/esm/src/components/c3-navigation-v2/stories/story-templates.d.ts +3 -0
- package/lib/esm/src/components/c3-navigation-v2/stories/story-templates.js +587 -2
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-info-panel.js +2 -2
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-notifications-panel.js +16 -11
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-user-panel.js +12 -12
- package/lib/esm/src/components/c3-navigation-v2/tools/panel-primitives.js +1 -1
- package/lib/esm/src/components/c3-navigation-v2/use-camunda-tools.js +2 -2
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-sidebar-entries.d.ts +58 -0
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-sidebar-entries.js +84 -0
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-webapp-breadcrumbs.js +7 -24
- package/lib/esm/src/index.d.ts +4 -2
- package/lib/esm/src/index.js +2 -1
- package/lib/esm/src/utils/camunda.d.ts +16 -0
- package/lib/esm/src/utils/camunda.js +29 -6
- package/package.json +2 -2
package/lib/esm/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
5
5
|
* You may not use this file except in compliance with the commercial license.
|
|
6
6
|
*/
|
|
7
|
-
import { FormLabel, HeaderGlobalAction, HeaderMenuItem, HeaderSideNavItems, Modal, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, } from '@carbon/react';
|
|
7
|
+
import { FormLabel, HeaderGlobalAction as HeaderGlobalActionBase, HeaderMenuItem, HeaderSideNavItems, Modal, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, } from '@carbon/react';
|
|
8
8
|
import { Close } from '@carbon/react/icons/index.esm.js';
|
|
9
9
|
import { Fragment, useCallback, useEffect, useState } from 'react';
|
|
10
10
|
import { styled } from 'styled-components';
|
|
@@ -17,6 +17,12 @@ import { useC3UserConfiguration } from '../../c3-user-configuration/c3-user-conf
|
|
|
17
17
|
import { ActiveOrgName } from '../c3-org-sidebar/components.js';
|
|
18
18
|
import { useOnClickOutside } from '../helpers.js';
|
|
19
19
|
import { NavWrapper, SideNav } from './components.js';
|
|
20
|
+
/**
|
|
21
|
+
* Carbon's `HeaderGlobalAction` is typed as `React.FC` and omits both `ref`
|
|
22
|
+
* (the component uses `forwardRef` internally) and `leaveDelayMs`. Both work
|
|
23
|
+
* at runtime, so we widen the type at the import site.
|
|
24
|
+
*/
|
|
25
|
+
const HeaderGlobalAction = HeaderGlobalActionBase;
|
|
20
26
|
const getOrgLink = (app, orgId, domain) => {
|
|
21
27
|
switch (app) {
|
|
22
28
|
case 'console': {
|
|
@@ -137,8 +143,8 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
|
|
|
137
143
|
optimize: status?.optimizeUrl,
|
|
138
144
|
console: '',
|
|
139
145
|
modeler: '',
|
|
140
|
-
identity: '',
|
|
141
|
-
admin: '',
|
|
146
|
+
identity: status?.identityUrl ?? '',
|
|
147
|
+
admin: status?.identityUrl ?? '',
|
|
142
148
|
};
|
|
143
149
|
const expectedStatus = {
|
|
144
150
|
tasklist: status?.tasklistStatus,
|
|
@@ -148,7 +154,7 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
|
|
|
148
154
|
modeler: '',
|
|
149
155
|
identity: '',
|
|
150
156
|
admin: '',
|
|
151
|
-
zeebe: '',
|
|
157
|
+
zeebe: status?.zeebeStatus ?? '',
|
|
152
158
|
};
|
|
153
159
|
const affectedCluster = {
|
|
154
160
|
uuid: clusterDto.uuid,
|
|
@@ -346,9 +352,7 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
|
|
|
346
352
|
const orgName = activeOrg?.name || navbar.orgName;
|
|
347
353
|
return (_jsxs(_Fragment, { children: [_jsx(HeaderGlobalAction, { ref: iconRef, "aria-label": 'Camunda components', isActive: appBar.isOpen, onClick: () => {
|
|
348
354
|
toggleAppbar(!appBar.isOpen);
|
|
349
|
-
}, tooltipAlignment: 'start',
|
|
350
|
-
// @ts-expect-error
|
|
351
|
-
leaveDelayMs: 100, children: appBar.isOpen ? _jsx(Close, { size: 20 }) : _jsx(C3AppMenuIcon, { size: 20 }) }), _jsx(OrgPickerModal, { activeOrg: activeOrg, appToNavigateTo: appToNavigateTo, isOpen: isOrgPickerModalOpen, orgs: clustersByOrgId, onCancel: () => {
|
|
355
|
+
}, tooltipAlignment: 'start', leaveDelayMs: 100, children: appBar.isOpen ? _jsx(Close, { size: 20 }) : _jsx(C3AppMenuIcon, { size: 20 }) }), _jsx(OrgPickerModal, { activeOrg: activeOrg, appToNavigateTo: appToNavigateTo, isOpen: isOrgPickerModalOpen, orgs: clustersByOrgId, onCancel: () => {
|
|
352
356
|
setIsOrgPickerModalOpen(false);
|
|
353
357
|
}, loadingStatus: loadingStatus, domain: domain }), _jsx(NavWrapper, { children: _jsx(SideNav, { ref: panelRef, "aria-label": appBar.ariaLabel || 'Side Navigation', expanded: appBar.isOpen, isPersistent: false, children: _jsxs(SideNavItems, { children: [orgName && (_jsx("li", { children: _jsxs(OrgNameWrapper, { children: [_jsx(FormLabel, { children: "Organization" }), _jsx(ActiveOrgName, { className: 'textPrimary', title: orgName, children: orgName })] }) })), _jsx("li", { children: navbar.elements.length > 0 && (_jsx(HeaderSideNavItems, { hasDivider: true, children: navbar.elements.map((element) => (_jsx(HeaderMenuItem, { as: element.routeProps && forwardRef, isActive: element.isCurrentPage, ...element.routeProps, onClick: () => {
|
|
354
358
|
if (element.routeProps.onClick) {
|
|
@@ -4,12 +4,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
5
5
|
* You may not use this file except in compliance with the commercial license.
|
|
6
6
|
*/
|
|
7
|
-
import { Button, HeaderPanel as CarbonHeaderPanel, HeaderGlobalAction, Stack, SwitcherDivider, } from '@carbon/react';
|
|
7
|
+
import { Button, HeaderPanel as CarbonHeaderPanel, HeaderGlobalAction as HeaderGlobalActionBase, Stack, SwitcherDivider, } from '@carbon/react';
|
|
8
8
|
import { useEffect } from 'react';
|
|
9
9
|
import styled from 'styled-components';
|
|
10
10
|
import { useOnClickOutside } from '../helpers.js';
|
|
11
11
|
import C3NavigationSidebarElement from './c3-navigation-sidebar-element.js';
|
|
12
12
|
import { useSidebarState } from './c3-sidebar-state-provider.js';
|
|
13
|
+
/**
|
|
14
|
+
* Carbon's `HeaderGlobalAction` is typed as `React.FC` and omits both `ref`
|
|
15
|
+
* (the component uses `forwardRef` internally) and `leaveDelayMs`. Both work
|
|
16
|
+
* at runtime, so we widen the type at the import site.
|
|
17
|
+
*/
|
|
18
|
+
const HeaderGlobalAction = HeaderGlobalActionBase;
|
|
13
19
|
const Wrapper = styled.div `
|
|
14
20
|
.cds--popover * {
|
|
15
21
|
z-index: 9000;
|
|
@@ -67,9 +73,7 @@ const C3NavigationSideBar = (props) => {
|
|
|
67
73
|
}, [isOpen]);
|
|
68
74
|
return (_jsxs(Wrapper, { children: [_jsx(HeaderGlobalAction, { ref: setIconRef, "aria-label": sideBar.tooltip ?? `Open ${sideBar.ariaLabel}`, "aria-expanded": isOpen, "aria-controls": id, onClick: () => {
|
|
69
75
|
setIsOpen(!isOpen);
|
|
70
|
-
}, isActive: isOpen, tooltipAlignment: sideBar.type === 'user' ? 'end' : 'center',
|
|
71
|
-
/* @ts-expect-error */
|
|
72
|
-
leaveDelayMs: 100, children: icon }), _jsxs(HeaderPanel, { ref: setPanelRef, expanded: isOpen, "data-floating-menu-container": true, children: [_jsxs(Stack, { children: [children, sideBar.elements &&
|
|
76
|
+
}, isActive: isOpen, tooltipAlignment: sideBar.type === 'user' ? 'end' : 'center', leaveDelayMs: 100, children: icon }), _jsxs(HeaderPanel, { ref: setPanelRef, expanded: isOpen, "data-floating-menu-container": true, children: [_jsxs(Stack, { children: [children, sideBar.elements &&
|
|
73
77
|
sideBar.elements.length > 0 &&
|
|
74
78
|
'customElements' in sideBar &&
|
|
75
79
|
sideBar.customElements &&
|
package/lib/esm/src/components/c3-navigation/c3-notification-provider/c3-notification-container.js
CHANGED
|
@@ -6,14 +6,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
*/
|
|
7
7
|
import { Button, Link, Tile } from '@carbon/react';
|
|
8
8
|
import { Close } from '@carbon/react/icons/index.esm.js';
|
|
9
|
-
import { useState } from 'react';
|
|
10
9
|
import styled from 'styled-components';
|
|
10
|
+
const CloseButtonWrapper = styled.div `
|
|
11
|
+
position: absolute;
|
|
12
|
+
top: var(--cds-spacing-02);
|
|
13
|
+
right: var(--cds-spacing-02);
|
|
14
|
+
opacity: 0;
|
|
15
|
+
|
|
16
|
+
&:focus-within {
|
|
17
|
+
opacity: 1;
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
11
20
|
const NotificationTile = styled(Tile) `
|
|
21
|
+
position: relative;
|
|
12
22
|
box-shadow: inset 0px -1px 0px var(--cds-border-subtle-01);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
|
|
24
|
+
&:hover ${CloseButtonWrapper} {
|
|
25
|
+
opacity: 1;
|
|
26
|
+
}
|
|
17
27
|
`;
|
|
18
28
|
const UnreadNotificationHeader = styled.div `
|
|
19
29
|
display: flex;
|
|
@@ -78,7 +88,6 @@ const getReadableTimestamp = (timestamp) => {
|
|
|
78
88
|
return date.toDateString();
|
|
79
89
|
};
|
|
80
90
|
const C3NotificationContainer = ({ description, state, timestamp, title, onDismiss, meta, onLinkClick, originalOnLinkClick, unread = false, }) => {
|
|
81
|
-
const [isHovering, setIsHovering] = useState(false);
|
|
82
91
|
const dismissNotification = (e) => {
|
|
83
92
|
e.stopPropagation();
|
|
84
93
|
onDismiss();
|
|
@@ -91,10 +100,6 @@ const C3NotificationContainer = ({ description, state, timestamp, title, onDismi
|
|
|
91
100
|
}
|
|
92
101
|
return true;
|
|
93
102
|
};
|
|
94
|
-
return (_jsxs(NotificationTile, {
|
|
95
|
-
setIsHovering(true);
|
|
96
|
-
}, onMouseLeave: () => {
|
|
97
|
-
setIsHovering(false);
|
|
98
|
-
}, children: [_jsxs(UnreadNotificationHeader, { children: [(state === 'new' || unread) && _jsx(Dot, {}), _jsxs(NotificationHeader, { children: [_jsx(Timestamp, { children: getReadableTimestamp(timestamp) }), _jsx(CloseButton, { kind: 'ghost', hasIconOnly: true, iconDescription: 'Dismiss', align: 'bottom-right', renderIcon: Close, onClick: dismissNotification, size: 'sm', "$show": isHovering })] })] }), _jsx(NotificationTitle, { children: title }), _jsx(NotificationDescription, { children: description }), meta && (_jsx(LinkContainer, { children: _jsx(Link, { href: meta.href, onClick: handleLinkClick, visited: true, style: { fontSize: 'var(--cds-helper-text-01-font-size)' }, children: meta.label }) }))] }));
|
|
103
|
+
return (_jsxs(NotificationTile, { children: [_jsxs(UnreadNotificationHeader, { children: [(state === 'new' || unread) && _jsx(Dot, {}), _jsx(NotificationHeader, { children: _jsx(Timestamp, { children: getReadableTimestamp(timestamp) }) })] }), _jsx(NotificationTitle, { children: title }), _jsx(NotificationDescription, { children: description }), meta && (_jsx(LinkContainer, { children: _jsx(Link, { href: meta.href, onClick: handleLinkClick, visited: true, style: { fontSize: 'var(--cds-helper-text-01-font-size)' }, children: meta.label }) })), _jsx(CloseButtonWrapper, { children: _jsx(Button, { kind: 'ghost', hasIconOnly: true, iconDescription: 'Dismiss', tooltipPosition: 'top', tooltipAlignment: 'end', renderIcon: Close, onClick: dismissNotification, size: 'sm' }) })] }));
|
|
99
104
|
};
|
|
100
105
|
export default C3NotificationContainer;
|
|
@@ -17,8 +17,8 @@ const SegmentWrapper = styled.div `
|
|
|
17
17
|
const SegmentButton = styled.button `
|
|
18
18
|
display: flex;
|
|
19
19
|
align-items: center;
|
|
20
|
-
gap:
|
|
21
|
-
padding:
|
|
20
|
+
gap: var(--cds-spacing-03);
|
|
21
|
+
padding: var(--cds-spacing-02) var(--cds-spacing-03);
|
|
22
22
|
background: transparent;
|
|
23
23
|
border: none;
|
|
24
24
|
border-radius: 4px;
|
|
@@ -45,7 +45,7 @@ const ChevronButton = styled.button `
|
|
|
45
45
|
display: flex;
|
|
46
46
|
align-items: center;
|
|
47
47
|
justify-content: center;
|
|
48
|
-
padding:
|
|
48
|
+
padding: var(--cds-spacing-02);
|
|
49
49
|
background: ${(p) => (p.$isOpen ? 'var(--cds-layer-01)' : 'transparent')};
|
|
50
50
|
border: none;
|
|
51
51
|
border-radius: 4px;
|
|
@@ -71,7 +71,7 @@ const ActionMenuButton = styled.button `
|
|
|
71
71
|
display: flex;
|
|
72
72
|
align-items: center;
|
|
73
73
|
justify-content: center;
|
|
74
|
-
padding:
|
|
74
|
+
padding: var(--cds-spacing-02);
|
|
75
75
|
background: ${(p) => (p.$isOpen ? 'var(--cds-layer-01)' : 'transparent')};
|
|
76
76
|
border: none;
|
|
77
77
|
border-radius: 4px;
|
|
@@ -92,7 +92,7 @@ const ActionMenuItem = styled.button `
|
|
|
92
92
|
width: 100%;
|
|
93
93
|
display: flex;
|
|
94
94
|
align-items: center;
|
|
95
|
-
padding: 0.625rem
|
|
95
|
+
padding: 0.625rem var(--cds-spacing-05);
|
|
96
96
|
background: transparent;
|
|
97
97
|
border: none;
|
|
98
98
|
border-top: ${(p) => (p.$hasDivider ? '1px solid var(--cds-border-subtle)' : 'none')};
|
|
@@ -133,8 +133,8 @@ const DropdownItem = styled.button `
|
|
|
133
133
|
width: 100%;
|
|
134
134
|
display: flex;
|
|
135
135
|
align-items: center;
|
|
136
|
-
gap:
|
|
137
|
-
padding: 0.625rem
|
|
136
|
+
gap: var(--cds-spacing-04);
|
|
137
|
+
padding: 0.625rem var(--cds-spacing-05);
|
|
138
138
|
background: ${(p) => (p.$isSelected ? 'var(--cds-layer-selected)' : 'transparent')};
|
|
139
139
|
border: none;
|
|
140
140
|
cursor: pointer;
|
|
@@ -163,7 +163,7 @@ const DropdownItemLabel = styled.span `
|
|
|
163
163
|
const Separator = styled.span `
|
|
164
164
|
display: flex;
|
|
165
165
|
align-items: center;
|
|
166
|
-
padding: 0
|
|
166
|
+
padding: 0 var(--cds-spacing-02);
|
|
167
167
|
color: var(--cds-text-secondary);
|
|
168
168
|
font-size: 0.875rem;
|
|
169
169
|
user-select: none;
|
|
@@ -181,7 +181,7 @@ const DropdownEntry = ({ item, onSelect, linkComponent, }) => {
|
|
|
181
181
|
: undefined, ...(item.linkProps ?? {}), "$isSelected": !!item.isSelected, onClick: () => onSelect(item), role: 'option', tabIndex: -1, "aria-selected": !!item.isSelected, children: [Icon && (_jsx(Icon, { size: 16, style: { color: 'var(--cds-icon-secondary)', flexShrink: 0 } })), _jsx(DropdownItemLabel, { children: item.label }), item.trailingElement, item.isSelected && (_jsx(Checkmark, { size: 16, style: { color: 'var(--cds-icon-primary)', flexShrink: 0 } }))] }));
|
|
182
182
|
};
|
|
183
183
|
const DropdownTitle = styled.div `
|
|
184
|
-
padding:
|
|
184
|
+
padding: var(--cds-spacing-04) var(--cds-spacing-05) var(--cds-spacing-03);
|
|
185
185
|
font-size: 0.6875rem;
|
|
186
186
|
font-weight: 600;
|
|
187
187
|
color: var(--cds-text-secondary);
|
|
@@ -366,6 +366,6 @@ const BreadcrumbBarWrapper = styled.div `
|
|
|
366
366
|
flex: 1;
|
|
367
367
|
min-width: 0;
|
|
368
368
|
overflow-x: auto;
|
|
369
|
-
padding-left:
|
|
369
|
+
padding-left: var(--cds-spacing-03);
|
|
370
370
|
`;
|
|
371
371
|
export const C3BreadcrumbBar = ({ segments, linkComponent, }) => (_jsx(BreadcrumbBarWrapper, { role: 'navigation', "aria-label": 'Breadcrumb', children: segments.map((segment, index) => (_jsx(BreadcrumbSegmentComponent, { segment: segment, isLast: index === segments.length - 1, linkComponent: linkComponent }, segment.key))) }));
|
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
* You may not use this file except in compliance with the commercial license.
|
|
6
6
|
*/
|
|
7
7
|
import { Header, HeaderGlobalAction, HeaderGlobalBar, SkipToContent, } from '@carbon/react';
|
|
8
|
-
import { useEffect } from 'react';
|
|
8
|
+
import { Fragment, useEffect } from 'react';
|
|
9
9
|
import styled from 'styled-components';
|
|
10
10
|
import { CamundaLogo } from '../../assets/c3-icons.js';
|
|
11
11
|
import { C3BreadcrumbBar } from './c3-breadcrumb-bar.js';
|
|
@@ -23,7 +23,7 @@ const LogoSection = styled.a `
|
|
|
23
23
|
justify-content: center;
|
|
24
24
|
width: 3rem;
|
|
25
25
|
flex-shrink: 0;
|
|
26
|
-
gap:
|
|
26
|
+
gap: var(--cds-spacing-03);
|
|
27
27
|
border-right: 1px solid var(--cds-border-subtle);
|
|
28
28
|
height: 100%;
|
|
29
29
|
text-decoration: none;
|
|
@@ -60,13 +60,17 @@ export const C3NavigationV2 = ({ app, skipToContentTargetId, skipToContentLabel
|
|
|
60
60
|
return (_jsxs(_Fragment, { children: [_jsxs(StyledHeader, { "aria-label": ariaLabel, children: [_jsx(SkipToContent, { href: `#${skipToContentTargetId}`, children: skipToContentLabel }), _jsxs(LogoSection, { as: app.linkProps ? LinkEl : 'div', ...(app.linkProps ?? {}), children: [_jsx(CamundaLogo, { "aria-label": 'Camunda' }), app.name && _jsx("span", { children: app.name })] }), breadcrumbs && breadcrumbs.length > 0 && (_jsx(C3BreadcrumbBar, { segments: breadcrumbs, linkComponent: LinkEl })), _jsxs(HeaderGlobalBar, { children: [headerTrailingContent && (_jsx("span", { style: {
|
|
61
61
|
display: 'flex',
|
|
62
62
|
alignItems: 'center',
|
|
63
|
-
padding: '0
|
|
64
|
-
}, children: headerTrailingContent })), tools && tools.length > 0 && (_jsx(C3ToolsArea, { tools: tools, activeToolKey: activeToolKey, onActiveToolChange: onActiveToolChange })), globalActions
|
|
63
|
+
padding: '0 var(--cds-spacing-03)',
|
|
64
|
+
}, children: headerTrailingContent })), tools && tools.length > 0 && (_jsx(C3ToolsArea, { tools: tools, activeToolKey: activeToolKey, onActiveToolChange: onActiveToolChange })), globalActions
|
|
65
|
+
?.filter((action) => action.element || action.icon)
|
|
66
|
+
.map((action, index, arr) => {
|
|
65
67
|
if (action.element) {
|
|
66
|
-
|
|
68
|
+
// Direct flex child of HeaderGlobalBar (no wrapper); preserves
|
|
69
|
+
// the layout context custom elements like C4Search rely on.
|
|
70
|
+
return _jsx(Fragment, { children: action.element }, action.key);
|
|
67
71
|
}
|
|
68
72
|
const Icon = action.icon;
|
|
69
|
-
const isLast = index ===
|
|
73
|
+
const isLast = index === arr.length - 1;
|
|
70
74
|
return (_jsx(HeaderGlobalAction, { "aria-label": action.label, onClick: action.onClick, tooltipAlignment: isLast ? 'end' : undefined, children: _jsx(Icon, { size: 20 }) }, action.key));
|
|
71
75
|
})] })] }), sidebar && _jsx(C3Sidebar, { ...sidebar })] }));
|
|
72
76
|
};
|
|
@@ -74,7 +74,11 @@ export interface BreadcrumbSegment {
|
|
|
74
74
|
export interface GlobalActionButton {
|
|
75
75
|
key: string;
|
|
76
76
|
label: string;
|
|
77
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Required when `element` is omitted. Ignored when `element` is supplied
|
|
79
|
+
* (the custom element renders instead of the default icon button).
|
|
80
|
+
*/
|
|
81
|
+
icon?: React.ComponentType<{
|
|
78
82
|
size?: number;
|
|
79
83
|
}>;
|
|
80
84
|
onClick?: () => void;
|
|
@@ -27,20 +27,22 @@ const ScrollArea = styled.div `
|
|
|
27
27
|
flex-direction: column;
|
|
28
28
|
overflow-y: ${(p) => (p.$sidebarExpanded ? 'auto' : 'visible')};
|
|
29
29
|
overflow-x: ${(p) => (p.$sidebarExpanded ? 'hidden' : 'visible')};
|
|
30
|
-
padding-top:
|
|
31
|
-
padding-bottom:
|
|
30
|
+
padding-top: var(--cds-spacing-03);
|
|
31
|
+
padding-bottom: var(--cds-spacing-05);
|
|
32
32
|
`;
|
|
33
33
|
const NavButton = styled.button `
|
|
34
34
|
display: flex;
|
|
35
35
|
align-items: center;
|
|
36
36
|
flex-wrap: nowrap;
|
|
37
|
-
gap:
|
|
37
|
+
gap: var(--cds-spacing-04);
|
|
38
38
|
width: 100%;
|
|
39
39
|
min-height: 2.5rem;
|
|
40
40
|
padding: ${(p) => {
|
|
41
41
|
if (p.$depth > 0)
|
|
42
|
-
return `0.625rem
|
|
43
|
-
return p.$isExpanded
|
|
42
|
+
return `0.625rem var(--cds-spacing-05) 0.625rem ${0.75 + p.$depth * 1.75}rem`;
|
|
43
|
+
return p.$isExpanded
|
|
44
|
+
? 'var(--cds-spacing-04) var(--cds-spacing-05)'
|
|
45
|
+
: 'var(--cds-spacing-04)';
|
|
44
46
|
}};
|
|
45
47
|
justify-content: ${(p) => (p.$isExpanded ? 'flex-start' : 'center')};
|
|
46
48
|
background: ${(p) => (p.$isActive ? 'var(--cds-layer-selected)' : 'transparent')};
|
|
@@ -68,6 +70,8 @@ const NavButton = styled.button `
|
|
|
68
70
|
}
|
|
69
71
|
`;
|
|
70
72
|
const NavLabel = styled.span `
|
|
73
|
+
flex: 1;
|
|
74
|
+
min-width: 0;
|
|
71
75
|
overflow: hidden;
|
|
72
76
|
text-overflow: ellipsis;
|
|
73
77
|
white-space: nowrap;
|
|
@@ -91,10 +95,11 @@ const GroupLabelButton = styled.button `
|
|
|
91
95
|
display: flex;
|
|
92
96
|
align-items: center;
|
|
93
97
|
flex: 1;
|
|
98
|
+
min-width: 0;
|
|
94
99
|
padding: ${(p) => {
|
|
95
100
|
if (p.$depth > 0)
|
|
96
|
-
return `
|
|
97
|
-
return '
|
|
101
|
+
return `var(--cds-spacing-04) 0 var(--cds-spacing-04) ${0.75 + p.$depth * 1.75}rem`;
|
|
102
|
+
return 'var(--cds-spacing-04) 0 var(--cds-spacing-04) var(--cds-spacing-05)';
|
|
98
103
|
}};
|
|
99
104
|
background: transparent;
|
|
100
105
|
border: none;
|
|
@@ -105,7 +110,7 @@ const GroupLabelButton = styled.button `
|
|
|
105
110
|
text-align: left;
|
|
106
111
|
text-decoration: none;
|
|
107
112
|
transition: color 0.15s;
|
|
108
|
-
gap:
|
|
113
|
+
gap: var(--cds-spacing-04);
|
|
109
114
|
|
|
110
115
|
&:hover {
|
|
111
116
|
color: var(--cds-text-primary);
|
|
@@ -121,8 +126,8 @@ const ExpandButton = styled.button `
|
|
|
121
126
|
display: flex;
|
|
122
127
|
align-items: center;
|
|
123
128
|
justify-content: center;
|
|
124
|
-
padding:
|
|
125
|
-
margin-right:
|
|
129
|
+
padding: var(--cds-spacing-02);
|
|
130
|
+
margin-right: var(--cds-spacing-04);
|
|
126
131
|
background: transparent;
|
|
127
132
|
border: none;
|
|
128
133
|
border-radius: 4px;
|
|
@@ -152,12 +157,13 @@ const PlainGroupLabel = styled.span `
|
|
|
152
157
|
display: flex;
|
|
153
158
|
align-items: center;
|
|
154
159
|
flex: 1;
|
|
160
|
+
min-width: 0;
|
|
155
161
|
padding: ${(p) => {
|
|
156
162
|
if (p.$depth > 0)
|
|
157
|
-
return `
|
|
158
|
-
return '
|
|
163
|
+
return `var(--cds-spacing-04) 0 var(--cds-spacing-04) ${0.75 + p.$depth * 1.75}rem`;
|
|
164
|
+
return 'var(--cds-spacing-04) 0 var(--cds-spacing-04) var(--cds-spacing-05)';
|
|
159
165
|
}};
|
|
160
|
-
gap:
|
|
166
|
+
gap: var(--cds-spacing-04);
|
|
161
167
|
color: var(--cds-text-secondary);
|
|
162
168
|
font-size: 0.875rem;
|
|
163
169
|
font-weight: 400;
|
|
@@ -166,8 +172,8 @@ const PlainGroupExpandButton = styled.button `
|
|
|
166
172
|
display: flex;
|
|
167
173
|
align-items: center;
|
|
168
174
|
justify-content: center;
|
|
169
|
-
padding:
|
|
170
|
-
margin-right:
|
|
175
|
+
padding: var(--cds-spacing-02);
|
|
176
|
+
margin-right: var(--cds-spacing-04);
|
|
171
177
|
background: transparent;
|
|
172
178
|
border: none;
|
|
173
179
|
border-radius: 4px;
|
|
@@ -189,7 +195,7 @@ const StyledPopover = styled(Popover) `
|
|
|
189
195
|
|
|
190
196
|
.cds--popover-content {
|
|
191
197
|
pointer-events: none;
|
|
192
|
-
padding: 0.1875rem
|
|
198
|
+
padding: 0.1875rem var(--cds-spacing-03);
|
|
193
199
|
font-size: var(--cds-body-compact-01-font-size);
|
|
194
200
|
white-space: nowrap;
|
|
195
201
|
}
|
|
@@ -214,18 +220,18 @@ const CollapsedItemTooltip = ({ label, children, }) => {
|
|
|
214
220
|
return (_jsxs(StyledPopover, { open: open, align: 'right', highContrast: true, dropShadow: false, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [children, _jsx(PopoverContent, { children: label })] }));
|
|
215
221
|
};
|
|
216
222
|
const SectionDivider = styled.div `
|
|
217
|
-
border-top: ${(p) => (p.$hideTopDivider ? 'none' : '1px solid var(--cds-border-subtle)')};
|
|
223
|
+
border-top: ${(p) => (p.$hideTopDivider ? 'none' : '1px solid var(--cds-border-subtle-01)')};
|
|
218
224
|
margin-top: ${(p) => {
|
|
219
225
|
if (p.$eatScrollPadding)
|
|
220
|
-
return '-
|
|
226
|
+
return 'calc(-1 * var(--cds-spacing-03))';
|
|
221
227
|
if (p.$tight)
|
|
222
228
|
return '0';
|
|
223
|
-
return p.$hideTopDivider ? '0' : '
|
|
229
|
+
return p.$hideTopDivider ? '0' : 'var(--cds-spacing-03)';
|
|
224
230
|
}};
|
|
225
|
-
padding-top: ${(p) => (p.$hideTopDivider ? '0' : '
|
|
231
|
+
padding-top: ${(p) => (p.$hideTopDivider ? '0' : 'var(--cds-spacing-03)')};
|
|
226
232
|
`;
|
|
227
233
|
const SectionTitle = styled.div `
|
|
228
|
-
padding:
|
|
234
|
+
padding: var(--cds-spacing-03) var(--cds-spacing-05);
|
|
229
235
|
font-size: 0.6875rem;
|
|
230
236
|
font-weight: 600;
|
|
231
237
|
color: var(--cds-text-secondary);
|
|
@@ -240,10 +246,12 @@ const CollapseButton = styled.button `
|
|
|
240
246
|
display: flex;
|
|
241
247
|
align-items: center;
|
|
242
248
|
flex-wrap: nowrap;
|
|
243
|
-
gap:
|
|
249
|
+
gap: var(--cds-spacing-04);
|
|
244
250
|
width: 100%;
|
|
245
251
|
min-height: 2.5rem;
|
|
246
|
-
padding: ${(p) =>
|
|
252
|
+
padding: ${(p) => p.$isExpanded
|
|
253
|
+
? 'var(--cds-spacing-04) var(--cds-spacing-05)'
|
|
254
|
+
: 'var(--cds-spacing-04)'};
|
|
247
255
|
justify-content: ${(p) => (p.$isExpanded ? 'flex-start' : 'center')};
|
|
248
256
|
background: transparent;
|
|
249
257
|
border: none;
|
|
@@ -272,6 +280,34 @@ const resolveLinkAs = (linkProps, linkComponent) => {
|
|
|
272
280
|
return 'a';
|
|
273
281
|
return linkComponent;
|
|
274
282
|
};
|
|
283
|
+
const pruneNode = (node) => {
|
|
284
|
+
if (node.type === 'item') {
|
|
285
|
+
if (!node.onClick && !node.linkProps)
|
|
286
|
+
return null;
|
|
287
|
+
return node;
|
|
288
|
+
}
|
|
289
|
+
if (node.type === 'group') {
|
|
290
|
+
const children = pruneChildren(node.children);
|
|
291
|
+
if (children.length === 0)
|
|
292
|
+
return null;
|
|
293
|
+
return { ...node, children };
|
|
294
|
+
}
|
|
295
|
+
if (node.type === 'group-item') {
|
|
296
|
+
const children = pruneChildren(node.children);
|
|
297
|
+
const isClickable = !!(node.onClick || node.linkProps);
|
|
298
|
+
if (children.length === 0 && !isClickable)
|
|
299
|
+
return null;
|
|
300
|
+
return { ...node, children };
|
|
301
|
+
}
|
|
302
|
+
const children = pruneChildren(node.children);
|
|
303
|
+
if (children.length === 0)
|
|
304
|
+
return null;
|
|
305
|
+
return { ...node, children };
|
|
306
|
+
};
|
|
307
|
+
const pruneChildren = (nodes) => nodes.flatMap((n) => {
|
|
308
|
+
const pruned = pruneNode(n);
|
|
309
|
+
return pruned ? [pruned] : [];
|
|
310
|
+
});
|
|
275
311
|
const ItemNode = ({ node, sidebarExpanded, depth, linkComponent, }) => {
|
|
276
312
|
const Icon = node.icon;
|
|
277
313
|
const content = (_jsxs(NavButton, { as: resolveLinkAs(node.linkProps, linkComponent), ...(node.linkProps ?? {}), "$isActive": !!node.isActive, "$isExpanded": sidebarExpanded, "$depth": depth, onClick: node.onClick, "aria-current": node.isActive ? 'page' : undefined, children: [_jsx(Icon, { size: 20, style: { flexShrink: 0 } }), sidebarExpanded && _jsx(NavLabel, { children: node.label }), sidebarExpanded && node.trailingElement] }));
|
|
@@ -287,7 +323,7 @@ const GroupItemNode = ({ node, sidebarExpanded, depth, linkComponent, }) => {
|
|
|
287
323
|
const collapsed = (_jsx(NavButton, { as: resolveLinkAs(node.linkProps, linkComponent), ...(node.linkProps ?? {}), "$isActive": isActive, "$isExpanded": false, "$depth": 0, onClick: node.onClick ?? node.onToggleExpand, "aria-current": isActive ? 'page' : undefined, children: _jsx(Icon, { size: 20, style: { flexShrink: 0 } }) }));
|
|
288
324
|
return (_jsx(CollapsedItemTooltip, { label: node.label, children: collapsed }));
|
|
289
325
|
}
|
|
290
|
-
return (_jsxs("div", { children: [_jsxs(GroupHeader, { "$isActive": isActive, "$depth": depth, children: [_jsxs(GroupLabelButton, { as: resolveLinkAs(node.linkProps, linkComponent), ...(node.linkProps ?? {}), "$isActive": isActive, "$isClickable": true, "$depth": depth, onClick: node.onClick, "aria-current": isActive ? 'page' : undefined, children: [_jsx(Icon, { size: 20, style: { flexShrink: 0 } }), _jsx(NavLabel, { children: node.label }), node.trailingElement] }), node.onToggleExpand && (_jsx(ExpandButton, { "data-expand": true, onClick: (e) => {
|
|
326
|
+
return (_jsxs("div", { children: [_jsxs(GroupHeader, { "$isActive": isActive, "$depth": depth, children: [_jsxs(GroupLabelButton, { as: resolveLinkAs(node.linkProps, linkComponent), ...(node.linkProps ?? {}), "$isActive": isActive, "$isClickable": true, "$depth": depth, onClick: node.onClick, "aria-current": isActive ? 'page' : undefined, children: [_jsx(Icon, { size: 20, style: { flexShrink: 0 } }), _jsx(NavLabel, { children: node.label }), node.trailingElement] }), node.onToggleExpand && node.children.length > 0 && (_jsx(ExpandButton, { "data-expand": true, onClick: (e) => {
|
|
291
327
|
e.stopPropagation();
|
|
292
328
|
node.onToggleExpand?.();
|
|
293
329
|
}, "aria-label": node.isExpanded
|
|
@@ -330,11 +366,12 @@ const SidebarNodeComponent = ({ node, sidebarExpanded, depth, linkComponent, hid
|
|
|
330
366
|
*/
|
|
331
367
|
export const C3Sidebar = ({ ariaLabel, children: nodes, isExpanded = true, onToggleExpanded, expandedWidth = '16rem', collapsedWidth = '3rem', linkComponent, }) => {
|
|
332
368
|
const width = isExpanded ? expandedWidth : collapsedWidth;
|
|
369
|
+
const prunedNodes = pruneChildren(nodes);
|
|
333
370
|
return (_jsxs(SidebarNav, { "$width": width, "aria-label": ariaLabel, children: [_jsx(ScrollArea, { "$sidebarExpanded": isExpanded, children: (() => {
|
|
334
371
|
let sectionSeen = false;
|
|
335
372
|
let prevSectionCompact = false;
|
|
336
373
|
let hasNonSectionNodes = false;
|
|
337
|
-
return
|
|
374
|
+
return prunedNodes.map((node) => {
|
|
338
375
|
let hideTopDivider = false;
|
|
339
376
|
let eatScrollPadding = false;
|
|
340
377
|
let tight = false;
|
|
@@ -20,6 +20,10 @@ const ToolsPanel = styled.div `
|
|
|
20
20
|
z-index: 8000;
|
|
21
21
|
display: flex;
|
|
22
22
|
flex-direction: column;
|
|
23
|
+
|
|
24
|
+
& > * {
|
|
25
|
+
flex-shrink: 0;
|
|
26
|
+
}
|
|
23
27
|
`;
|
|
24
28
|
/**
|
|
25
29
|
* Renders tool buttons inline (for HeaderGlobalBar) and manages a single shared
|
|
@@ -85,9 +89,11 @@ export const C3ToolsArea = ({ tools, activeToolKey: controlledKey, onActiveToolC
|
|
|
85
89
|
}, [activeKey, setActive]);
|
|
86
90
|
const handlePanelBlur = useCallback((event) => {
|
|
87
91
|
const next = event.relatedTarget;
|
|
88
|
-
if (next
|
|
92
|
+
if (!next)
|
|
89
93
|
return;
|
|
90
|
-
if (
|
|
94
|
+
if (panelRef.current?.contains(next))
|
|
95
|
+
return;
|
|
96
|
+
if (next.closest?.('.cds--header'))
|
|
91
97
|
return;
|
|
92
98
|
setActive(null);
|
|
93
99
|
}, [setActive]);
|
|
@@ -14,5 +14,7 @@ export type { BreadcrumbDescriptor, BreadcrumbDropdownItemDescriptor, GroupDescr
|
|
|
14
14
|
export { useC3NavigationV2 } from './use-c3-navigation-v2';
|
|
15
15
|
export type { HelpToolOptions, InfoToolOptions, NotificationsToolOptions, UseCamundaToolsOptions, UserToolOptions, } from './use-camunda-tools';
|
|
16
16
|
export { useCamundaTools } from './use-camunda-tools';
|
|
17
|
+
export type { UseClusterSidebarEntriesOptions } from './use-cluster-sidebar-entries';
|
|
18
|
+
export { useClusterSidebarEntries } from './use-cluster-sidebar-entries';
|
|
17
19
|
export type { UseClusterWebappBreadcrumbsOptions } from './use-cluster-webapp-breadcrumbs';
|
|
18
20
|
export { useClusterWebappBreadcrumbs } from './use-cluster-webapp-breadcrumbs';
|
|
@@ -12,4 +12,5 @@ export { C3NotificationsPanel } from './tools/c3-notifications-panel.js';
|
|
|
12
12
|
export { C3UserPanel } from './tools/c3-user-panel.js';
|
|
13
13
|
export { useC3NavigationV2 } from './use-c3-navigation-v2.js';
|
|
14
14
|
export { useCamundaTools } from './use-camunda-tools.js';
|
|
15
|
+
export { useClusterSidebarEntries } from './use-cluster-sidebar-entries.js';
|
|
15
16
|
export { useClusterWebappBreadcrumbs } from './use-cluster-webapp-breadcrumbs.js';
|
|
@@ -8,4 +8,7 @@ export declare const ToolPanelsTemplate: FC;
|
|
|
8
8
|
export declare const BreadcrumbActionsTemplate: FC;
|
|
9
9
|
export declare const ClusterWebappTemplate: FC;
|
|
10
10
|
export declare const HeaderTrailingContentTemplate: FC;
|
|
11
|
+
export declare const PruningTemplate: FC;
|
|
12
|
+
export declare const BuildClusterSidebarEntriesTemplate: FC;
|
|
11
13
|
export declare const CompactSectionTemplate: FC;
|
|
14
|
+
export declare const GlobalActionWithCustomElementTemplate: FC;
|