@dbcdk/react-components 0.0.13 → 0.0.15
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 +2 -1
- package/dist/components/accordion/Accordion.js +14 -3
- package/dist/components/accordion/Accordion.module.css +1 -1
- package/dist/components/accordion/components/AccordionRow.d.ts +2 -1
- package/dist/components/accordion/components/AccordionRow.js +8 -6
- package/dist/components/accordion/components/AccordionRow.module.css +12 -8
- package/dist/components/button/Button.d.ts +1 -0
- package/dist/components/button/Button.js +3 -3
- package/dist/components/button/Button.module.css +12 -1
- package/dist/components/card/Card.module.css +1 -1
- package/dist/components/chip/Chip.js +11 -1
- package/dist/components/chip/Chip.module.css +92 -30
- package/dist/components/circle/Circle.d.ts +1 -1
- package/dist/components/circle/Circle.module.css +5 -1
- package/dist/components/clear-button/ClearButton.js +1 -1
- package/dist/components/clear-button/ClearButton.module.css +3 -0
- package/dist/components/code-block/CodeBlock.d.ts +7 -3
- package/dist/components/code-block/CodeBlock.js +35 -2
- package/dist/components/code-block/CodeBlock.module.css +49 -2
- package/dist/components/filter-field/FilterField.d.ts +2 -1
- package/dist/components/filter-field/FilterField.js +22 -7
- package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.d.ts +4 -3
- package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +3 -2
- package/dist/components/forms/checkbox/Checkbox.d.ts +1 -1
- package/dist/components/forms/checkbox/Checkbox.module.css +11 -0
- package/dist/components/hyperlink/Hyperlink.module.css +0 -1
- package/dist/components/overlay/modal/Modal.js +1 -1
- package/dist/components/overlay/side-panel/SidePanel.js +1 -1
- package/dist/components/page-layout/PageLayout.module.css +0 -2
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +1 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +1 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +0 -4
- package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.d.ts +2 -1
- package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +2 -2
- package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.module.css +9 -0
- package/dist/components/split-pane/SplitPane.js +1 -1
- package/dist/components/state-page/StatePage.module.css +1 -1
- package/dist/components/table/Table.js +5 -2
- package/dist/components/table/Table.module.css +19 -16
- package/dist/components/table/components/empty-state/EmptyState.d.ts +7 -22
- package/dist/components/table/components/empty-state/EmptyState.js +12 -8
- package/dist/components/table/components/empty-state/EmptyState.module.css +2 -14
- package/dist/components/tabs/Tabs.js +1 -1
- package/dist/components/tabs/Tabs.module.css +1 -1
- package/dist/components/toast/Toast.js +1 -1
- package/dist/hooks/useTableSelection.d.ts +1 -1
- package/dist/hooks/useTableSelection.js +97 -77
- package/dist/hooks/useViewportFill.js +12 -0
- package/dist/src/styles/styles.css +8 -0
- package/dist/styles/styles.css +8 -0
- package/dist/styles/themes/dbc/base.css +1 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import type { JSX, ReactNode } from 'react';
|
|
|
2
2
|
import type { Severity } from '../../constants/severity.types';
|
|
3
3
|
export interface AccordionItem {
|
|
4
4
|
header: string;
|
|
5
|
+
headerAddition?: ReactNode;
|
|
5
6
|
headerIcon?: ReactNode;
|
|
6
7
|
severity?: Severity;
|
|
7
8
|
children: ReactNode;
|
|
@@ -15,7 +16,7 @@ export interface AccordionProps {
|
|
|
15
16
|
size?: Size;
|
|
16
17
|
/** Uncontrolled defaults */
|
|
17
18
|
defaultOpenIndex?: number | null;
|
|
18
|
-
defaultOpenIndexes?: number[];
|
|
19
|
+
defaultOpenIndexes?: number[] | 'all';
|
|
19
20
|
/** Controlled state */
|
|
20
21
|
openIndex?: number | null;
|
|
21
22
|
openIndexes?: number[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useId, useMemo, useState } from 'react';
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import styles from './Accordion.module.css';
|
|
5
5
|
import { AccordionRow } from './components/AccordionRow';
|
|
6
6
|
function uniqSorted(nums) {
|
|
@@ -12,8 +12,19 @@ function normalizeMultiple(indexes) {
|
|
|
12
12
|
export function Accordion({ items, mode = 'single', size = 'md', defaultOpenIndex = null, defaultOpenIndexes = [], openIndex, openIndexes, onOpenIndexChange, onOpenIndexesChange, }) {
|
|
13
13
|
const uid = useId();
|
|
14
14
|
const isControlled = mode === 'single' ? openIndex !== undefined : openIndexes !== undefined;
|
|
15
|
+
// Disable animation on initial render (for default open state).
|
|
16
|
+
const hasMountedRef = useRef(false);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
hasMountedRef.current = true;
|
|
19
|
+
}, []);
|
|
15
20
|
const [internalSingle, setInternalSingle] = useState(mode === 'single' ? defaultOpenIndex : null);
|
|
16
|
-
const [internalMultiple, setInternalMultiple] = useState(
|
|
21
|
+
const [internalMultiple, setInternalMultiple] = useState(() => {
|
|
22
|
+
if (mode !== 'multiple')
|
|
23
|
+
return [];
|
|
24
|
+
if (defaultOpenIndexes === 'all')
|
|
25
|
+
return items.map((_, i) => i);
|
|
26
|
+
return normalizeMultiple(defaultOpenIndexes);
|
|
27
|
+
});
|
|
17
28
|
const currentOpenIndexes = useMemo(() => {
|
|
18
29
|
if (mode === 'single') {
|
|
19
30
|
const current = isControlled ? (openIndex !== null && openIndex !== void 0 ? openIndex : null) : internalSingle;
|
|
@@ -55,5 +66,5 @@ export function Accordion({ items, mode = 'single', size = 'md', defaultOpenInde
|
|
|
55
66
|
else
|
|
56
67
|
commit([...currentOpenIndexes, index]);
|
|
57
68
|
}
|
|
58
|
-
return (_jsx("div", { className: `${styles.container} ${styles[size]}`, children: items.map((item, i) => (_jsx(AccordionRow, { uid: uid, index: i, item: item, isOpen: openSet.has(i), onToggle: toggle }, i))) }));
|
|
69
|
+
return (_jsx("div", { className: `${styles.container} ${styles[size]}`, children: items.map((item, i) => (_jsx(AccordionRow, { uid: uid, index: i, item: item, isOpen: openSet.has(i), onToggle: toggle, shouldAnimate: hasMountedRef.current }, i))) }));
|
|
59
70
|
}
|
|
@@ -6,5 +6,6 @@ export type AccordionRowProps = {
|
|
|
6
6
|
item: AccordionItem;
|
|
7
7
|
isOpen: boolean;
|
|
8
8
|
onToggle: (index: number) => void;
|
|
9
|
+
shouldAnimate?: boolean;
|
|
9
10
|
};
|
|
10
|
-
export declare function AccordionRow({ uid, index, item, isOpen, onToggle, }: AccordionRowProps): JSX.Element;
|
|
11
|
+
export declare function AccordionRow({ uid, index, item, isOpen, onToggle, shouldAnimate, }: AccordionRowProps): JSX.Element;
|
|
@@ -3,7 +3,7 @@ import { ChevronDown } from 'lucide-react';
|
|
|
3
3
|
import { useLayoutEffect, useRef, useState } from 'react';
|
|
4
4
|
import { Headline } from '../../../components/headline/Headline';
|
|
5
5
|
import styles from './AccordionRow.module.css';
|
|
6
|
-
function useCollapsibleHeight(isOpen) {
|
|
6
|
+
function useCollapsibleHeight(isOpen, shouldAnimate) {
|
|
7
7
|
const innerRef = useRef(null);
|
|
8
8
|
const [height, setHeight] = useState('0px');
|
|
9
9
|
useLayoutEffect(() => {
|
|
@@ -13,7 +13,9 @@ function useCollapsibleHeight(isOpen) {
|
|
|
13
13
|
return;
|
|
14
14
|
const prefersReduced = typeof window !== 'undefined' &&
|
|
15
15
|
((_b = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-reduced-motion: reduce)')) === null || _b === void 0 ? void 0 : _b.matches);
|
|
16
|
-
|
|
16
|
+
// No animation on first render when default-open is used:
|
|
17
|
+
// just set the final height.
|
|
18
|
+
if (!shouldAnimate || prefersReduced) {
|
|
17
19
|
setHeight(isOpen ? 'auto' : '0px');
|
|
18
20
|
return;
|
|
19
21
|
}
|
|
@@ -31,7 +33,7 @@ function useCollapsibleHeight(isOpen) {
|
|
|
31
33
|
setHeight('0px');
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
|
-
}, [isOpen]);
|
|
36
|
+
}, [isOpen, shouldAnimate]);
|
|
35
37
|
function onTransitionEnd(e) {
|
|
36
38
|
if (e.propertyName !== 'height')
|
|
37
39
|
return;
|
|
@@ -42,10 +44,10 @@ function useCollapsibleHeight(isOpen) {
|
|
|
42
44
|
}
|
|
43
45
|
return { innerRef, height, onTransitionEnd };
|
|
44
46
|
}
|
|
45
|
-
export function AccordionRow({ uid, index, item, isOpen, onToggle, }) {
|
|
47
|
+
export function AccordionRow({ uid, index, item, isOpen, onToggle, shouldAnimate = true, }) {
|
|
46
48
|
const isDisabled = !!item.disabled;
|
|
47
49
|
const buttonId = `${uid}-acc-btn-${index}`;
|
|
48
50
|
const panelId = `${uid}-acc-panel-${index}`;
|
|
49
|
-
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen);
|
|
50
|
-
return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsx("
|
|
51
|
+
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
|
|
52
|
+
return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsx("div", { children: _jsxs("button", { type: "button", id: buttonId, className: styles.trigger, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => onToggle(index), disabled: isDisabled, children: [_jsxs("span", { className: styles.title, children: [item.headerIcon ? _jsx("span", { className: styles.icon, children: item.headerIcon }) : null, _jsx(Headline, { disableMargin: true, size: 4, weight: 500, severity: item.severity, allowWrap: isOpen, children: item.header }), item.headerAddition] }), _jsx("span", { className: styles.chevron, "aria-hidden": "true", children: _jsx(ChevronDown, {}) })] }) }), _jsx("div", { id: panelId, role: "region", "aria-labelledby": buttonId, className: `${styles.panel} ${shouldAnimate ? styles.animate : styles.noAnimate}`, style: { height }, onTransitionEnd: onTransitionEnd, children: _jsx("div", { ref: innerRef, className: styles.content, children: item.children }) })] }));
|
|
51
53
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
.heading {
|
|
2
|
-
margin: 0;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
1
|
.trigger {
|
|
6
2
|
all: unset;
|
|
7
3
|
box-sizing: border-box;
|
|
@@ -16,7 +12,7 @@
|
|
|
16
12
|
user-select: none;
|
|
17
13
|
|
|
18
14
|
padding: var(--acc-trigger-py) var(--acc-trigger-px);
|
|
19
|
-
background: var(--color-bg-contextual);
|
|
15
|
+
background: var(--color-bg-contextual-subtle);
|
|
20
16
|
|
|
21
17
|
min-width: 0;
|
|
22
18
|
}
|
|
@@ -35,10 +31,10 @@
|
|
|
35
31
|
display: flex;
|
|
36
32
|
align-items: center;
|
|
37
33
|
gap: var(--spacing-xs);
|
|
38
|
-
|
|
39
34
|
min-width: 0;
|
|
40
35
|
flex: 1 1 auto;
|
|
41
36
|
overflow: hidden;
|
|
37
|
+
justify-content: space-between;
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
.icon {
|
|
@@ -67,12 +63,20 @@
|
|
|
67
63
|
.panel {
|
|
68
64
|
overflow: hidden;
|
|
69
65
|
height: 0px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Default: animate only when class is present */
|
|
69
|
+
.animate {
|
|
70
70
|
transition: height var(--transition-slow) var(--ease-decelerate);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/*
|
|
73
|
+
/* No animation (initial render default-open) */
|
|
74
|
+
.noAnimate {
|
|
75
|
+
transition: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
.content {
|
|
75
|
-
padding: var(--acc-content-py)
|
|
79
|
+
padding: var(--acc-content-py) 0;
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -4,6 +4,7 @@ export type ButtonVariant = 'primary' | 'secondary' | 'outlined' | 'default' | '
|
|
|
4
4
|
export type ButtonSize = Exclude<Size, 'xl'>;
|
|
5
5
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
6
|
variant?: ButtonVariant;
|
|
7
|
+
shape?: 'default' | 'rounded' | 'round';
|
|
7
8
|
size?: ButtonSize;
|
|
8
9
|
fullWidth?: boolean;
|
|
9
10
|
icon?: React.ReactNode;
|
|
@@ -19,9 +19,9 @@ function mergeRefs(...refs) {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
export const Button = React.forwardRef(function Button({ variant = 'outlined', size = 'md', fullWidth, icon, children, loading, active, spinIcon, tooltip, tooltipPlacement = 'top', isLink, type = 'button', ...rest }, ref) {
|
|
22
|
+
export const Button = React.forwardRef(function Button({ variant = 'outlined', shape = 'default', size = 'md', fullWidth, icon, children, loading, active, spinIcon, tooltip, tooltipPlacement = 'top', isLink, type = 'button', ...rest }, ref) {
|
|
23
23
|
const { className: userClassName, ...buttonProps } = rest;
|
|
24
|
-
const computedClassName = cx(styles.button, styles[variant], styles[size], fullWidth ? styles.fullWidth : '', active ? styles.active : '', loading ? styles.loading : '',
|
|
24
|
+
const computedClassName = cx(styles.button, styles[variant], styles[size], fullWidth ? styles.fullWidth : '', active ? styles.active : '', loading ? styles.loading : '', shape !== 'default' ? styles[shape] : '', userClassName);
|
|
25
25
|
const tooltipEnabled = Boolean(tooltip);
|
|
26
26
|
// Tooltip anchored to the actual clickable element (button or link element)
|
|
27
27
|
const { triggerProps, id: tooltipId } = useTooltipTrigger({
|
|
@@ -46,7 +46,7 @@ export const Button = React.forwardRef(function Button({ variant = 'outlined', s
|
|
|
46
46
|
buttonEl = React.cloneElement(children, {
|
|
47
47
|
...buttonProps,
|
|
48
48
|
ref: mergeRefs(childRef, ref),
|
|
49
|
-
className: cx(childClassName, computedClassName),
|
|
49
|
+
className: cx(childClassName, computedClassName, styles.buttonLink),
|
|
50
50
|
...(tooltipEnabled ? triggerProps : {}),
|
|
51
51
|
'aria-describedby': describedBy,
|
|
52
52
|
children: (_jsxs(_Fragment, { children: [icon && _jsx("span", { className: cx(styles.icon, spinIcon ? 'spin' : ''), children: icon }), children.props.children, loading && (_jsx("span", { style: { display: 'flex', opacity: 0.5 }, className: "spin", children: _jsx(LoaderCircle, {}) }))] })),
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
user-select: none;
|
|
28
28
|
white-space: nowrap;
|
|
29
29
|
}
|
|
30
|
+
.buttonLink {
|
|
31
|
+
color: inherit;
|
|
32
|
+
text-decoration: none;
|
|
33
|
+
}
|
|
30
34
|
|
|
31
35
|
.button:hover {
|
|
32
36
|
transition:
|
|
@@ -40,6 +44,13 @@
|
|
|
40
44
|
box-shadow: var(--focus-ring);
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
.round {
|
|
48
|
+
border-radius: 100%;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.rounded {
|
|
52
|
+
border-radius: var(--border-radius-rounded);
|
|
53
|
+
}
|
|
43
54
|
.button:disabled,
|
|
44
55
|
.button[aria-disabled='true'] {
|
|
45
56
|
cursor: not-allowed;
|
|
@@ -93,7 +104,7 @@
|
|
|
93
104
|
.button.sm {
|
|
94
105
|
height: var(--component-size-sm);
|
|
95
106
|
min-block-size: var(--component-size-sm);
|
|
96
|
-
padding-inline: var(--spacing-
|
|
107
|
+
padding-inline: var(--spacing-xs);
|
|
97
108
|
}
|
|
98
109
|
|
|
99
110
|
.button.xs {
|
|
@@ -16,5 +16,15 @@ export function Chip({ children, severity = 'neutral', loading, disableIcon = tr
|
|
|
16
16
|
if (loading) {
|
|
17
17
|
return _jsx(SkeletonLoaderItem, { width: chipWidth !== null && chipWidth !== void 0 ? chipWidth : '100px', height: "26px", radius: "25px" });
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
const hasLeading = Boolean(customIcon) || (Boolean(severity) && !disableIcon);
|
|
20
|
+
const hasClose = typeof onClose === 'function';
|
|
21
|
+
return (_jsxs("div", { ref: chipRef, className: [
|
|
22
|
+
styles.container,
|
|
23
|
+
severity ? styles[severity] : '',
|
|
24
|
+
fullWidth ? styles.fullWidth : '',
|
|
25
|
+
styles[size],
|
|
26
|
+
styles[type],
|
|
27
|
+
hasLeading ? styles.hasLeading : '',
|
|
28
|
+
hasClose ? styles.hasClose : '',
|
|
29
|
+
].join(' '), children: [hasLeading ? (_jsxs("span", { className: styles.leading, children: [severity && !disableIcon && _jsx(Icon, { severity: severity }), customIcon] })) : null, _jsx("span", { className: styles.label, children: children }), hasClose && (_jsx("button", { type: "button", onClick: onClose, className: styles.close, "aria-label": "Luk", children: _jsx(X, {}) }))] }));
|
|
20
30
|
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
.container {
|
|
2
|
+
/* local layout tokens */
|
|
3
|
+
--chip-gap: var(--spacing-xxs);
|
|
4
|
+
--chip-pad-y: var(--spacing-xxs);
|
|
5
|
+
--chip-pad-x: var(--spacing-md);
|
|
6
|
+
|
|
7
|
+
/* when no icon, compensate by half the gap on each side */
|
|
8
|
+
--chip-pad-x-noicon: calc(var(--chip-pad-x) + (var(--chip-gap) / 2));
|
|
9
|
+
|
|
2
10
|
display: inline-flex;
|
|
3
11
|
align-items: center;
|
|
4
|
-
gap: var(--
|
|
12
|
+
gap: var(--chip-gap);
|
|
5
13
|
white-space: nowrap;
|
|
6
14
|
|
|
7
|
-
/* Neutral pill background + text */
|
|
8
|
-
|
|
9
15
|
color: var(--chip-fg-default, var(--color-fg-default));
|
|
10
|
-
|
|
11
|
-
border-radius: var(--border-radius-default);
|
|
12
16
|
border: var(--border-width-thin) solid transparent;
|
|
17
|
+
border-radius: var(--border-radius-default);
|
|
13
18
|
|
|
14
|
-
padding-block: var(--
|
|
15
|
-
padding-inline: var(--
|
|
19
|
+
padding-block: var(--chip-pad-y);
|
|
20
|
+
padding-inline: var(--chip-pad-x-noicon);
|
|
16
21
|
|
|
17
22
|
font-family: var(--font-family);
|
|
18
23
|
font-size: var(--font-size-sm);
|
|
@@ -25,71 +30,126 @@
|
|
|
25
30
|
box-shadow var(--transition-fast) var(--ease-standard);
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
/* Keep your preferred pill look */
|
|
34
|
+
.rounded {
|
|
29
35
|
border-radius: var(--border-radius-rounded);
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
.
|
|
38
|
+
.outlined {
|
|
33
39
|
border-radius: var(--border-radius-rounded);
|
|
34
40
|
border: var(--border-width-thin) solid var(--color-border-default);
|
|
41
|
+
background-color: transparent;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
.default {
|
|
45
|
+
border-radius: var(--border-radius-default);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ---- Leading icon logic ---- */
|
|
49
|
+
.hasLeading {
|
|
50
|
+
/* symmetric tighter padding when icon exists */
|
|
51
|
+
padding-left: var(--spacing-xs);
|
|
52
|
+
padding-right: var(--spacing-xs);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Leading slot */
|
|
56
|
+
.leading {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
flex: 0 0 auto;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.label {
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
min-width: 0;
|
|
40
67
|
}
|
|
41
68
|
|
|
42
|
-
|
|
69
|
+
/* ---- Icon sizing ---- */
|
|
70
|
+
.leading svg,
|
|
71
|
+
.close svg {
|
|
43
72
|
inline-size: var(--icon-size-sm);
|
|
44
73
|
block-size: var(--icon-size-sm);
|
|
74
|
+
color: currentColor;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sm .leading svg,
|
|
78
|
+
.sm .close svg {
|
|
79
|
+
inline-size: 14px;
|
|
80
|
+
block-size: 14px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.lg .leading svg,
|
|
84
|
+
.lg .close svg {
|
|
85
|
+
inline-size: var(--icon-size-md);
|
|
86
|
+
block-size: var(--icon-size-md);
|
|
45
87
|
}
|
|
46
88
|
|
|
47
|
-
/*
|
|
89
|
+
/* ---- Sizes ---- */
|
|
48
90
|
.sm {
|
|
91
|
+
--chip-pad-y: var(--spacing-2xs);
|
|
92
|
+
--chip-pad-x: var(--spacing-xs);
|
|
93
|
+
/* keep same gap unless you explicitly want tighter; if you do, change only here */
|
|
94
|
+
/* --chip-gap: var(--spacing-2xs); */
|
|
95
|
+
|
|
49
96
|
height: var(--component-size-xs);
|
|
50
|
-
padding-block: var(--spacing-xxs);
|
|
51
|
-
padding-inline: var(--spacing-xs);
|
|
52
97
|
font-size: var(--font-size-xs);
|
|
98
|
+
|
|
99
|
+
/* recompute derived value */
|
|
100
|
+
--chip-pad-x-noicon: calc(var(--chip-pad-x) + (var(--chip-gap) / 2));
|
|
101
|
+
|
|
102
|
+
padding-block: var(--chip-pad-y);
|
|
103
|
+
padding-inline: var(--chip-pad-x-noicon);
|
|
53
104
|
}
|
|
54
105
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
color: var(--color-fg-on-strong);
|
|
59
|
-
border-color: transparent;
|
|
106
|
+
.sm.hasLeading {
|
|
107
|
+
padding-left: var(--spacing-xxs);
|
|
108
|
+
padding-right: var(--spacing-xxs);
|
|
60
109
|
}
|
|
61
110
|
|
|
62
|
-
|
|
111
|
+
.md {
|
|
112
|
+
height: var(--component-size-sm);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.lg {
|
|
116
|
+
--chip-pad-y: var(--spacing-xs);
|
|
117
|
+
|
|
118
|
+
height: var(--component-size-md);
|
|
119
|
+
padding-block: var(--chip-pad-y);
|
|
120
|
+
}
|
|
63
121
|
|
|
64
|
-
|
|
122
|
+
/* ---- Variants / severities ---- */
|
|
123
|
+
.neutral {
|
|
65
124
|
background-color: var(--color-bg-contextual);
|
|
125
|
+
border-color: transparent;
|
|
66
126
|
}
|
|
67
|
-
|
|
127
|
+
|
|
128
|
+
.success {
|
|
68
129
|
background-color: var(--color-status-success-bg);
|
|
69
130
|
color: var(--color-status-success-fg);
|
|
70
131
|
border-color: var(--color-status-success-border);
|
|
71
132
|
}
|
|
72
133
|
|
|
73
|
-
.
|
|
134
|
+
.warning {
|
|
74
135
|
background-color: var(--color-status-warning-bg);
|
|
75
136
|
color: var(--color-status-warning-fg);
|
|
76
137
|
border-color: var(--color-status-warning-border);
|
|
77
138
|
}
|
|
78
139
|
|
|
79
|
-
.
|
|
140
|
+
.error {
|
|
80
141
|
background-color: var(--color-status-error-bg);
|
|
81
142
|
color: var(--color-status-error-fg);
|
|
82
143
|
border-color: var(--color-status-error-border);
|
|
83
144
|
}
|
|
84
145
|
|
|
85
|
-
.
|
|
146
|
+
.info {
|
|
86
147
|
background-color: var(--color-status-info-bg);
|
|
87
148
|
color: var(--color-status-info-fg);
|
|
88
149
|
border-color: var(--color-status-info-border);
|
|
89
150
|
}
|
|
90
151
|
|
|
91
|
-
|
|
92
|
-
.container.brand {
|
|
152
|
+
.brand {
|
|
93
153
|
background-color: var(--color-brand);
|
|
94
154
|
color: var(--color-fg-on-brand);
|
|
95
155
|
border-color: transparent;
|
|
@@ -101,7 +161,7 @@
|
|
|
101
161
|
justify-content: center;
|
|
102
162
|
}
|
|
103
163
|
|
|
104
|
-
/* Close button
|
|
164
|
+
/* Close button */
|
|
105
165
|
.close {
|
|
106
166
|
all: unset;
|
|
107
167
|
display: inline-flex;
|
|
@@ -109,9 +169,11 @@
|
|
|
109
169
|
justify-content: center;
|
|
110
170
|
cursor: pointer;
|
|
111
171
|
color: inherit;
|
|
172
|
+
|
|
112
173
|
inline-size: var(--icon-size-md);
|
|
113
174
|
block-size: var(--icon-size-md);
|
|
114
175
|
border-radius: var(--border-radius-round);
|
|
176
|
+
|
|
115
177
|
transition: background-color var(--transition-fast) var(--ease-standard);
|
|
116
178
|
}
|
|
117
179
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode, JSX } from 'react';
|
|
2
2
|
import { Severity } from '../../constants/severity.types';
|
|
3
|
-
type CircleSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
3
|
+
type CircleSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg';
|
|
4
4
|
interface CircleProps {
|
|
5
5
|
severity: Severity;
|
|
6
6
|
children?: ReactNode;
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
gap: var(--spacing-xs);
|
|
6
6
|
white-space: nowrap;
|
|
7
7
|
font-family: var(--font-family);
|
|
8
|
-
font-size: var(--font-size-sm);
|
|
9
8
|
color: var(--color-fg-default);
|
|
10
9
|
}
|
|
11
10
|
|
|
@@ -62,6 +61,11 @@
|
|
|
62
61
|
box-shadow: 0 0 0 2px var(--color-status-info-bg);
|
|
63
62
|
}
|
|
64
63
|
|
|
64
|
+
.circle[data-size='2xs'] {
|
|
65
|
+
inline-size: var(--component-size-2xs);
|
|
66
|
+
block-size: var(--component-size-2xs);
|
|
67
|
+
}
|
|
68
|
+
|
|
65
69
|
.circle[data-size='xs'] {
|
|
66
70
|
inline-size: var(--component-size-xxs);
|
|
67
71
|
block-size: var(--component-size-xxs);
|
|
@@ -5,5 +5,5 @@ export function ClearButton({ onClick, absolute }) {
|
|
|
5
5
|
return (_jsx("span", { className: `${styles.clearButton} ${absolute ? styles.absolute : ''}`, children: _jsx("span", { className: styles.button, role: "button", onClick: e => {
|
|
6
6
|
e.stopPropagation();
|
|
7
7
|
onClick();
|
|
8
|
-
}, children: _jsx(X, { size:
|
|
8
|
+
}, children: _jsx(X, { size: 16 }) }) }));
|
|
9
9
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type { JSX } from 'react';
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
2
|
export interface CodeBlockProps {
|
|
3
|
-
code
|
|
3
|
+
code?: string;
|
|
4
|
+
children?: ReactNode;
|
|
4
5
|
copyButton?: boolean;
|
|
6
|
+
copyText?: string;
|
|
5
7
|
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
smart?: boolean;
|
|
9
|
+
wrap?: boolean;
|
|
6
10
|
}
|
|
7
|
-
export declare function CodeBlock({ code, copyButton, size }: CodeBlockProps): JSX.Element;
|
|
11
|
+
export declare function CodeBlock({ code, children, copyButton, copyText, size, smart, wrap, }: CodeBlockProps): JSX.Element;
|
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styles from './CodeBlock.module.css';
|
|
3
3
|
import { CopyButton } from '../copy-button/CopyButton';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const looksLikeStackFrame = (line) => {
|
|
5
|
+
const t = line.trim();
|
|
6
|
+
return (t.startsWith('at ') || // Java, JS
|
|
7
|
+
t.startsWith('...') ||
|
|
8
|
+
t.startsWith('Caused by:') ||
|
|
9
|
+
t.startsWith('Suppressed:') ||
|
|
10
|
+
t.startsWith('Traceback') || // Python header
|
|
11
|
+
t.startsWith('File ') || // Python
|
|
12
|
+
t.startsWith('↳') || // some tools
|
|
13
|
+
/^at\s+\w/.test(t));
|
|
14
|
+
};
|
|
15
|
+
export function CodeBlock({ code, children, copyButton, copyText, size = 'md', smart = true, wrap = true, }) {
|
|
16
|
+
var _a;
|
|
17
|
+
const text = typeof code === 'string' ? code : undefined;
|
|
18
|
+
const copy = (_a = copyText !== null && copyText !== void 0 ? copyText : text) !== null && _a !== void 0 ? _a : '';
|
|
19
|
+
// If children are provided, render them as-is (no line processing).
|
|
20
|
+
const hasChildren = children !== undefined && children !== null;
|
|
21
|
+
// Smart rendering only when we have plain text + no children.
|
|
22
|
+
const lines = smart && !hasChildren && typeof text === 'string' ? text.split('\n') : null;
|
|
23
|
+
return (_jsxs("pre", { className: [styles.container, styles[size], wrap ? styles.wrap : styles.noWrap].join(' '), tabIndex: 0, children: [copyButton && (_jsx("span", { className: styles.copyButton, children: _jsx(CopyButton, { shape: "round", variant: "inline", text: copy }) })), _jsx("code", { className: styles.code, children: hasChildren
|
|
24
|
+
? children
|
|
25
|
+
: lines
|
|
26
|
+
? lines.map((line, i) => {
|
|
27
|
+
const isFirst = i === 0;
|
|
28
|
+
const isFrame = looksLikeStackFrame(line);
|
|
29
|
+
const cls = [
|
|
30
|
+
styles.line,
|
|
31
|
+
isFirst ? styles.lineFirst : '',
|
|
32
|
+
isFrame ? styles.lineFrame : '',
|
|
33
|
+
]
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join(' ');
|
|
36
|
+
return (_jsxs("span", { className: cls, children: [line, '\n'] }, i));
|
|
37
|
+
})
|
|
38
|
+
: text })] }));
|
|
6
39
|
}
|
|
@@ -47,8 +47,6 @@
|
|
|
47
47
|
margin: 0;
|
|
48
48
|
font-family: var(--font-family-mono);
|
|
49
49
|
color: var(--color-fg-default);
|
|
50
|
-
|
|
51
|
-
/* ✅ Preserve formatting but avoid ugly breaking */
|
|
52
50
|
white-space: pre-wrap;
|
|
53
51
|
overflow-wrap: anywhere;
|
|
54
52
|
word-break: normal; /* <- not break-all */
|
|
@@ -71,3 +69,52 @@
|
|
|
71
69
|
opacity: 1;
|
|
72
70
|
pointer-events: auto;
|
|
73
71
|
}
|
|
72
|
+
|
|
73
|
+
/* --- New: wrap control --- */
|
|
74
|
+
.wrap .code {
|
|
75
|
+
white-space: pre-wrap;
|
|
76
|
+
overflow-wrap: anywhere;
|
|
77
|
+
word-break: normal;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.noWrap .code {
|
|
81
|
+
white-space: pre;
|
|
82
|
+
overflow-wrap: normal;
|
|
83
|
+
word-break: normal;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* --- New: per-line styling (for smart mode) --- */
|
|
87
|
+
.line {
|
|
88
|
+
display: inline; /* keep selection/copy behavior natural */
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.lineFirst {
|
|
92
|
+
font-family: inherit;
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
color: var(--color-fg-default);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Common stack frames are “noise”; deemphasize without hiding */
|
|
98
|
+
.lineFrame {
|
|
99
|
+
color: var(--color-fg-subtle);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Optional: make the container a bit denser for logs */
|
|
103
|
+
.container {
|
|
104
|
+
/* keep your existing properties ... */
|
|
105
|
+
|
|
106
|
+
/* Easy win: stacktraces feel less tall */
|
|
107
|
+
line-height: 1.35; /* instead of relaxed */
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Optional: differentiate the code area slightly from surrounding UI */
|
|
111
|
+
.container {
|
|
112
|
+
background: var(--color-bg-surface-strong); /* a touch more neutral than contextual */
|
|
113
|
+
border-color: var(--color-border-subtle);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Keep focus ring behavior */
|
|
117
|
+
.container:focus-within {
|
|
118
|
+
border-color: var(--color-border-selected);
|
|
119
|
+
box-shadow: var(--shadow-xs), var(--focus-ring);
|
|
120
|
+
}
|
|
@@ -23,9 +23,10 @@ export interface FilterFieldProps extends Omit<React.InputHTMLAttributes<HTMLInp
|
|
|
23
23
|
label?: string;
|
|
24
24
|
placeholder?: string;
|
|
25
25
|
disabled?: boolean;
|
|
26
|
+
width?: string;
|
|
26
27
|
}
|
|
27
28
|
export declare const NUMBER_OPERATORS: Operator[];
|
|
28
|
-
export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, label, placeholder, disabled, 'data-cy': dataCy, ...inputProps }: FilterFieldProps & {
|
|
29
|
+
export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, label, placeholder, disabled, 'data-cy': dataCy, width, ...inputProps }: FilterFieldProps & {
|
|
29
30
|
'data-cy'?: string;
|
|
30
31
|
}): React.ReactElement;
|
|
31
32
|
export {};
|