@iota/apps-ui-kit 0.10.1 → 0.12.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/CHANGELOG.md +25 -0
- package/dist/index.d.ts +40 -16
- package/dist/index.es.js +228 -189
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +4 -4
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/lib/components/atoms/badge/Badge.tsx +18 -2
- package/src/lib/components/atoms/button/Button.tsx +1 -1
- package/src/lib/components/atoms/checkbox/Checkbox.tsx +2 -2
- package/src/lib/components/atoms/info-box/InfoBox.tsx +3 -1
- package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +32 -8
- package/src/lib/components/atoms/tooltip/Tooltip.tsx +45 -18
- package/src/lib/components/molecules/card/CardAction.tsx +2 -2
- package/src/lib/components/molecules/card/CardBody.tsx +2 -2
- package/src/lib/components/molecules/display-stats/DisplayStats.tsx +2 -2
- package/src/lib/components/molecules/input/Input.tsx +2 -2
- package/src/lib/components/molecules/input/InputWrapper.tsx +3 -2
- package/src/lib/components/molecules/table-cell/TableCell.tsx +6 -0
- package/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +13 -7
- package/src/lib/components/organisms/accordion/Accordion.tsx +10 -1
- package/src/lib/components/organisms/table/Table.tsx +12 -2
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import cx from 'classnames';
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
5
6
|
import { BadgeSize, BadgeType } from './badge.enums';
|
|
6
7
|
import { BACKGROUND_COLORS, BORDER_COLORS, TEXT_COLORS } from './badge.classes';
|
|
7
8
|
|
|
@@ -18,9 +19,18 @@ interface BadgeProps {
|
|
|
18
19
|
* The size of the badge
|
|
19
20
|
*/
|
|
20
21
|
size?: BadgeSize;
|
|
22
|
+
/**
|
|
23
|
+
* An icon rendered before the label.
|
|
24
|
+
*/
|
|
25
|
+
icon?: ReactNode;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
export function Badge({
|
|
28
|
+
export function Badge({
|
|
29
|
+
type,
|
|
30
|
+
label,
|
|
31
|
+
size = BadgeSize.Medium,
|
|
32
|
+
icon,
|
|
33
|
+
}: BadgeProps): React.JSX.Element {
|
|
24
34
|
const backgroundClasses = BACKGROUND_COLORS[type];
|
|
25
35
|
const textClasses = TEXT_COLORS[type];
|
|
26
36
|
const isSmall = size === BadgeSize.Small;
|
|
@@ -31,7 +41,8 @@ export function Badge({ type, label, size = BadgeSize.Medium }: BadgeProps): Rea
|
|
|
31
41
|
return (
|
|
32
42
|
<div
|
|
33
43
|
className={cx(
|
|
34
|
-
'inline-flex items-center
|
|
44
|
+
'inline-flex items-center rounded-full disabled:opacity-30',
|
|
45
|
+
icon ? 'gap-xxs' : 'space-x-2',
|
|
35
46
|
{ border: !isSmall },
|
|
36
47
|
{ [BORDER_COLORS[type]]: !isSmall },
|
|
37
48
|
{ 'badge-ring-outlined': isSmall && isOutlined },
|
|
@@ -39,6 +50,11 @@ export function Badge({ type, label, size = BadgeSize.Medium }: BadgeProps): Rea
|
|
|
39
50
|
labelClasses,
|
|
40
51
|
)}
|
|
41
52
|
>
|
|
53
|
+
{icon && (
|
|
54
|
+
<span className={cx('flex h-4 w-4 items-center justify-center', textClasses)}>
|
|
55
|
+
{icon}
|
|
56
|
+
</span>
|
|
57
|
+
)}
|
|
42
58
|
<span className={cx(textSizeClass, textClasses)}>{label}</span>
|
|
43
59
|
</div>
|
|
44
60
|
);
|
|
@@ -98,7 +98,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
98
98
|
<span
|
|
99
99
|
onClick={() => inputRef.current?.click()}
|
|
100
100
|
className={cx(
|
|
101
|
-
'checkbox-base checkbox-state checkbox-icon checkbox-icon-hidden',
|
|
101
|
+
'checkbox-base checkbox-state checkbox-icon checkbox-icon-hidden shrink-0',
|
|
102
102
|
'checkbox-border-default',
|
|
103
103
|
'peer-[&:is(:checked,:indeterminate)]:checkbox-border-checked',
|
|
104
104
|
'peer-[&:is(:checked,:indeterminate)]:checkbox-bg-checked',
|
|
@@ -119,7 +119,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
119
119
|
|
|
120
120
|
function LabelText({ label, name }: Pick<CheckboxProps, 'label' | 'name'>) {
|
|
121
121
|
return (
|
|
122
|
-
<label htmlFor={name} className="checkbox-label checkbox-label-disabled">
|
|
122
|
+
<label htmlFor={name} className="checkbox-label checkbox-label-disabled flex-1">
|
|
123
123
|
{label}
|
|
124
124
|
</label>
|
|
125
125
|
);
|
|
@@ -41,7 +41,9 @@ export function InfoBox({
|
|
|
41
41
|
return (
|
|
42
42
|
<div
|
|
43
43
|
className={cx('flex flex-row items-start gap-4 py-xs pr-lg', backgroundClass, {
|
|
44
|
-
'rounded-lg
|
|
44
|
+
'rounded-lg': style === InfoBoxStyle.Elevated,
|
|
45
|
+
'pl-xs': style === InfoBoxStyle.Elevated && !!icon,
|
|
46
|
+
'pl-lg': style === InfoBoxStyle.Elevated && !icon,
|
|
45
47
|
})}
|
|
46
48
|
>
|
|
47
49
|
{icon && (
|
|
@@ -13,7 +13,11 @@ interface KeyValueProps {
|
|
|
13
13
|
/**
|
|
14
14
|
* The key of the KeyValue.
|
|
15
15
|
*/
|
|
16
|
-
keyText:
|
|
16
|
+
keyText: ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* An icon shown next to the key text (optional).
|
|
19
|
+
*/
|
|
20
|
+
keyIcon?: ReactNode;
|
|
17
21
|
/**
|
|
18
22
|
* The value of the KeyValue.
|
|
19
23
|
*/
|
|
@@ -29,7 +33,7 @@ interface KeyValueProps {
|
|
|
29
33
|
/**
|
|
30
34
|
* The supporting label of the KeyValue (optional).
|
|
31
35
|
*/
|
|
32
|
-
supportingLabel?: string;
|
|
36
|
+
supportingLabel?: string | ReactNode;
|
|
33
37
|
/**
|
|
34
38
|
* The size of the value (optional).
|
|
35
39
|
*/
|
|
@@ -58,6 +62,11 @@ interface KeyValueProps {
|
|
|
58
62
|
* Reverse the KeyValue (optional).
|
|
59
63
|
*/
|
|
60
64
|
isReverse?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Use a receipt-style row with a dotted leader and right-aligned value.
|
|
67
|
+
* This is opt-in so existing KeyValueInfo layouts remain unchanged.
|
|
68
|
+
*/
|
|
69
|
+
layout?: 'default' | 'receipt';
|
|
61
70
|
/**
|
|
62
71
|
* Text shown on value hover.
|
|
63
72
|
*/
|
|
@@ -66,6 +75,7 @@ interface KeyValueProps {
|
|
|
66
75
|
|
|
67
76
|
export function KeyValueInfo({
|
|
68
77
|
keyText,
|
|
78
|
+
keyIcon,
|
|
69
79
|
value,
|
|
70
80
|
tooltipPosition,
|
|
71
81
|
tooltipText,
|
|
@@ -77,9 +87,11 @@ export function KeyValueInfo({
|
|
|
77
87
|
onCopyError,
|
|
78
88
|
fullwidth,
|
|
79
89
|
isReverse = false,
|
|
90
|
+
layout = 'default',
|
|
80
91
|
valueHoverTitle,
|
|
81
92
|
}: KeyValueProps): React.JSX.Element {
|
|
82
93
|
const flexDirectionClass = isReverse ? 'flex-row-reverse' : 'flex-row';
|
|
94
|
+
const isReceiptLayout = layout === 'receipt';
|
|
83
95
|
async function handleCopyClick(event: React.MouseEvent<HTMLButtonElement>) {
|
|
84
96
|
if (!navigator.clipboard) {
|
|
85
97
|
return;
|
|
@@ -102,32 +114,44 @@ export function KeyValueInfo({
|
|
|
102
114
|
'flex w-full items-baseline gap-xs py-xxs font-inter',
|
|
103
115
|
flexDirectionClass,
|
|
104
116
|
{
|
|
105
|
-
'justify-between': fullwidth,
|
|
117
|
+
'flex-wrap justify-between': fullwidth,
|
|
106
118
|
},
|
|
107
119
|
)}
|
|
108
120
|
>
|
|
109
121
|
<div
|
|
110
122
|
className={cx('flex shrink-0 flex-row items-center gap-x-0.5', {
|
|
111
|
-
'w-1/4': !fullwidth,
|
|
123
|
+
'w-1/4': !fullwidth && !isReceiptLayout,
|
|
112
124
|
})}
|
|
113
125
|
>
|
|
114
|
-
|
|
126
|
+
{keyIcon}
|
|
127
|
+
<span className="key-value-key-text-color break-normal text-body-md">
|
|
128
|
+
{keyText}
|
|
129
|
+
</span>
|
|
115
130
|
{tooltipText && (
|
|
116
131
|
<Tooltip text={tooltipText} position={tooltipPosition}>
|
|
117
132
|
<Info className="key-supporting-text-color" />
|
|
118
133
|
</Tooltip>
|
|
119
134
|
)}
|
|
120
135
|
</div>
|
|
136
|
+
{isReceiptLayout && !fullwidth && (
|
|
137
|
+
<span
|
|
138
|
+
aria-hidden="true"
|
|
139
|
+
className="mb-1 min-w-[0.5rem] flex-1 border-b border-dotted border-iota-neutral-80 opacity-60 dark:border-iota-neutral-20"
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
121
142
|
<div
|
|
122
|
-
className={cx('flex flex-row items-baseline gap-1 break-all', {
|
|
123
|
-
'w-3/4': !fullwidth,
|
|
143
|
+
className={cx('flex min-w-0 flex-row items-baseline gap-1 break-all', {
|
|
144
|
+
'w-3/4': !fullwidth && !isReceiptLayout,
|
|
145
|
+
'max-w-[60%] justify-end text-right': !fullwidth && isReceiptLayout,
|
|
146
|
+
'flex-wrap': fullwidth,
|
|
147
|
+
'justify-end text-right': fullwidth && isReceiptLayout,
|
|
124
148
|
truncate: isTruncated,
|
|
125
149
|
})}
|
|
126
150
|
>
|
|
127
151
|
<span
|
|
128
152
|
title={valueHoverTitle}
|
|
129
153
|
className={cx(
|
|
130
|
-
'key-value-hover-text-color',
|
|
154
|
+
'key-value-hover-text-color min-w-0',
|
|
131
155
|
size === ValueSize.Medium ? 'text-body-lg' : 'text-body-md',
|
|
132
156
|
{ truncate: isTruncated },
|
|
133
157
|
)}
|
|
@@ -49,51 +49,78 @@ export function Tooltip({
|
|
|
49
49
|
closeTimer.current = setTimeout(() => setVisible(false), closeDelay);
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const rect = triggerRef.current?.getBoundingClientRect();
|
|
56
|
-
if (!rect) return;
|
|
57
|
-
|
|
58
|
-
const pos = {
|
|
52
|
+
const computePosition = (rect: DOMRect) =>
|
|
53
|
+
({
|
|
59
54
|
[TooltipPosition.Top]: {
|
|
60
55
|
top: rect.top - offset,
|
|
61
56
|
left: rect.left + rect.width / 2,
|
|
62
57
|
transform: 'translate(-50%, -100%)',
|
|
58
|
+
anchorX: 0.5,
|
|
59
|
+
anchorY: 1,
|
|
63
60
|
},
|
|
64
61
|
[TooltipPosition.Bottom]: {
|
|
65
62
|
top: rect.bottom + offset,
|
|
66
63
|
left: rect.left + rect.width / 2,
|
|
67
64
|
transform: 'translate(-50%, 0)',
|
|
65
|
+
anchorX: 0.5,
|
|
66
|
+
anchorY: 0,
|
|
68
67
|
},
|
|
69
68
|
[TooltipPosition.Left]: {
|
|
70
69
|
top: rect.top + rect.height / 2,
|
|
71
70
|
left: rect.left - offset,
|
|
72
71
|
transform: 'translate(-100%, -50%)',
|
|
72
|
+
anchorX: 1,
|
|
73
|
+
anchorY: 0.5,
|
|
73
74
|
},
|
|
74
75
|
[TooltipPosition.Right]: {
|
|
75
76
|
top: rect.top + rect.height / 2,
|
|
76
77
|
left: rect.right + offset,
|
|
77
78
|
transform: 'translate(0, -50%)',
|
|
79
|
+
anchorX: 0,
|
|
80
|
+
anchorY: 0.5,
|
|
78
81
|
},
|
|
79
|
-
}[position];
|
|
82
|
+
})[position];
|
|
83
|
+
|
|
84
|
+
const clampDelta = (boxStart: number, size: number, viewportSize: number, margin: number) => {
|
|
85
|
+
const boxEnd = boxStart + size;
|
|
86
|
+
if (boxEnd > viewportSize - margin) return viewportSize - margin - boxEnd;
|
|
87
|
+
if (boxStart < margin) return margin - boxStart;
|
|
88
|
+
return 0;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
useLayoutEffect(() => {
|
|
92
|
+
if (!visible) return;
|
|
93
|
+
|
|
94
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
95
|
+
const tooltipEl = tooltipRef.current;
|
|
96
|
+
if (!rect || !tooltipEl) return;
|
|
97
|
+
|
|
98
|
+
const pos = computePosition(rect);
|
|
99
|
+
tooltipEl.style.transform = pos.transform;
|
|
100
|
+
|
|
101
|
+
const { width, height } = tooltipEl.getBoundingClientRect();
|
|
102
|
+
const margin = 8;
|
|
103
|
+
|
|
104
|
+
const boxLeft = pos.left - width * pos.anchorX;
|
|
105
|
+
const boxTop = pos.top - height * pos.anchorY;
|
|
106
|
+
|
|
107
|
+
const deltaX = clampDelta(boxLeft, width, window.innerWidth, margin);
|
|
108
|
+
const deltaY = clampDelta(boxTop, height, window.innerHeight, margin);
|
|
80
109
|
|
|
81
|
-
setCoords({ top: pos.top, left: pos.left });
|
|
82
|
-
tooltipRef.current!.style.transform = pos.transform;
|
|
110
|
+
setCoords({ top: pos.top + deltaY, left: pos.left + deltaX });
|
|
83
111
|
}, [visible, position, offset]);
|
|
84
112
|
|
|
85
113
|
useLayoutEffect(() => {
|
|
86
114
|
if (!visible) return;
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
setCoords((prev) => ({ ...prev, left: rect.left + rect.width / 2 }));
|
|
115
|
+
const dismiss = () => {
|
|
116
|
+
clearTimers();
|
|
117
|
+
setVisible(false);
|
|
91
118
|
};
|
|
92
|
-
window.addEventListener('scroll',
|
|
93
|
-
window.addEventListener('resize',
|
|
119
|
+
window.addEventListener('scroll', dismiss, true);
|
|
120
|
+
window.addEventListener('resize', dismiss);
|
|
94
121
|
return () => {
|
|
95
|
-
window.removeEventListener('scroll',
|
|
96
|
-
window.removeEventListener('resize',
|
|
122
|
+
window.removeEventListener('scroll', dismiss, true);
|
|
123
|
+
window.removeEventListener('resize', dismiss);
|
|
97
124
|
};
|
|
98
125
|
}, [visible]);
|
|
99
126
|
|
|
@@ -6,8 +6,8 @@ import { CardActionType } from './card.enums';
|
|
|
6
6
|
import { Button, ButtonSize, ButtonType } from '@/components/atoms/button';
|
|
7
7
|
|
|
8
8
|
export type CardActionProps = {
|
|
9
|
-
title?:
|
|
10
|
-
subtitle?: string;
|
|
9
|
+
title?: React.ReactNode;
|
|
10
|
+
subtitle?: string | React.ReactNode;
|
|
11
11
|
type: CardActionType;
|
|
12
12
|
onClick?: () => void;
|
|
13
13
|
icon?: React.ReactNode;
|
|
@@ -39,7 +39,7 @@ export function CardBody({
|
|
|
39
39
|
})}
|
|
40
40
|
>
|
|
41
41
|
<div
|
|
42
|
-
className={cx('card-body-title-color font-inter text-title-md', {
|
|
42
|
+
className={cx('card-body-title-color text-start font-inter text-title-md', {
|
|
43
43
|
truncate: isTextTruncated,
|
|
44
44
|
})}
|
|
45
45
|
>
|
|
@@ -61,7 +61,7 @@ export function CardBody({
|
|
|
61
61
|
</div>
|
|
62
62
|
{subtitle && (
|
|
63
63
|
<div
|
|
64
|
-
className={cx('card-body-subtitle-color font-inter text-body-md', {
|
|
64
|
+
className={cx('card-body-subtitle-color text-start font-inter text-body-md', {
|
|
65
65
|
truncate: isTextTruncated,
|
|
66
66
|
})}
|
|
67
67
|
>
|
|
@@ -28,7 +28,7 @@ interface DisplayStatsProps {
|
|
|
28
28
|
/**
|
|
29
29
|
* The tooltip text.
|
|
30
30
|
*/
|
|
31
|
-
tooltipText?:
|
|
31
|
+
tooltipText?: ReactNode;
|
|
32
32
|
/**
|
|
33
33
|
* The value of the stats.
|
|
34
34
|
*/
|
|
@@ -123,7 +123,7 @@ export function DisplayStats({
|
|
|
123
123
|
{icon && <span className="display-stats-icon-color">{icon}</span>}
|
|
124
124
|
</div>
|
|
125
125
|
<div className="flex w-full flex-row items-baseline gap-xxs">
|
|
126
|
-
<span className={cx('break-all', valueClass)}>{value}</span>
|
|
126
|
+
<span className={cx('min-w-0 break-all', valueClass)}>{value}</span>
|
|
127
127
|
{supportingLabel && (
|
|
128
128
|
<span className={cx('opacity-40', supportingLabelTextClass)}>
|
|
129
129
|
{supportingLabel}
|
|
@@ -31,7 +31,7 @@ export interface BaseInputProps extends InputWrapperProps {
|
|
|
31
31
|
/**
|
|
32
32
|
* Amount counter that is shown at the side of the caption text.
|
|
33
33
|
*/
|
|
34
|
-
amountCounter?:
|
|
34
|
+
amountCounter?: React.ReactNode;
|
|
35
35
|
/**
|
|
36
36
|
* Trailing element that is shown after the input
|
|
37
37
|
*/
|
|
@@ -47,7 +47,7 @@ export interface BaseInputProps extends InputWrapperProps {
|
|
|
47
47
|
/**
|
|
48
48
|
* Text that is shown below the value of the input.
|
|
49
49
|
*/
|
|
50
|
-
supportingValue?:
|
|
50
|
+
supportingValue?: React.ReactNode;
|
|
51
51
|
/**
|
|
52
52
|
* Default value of the input
|
|
53
53
|
*/
|
|
@@ -5,6 +5,7 @@ import cx from 'classnames';
|
|
|
5
5
|
import { SecondaryText } from '@/components/atoms/secondary-text';
|
|
6
6
|
import { LABEL_CLASSES } from './input.classes';
|
|
7
7
|
import { createElement } from 'react';
|
|
8
|
+
import type { ReactNode } from 'react';
|
|
8
9
|
|
|
9
10
|
export enum LabelHtmlTag {
|
|
10
11
|
Label = 'label',
|
|
@@ -19,7 +20,7 @@ export interface InputWrapperProps {
|
|
|
19
20
|
/**
|
|
20
21
|
* Shows a caption with the text below the input.
|
|
21
22
|
*/
|
|
22
|
-
caption?:
|
|
23
|
+
caption?: ReactNode;
|
|
23
24
|
/**
|
|
24
25
|
* Error Message. Overrides the caption.
|
|
25
26
|
*/
|
|
@@ -27,7 +28,7 @@ export interface InputWrapperProps {
|
|
|
27
28
|
/**
|
|
28
29
|
* Amount counter that is shown at the side of the caption text.
|
|
29
30
|
*/
|
|
30
|
-
amountCounter?:
|
|
31
|
+
amountCounter?: React.ReactNode;
|
|
31
32
|
/**
|
|
32
33
|
* Is the input required
|
|
33
34
|
*/
|
|
@@ -17,15 +17,21 @@ interface TableCellBaseProps {
|
|
|
17
17
|
* Whether the cell content should be centered.
|
|
18
18
|
*/
|
|
19
19
|
isContentCentered?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The number of columns the cell should span.
|
|
22
|
+
*/
|
|
23
|
+
colSpan?: number;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
export function TableCellBase({
|
|
23
27
|
children,
|
|
24
28
|
hasLastBorderNoneClass,
|
|
25
29
|
isContentCentered,
|
|
30
|
+
colSpan,
|
|
26
31
|
}: PropsWithChildren<TableCellBaseProps>) {
|
|
27
32
|
return (
|
|
28
33
|
<td
|
|
34
|
+
colSpan={colSpan}
|
|
29
35
|
className={cx(
|
|
30
36
|
'table-cell-border-color h-14 border-b px-md',
|
|
31
37
|
{ 'last:border-none': hasLastBorderNoneClass },
|
|
@@ -60,6 +60,8 @@ export interface TableHeaderCellProps extends React.AriaAttributes {
|
|
|
60
60
|
export function TableHeaderCell({
|
|
61
61
|
label,
|
|
62
62
|
columnKey,
|
|
63
|
+
actionLeft,
|
|
64
|
+
actionRight,
|
|
63
65
|
hasSort,
|
|
64
66
|
hasCheckbox,
|
|
65
67
|
isChecked,
|
|
@@ -136,15 +138,19 @@ export function TableHeaderCell({
|
|
|
136
138
|
onCheckedChange={onCheckboxChange}
|
|
137
139
|
/>
|
|
138
140
|
) : (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
<>
|
|
142
|
+
{actionLeft}
|
|
143
|
+
<span
|
|
144
|
+
className={cx({
|
|
145
|
+
'text-left': !isContentCentered,
|
|
146
|
+
})}
|
|
147
|
+
>
|
|
148
|
+
{label}
|
|
149
|
+
</span>
|
|
150
|
+
</>
|
|
146
151
|
)}
|
|
147
152
|
{sortElement}
|
|
153
|
+
{actionRight}
|
|
148
154
|
</div>
|
|
149
155
|
</th>
|
|
150
156
|
);
|
|
@@ -30,6 +30,13 @@ export interface AccordionHeaderProps {
|
|
|
30
30
|
* Flag for hiding border.
|
|
31
31
|
*/
|
|
32
32
|
hideBorder?: boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Disable the header state layer while an interactive child is active.
|
|
36
|
+
* This keeps the parent hover treatment from competing with child links
|
|
37
|
+
* and controls.
|
|
38
|
+
*/
|
|
39
|
+
disableStateLayer?: boolean;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
interface AccordionContentProps {
|
|
@@ -44,6 +51,7 @@ export function AccordionHeader({
|
|
|
44
51
|
children,
|
|
45
52
|
isExpanded,
|
|
46
53
|
hideArrow,
|
|
54
|
+
disableStateLayer = false,
|
|
47
55
|
}: PropsWithChildren<AccordionHeaderProps>) {
|
|
48
56
|
return (
|
|
49
57
|
<div
|
|
@@ -51,7 +59,8 @@ export function AccordionHeader({
|
|
|
51
59
|
role="button"
|
|
52
60
|
aria-expanded={isExpanded}
|
|
53
61
|
className={cx(
|
|
54
|
-
'
|
|
62
|
+
'relative flex cursor-pointer items-center justify-between gap-md overflow-hidden rounded-xl py-sm--rs',
|
|
63
|
+
!disableStateLayer && 'state-layer',
|
|
55
64
|
{
|
|
56
65
|
'pr-md--rs': !hideArrow,
|
|
57
66
|
},
|
|
@@ -177,9 +177,19 @@ export function TableHeader({ children }: PropsWithChildren): JSX.Element {
|
|
|
177
177
|
export function TableRow({
|
|
178
178
|
children,
|
|
179
179
|
leading,
|
|
180
|
-
|
|
180
|
+
onClick,
|
|
181
|
+
}: PropsWithChildren<{
|
|
182
|
+
leading?: React.ReactNode;
|
|
183
|
+
onClick?: React.MouseEventHandler<HTMLTableRowElement>;
|
|
184
|
+
}>): JSX.Element {
|
|
181
185
|
return (
|
|
182
|
-
<tr
|
|
186
|
+
<tr
|
|
187
|
+
onClick={onClick}
|
|
188
|
+
className={cx({
|
|
189
|
+
'cursor-pointer hover:bg-shader-neutral-light-8 dark:hover:bg-shader-neutral-dark-8':
|
|
190
|
+
onClick,
|
|
191
|
+
})}
|
|
192
|
+
>
|
|
183
193
|
{leading}
|
|
184
194
|
{children}
|
|
185
195
|
</tr>
|