@dbcdk/react-components 0.0.9 → 0.0.12
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/dist/components/accordion/Accordion.d.ts +27 -0
- package/dist/components/accordion/Accordion.js +66 -0
- package/dist/components/accordion/Accordion.module.css +87 -0
- package/dist/components/button/Button.module.css +1 -0
- package/dist/components/card/Card.d.ts +21 -3
- package/dist/components/card/Card.js +17 -2
- package/dist/components/card/Card.module.css +59 -0
- package/dist/components/circle/Circle.d.ts +5 -1
- package/dist/components/circle/Circle.js +2 -2
- package/dist/components/circle/Circle.module.css +60 -4
- package/dist/components/code-block/CodeBlock.js +1 -1
- package/dist/components/code-block/CodeBlock.module.css +30 -17
- package/dist/components/copy-button/CopyButton.d.ts +1 -0
- package/dist/components/copy-button/CopyButton.js +10 -2
- package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
- package/dist/components/datetime-picker/DateTimePicker.js +72 -92
- package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
- package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
- package/dist/components/filter-field/FilterField.js +16 -11
- package/dist/components/filter-field/FilterField.module.css +133 -12
- package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
- package/dist/components/forms/checkbox/Checkbox.js +3 -5
- package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
- package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
- package/dist/components/forms/input/Input.d.ts +1 -0
- package/dist/components/forms/input/Input.js +2 -4
- package/dist/components/forms/input/Input.module.css +10 -11
- package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
- package/dist/components/forms/input-container/InputContainer.js +3 -3
- package/dist/components/forms/input-container/InputContainer.module.css +65 -0
- package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
- package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
- package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
- package/dist/components/forms/select/Select.d.ts +1 -1
- package/dist/components/forms/select/Select.js +3 -3
- package/dist/components/forms/text-area/Textarea.js +3 -3
- package/dist/components/forms/text-area/Textarea.module.css +8 -1
- package/dist/components/headline/Headline.d.ts +2 -7
- package/dist/components/headline/Headline.js +5 -2
- package/dist/components/headline/Headline.module.css +61 -2
- package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
- package/dist/components/hyperlink/Hyperlink.js +35 -7
- package/dist/components/hyperlink/Hyperlink.module.css +50 -2
- package/dist/components/icon/Icon.module.css +1 -0
- package/dist/components/interval-select/IntervalSelect.js +1 -1
- package/dist/components/menu/Menu.d.ts +32 -0
- package/dist/components/menu/Menu.js +73 -13
- package/dist/components/menu/Menu.module.css +72 -4
- package/dist/components/nav-bar/NavBar.d.ts +24 -6
- package/dist/components/overlay/modal/Modal.module.css +2 -2
- package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
- package/dist/components/overlay/side-panel/SidePanel.js +77 -4
- package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
- package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
- package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
- package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
- package/dist/components/page-layout/PageLayout.js +0 -2
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
- package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
- package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
- package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
- package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
- package/dist/components/split-button/SplitButton.d.ts +1 -1
- package/dist/components/split-button/SplitButton.js +3 -1
- package/dist/components/split-button/SplitButton.module.css +4 -4
- package/dist/components/state-page/StatePage.d.ts +9 -0
- package/dist/components/state-page/StatePage.js +20 -0
- package/dist/components/state-page/StatePage.module.css +9 -0
- package/dist/components/state-page/empty.d.ts +2 -0
- package/dist/components/state-page/empty.js +2 -0
- package/dist/components/state-page/error.d.ts +2 -0
- package/dist/components/state-page/error.js +2 -0
- package/dist/components/state-page/notFound.d.ts +2 -0
- package/dist/components/state-page/notFound.js +2 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
- package/dist/components/table/Table.d.ts +9 -4
- package/dist/components/table/Table.js +6 -9
- package/dist/components/table/Table.module.css +180 -59
- package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
- package/dist/components/table/components/empty-state/EmptyState.js +6 -7
- package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
- package/dist/components/table/components/table-settings/TableSettings.js +55 -4
- package/dist/components/table/tanstack.d.ts +12 -1
- package/dist/components/table/tanstack.js +75 -23
- package/dist/components/toast/Toast.js +5 -1
- package/dist/components/toast/Toast.module.css +40 -15
- package/dist/components/toast/provider/ToastProvider.js +1 -0
- package/dist/hooks/useTableSettings.d.ts +23 -4
- package/dist/hooks/useTableSettings.js +64 -17
- package/dist/hooks/useTimeDuration.js +9 -3
- package/dist/hooks/useViewportFill.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -1
- package/dist/src/styles/styles.css +60 -25
- package/dist/styles/animation.d.ts +5 -0
- package/dist/styles/animation.js +5 -0
- package/dist/styles/styles.css +60 -25
- package/dist/styles/themes/dbc/dark.css +1 -1
- package/dist/styles/themes/dbc/light.css +2 -1
- package/dist/utils/localStorage.utils.d.ts +19 -0
- package/dist/utils/localStorage.utils.js +78 -0
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* Menu.module.css */
|
|
1
2
|
.container {
|
|
2
3
|
list-style: none;
|
|
3
4
|
margin: 0;
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
display: contents;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/* Applied to actual interactive elements (button/a/custom that forwards className) */
|
|
20
22
|
.interactive {
|
|
21
23
|
display: flex;
|
|
22
24
|
align-items: center;
|
|
@@ -45,29 +47,95 @@
|
|
|
45
47
|
color var(--transition-fast) var(--ease-standard);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
/*
|
|
51
|
+
Applied to the immediate child of <li> even if it's NOT an interactive element (e.g. a <div>)
|
|
52
|
+
so that menu row styling still works for components that render a wrapper.
|
|
53
|
+
*/
|
|
54
|
+
.interactiveChild {
|
|
55
|
+
display: block;
|
|
56
|
+
inline-size: 100%;
|
|
57
|
+
border-radius: var(--border-radius-sm);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* NEW: make wrapper-children (Checkbox/Radio) look/space like menu rows */
|
|
61
|
+
.row > .interactiveChild {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
inline-size: 100%;
|
|
65
|
+
padding-block: calc(var(--spacing-xxs) + var(--density-comfortable));
|
|
66
|
+
padding-inline: var(--spacing-md);
|
|
67
|
+
border-radius: var(--border-radius-sm);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* NEW: let Checkbox/Radio consume full width so the hover area feels right */
|
|
71
|
+
.row > .interactiveChild > * {
|
|
72
|
+
inline-size: 100%;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* NEW: add consistent gap between control and label inside Checkbox/Radio
|
|
76
|
+
Both components use a root element with className={styles.container}.
|
|
77
|
+
Because they're CSS modules, we must target it with :global(.container). */
|
|
78
|
+
.row :global(.container) {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: var(--spacing-sm);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Hover: support both cases (interactive element, or wrapper child) */
|
|
85
|
+
.interactive:hover,
|
|
86
|
+
.row:hover > .interactiveChild {
|
|
49
87
|
background-color: var(--color-bg-hover-subtle);
|
|
50
88
|
}
|
|
51
89
|
|
|
90
|
+
/* Focus ring: support both cases */
|
|
52
91
|
.interactive:focus-visible {
|
|
53
92
|
outline: none;
|
|
54
93
|
box-shadow: var(--focus-ring);
|
|
55
94
|
}
|
|
56
95
|
|
|
96
|
+
/* If wrapper contains a focusable element, show ring when any child is focused */
|
|
97
|
+
.row:focus-within > .interactiveChild {
|
|
98
|
+
outline: none;
|
|
99
|
+
box-shadow: var(--focus-ring);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Selected/active (legacy + item variant) */
|
|
57
103
|
.active,
|
|
58
|
-
.interactive[aria-selected='true']
|
|
104
|
+
.interactive[aria-selected='true'],
|
|
105
|
+
.row > .interactiveChild.active,
|
|
106
|
+
.row > .interactiveChild[aria-selected='true'] {
|
|
59
107
|
background-color: var(--color-bg-selected);
|
|
60
108
|
color: var(--color-fg-default);
|
|
61
109
|
}
|
|
62
110
|
|
|
111
|
+
/* Checked (legacy support; kept in case any interactive element still uses aria-checked) */
|
|
112
|
+
.interactive[aria-checked='true'],
|
|
113
|
+
.row > .interactiveChild[aria-checked='true'] {
|
|
114
|
+
background-color: var(--color-bg-selected);
|
|
115
|
+
color: var(--color-fg-default);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Disabled: support both cases */
|
|
63
119
|
.interactive[aria-disabled='true'],
|
|
64
|
-
.interactive:disabled
|
|
120
|
+
.interactive:disabled,
|
|
121
|
+
.row > .interactiveChild[aria-disabled='true'] {
|
|
65
122
|
color: var(--color-disabled-fg);
|
|
66
123
|
cursor: not-allowed;
|
|
67
124
|
pointer-events: none;
|
|
68
125
|
}
|
|
69
126
|
|
|
70
|
-
|
|
127
|
+
/* Icons inside either interactive element or wrapper */
|
|
128
|
+
.interactive svg,
|
|
129
|
+
.interactiveChild svg {
|
|
71
130
|
inline-size: var(--icon-size-md);
|
|
72
131
|
block-size: var(--icon-size-md);
|
|
73
132
|
}
|
|
133
|
+
|
|
134
|
+
/* Visual separator row (used by <Menu.Separator />) */
|
|
135
|
+
.separator {
|
|
136
|
+
block-size: 1px;
|
|
137
|
+
margin-block: var(--spacing-2xs);
|
|
138
|
+
background: var(--color-border-subtle);
|
|
139
|
+
opacity: 0.8;
|
|
140
|
+
border-radius: 999px;
|
|
141
|
+
}
|
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
import type { ElementType, ReactNode, JSX } from 'react';
|
|
2
|
-
export type NavBarItem =
|
|
3
|
-
|
|
2
|
+
export type NavBarItem = NavBarLinkItem | NavBarExpandableItem | NavBarGroupItem;
|
|
3
|
+
type NavBarBase = {
|
|
4
4
|
label: string;
|
|
5
5
|
icon?: ReactNode;
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
};
|
|
9
|
+
/** Simple clickable item */
|
|
10
|
+
export type NavBarLinkItem = NavBarBase & {
|
|
11
|
+
type?: 'item';
|
|
12
|
+
href: string;
|
|
13
|
+
component?: ElementType<any>;
|
|
6
14
|
active?: boolean;
|
|
7
15
|
external?: boolean;
|
|
8
|
-
|
|
16
|
+
};
|
|
17
|
+
/** Clickable + expandable item (has href AND children) */
|
|
18
|
+
export type NavBarExpandableItem = NavBarBase & {
|
|
19
|
+
type: 'expandable';
|
|
9
20
|
href: string;
|
|
10
|
-
|
|
11
|
-
|
|
21
|
+
component?: ElementType<any>;
|
|
22
|
+
active?: boolean;
|
|
23
|
+
external?: boolean;
|
|
24
|
+
children: NavBarItem[];
|
|
25
|
+
};
|
|
26
|
+
/** Non-clickable group header */
|
|
27
|
+
export type NavBarGroupItem = NavBarBase & {
|
|
28
|
+
type: 'group';
|
|
29
|
+
children: NavBarItem[];
|
|
12
30
|
};
|
|
13
31
|
interface NavBarProps {
|
|
14
32
|
logo?: ReactNode;
|
|
15
|
-
items:
|
|
33
|
+
items: NavBarLinkItem[];
|
|
16
34
|
productName?: string;
|
|
17
35
|
addition?: ReactNode;
|
|
18
36
|
}
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
background: var(--color-bg-surface);
|
|
16
16
|
border-radius: var(--border-radius-lg);
|
|
17
17
|
min-width: 320px;
|
|
18
|
-
max-width:
|
|
18
|
+
max-width: 700px;
|
|
19
19
|
max-height: calc(100vh - (2 * var(--spacing-md)));
|
|
20
20
|
display: flex;
|
|
21
21
|
flex-direction: column;
|
|
22
22
|
box-shadow: var(--shadow-lg);
|
|
23
23
|
font-family: var(--font-family);
|
|
24
|
-
min-width:
|
|
24
|
+
min-width: 500px;
|
|
25
25
|
color: var(--color-fg-default);
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
2
|
import { Severity } from '../../../constants/severity.types';
|
|
3
3
|
interface SidePanelProps {
|
|
4
4
|
children?: ReactNode;
|
|
5
5
|
header: ReactNode;
|
|
6
6
|
headerAddition?: ReactNode;
|
|
7
|
-
actions
|
|
8
|
-
onClose: () => void;
|
|
7
|
+
actions?: ReactNode;
|
|
8
|
+
onClose: (event?: React.MouseEvent<HTMLButtonElement> | React.MouseEvent<HTMLDivElement>) => void;
|
|
9
9
|
isOpen: boolean;
|
|
10
10
|
showBackdrop?: boolean;
|
|
11
11
|
severity?: Severity;
|
|
12
12
|
showHeaderMarker?: boolean;
|
|
13
13
|
width?: number | string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional details pane (separate column).
|
|
16
|
+
*/
|
|
17
|
+
details?: ReactNode;
|
|
18
|
+
detailsHeader?: ReactNode;
|
|
19
|
+
detailsWidth?: number | string;
|
|
20
|
+
onCloseDetails?: () => void;
|
|
21
|
+
detailsHeaderAddition?: ReactNode;
|
|
14
22
|
}
|
|
15
|
-
export declare function SidePanel({ isOpen, onClose, children, header, headerAddition, actions, showBackdrop, severity, showHeaderMarker, width, ...props }: SidePanelProps & HTMLAttributes<HTMLElement>): ReactNode;
|
|
23
|
+
export declare function SidePanel({ isOpen, onClose, children, header, headerAddition, actions, showBackdrop, severity, showHeaderMarker, width, details, detailsHeader, detailsWidth, onCloseDetails, detailsHeaderAddition, ...props }: SidePanelProps & HTMLAttributes<HTMLElement>): ReactNode;
|
|
16
24
|
export {};
|
|
@@ -1,10 +1,83 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { X } from 'lucide-react';
|
|
3
|
+
import { useEffect, useRef, useState, } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
3
5
|
import { Button } from '../../../components/button/Button';
|
|
4
6
|
import { Headline } from '../../../components/headline/Headline';
|
|
7
|
+
import { MOTION_MS } from '../../../styles/animation';
|
|
5
8
|
import styles from './SidePanel.module.css';
|
|
6
|
-
export function SidePanel({ isOpen, onClose, children, header, headerAddition, actions, showBackdrop = true, severity, showHeaderMarker = true, width = '
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
export function SidePanel({ isOpen, onClose, children, header, headerAddition, actions, showBackdrop = true, severity, showHeaderMarker = true, width = '400px', details, detailsHeader = 'Output', detailsWidth = '420px', onCloseDetails, detailsHeaderAddition, ...props }) {
|
|
10
|
+
const [mounted, setMounted] = useState(false);
|
|
11
|
+
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
12
|
+
const [isActive, setIsActive] = useState(false);
|
|
13
|
+
const panelRef = useRef(null);
|
|
14
|
+
useEffect(() => setMounted(true), []);
|
|
15
|
+
// OPEN: ensure rendered so animation can play
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (isOpen)
|
|
18
|
+
setShouldRender(true);
|
|
19
|
+
}, [isOpen]);
|
|
20
|
+
// Close on ESC key
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!isOpen)
|
|
23
|
+
return;
|
|
24
|
+
const handleKeyDown = (e) => {
|
|
25
|
+
if (e.key === 'Escape') {
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
onClose();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
31
|
+
return () => {
|
|
32
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
33
|
+
};
|
|
34
|
+
}, [isOpen, onClose]);
|
|
35
|
+
// Two-phase OPEN/CLOSE class toggle (lets CSS transitions kick in reliably)
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!shouldRender)
|
|
38
|
+
return;
|
|
39
|
+
if (!isOpen) {
|
|
40
|
+
setIsActive(false);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const raf = requestAnimationFrame(() => setIsActive(true));
|
|
44
|
+
return () => cancelAnimationFrame(raf);
|
|
45
|
+
}, [isOpen, shouldRender]);
|
|
46
|
+
// When closing: wait for transform transition end to unmount.
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!shouldRender)
|
|
49
|
+
return;
|
|
50
|
+
const el = panelRef.current;
|
|
51
|
+
if (!el)
|
|
52
|
+
return;
|
|
53
|
+
const onTransitionEnd = (e) => {
|
|
54
|
+
if (e.target !== el)
|
|
55
|
+
return;
|
|
56
|
+
if (e.propertyName !== 'transform')
|
|
57
|
+
return;
|
|
58
|
+
if (!isOpen)
|
|
59
|
+
setShouldRender(false);
|
|
60
|
+
};
|
|
61
|
+
el.addEventListener('transitionend', onTransitionEnd);
|
|
62
|
+
return () => el.removeEventListener('transitionend', onTransitionEnd);
|
|
63
|
+
}, [isOpen, shouldRender]);
|
|
64
|
+
if (!mounted)
|
|
65
|
+
return null;
|
|
66
|
+
if (!shouldRender)
|
|
67
|
+
return null;
|
|
68
|
+
const hasDetails = Boolean(details);
|
|
69
|
+
return createPortal(_jsxs(_Fragment, { children: [showBackdrop && (_jsx("div", { className: `${styles.backdrop} ${isActive ? styles.backdropOpen : ''}`, onClick: e => {
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
onClose(e);
|
|
72
|
+
} })), _jsxs("div", { ref: panelRef, ...props, className: `${styles.sidePanel} ${isActive ? styles.open : ''} ${hasDetails ? styles.withDetails : styles.noDetails}`, style: {
|
|
73
|
+
'--side-panel-width': width,
|
|
74
|
+
'--details-width': detailsWidth,
|
|
75
|
+
'--panel-dur': MOTION_MS.panelSlide + 'ms',
|
|
76
|
+
}, "data-cy": "details-panel", role: "dialog", "aria-modal": "true", children: [hasDetails ? (_jsxs("aside", { className: styles.detailsCol, "data-cy": "details-panel-details", children: [_jsxs("div", { className: styles.detailsHeader, children: [_jsx("div", { className: styles.detailsTitle, children: detailsHeader }), _jsxs("div", { className: styles.detailsHeaderActions, children: [detailsHeaderAddition, onCloseDetails ? (_jsx(Button, { type: "button", size: "sm", variant: "outlined", onClick: e => {
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
onCloseDetails();
|
|
79
|
+
}, children: "Luk" })) : null] })] }), _jsx("div", { className: styles.detailsContent, children: details })] })) : null, _jsxs("section", { className: styles.mainCol, "data-cy": "details-panel-main", children: [_jsx("div", { className: styles.header, children: _jsxs("div", { className: "dbc-flex dbc-justify-between", children: [_jsx(Headline, { size: 3, disableMargin: true, severity: severity, marker: showHeaderMarker, children: header }), _jsxs("span", { className: "dbc-flex dbc-items-center dbc-gap-xs", children: [headerAddition, _jsx(Button, { type: "button", size: "sm", variant: "inline", onClick: e => {
|
|
80
|
+
e.stopPropagation();
|
|
81
|
+
onClose(e);
|
|
82
|
+
}, "aria-label": "Close panel", children: _jsx(X, {}) })] })] }) }), _jsx("div", { className: styles.content, "data-cy": "details-panel-content", children: children }), actions && _jsx("div", { className: styles.actions, children: actions })] })] })] }), document.body);
|
|
10
83
|
}
|
|
@@ -1,56 +1,177 @@
|
|
|
1
1
|
.sidePanel {
|
|
2
|
-
|
|
2
|
+
--col-pad: var(--spacing-md);
|
|
3
|
+
|
|
4
|
+
--panel-ease: cubic-bezier(0.22, 1, 0.36, 1); /* smooth spring-ish without overshoot */
|
|
5
|
+
|
|
6
|
+
/* Shadow + edge */
|
|
7
|
+
--shadow-opacity: 0.22;
|
|
8
|
+
--edge-opacity: 0.12;
|
|
9
|
+
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
padding: 0;
|
|
3
12
|
height: 100vh;
|
|
4
|
-
|
|
13
|
+
|
|
5
14
|
position: fixed;
|
|
6
15
|
right: 0;
|
|
7
16
|
top: 0;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
|
|
18
|
+
background-color: var(--color-bg-surface);
|
|
19
|
+
z-index: var(--z-drawer);
|
|
20
|
+
|
|
21
|
+
transform: translate3d(100%, 0, 0);
|
|
22
|
+
transition: transform var(--panel-dur) var(--panel-ease);
|
|
23
|
+
will-change: transform;
|
|
24
|
+
|
|
25
|
+
display: grid;
|
|
26
|
+
gap: var(--spacing-md);
|
|
27
|
+
align-items: stretch;
|
|
28
|
+
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
pointer-events: auto;
|
|
31
|
+
|
|
32
|
+
/* Make pseudo-elements layer properly */
|
|
33
|
+
isolation: isolate;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* “Lift” layer: drop-shadow + edge highlight (both fade in) */
|
|
37
|
+
.sidePanel::before {
|
|
38
|
+
content: '';
|
|
39
|
+
position: absolute;
|
|
40
|
+
inset: 0;
|
|
41
|
+
pointer-events: none;
|
|
42
|
+
z-index: -1; /* behind content but within isolated stacking context */
|
|
43
|
+
|
|
44
|
+
/* 1) drop-shadow = smoother than animating box-shadow
|
|
45
|
+
2) edge gradient = premium depth cue */
|
|
46
|
+
filter: drop-shadow(0 16px 32px rgba(0, 0, 0, var(--shadow-opacity)));
|
|
47
|
+
opacity: 0;
|
|
48
|
+
|
|
49
|
+
/* Edge highlight from the left edge (panel’s leading edge) */
|
|
50
|
+
background: linear-gradient(
|
|
51
|
+
90deg,
|
|
52
|
+
rgba(255, 255, 255, var(--edge-opacity)),
|
|
53
|
+
rgba(255, 255, 255, 0) 36%
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
transition: opacity var(--panel-dur) var(--panel-ease);
|
|
57
|
+
|
|
58
|
+
will-change: opacity;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Optional: super subtle “sheen” right as it settles (feels snappy) */
|
|
62
|
+
.sidePanel.open::before {
|
|
63
|
+
opacity: 1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sidePanel.open {
|
|
67
|
+
transform: translate3d(0, 0, 0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* MAIN TRACK WIDTH = content + padding*2 */
|
|
71
|
+
.sidePanel.noDetails {
|
|
72
|
+
grid-template-columns: calc(var(--side-panel-width, 400px) + (var(--col-pad) * 2));
|
|
73
|
+
width: calc(var(--side-panel-width, 400px) + (var(--col-pad) * 2));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* when details show, main track stays the same; panel grows */
|
|
77
|
+
.sidePanel.withDetails {
|
|
78
|
+
grid-template-columns:
|
|
79
|
+
calc(var(--side-panel-width, 400px) + (var(--col-pad) * 2))
|
|
80
|
+
calc(var(--details-width, 420px) + (var(--col-pad) * 2));
|
|
81
|
+
|
|
82
|
+
width: calc(
|
|
83
|
+
(var(--side-panel-width, 400px) + (var(--col-pad) * 2)) +
|
|
84
|
+
(var(--details-width, 420px) + (var(--col-pad) * 2)) + var(--spacing-md)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* columns get the padding */
|
|
89
|
+
.mainCol,
|
|
90
|
+
.detailsCol {
|
|
91
|
+
box-sizing: border-box;
|
|
92
|
+
padding: 0 var(--col-pad);
|
|
93
|
+
|
|
94
|
+
min-width: 0;
|
|
95
|
+
min-height: 0;
|
|
96
|
+
|
|
11
97
|
display: flex;
|
|
12
98
|
flex-direction: column;
|
|
13
99
|
gap: var(--spacing-md);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
background-color: var(--color-bg-surface);
|
|
19
|
-
max-height: 100vh;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.header {
|
|
103
|
+
padding: var(--spacing-md) 0;
|
|
20
104
|
}
|
|
21
105
|
|
|
22
106
|
.content {
|
|
23
107
|
flex: 1;
|
|
108
|
+
min-height: 0;
|
|
109
|
+
overflow: auto;
|
|
24
110
|
font-size: var(--font-size-sm);
|
|
25
111
|
}
|
|
26
112
|
|
|
27
|
-
.header {
|
|
28
|
-
position: sticky;
|
|
29
|
-
top: 0;
|
|
30
|
-
padding: var(--spacing-md) 0;
|
|
31
|
-
background: inherit;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
113
|
.actions {
|
|
35
|
-
position: sticky;
|
|
36
114
|
padding: var(--spacing-md) 0;
|
|
37
|
-
background: inherit;
|
|
38
|
-
bottom: 0;
|
|
39
115
|
display: flex;
|
|
40
116
|
justify-content: flex-end;
|
|
41
117
|
gap: var(--spacing-sm);
|
|
118
|
+
min-width: 0;
|
|
42
119
|
}
|
|
43
120
|
|
|
44
|
-
|
|
45
|
-
|
|
121
|
+
/* details styling */
|
|
122
|
+
.detailsCol {
|
|
123
|
+
border: 1px solid var(--color-border-subtle);
|
|
124
|
+
border-radius: var(--radius-md);
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
background: var(--color-bg-surface);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.detailsHeader {
|
|
130
|
+
padding: var(--spacing-sm) 0;
|
|
131
|
+
border-bottom: 1px solid var(--color-border-subtle);
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
justify-content: space-between;
|
|
135
|
+
gap: var(--spacing-sm);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.detailsTitle {
|
|
139
|
+
font-weight: 600;
|
|
46
140
|
}
|
|
47
141
|
|
|
142
|
+
.detailsHeaderActions {
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
gap: var(--spacing-sm);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.detailsContent {
|
|
149
|
+
padding: var(--spacing-md) 0;
|
|
150
|
+
overflow: auto;
|
|
151
|
+
min-height: 0;
|
|
152
|
+
flex: 1 1 auto;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Backdrop with a nice fade */
|
|
48
156
|
.backdrop {
|
|
49
157
|
position: fixed;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
width: 100%;
|
|
53
|
-
height: 100%;
|
|
54
|
-
background: var(--overlay-scrim);
|
|
158
|
+
inset: 0;
|
|
159
|
+
background-color: rgba(0, 0, 0, 0.45);
|
|
55
160
|
z-index: var(--z-backdrop);
|
|
161
|
+
|
|
162
|
+
opacity: 0;
|
|
163
|
+
transition: opacity var(--panel-dur) var(--panel-ease);
|
|
164
|
+
will-change: opacity;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.backdropOpen {
|
|
168
|
+
opacity: 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@media (prefers-reduced-motion: reduce) {
|
|
172
|
+
.sidePanel,
|
|
173
|
+
.sidePanel::before,
|
|
174
|
+
.backdrop {
|
|
175
|
+
transition: none !important;
|
|
176
|
+
}
|
|
56
177
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
export function useSidePanel() {
|
|
3
|
-
const [isOpen, setIsOpen] = useState(
|
|
2
|
+
export function useSidePanel(initialOpen = false) {
|
|
3
|
+
const [isOpen, setIsOpen] = useState(initialOpen);
|
|
4
4
|
const openSidePanel = () => setIsOpen(true);
|
|
5
5
|
const closeSidePanel = () => setIsOpen(false);
|
|
6
6
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useContext, useEffect, useId, useRef, useState } from 'react';
|
|
2
|
+
import { MOTION_MS } from '../../../styles/animation';
|
|
2
3
|
import { TooltipContext } from './TooltipProvider';
|
|
3
4
|
export function useTooltipTrigger(options) {
|
|
4
5
|
const ctx = useContext(TooltipContext);
|
|
@@ -45,7 +46,6 @@ export function useTooltipTrigger(options) {
|
|
|
45
46
|
}
|
|
46
47
|
show();
|
|
47
48
|
}, [isOpen, show, hide]);
|
|
48
|
-
// ✅ Only call update if THIS tooltip is the active one AND something changed
|
|
49
49
|
useEffect(() => {
|
|
50
50
|
var _a;
|
|
51
51
|
if (!isOpen)
|
|
@@ -84,7 +84,9 @@ export function useTooltipTrigger(options) {
|
|
|
84
84
|
const onFocus = () => {
|
|
85
85
|
clearTimers();
|
|
86
86
|
if (!isControlled)
|
|
87
|
-
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
setOpen(true);
|
|
89
|
+
}, MOTION_MS.tooltipOpen);
|
|
88
90
|
};
|
|
89
91
|
const onBlur = () => {
|
|
90
92
|
clearTimers();
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { PageLayoutHero } from './components/page-layout-hero/PageLayoutHero';
|
|
4
4
|
import styles from './PageLayout.module.css';
|
|
5
|
-
/** Base component */
|
|
6
5
|
const PageLayoutBase = ({ children, sidebar, header, containScrolling = false, orientation = 'vertical', }) => {
|
|
7
6
|
if (orientation === 'vertical') {
|
|
8
7
|
return (_jsx("div", { className: `${styles.container} ${styles.vertical} ${containScrolling ? styles.containScrolling : ''}`, children: _jsxs("div", { style: { flex: 1, display: 'flex', height: '100%', maxWidth: '100%' }, children: [sidebar, _jsxs("div", { style: {
|
|
@@ -17,7 +16,6 @@ const PageLayoutBase = ({ children, sidebar, header, containScrolling = false, o
|
|
|
17
16
|
display: 'flex',
|
|
18
17
|
flexDirection: 'column',
|
|
19
18
|
padding: 'var(--spacing-md)',
|
|
20
|
-
gap: 'var(--spacing-md)',
|
|
21
19
|
backgroundColor: 'var(--color-bg-surface)',
|
|
22
20
|
overflow: 'auto',
|
|
23
21
|
}, children: children })] })] }) }));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { ChevronDown, ChevronUp } from 'lucide-react';
|
|
4
|
-
import { createPortal } from 'react-dom';
|
|
5
4
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
6
|
import styles from './Popover.module.css';
|
|
7
7
|
export const Popover = forwardRef(function Popover({ trigger: Trigger, children, minWidth = '200px', matchTriggerWidth = true, viewportPadding = 8, edgeBuffer = 100, dataCy, }, ref) {
|
|
8
8
|
const [pos, setPos] = useState({ top: 0, left: 0, width: 0, visible: false });
|
package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { NavBarItem } from '../../../../components/nav-bar/NavBar';
|
|
3
|
-
|
|
2
|
+
import type { NavBarItem } from '../../../../components/nav-bar/NavBar';
|
|
3
|
+
type ExpandableSidebarItemProps = {
|
|
4
4
|
items: NavBarItem[];
|
|
5
5
|
label: string;
|
|
6
|
-
component
|
|
6
|
+
component: React.ElementType;
|
|
7
7
|
icon: React.ReactNode;
|
|
8
|
-
href
|
|
9
|
-
}
|
|
8
|
+
href: string;
|
|
9
|
+
};
|
|
10
10
|
export declare function ExpandableSidebarItem({ items, label, icon, component: Component, href, }: ExpandableSidebarItemProps): React.ReactNode;
|
|
11
11
|
export {};
|