@camunda/camunda-composite-components 0.23.3 → 0.24.0
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 +26 -26
- package/lib/esm/src/components/c3-data-table/c3-data-table.js +1 -1
- package/lib/esm/src/components/c3-help-center/c3-help-center-provider.d.ts +2 -1
- package/lib/esm/src/components/c3-help-center/c3-help-center-provider.js +4 -1
- package/lib/esm/src/components/c3-help-center/c3-help-center.d.ts +2 -1
- package/lib/esm/src/components/c3-help-center/c3-help-center.js +4 -3
- package/lib/esm/src/components/c3-license-tag/c3-license-tag.d.ts +4 -5
- package/lib/esm/src/components/c3-license-tag/c3-license-tag.js +54 -47
- package/lib/esm/src/components/c3-navigation/c3-navigation-appbar/c3-navigation-appbar.js +6 -6
- package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.js +3 -0
- package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar.js +10 -1
- package/lib/esm/src/components/c3-navigation/helpers.js +12 -0
- package/lib/esm/src/components/c3-navigation-v2/c3-breadcrumb-bar.js +33 -31
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.js +7 -1
- package/lib/esm/src/components/c3-navigation-v2/c3-navigation-v2.types.d.ts +18 -0
- package/lib/esm/src/components/c3-navigation-v2/c3-sidebar.d.ts +1 -1
- package/lib/esm/src/components/c3-navigation-v2/c3-sidebar.js +82 -84
- package/lib/esm/src/components/c3-navigation-v2/c3-tools-area.js +18 -5
- package/lib/esm/src/components/c3-navigation-v2/index.d.ts +5 -3
- 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 +1 -0
- package/lib/esm/src/components/c3-navigation-v2/stories/story-templates.js +112 -0
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-info-panel.d.ts +2 -1
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-info-panel.js +1 -1
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-notifications-panel.d.ts +11 -0
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-notifications-panel.js +9 -5
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-theme-selector.d.ts +25 -0
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-theme-selector.js +15 -0
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-user-panel.d.ts +15 -0
- package/lib/esm/src/components/c3-navigation-v2/tools/c3-user-panel.js +10 -17
- package/lib/esm/src/components/c3-navigation-v2/use-c3-navigation-v2.d.ts +3 -1
- package/lib/esm/src/components/c3-navigation-v2/use-c3-navigation-v2.js +2 -1
- package/lib/esm/src/components/c3-navigation-v2/use-camunda-tools.d.ts +28 -5
- package/lib/esm/src/components/c3-navigation-v2/use-camunda-tools.js +42 -23
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-sidebar-entries.js +10 -8
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-webapp-breadcrumbs.d.ts +16 -18
- package/lib/esm/src/components/c3-navigation-v2/use-cluster-webapp-breadcrumbs.js +146 -36
- package/lib/esm/src/index.d.ts +2 -2
- package/lib/esm/src/index.js +1 -1
- package/package.json +27 -27
package/lib/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camunda/camunda-composite-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Camunda Composite Components",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/camunda/camunda-cloud-management-apps/issues"
|
|
@@ -52,41 +52,41 @@
|
|
|
52
52
|
"jwt-decode": "4.0.0",
|
|
53
53
|
"react-error-boundary": "6.1.1",
|
|
54
54
|
"react-markdown": "10.1.0",
|
|
55
|
-
"semver": "7.
|
|
55
|
+
"semver": "7.8.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@auth0/auth0-spa-js": "2.19.
|
|
58
|
+
"@auth0/auth0-spa-js": "2.19.3",
|
|
59
59
|
"@camunda/ccma-shared-types": "workspace:*",
|
|
60
|
-
"@carbon/react": "1.
|
|
61
|
-
"@chromatic-com/storybook": "5.
|
|
60
|
+
"@carbon/react": "1.107.1",
|
|
61
|
+
"@chromatic-com/storybook": "5.2.1",
|
|
62
62
|
"@mdx-js/react": "3.1.1",
|
|
63
|
-
"@playwright/test": "1.
|
|
64
|
-
"@storybook/addon-a11y": "10.
|
|
65
|
-
"@storybook/addon-docs": "10.
|
|
66
|
-
"@storybook/addon-links": "10.
|
|
67
|
-
"@storybook/addon-vitest": "10.
|
|
68
|
-
"@storybook/react": "10.
|
|
69
|
-
"@storybook/react-vite": "10.
|
|
70
|
-
"@vitest/browser": "4.1.
|
|
71
|
-
"@vitest/browser-playwright": "4.1.
|
|
72
|
-
"vitest": "4.1.
|
|
63
|
+
"@playwright/test": "1.60.0",
|
|
64
|
+
"@storybook/addon-a11y": "10.4.0",
|
|
65
|
+
"@storybook/addon-docs": "10.4.0",
|
|
66
|
+
"@storybook/addon-links": "10.4.0",
|
|
67
|
+
"@storybook/addon-vitest": "10.4.0",
|
|
68
|
+
"@storybook/react": "10.4.0",
|
|
69
|
+
"@storybook/react-vite": "10.4.0",
|
|
70
|
+
"@vitest/browser": "4.1.7",
|
|
71
|
+
"@vitest/browser-playwright": "4.1.7",
|
|
72
|
+
"vitest": "4.1.7",
|
|
73
73
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
74
74
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
75
75
|
"eslint-plugin-react": "7.37.5",
|
|
76
|
-
"eslint-plugin-react-hooks": "7.
|
|
77
|
-
"eslint-plugin-storybook": "10.
|
|
76
|
+
"eslint-plugin-react-hooks": "7.1.1",
|
|
77
|
+
"eslint-plugin-storybook": "10.4.0",
|
|
78
78
|
"event-source-polyfill": "1.0.31",
|
|
79
|
-
"mixpanel-browser": "2.
|
|
80
|
-
"playwright": "1.
|
|
81
|
-
"react": "19.2.
|
|
82
|
-
"react-dom": "19.2.
|
|
83
|
-
"react-is": "19.2.
|
|
79
|
+
"mixpanel-browser": "2.79.0",
|
|
80
|
+
"playwright": "1.60.0",
|
|
81
|
+
"react": "19.2.6",
|
|
82
|
+
"react-dom": "19.2.6",
|
|
83
|
+
"react-is": "19.2.6",
|
|
84
84
|
"rimraf": "6.1.3",
|
|
85
85
|
"serve": "14.2.6",
|
|
86
|
-
"storybook": "10.
|
|
87
|
-
"styled-components": "6.4.
|
|
88
|
-
"typescript-eslint": "8.
|
|
89
|
-
"wait-on": "9.0.
|
|
86
|
+
"storybook": "10.4.0",
|
|
87
|
+
"styled-components": "6.4.2",
|
|
88
|
+
"typescript-eslint": "8.59.4",
|
|
89
|
+
"wait-on": "9.0.10"
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
92
|
"@carbon/react": "1.x",
|
|
@@ -371,7 +371,7 @@ export const C3DataTable = ({ data, headers, options, toolbar: singleToolbar, to
|
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
-
if (toolbarComponents.length > 0 ||
|
|
374
|
+
if (toolbarComponents.length > 0 || searchComponent) {
|
|
375
375
|
toolbarComponent = (_jsx(TableToolbar, { "aria-label": 'data table toolbar', children: _jsxs(ToolbarWrapper, { style: {
|
|
376
376
|
justifyContent: toolbarComponents.length > 5 ? 'normal' : 'end',
|
|
377
377
|
flexWrap: toolbarComponents.length > 5 ? 'wrap' : undefined,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { type FC, type PropsWithChildren } from 'react';
|
|
1
|
+
import React, { type FC, type PropsWithChildren, type RefObject } from 'react';
|
|
2
2
|
export declare enum HelpCenterHintType {
|
|
3
3
|
HelpCenter = "help-center",
|
|
4
4
|
Onboarding = "onboarding"
|
|
@@ -13,6 +13,7 @@ export type C3HelpCenterContextValue = {
|
|
|
13
13
|
setShowHintOnClose: (showHintOnClose: boolean) => void;
|
|
14
14
|
hintType: HelpCenterHintType;
|
|
15
15
|
setHintType: (hintType: HelpCenterHintType) => void;
|
|
16
|
+
launcherButtonRef: RefObject<HTMLButtonElement | null>;
|
|
16
17
|
};
|
|
17
18
|
export declare const C3HelpCenterContext: React.Context<C3HelpCenterContextValue>;
|
|
18
19
|
export declare const C3HelpCenterProvider: FC<PropsWithChildren>;
|
|
@@ -4,7 +4,7 @@ import { jsx as _jsx } 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 React, { useEffect, useState, } from 'react';
|
|
7
|
+
import React, { useEffect, useRef, useState, } from 'react';
|
|
8
8
|
export var HelpCenterHintType;
|
|
9
9
|
(function (HelpCenterHintType) {
|
|
10
10
|
HelpCenterHintType["HelpCenter"] = "help-center";
|
|
@@ -19,6 +19,7 @@ export const C3HelpCenterContext = React.createContext({
|
|
|
19
19
|
setShowHintOnClose: () => undefined,
|
|
20
20
|
hintType: HelpCenterHintType.Onboarding,
|
|
21
21
|
setHintType: () => undefined,
|
|
22
|
+
launcherButtonRef: { current: null },
|
|
22
23
|
});
|
|
23
24
|
export const C3HelpCenterProvider = ({ children }) => {
|
|
24
25
|
const [isHelpCenterOpen, setIsHelpCenterOpen] = useState(false);
|
|
@@ -26,6 +27,7 @@ export const C3HelpCenterProvider = ({ children }) => {
|
|
|
26
27
|
const [showHint, setShowHint] = useState(false);
|
|
27
28
|
const [showHintOnClose, setShowHintOnClose] = useState(false);
|
|
28
29
|
const [hintType, setHintType] = useState(HelpCenterHintType.Onboarding);
|
|
30
|
+
const launcherButtonRef = useRef(null);
|
|
29
31
|
const openHelpCenter = (showTabId) => {
|
|
30
32
|
if (!isHelpCenterOpen) {
|
|
31
33
|
setIsHelpCenterOpen(true);
|
|
@@ -53,6 +55,7 @@ export const C3HelpCenterProvider = ({ children }) => {
|
|
|
53
55
|
setShowHintOnClose,
|
|
54
56
|
hintType,
|
|
55
57
|
setHintType,
|
|
58
|
+
launcherButtonRef,
|
|
56
59
|
}, children: children }));
|
|
57
60
|
};
|
|
58
61
|
export const useC3HelpCenter = () => React.useContext(C3HelpCenterContext);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Dict } from 'mixpanel-browser';
|
|
2
|
-
import { type FC } from 'react';
|
|
2
|
+
import React, { type FC } from 'react';
|
|
3
3
|
import { type Theme } from '../c3-user-configuration/c3-profile-provider/c3-profile-provider';
|
|
4
4
|
import type { Persona } from './c3-help-center.types';
|
|
5
5
|
export interface C3HelpCenterProps {
|
|
@@ -12,5 +12,6 @@ export interface C3HelpCenterProps {
|
|
|
12
12
|
onRequestClose?: () => void;
|
|
13
13
|
onRequestOpen?: () => void;
|
|
14
14
|
mixpanelTrack?: (event: string, data: Dict | undefined) => void;
|
|
15
|
+
launcherButtonRef?: React.RefObject<HTMLButtonElement | null>;
|
|
15
16
|
}
|
|
16
17
|
export declare const C3HelpCenter: FC<C3HelpCenterProps>;
|
|
@@ -21,8 +21,9 @@ const StyledComposedModal = styled(ComposedModal) `
|
|
|
21
21
|
mask-image: none;
|
|
22
22
|
}
|
|
23
23
|
`;
|
|
24
|
-
export const C3HelpCenter = ({ autoStartSurvey, origin, flags, onRequestClose, mixpanelTrack: customMixpanelTrack, onRequestOpen, theme, onPersonaChange, activeTab, }) => {
|
|
25
|
-
const { isHelpCenterOpen: isOpen, setIsHelpCenterOpen, setShowHintOnClose, } = useC3HelpCenter();
|
|
24
|
+
export const C3HelpCenter = ({ autoStartSurvey, origin, flags, onRequestClose, mixpanelTrack: customMixpanelTrack, onRequestOpen, theme, onPersonaChange, activeTab, launcherButtonRef, }) => {
|
|
25
|
+
const { isHelpCenterOpen: isOpen, setIsHelpCenterOpen, setShowHintOnClose, launcherButtonRef: contextLauncherButtonRef, } = useC3HelpCenter();
|
|
26
|
+
const effectiveLauncherButtonRef = launcherButtonRef ?? contextLauncherButtonRef;
|
|
26
27
|
const { userToken, decodedToken, activeOrganizationId, handleTheme, decodedAudience, analyticsTrack, currentApp, } = useC3UserConfiguration();
|
|
27
28
|
const { theme: themeConfig, isEnabled, reloadClusters } = useC3Profile();
|
|
28
29
|
const themeHandlingEnabled = isEnabled && !!handleTheme && !!themeConfig;
|
|
@@ -212,7 +213,7 @@ export const C3HelpCenter = ({ autoStartSurvey, origin, flags, onRequestClose, m
|
|
|
212
213
|
setShowSurvey(false);
|
|
213
214
|
}, 400);
|
|
214
215
|
};
|
|
215
|
-
return (_jsx(Layer, { children: _jsx(StyledComposedModal, { open: isOpen, size: 'lg', onClose: closeFn, className: 'help-center', "aria-label": 'HelpCenter', preventCloseOnClickOutside: true, style: showSurvey || !persona?.wasShown
|
|
216
|
+
return (_jsx(Layer, { children: _jsx(StyledComposedModal, { open: isOpen, size: 'lg', onClose: closeFn, launcherButtonRef: effectiveLauncherButtonRef, className: 'help-center', "aria-label": 'HelpCenter', preventCloseOnClickOutside: true, style: showSurvey || !persona?.wasShown
|
|
216
217
|
? { backgroundColor: 'rgba(22,22,22, 0.8)' }
|
|
217
218
|
: {}, children: _jsx(ErrorBoundary, { fallbackRender: () => (_jsxs(_Fragment, { children: [_jsx(ModalHeader, { title: 'Help Center', closeModal: closeFn }), _jsx(ModalBody, { children: _jsx(ActionableNotification, { inline: true, hideCloseButton: true, lowContrast: true, kind: 'error', title: 'Something went wrong.', subtitle: 'Try reloading the page.', actionButtonLabel: 'Reload', onActionButtonClick: () => window.location.reload() }) })] })), children: showSurvey || !persona?.wasShown ? (_jsx(C3OnboardingSurvey, { personaCallback: personaCallback, persona: persona, mixpanelTrack: mixpanelTrack, onRequestClose: closeFn, onRequestSkip: onRequestSkipSurvey, theme: resolvedTheme, origin: hostApp, modal: true })) : (_jsx(HelpCenter, { configuration: helpCenterConfig, persona: persona, audience: decodedAudience || '', flags: flags, onRequestResumeSurvey: onRequestResumeSurvey, onRequestRetakeSurvey: onRequestRetakeSurvey, onRequestClose: closeFn, mixpanelTrack: mixpanelTrack, email: email, theme: resolvedTheme, origin: hostApp, initialTab: activeTab })) }) }) }));
|
|
218
219
|
};
|
|
@@ -8,10 +8,9 @@ export interface C3LicenseTagProps {
|
|
|
8
8
|
expiresAt?: number | string;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Renders
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Drop into `headerTrailingContent` of C3NavigationV2.
|
|
11
|
+
* Renders license status tags for the Camunda header. Mirrors V1 c3-navigation:
|
|
12
|
+
* always renders a production-status tag, plus a non-commercial tag (or its
|
|
13
|
+
* expiring/expired variant) when isCommercial === false. Drop the element into
|
|
14
|
+
* `headerTrailingContent` of C3NavigationV2.
|
|
16
15
|
*/
|
|
17
16
|
export declare const C3LicenseTag: (props: C3LicenseTagProps) => JSX.Element | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
|
|
4
4
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
@@ -17,63 +17,70 @@ function resolveExpiresAt(value) {
|
|
|
17
17
|
return Date.parse(value);
|
|
18
18
|
return value;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
// Matches V1 c3-navigation: production-status tag is always shown, and a
|
|
21
|
+
// non-commercial tag is shown additionally when isCommercial === false. They
|
|
22
|
+
// stack rather than override each other.
|
|
23
|
+
function getTagVariants(props) {
|
|
21
24
|
const { isProductionLicense, isCommercial, expiresAt: rawExpiresAt } = props;
|
|
22
25
|
const expiresAt = resolveExpiresAt(rawExpiresAt);
|
|
23
26
|
const now = Date.now();
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
label: 'Non-commercial license - expired',
|
|
28
|
-
color: 'red',
|
|
29
|
-
icon: Warning,
|
|
30
|
-
tooltip: (_jsx("p", { children: "To continue using all features, please renew your license." })),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
// Non-commercial about to expire (within 30 days)
|
|
34
|
-
if (isCommercial === false &&
|
|
35
|
-
expiresAt !== undefined &&
|
|
36
|
-
expiresAt - LICENSE_EXPIRY_THRESHOLD < now &&
|
|
37
|
-
expiresAt > now) {
|
|
38
|
-
const daysLeft = Math.floor((expiresAt - now) / DAY);
|
|
39
|
-
return {
|
|
40
|
-
label: `Non-commercial license - ${daysLeft} ${daysLeft > 1 ? 'days' : 'day'} left`,
|
|
41
|
-
color: 'blue',
|
|
42
|
-
icon: Time,
|
|
43
|
-
tooltip: (_jsx("p", { children: "Please renew and provide new license keys to continue production use of Camunda." })),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
// Non-commercial (not expiring soon or no expiry)
|
|
47
|
-
if (isCommercial === false &&
|
|
48
|
-
(expiresAt === undefined || expiresAt - LICENSE_EXPIRY_THRESHOLD >= now)) {
|
|
49
|
-
return {
|
|
50
|
-
label: 'Non-commercial license',
|
|
51
|
-
color: 'gray',
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// Production or non-production license
|
|
55
|
-
return {
|
|
27
|
+
const variants = [];
|
|
28
|
+
variants.push({
|
|
29
|
+
key: 'license-tag',
|
|
56
30
|
label: isProductionLicense
|
|
57
31
|
? 'Production license'
|
|
58
32
|
: 'Non-production license',
|
|
59
33
|
color: 'gray',
|
|
60
34
|
tooltip: isProductionLicense ? undefined : (_jsxs("p", { children: ["Non-production license. For production usage details, visit our", ' ', _jsx(Link, { href: NON_PRODUCTION_TERMS_LINK, target: '_blank', rel: 'noopener noreferrer', style: { display: 'inline' }, children: "terms & conditions page" }), ' ', "or", ' ', _jsx(Link, { href: SALES_CONTACT_LINK, target: '_blank', rel: 'noopener noreferrer', style: { display: 'inline' }, children: "contact our sales team" }), "."] })),
|
|
61
|
-
};
|
|
35
|
+
});
|
|
36
|
+
if (isCommercial === false) {
|
|
37
|
+
if (expiresAt !== undefined && expiresAt < now) {
|
|
38
|
+
variants.push({
|
|
39
|
+
key: 'non-commercial-license-tag-is-expired',
|
|
40
|
+
label: 'Non-commercial license - expired',
|
|
41
|
+
color: 'red',
|
|
42
|
+
icon: Warning,
|
|
43
|
+
tooltip: (_jsx("p", { children: "To continue using all features, please renew your license." })),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
else if (expiresAt !== undefined &&
|
|
47
|
+
expiresAt - LICENSE_EXPIRY_THRESHOLD < now &&
|
|
48
|
+
expiresAt > now) {
|
|
49
|
+
const daysLeft = Math.floor((expiresAt - now) / DAY);
|
|
50
|
+
variants.push({
|
|
51
|
+
key: 'non-commercial-license-tag-about-to-expire',
|
|
52
|
+
label: `Non-commercial license - ${daysLeft} ${daysLeft > 1 ? 'days' : 'day'} left`,
|
|
53
|
+
color: 'blue',
|
|
54
|
+
icon: Time,
|
|
55
|
+
tooltip: (_jsx("p", { children: "Please renew and provide new license keys to continue production use of Camunda." })),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
variants.push({
|
|
60
|
+
key: 'non-commercial-license-tag',
|
|
61
|
+
label: 'Non-commercial license',
|
|
62
|
+
color: 'gray',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return variants;
|
|
67
|
+
}
|
|
68
|
+
function renderVariant(variant) {
|
|
69
|
+
const { key, label, color, icon, tooltip } = variant;
|
|
70
|
+
if (tooltip) {
|
|
71
|
+
return (_jsxs(Toggletip, { align: 'bottom', children: [_jsx(ToggletipButton, { as: 'span', label: label, children: _jsx(Tag, { type: color, renderIcon: icon, style: { margin: 0, cursor: 'pointer' }, children: label }) }), _jsx(ToggletipContent, { children: tooltip })] }, key));
|
|
72
|
+
}
|
|
73
|
+
return (_jsx(Tag, { type: color, renderIcon: icon, style: { margin: 0 }, children: label }, key));
|
|
62
74
|
}
|
|
63
75
|
/**
|
|
64
|
-
* Renders
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* Drop into `headerTrailingContent` of C3NavigationV2.
|
|
76
|
+
* Renders license status tags for the Camunda header. Mirrors V1 c3-navigation:
|
|
77
|
+
* always renders a production-status tag, plus a non-commercial tag (or its
|
|
78
|
+
* expiring/expired variant) when isCommercial === false. Drop the element into
|
|
79
|
+
* `headerTrailingContent` of C3NavigationV2.
|
|
69
80
|
*/
|
|
70
81
|
export const C3LicenseTag = (props) => {
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
82
|
+
const variants = getTagVariants(props);
|
|
83
|
+
if (variants.length === 0)
|
|
73
84
|
return null;
|
|
74
|
-
|
|
75
|
-
if (tooltip) {
|
|
76
|
-
return (_jsxs(Toggletip, { align: 'bottom', children: [_jsx(ToggletipButton, { as: 'span', label: label, children: _jsx(Tag, { type: color, renderIcon: icon, style: { margin: 0, cursor: 'pointer' }, children: label }) }), _jsx(ToggletipContent, { children: tooltip })] }));
|
|
77
|
-
}
|
|
78
|
-
return (_jsx(Tag, { type: color, renderIcon: icon, style: { margin: 0 }, children: label }));
|
|
85
|
+
return _jsx(_Fragment, { children: variants.map(renderVariant) });
|
|
79
86
|
};
|
|
@@ -138,18 +138,18 @@ export const C3NavigationAppBar = ({ app: appProps, appBar, forwardRef, navbar,
|
|
|
138
138
|
const clusterDto = data.payload;
|
|
139
139
|
const status = clusterDto.status;
|
|
140
140
|
const endpoints = {
|
|
141
|
-
tasklist: status?.tasklistUrl,
|
|
142
|
-
operate: status?.operateUrl,
|
|
143
|
-
optimize: status?.optimizeUrl,
|
|
141
|
+
tasklist: status?.tasklistUrl ?? '',
|
|
142
|
+
operate: status?.operateUrl ?? '',
|
|
143
|
+
optimize: status?.optimizeUrl ?? '',
|
|
144
144
|
console: '',
|
|
145
145
|
modeler: '',
|
|
146
146
|
identity: status?.identityUrl ?? '',
|
|
147
147
|
admin: status?.identityUrl ?? '',
|
|
148
148
|
};
|
|
149
149
|
const expectedStatus = {
|
|
150
|
-
tasklist: status?.tasklistStatus,
|
|
151
|
-
operate: status?.operateStatus,
|
|
152
|
-
optimize: status?.optimizeStatus,
|
|
150
|
+
tasklist: status?.tasklistStatus ?? '',
|
|
151
|
+
operate: status?.operateStatus ?? '',
|
|
152
|
+
optimize: status?.optimizeStatus ?? '',
|
|
153
153
|
console: '',
|
|
154
154
|
modeler: '',
|
|
155
155
|
identity: '',
|
package/lib/esm/src/components/c3-navigation/c3-navigation-sidebar/c3-navigation-sidebar-element.js
CHANGED
|
@@ -39,6 +39,9 @@ const C3NavigationSidebarElement = (props) => {
|
|
|
39
39
|
setIsOverflown(element ? element.offsetWidth < element.scrollWidth : false);
|
|
40
40
|
};
|
|
41
41
|
useEffect(() => {
|
|
42
|
+
if (typeof window === 'undefined') {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
42
45
|
window.addEventListener('resize', handleSetIsOverflown);
|
|
43
46
|
handleSetIsOverflown();
|
|
44
47
|
return () => window.removeEventListener('resize', handleSetIsOverflown);
|
|
@@ -60,16 +60,25 @@ const C3NavigationSideBar = (props) => {
|
|
|
60
60
|
setScrollBarWidth(scrollbarWidth);
|
|
61
61
|
};
|
|
62
62
|
useEffect(() => {
|
|
63
|
+
if (typeof window === 'undefined') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
63
66
|
window.addEventListener('resize', handleResize);
|
|
64
67
|
handleResize();
|
|
65
68
|
return () => window.removeEventListener('resize', handleResize);
|
|
66
69
|
}, []);
|
|
67
70
|
useEffect(() => {
|
|
71
|
+
let timeoutId;
|
|
68
72
|
if (isOpen) {
|
|
69
|
-
setTimeout(() => {
|
|
73
|
+
timeoutId = setTimeout(() => {
|
|
70
74
|
handleResize();
|
|
71
75
|
}, 120);
|
|
72
76
|
}
|
|
77
|
+
return () => {
|
|
78
|
+
if (timeoutId !== undefined) {
|
|
79
|
+
clearTimeout(timeoutId);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
73
82
|
}, [isOpen]);
|
|
74
83
|
return (_jsxs(Wrapper, { children: [_jsx(HeaderGlobalAction, { ref: setIconRef, "aria-label": sideBar.tooltip ?? `Open ${sideBar.ariaLabel}`, "aria-expanded": isOpen, "aria-controls": id, onClick: () => {
|
|
75
84
|
setIsOpen(!isOpen);
|
|
@@ -40,6 +40,18 @@ export function useOnClickOutside(handler) {
|
|
|
40
40
|
return { panelRef, setPanelRef, iconRef, setIconRef };
|
|
41
41
|
}
|
|
42
42
|
export function executeMediaQuery(mediaQuery) {
|
|
43
|
+
if (typeof window === 'undefined') {
|
|
44
|
+
return {
|
|
45
|
+
matches: false,
|
|
46
|
+
media: mediaQuery,
|
|
47
|
+
onchange: null,
|
|
48
|
+
addEventListener: () => { },
|
|
49
|
+
removeEventListener: () => { },
|
|
50
|
+
addListener: () => { },
|
|
51
|
+
removeListener: () => { },
|
|
52
|
+
dispatchEvent: () => false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
43
55
|
return window.matchMedia(mediaQuery);
|
|
44
56
|
}
|
|
45
57
|
export function useMediaQuery(mediaQuery) {
|
|
@@ -9,16 +9,16 @@ import { Checkmark, ChevronDown, OverflowMenuVertical, } from '@carbon/react/ico
|
|
|
9
9
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
11
11
|
import styled from 'styled-components';
|
|
12
|
+
// `display: contents` so nested flex doesn't trap min-content; label
|
|
13
|
+
// shrinkage propagates to the breadcrumb row directly.
|
|
12
14
|
const SegmentWrapper = styled.div `
|
|
13
|
-
display:
|
|
14
|
-
align-items: center;
|
|
15
|
-
position: relative;
|
|
15
|
+
display: contents;
|
|
16
16
|
`;
|
|
17
17
|
const SegmentButton = styled.button `
|
|
18
18
|
display: flex;
|
|
19
19
|
align-items: center;
|
|
20
20
|
gap: var(--cds-spacing-03);
|
|
21
|
-
padding: var(--cds-spacing-02) var(--cds-spacing-
|
|
21
|
+
padding: var(--cds-spacing-02) var(--cds-spacing-04);
|
|
22
22
|
background: transparent;
|
|
23
23
|
border: none;
|
|
24
24
|
border-radius: 4px;
|
|
@@ -29,6 +29,8 @@ const SegmentButton = styled.button `
|
|
|
29
29
|
text-decoration: none;
|
|
30
30
|
white-space: nowrap;
|
|
31
31
|
transition: background 0.15s, color 0.15s;
|
|
32
|
+
min-width: 0;
|
|
33
|
+
flex-shrink: ${(p) => (p.$isLast ? 0 : 1)};
|
|
32
34
|
|
|
33
35
|
&:hover {
|
|
34
36
|
background: ${(p) => (p.$isInteractive ? 'var(--cds-layer-hover)' : 'transparent')};
|
|
@@ -41,7 +43,13 @@ const SegmentButton = styled.button `
|
|
|
41
43
|
outline-offset: -2px;
|
|
42
44
|
}
|
|
43
45
|
`;
|
|
44
|
-
const
|
|
46
|
+
const SegmentLabel = styled.span `
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
text-overflow: ellipsis;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
min-width: 0;
|
|
51
|
+
`;
|
|
52
|
+
const ControlButton = styled.button `
|
|
45
53
|
display: flex;
|
|
46
54
|
align-items: center;
|
|
47
55
|
justify-content: center;
|
|
@@ -52,6 +60,7 @@ const ChevronButton = styled.button `
|
|
|
52
60
|
cursor: pointer;
|
|
53
61
|
color: var(--cds-icon-secondary);
|
|
54
62
|
transition: background 0.15s;
|
|
63
|
+
flex-shrink: 0;
|
|
55
64
|
|
|
56
65
|
&:hover {
|
|
57
66
|
background: var(--cds-layer-hover);
|
|
@@ -62,32 +71,20 @@ const ChevronButton = styled.button `
|
|
|
62
71
|
outline-offset: -2px;
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
${SegmentButton} + & {
|
|
75
|
+
margin-left: -0.125rem;
|
|
76
|
+
}
|
|
77
|
+
& + & {
|
|
78
|
+
margin-left: 0.375rem;
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
const ChevronButton = styled(ControlButton) `
|
|
65
82
|
svg {
|
|
66
83
|
transform: ${(p) => (p.$isOpen ? 'rotate(180deg)' : 'rotate(0deg)')};
|
|
67
84
|
transition: transform 0.15s;
|
|
68
85
|
}
|
|
69
86
|
`;
|
|
70
|
-
const ActionMenuButton = styled
|
|
71
|
-
display: flex;
|
|
72
|
-
align-items: center;
|
|
73
|
-
justify-content: center;
|
|
74
|
-
padding: var(--cds-spacing-02);
|
|
75
|
-
background: ${(p) => (p.$isOpen ? 'var(--cds-layer-01)' : 'transparent')};
|
|
76
|
-
border: none;
|
|
77
|
-
border-radius: 4px;
|
|
78
|
-
cursor: pointer;
|
|
79
|
-
color: var(--cds-icon-secondary);
|
|
80
|
-
transition: background 0.15s;
|
|
81
|
-
|
|
82
|
-
&:hover {
|
|
83
|
-
background: var(--cds-layer-hover);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
&:focus-visible {
|
|
87
|
-
outline: 2px solid var(--cds-focus);
|
|
88
|
-
outline-offset: -2px;
|
|
89
|
-
}
|
|
90
|
-
`;
|
|
87
|
+
const ActionMenuButton = styled(ControlButton) ``;
|
|
91
88
|
const ActionMenuItem = styled.button `
|
|
92
89
|
width: 100%;
|
|
93
90
|
display: flex;
|
|
@@ -167,6 +164,7 @@ const Separator = styled.span `
|
|
|
167
164
|
color: var(--cds-text-secondary);
|
|
168
165
|
font-size: 0.875rem;
|
|
169
166
|
user-select: none;
|
|
167
|
+
flex-shrink: 0;
|
|
170
168
|
|
|
171
169
|
&::after {
|
|
172
170
|
content: '/';
|
|
@@ -312,6 +310,7 @@ const BreadcrumbSegmentComponent = ({ segment, isLast, linkComponent, }) => {
|
|
|
312
310
|
const dropdownId = useRef(`dropdown-${Math.random().toString(36).slice(2, 8)}`).current;
|
|
313
311
|
const { isOpen, close, toggle } = useBreadcrumbDropdown(dropdownId);
|
|
314
312
|
const wrapperRef = useRef(null);
|
|
313
|
+
const segmentButtonRef = useRef(null);
|
|
315
314
|
const chevronRef = useRef(null);
|
|
316
315
|
const dropdownPanelRef = useRef(null);
|
|
317
316
|
const hasDropdown = segment.dropdownItems && segment.dropdownItems.length > 0;
|
|
@@ -319,8 +318,9 @@ const BreadcrumbSegmentComponent = ({ segment, isLast, linkComponent, }) => {
|
|
|
319
318
|
const dropdownAriaLabel = segment.dropdownAriaLabel ?? `Switch ${segment.label}`;
|
|
320
319
|
const [dropdownPos, setDropdownPos] = useState(undefined);
|
|
321
320
|
const updateDropdownPosition = useCallback(() => {
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
// SegmentWrapper has no box (display: contents); anchor on the button.
|
|
322
|
+
if (segmentButtonRef.current) {
|
|
323
|
+
const rect = segmentButtonRef.current.getBoundingClientRect();
|
|
324
324
|
setDropdownPos({ top: rect.bottom + 4, left: rect.left });
|
|
325
325
|
}
|
|
326
326
|
}, []);
|
|
@@ -344,11 +344,11 @@ const BreadcrumbSegmentComponent = ({ segment, isLast, linkComponent, }) => {
|
|
|
344
344
|
close();
|
|
345
345
|
}, [close]);
|
|
346
346
|
const handleDropdownKeyDown = usePanelKeyboard(dropdownPanelRef, close, chevronRef, isOpen, '[role="option"]');
|
|
347
|
-
return (_jsxs(_Fragment, { children: [_jsxs(SegmentWrapper, { ref: wrapperRef, children: [_jsxs(SegmentButton, { as: segment.linkProps?.href !== undefined
|
|
347
|
+
return (_jsxs(_Fragment, { children: [_jsxs(SegmentWrapper, { ref: wrapperRef, children: [_jsxs(SegmentButton, { ref: segmentButtonRef, as: segment.linkProps?.href !== undefined
|
|
348
348
|
? (linkComponent ?? 'a')
|
|
349
349
|
: segment.linkProps
|
|
350
350
|
? linkComponent
|
|
351
|
-
: undefined, ...(segment.linkProps ?? {}), "$isInteractive": !!(segment.onClick || segment.linkProps), "$isLast": isLast, onClick: segment.onClick, "aria-label": segment.label, children: [Icon && _jsx(Icon, { size: 16, style: { flexShrink: 0 } }), _jsx(
|
|
351
|
+
: undefined, ...(segment.linkProps ?? {}), "$isInteractive": !!(segment.onClick || segment.linkProps), "$isLast": isLast, onClick: segment.onClick, "aria-label": segment.label, title: segment.label, children: [Icon && _jsx(Icon, { size: 16, style: { flexShrink: 0 } }), _jsx(SegmentLabel, { children: segment.label }), segment.trailingElement] }), segment.menuElement, segment.actions && segment.actions.length > 0 && (_jsx(ActionsMenu, { actions: segment.actions, ariaLabel: `${segment.label} actions` })), hasDropdown && (_jsx(ChevronButton, { ref: chevronRef, "$isOpen": isOpen, onClick: toggle, onKeyDown: (e) => {
|
|
352
352
|
if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {
|
|
353
353
|
if (!isOpen) {
|
|
354
354
|
e.preventDefault();
|
|
@@ -365,7 +365,9 @@ const BreadcrumbBarWrapper = styled.div `
|
|
|
365
365
|
align-items: center;
|
|
366
366
|
flex: 1;
|
|
367
367
|
min-width: 0;
|
|
368
|
+
height: 100%;
|
|
368
369
|
overflow-x: auto;
|
|
369
|
-
|
|
370
|
+
margin-left: var(--cds-spacing-03);
|
|
371
|
+
margin-right: var(--cds-spacing-03);
|
|
370
372
|
`;
|
|
371
373
|
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))) }));
|
|
@@ -16,6 +16,12 @@ const StyledHeader = styled(Header) `
|
|
|
16
16
|
border-bottom: 1px solid var(--cds-border-subtle) !important;
|
|
17
17
|
box-shadow: none !important;
|
|
18
18
|
z-index: 8001 !important;
|
|
19
|
+
|
|
20
|
+
// Carbon defaults the tools area to flex: 1, which splits the row
|
|
21
|
+
// 50/50 with breadcrumbs. Make it intrinsic instead.
|
|
22
|
+
.cds--header__global {
|
|
23
|
+
flex: 0 0 auto;
|
|
24
|
+
}
|
|
19
25
|
`;
|
|
20
26
|
const LogoSection = styled.a `
|
|
21
27
|
display: flex;
|
|
@@ -57,7 +63,7 @@ export const C3NavigationV2 = ({ app, skipToContentTargetId, skipToContentLabel
|
|
|
57
63
|
root.style.removeProperty('--c3-sidebar-width');
|
|
58
64
|
};
|
|
59
65
|
}, [sidebarWidth]);
|
|
60
|
-
return (_jsxs(_Fragment, { children: [_jsxs(StyledHeader, { "aria-label": ariaLabel, children: [_jsx(SkipToContent, { href: `#${skipToContentTargetId}`, children: skipToContentLabel }),
|
|
66
|
+
return (_jsxs(_Fragment, { children: [_jsxs(StyledHeader, { "aria-label": ariaLabel, children: [_jsx(SkipToContent, { href: `#${skipToContentTargetId}`, children: skipToContentLabel }), _jsx(LogoSection, { as: app.linkProps ? LinkEl : 'div', "aria-label": app.name ? `Camunda ${app.name}` : 'Camunda', ...(app.linkProps ?? {}), children: _jsx(CamundaLogo, {}) }), breadcrumbs && breadcrumbs.length > 0 && (_jsx(C3BreadcrumbBar, { segments: breadcrumbs, linkComponent: LinkEl })), _jsxs(HeaderGlobalBar, { children: [headerTrailingContent && (_jsx("span", { style: {
|
|
61
67
|
display: 'flex',
|
|
62
68
|
alignItems: 'center',
|
|
63
69
|
padding: '0 var(--cds-spacing-03)',
|
|
@@ -2,6 +2,10 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
/**
|
|
3
3
|
* Describes a tool button in the header. If `panel` is provided, clicking the
|
|
4
4
|
* button toggles a slide-over panel. Without `panel`, the button is standalone.
|
|
5
|
+
*
|
|
6
|
+
* `renderButton` is rendered via JSX (`<tool.renderButton ... />`), so it
|
|
7
|
+
* may call hooks internally — e.g. reading `C3NotificationContext` to drive
|
|
8
|
+
* an unread-state badge.
|
|
5
9
|
*/
|
|
6
10
|
export interface ToolDescriptor {
|
|
7
11
|
key: string;
|
|
@@ -143,6 +147,19 @@ export interface SidebarSection {
|
|
|
143
147
|
compact?: boolean;
|
|
144
148
|
}
|
|
145
149
|
export type SidebarNode = SidebarItem | SidebarGroupItem | SidebarGroup | SidebarSection;
|
|
150
|
+
export interface SidebarLabels {
|
|
151
|
+
/** Toggle button text when expanded. Defaults to `'Collapse'`. */
|
|
152
|
+
collapse?: string;
|
|
153
|
+
/** Tooltip on the collapsed toggle button. Defaults to `'Expand'`. */
|
|
154
|
+
expand?: string;
|
|
155
|
+
/** Aria-label on the toggle button. Receives `isExpanded`. Defaults to `'Collapse sidebar'` / `'Expand sidebar'`. */
|
|
156
|
+
toggleAriaLabel?: (isExpanded: boolean) => string;
|
|
157
|
+
/** Aria-label on a group's chevron. Receives `{label, isExpanded}`. Defaults to `'Collapse {label}'` / `'Expand {label}'`. */
|
|
158
|
+
groupToggleAriaLabel?: (args: {
|
|
159
|
+
label: string;
|
|
160
|
+
isExpanded: boolean;
|
|
161
|
+
}) => string;
|
|
162
|
+
}
|
|
146
163
|
export interface SidebarProps {
|
|
147
164
|
ariaLabel: string;
|
|
148
165
|
children: SidebarNode[];
|
|
@@ -151,6 +168,7 @@ export interface SidebarProps {
|
|
|
151
168
|
expandedWidth?: string;
|
|
152
169
|
collapsedWidth?: string;
|
|
153
170
|
linkComponent?: LinkComponent;
|
|
171
|
+
labels?: SidebarLabels;
|
|
154
172
|
}
|
|
155
173
|
export interface AppProps {
|
|
156
174
|
name?: string;
|
|
@@ -5,4 +5,4 @@ import type { SidebarProps } from './c3-navigation-v2.types';
|
|
|
5
5
|
* Loose items (not wrapped in a section) are valid and behave as an implicit
|
|
6
6
|
* untitled group at the top.
|
|
7
7
|
*/
|
|
8
|
-
export declare const C3Sidebar: ({ ariaLabel, children: nodes, isExpanded, onToggleExpanded, expandedWidth, collapsedWidth, linkComponent, }: SidebarProps) => JSX.Element;
|
|
8
|
+
export declare const C3Sidebar: ({ ariaLabel, children: nodes, isExpanded, onToggleExpanded, expandedWidth, collapsedWidth, linkComponent, labels, }: SidebarProps) => JSX.Element;
|