@iota/apps-ui-kit 0.0.0-experimental-20250613144451
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 +106 -0
- package/LICENSE +201 -0
- package/README.md +16 -0
- package/dist/index.d.ts +1726 -0
- package/dist/index.es.js +6923 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +118 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +75 -0
- package/src/lib/components/atoms/badge/Badge.tsx +37 -0
- package/src/lib/components/atoms/badge/badge.classes.ts +33 -0
- package/src/lib/components/atoms/badge/badge.enums.ts +11 -0
- package/src/lib/components/atoms/badge/index.ts +6 -0
- package/src/lib/components/atoms/button/Button.tsx +99 -0
- package/src/lib/components/atoms/button/button-variants/ButtonPill.tsx +23 -0
- package/src/lib/components/atoms/button/button-variants/ButtonUnstyled.tsx +27 -0
- package/src/lib/components/atoms/button/button-variants/buttonVariants.types.ts +11 -0
- package/src/lib/components/atoms/button/button-variants/index.ts +5 -0
- package/src/lib/components/atoms/button/button.classes.ts +53 -0
- package/src/lib/components/atoms/button/button.enums.ts +21 -0
- package/src/lib/components/atoms/button/index.ts +7 -0
- package/src/lib/components/atoms/button-segment/ButtonSegment.tsx +98 -0
- package/src/lib/components/atoms/button-segment/buttonSegment.classes.ts +45 -0
- package/src/lib/components/atoms/button-segment/buttonSegment.enums.ts +7 -0
- package/src/lib/components/atoms/button-segment/index.ts +5 -0
- package/src/lib/components/atoms/checkbox/Checkbox.tsx +114 -0
- package/src/lib/components/atoms/checkbox/index.ts +4 -0
- package/src/lib/components/atoms/divider/Divider.tsx +48 -0
- package/src/lib/components/atoms/divider/divider.classes.ts +11 -0
- package/src/lib/components/atoms/divider/divider.enums.ts +7 -0
- package/src/lib/components/atoms/divider/index.ts +6 -0
- package/src/lib/components/atoms/header/Header.tsx +73 -0
- package/src/lib/components/atoms/header/index.ts +4 -0
- package/src/lib/components/atoms/index.ts +23 -0
- package/src/lib/components/atoms/info-box/InfoBox.tsx +74 -0
- package/src/lib/components/atoms/info-box/index.ts +5 -0
- package/src/lib/components/atoms/info-box/infoBox.classes.ts +19 -0
- package/src/lib/components/atoms/info-box/infoBox.enums.ts +14 -0
- package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +157 -0
- package/src/lib/components/atoms/key-value-info/index.ts +6 -0
- package/src/lib/components/atoms/key-value-info/keyValue.enums.ts +7 -0
- package/src/lib/components/atoms/label-text/LabelText.tsx +94 -0
- package/src/lib/components/atoms/label-text/index.ts +5 -0
- package/src/lib/components/atoms/label-text/labelText.classes.ts +22 -0
- package/src/lib/components/atoms/label-text/labelText.enums.ts +8 -0
- package/src/lib/components/atoms/list-item/ListItem.tsx +89 -0
- package/src/lib/components/atoms/list-item/index.ts +4 -0
- package/src/lib/components/atoms/loading-indicator/LoadingIndicator.tsx +38 -0
- package/src/lib/components/atoms/loading-indicator/index.ts +4 -0
- package/src/lib/components/atoms/panel/Panel.tsx +30 -0
- package/src/lib/components/atoms/panel/index.ts +4 -0
- package/src/lib/components/atoms/placeholder/Placeholder.tsx +27 -0
- package/src/lib/components/atoms/placeholder/index.ts +4 -0
- package/src/lib/components/atoms/radio-button/RadioButton.tsx +68 -0
- package/src/lib/components/atoms/radio-button/index.ts +4 -0
- package/src/lib/components/atoms/secondary-text/SecondaryText.tsx +28 -0
- package/src/lib/components/atoms/secondary-text/index.ts +4 -0
- package/src/lib/components/atoms/skeleton/Skeleton.tsx +47 -0
- package/src/lib/components/atoms/skeleton/index.ts +4 -0
- package/src/lib/components/atoms/snackbar/Snackbar.tsx +69 -0
- package/src/lib/components/atoms/snackbar/index.ts +5 -0
- package/src/lib/components/atoms/snackbar/snackbar.classes.ts +18 -0
- package/src/lib/components/atoms/snackbar/snackbar.enums.tsx +9 -0
- package/src/lib/components/atoms/toggle/Toggle.tsx +140 -0
- package/src/lib/components/atoms/toggle/index.ts +6 -0
- package/src/lib/components/atoms/toggle/toggle.classes.ts +41 -0
- package/src/lib/components/atoms/toggle/toggle.enums.ts +12 -0
- package/src/lib/components/atoms/tooltip/Tooltip.tsx +138 -0
- package/src/lib/components/atoms/tooltip/index.ts +5 -0
- package/src/lib/components/atoms/tooltip/tooltip.classes.ts +11 -0
- package/src/lib/components/atoms/tooltip/tooltip.enums.ts +9 -0
- package/src/lib/components/atoms/visual-asset-card/VisualAssetCard.tsx +101 -0
- package/src/lib/components/atoms/visual-asset-card/index.ts +5 -0
- package/src/lib/components/atoms/visual-asset-card/visualAssetCard.enums.ts +7 -0
- package/src/lib/components/index.ts +8 -0
- package/src/lib/components/molecules/account/Account.tsx +192 -0
- package/src/lib/components/molecules/account/index.ts +4 -0
- package/src/lib/components/molecules/address/Address.tsx +101 -0
- package/src/lib/components/molecules/address/index.ts +4 -0
- package/src/lib/components/molecules/card/Card.tsx +70 -0
- package/src/lib/components/molecules/card/CardAction.tsx +80 -0
- package/src/lib/components/molecules/card/CardBody.tsx +72 -0
- package/src/lib/components/molecules/card/CardImage.tsx +43 -0
- package/src/lib/components/molecules/card/CardImagePlaceholder.tsx +146 -0
- package/src/lib/components/molecules/card/card.classes.ts +27 -0
- package/src/lib/components/molecules/card/card.enums.ts +26 -0
- package/src/lib/components/molecules/card/index.ts +8 -0
- package/src/lib/components/molecules/chip/Chip.tsx +105 -0
- package/src/lib/components/molecules/chip/chip.classes.ts +32 -0
- package/src/lib/components/molecules/chip/chip.enums.ts +7 -0
- package/src/lib/components/molecules/chip/index.ts +4 -0
- package/src/lib/components/molecules/display-stats/DisplayStats.tsx +142 -0
- package/src/lib/components/molecules/display-stats/displayStats.classes.ts +36 -0
- package/src/lib/components/molecules/display-stats/displayStats.enums.ts +13 -0
- package/src/lib/components/molecules/display-stats/index.ts +5 -0
- package/src/lib/components/molecules/dropdown/Dropdown.tsx +10 -0
- package/src/lib/components/molecules/dropdown/dropdownPosition.enums.ts +7 -0
- package/src/lib/components/molecules/dropdown/index.ts +5 -0
- package/src/lib/components/molecules/index.ts +17 -0
- package/src/lib/components/molecules/input/Input.tsx +246 -0
- package/src/lib/components/molecules/input/InputWrapper.tsx +97 -0
- package/src/lib/components/molecules/input/TextArea.tsx +150 -0
- package/src/lib/components/molecules/input/index.ts +8 -0
- package/src/lib/components/molecules/input/input.classes.ts +14 -0
- package/src/lib/components/molecules/input/input.enums.ts +14 -0
- package/src/lib/components/molecules/input/input.types.ts +29 -0
- package/src/lib/components/molecules/navbar-item/NavbarItem.tsx +48 -0
- package/src/lib/components/molecules/navbar-item/NavbarItemHorizontal.tsx +65 -0
- package/src/lib/components/molecules/navbar-item/NavbarItemVertical.tsx +54 -0
- package/src/lib/components/molecules/navbar-item/index.ts +5 -0
- package/src/lib/components/molecules/navbar-item/navbarItem.classes.ts +16 -0
- package/src/lib/components/molecules/navbar-item/navbarItem.enums.ts +7 -0
- package/src/lib/components/molecules/search/Search.tsx +216 -0
- package/src/lib/components/molecules/search/index.ts +5 -0
- package/src/lib/components/molecules/search/search.classes.ts +20 -0
- package/src/lib/components/molecules/search/search.enums.ts +7 -0
- package/src/lib/components/molecules/segmented-button/SegmentedButton.tsx +38 -0
- package/src/lib/components/molecules/segmented-button/index.ts +6 -0
- package/src/lib/components/molecules/segmented-button/segmentedButton.classes.ts +12 -0
- package/src/lib/components/molecules/segmented-button/segmentedButton.enums.ts +8 -0
- package/src/lib/components/molecules/select/Select.tsx +222 -0
- package/src/lib/components/molecules/select/index.ts +5 -0
- package/src/lib/components/molecules/select/select.enums.ts +7 -0
- package/src/lib/components/molecules/table-cell/TableCell.tsx +62 -0
- package/src/lib/components/molecules/table-cell/index.ts +4 -0
- package/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +140 -0
- package/src/lib/components/molecules/table-header-cell/index.ts +5 -0
- package/src/lib/components/molecules/table-header-cell/tableHeaderCell.enums.ts +7 -0
- package/src/lib/components/molecules/title/Title.tsx +78 -0
- package/src/lib/components/molecules/title/index.ts +5 -0
- package/src/lib/components/molecules/title/titleClasses.constants.ts +14 -0
- package/src/lib/components/molecules/title/titleSize.enums.ts +7 -0
- package/src/lib/components/organisms/accordion/Accordion.tsx +109 -0
- package/src/lib/components/organisms/accordion/accordion.classes.ts +4 -0
- package/src/lib/components/organisms/accordion/index.ts +4 -0
- package/src/lib/components/organisms/dialog/Dialog.tsx +142 -0
- package/src/lib/components/organisms/dialog/dialog.enums.ts +7 -0
- package/src/lib/components/organisms/dialog/index.ts +5 -0
- package/src/lib/components/organisms/index.ts +7 -0
- package/src/lib/components/organisms/navbar/Navbar.tsx +101 -0
- package/src/lib/components/organisms/navbar/NavbarSlideout.tsx +59 -0
- package/src/lib/components/organisms/navbar/index.ts +5 -0
- package/src/lib/components/organisms/table/Table.tsx +234 -0
- package/src/lib/components/organisms/table/TableContext.tsx +56 -0
- package/src/lib/components/organisms/table/index.ts +4 -0
- package/src/lib/constants/colors.constants.ts +133 -0
- package/src/lib/constants/index.ts +4 -0
- package/src/lib/enums/index.ts +4 -0
- package/src/lib/enums/screenSize.enums.ts +9 -0
- package/src/lib/index.ts +8 -0
- package/src/lib/styles/fonts.css +5 -0
- package/src/lib/styles/index.css +149 -0
- package/src/lib/tailwind/base.presets.ts +49 -0
- package/src/lib/tailwind/constants/fontSizes.constants.ts +201 -0
- package/src/lib/tailwind/constants/index.ts +6 -0
- package/src/lib/tailwind/constants/scaling.constants.ts +41 -0
- package/src/lib/tailwind/constants/variableSpacing.constants.ts +66 -0
- package/src/lib/tailwind/helpers.ts +20 -0
- package/src/lib/tailwind/index.ts +5 -0
- package/src/lib/tailwind/plugins.ts +8 -0
- package/src/lib/tailwind/responsive.presets.ts +36 -0
- package/src/lib/tailwind/static.presets.ts +25 -0
- package/src/lib/tailwind/types.ts +6 -0
- package/src/lib/utils/format.ts +8 -0
- package/src/lib/utils/index.ts +4 -0
- package/src/storybook/blocks/Showcase.tsx +20 -0
- package/src/storybook/blocks/TypeSet.tsx +34 -0
- package/src/storybook/blocks/TypeSetItem.tsx +74 -0
- package/src/storybook/blocks/index.ts +6 -0
- package/src/storybook/constants/index.ts +5 -0
- package/src/storybook/constants/typeset.constants.ts +39 -0
- package/src/storybook/constants/variableSpacing.constants.ts +6 -0
- package/src/storybook/helpers/getFontSizeLabel.ts +15 -0
- package/src/storybook/helpers/index.ts +4 -0
- package/src/storybook/stories/atoms/Badge.stories.tsx +32 -0
- package/src/storybook/stories/atoms/Button.stories.tsx +45 -0
- package/src/storybook/stories/atoms/ButtonSegment.stories.tsx +45 -0
- package/src/storybook/stories/atoms/Checkbox.stories.tsx +34 -0
- package/src/storybook/stories/atoms/CustomScrollbar.stories.tsx +22 -0
- package/src/storybook/stories/atoms/Divider.stories.tsx +41 -0
- package/src/storybook/stories/atoms/Header.stories.tsx +58 -0
- package/src/storybook/stories/atoms/InfoBox.stories.tsx +67 -0
- package/src/storybook/stories/atoms/KeyValueInfo.stories.tsx +59 -0
- package/src/storybook/stories/atoms/LabelText.stories.tsx +55 -0
- package/src/storybook/stories/atoms/ListItem.stories.tsx +41 -0
- package/src/storybook/stories/atoms/LoadingIndicator.stories.tsx +32 -0
- package/src/storybook/stories/atoms/Panel.stories.tsx +36 -0
- package/src/storybook/stories/atoms/Placeholder.stories.tsx +33 -0
- package/src/storybook/stories/atoms/RadioButton.stories.tsx +51 -0
- package/src/storybook/stories/atoms/Skeleton.stories.tsx +33 -0
- package/src/storybook/stories/atoms/Snackbar.stories.tsx +43 -0
- package/src/storybook/stories/atoms/Toggle.stories.tsx +59 -0
- package/src/storybook/stories/atoms/Tooltip.stories.tsx +57 -0
- package/src/storybook/stories/atoms/VisualAssetCard.stories.tsx +56 -0
- package/src/storybook/stories/components/VariableSpacingShowcase.tsx +46 -0
- package/src/storybook/stories/components/index.ts +4 -0
- package/src/storybook/stories/design-tokens/colors.stories.mdx +23 -0
- package/src/storybook/stories/design-tokens/icons.stories.mdx +17 -0
- package/src/storybook/stories/design-tokens/typeset.stories.mdx +15 -0
- package/src/storybook/stories/design-tokens/variable-spacing.stories.mdx +10 -0
- package/src/storybook/stories/molecules/Account.stories.tsx +69 -0
- package/src/storybook/stories/molecules/Address.stories.tsx +39 -0
- package/src/storybook/stories/molecules/Card.stories.tsx +112 -0
- package/src/storybook/stories/molecules/Chip.stories.tsx +122 -0
- package/src/storybook/stories/molecules/DisplayStats.stories.tsx +63 -0
- package/src/storybook/stories/molecules/Dropdown.stories.tsx +38 -0
- package/src/storybook/stories/molecules/Input.stories.tsx +162 -0
- package/src/storybook/stories/molecules/NavbarItem.stories.tsx +45 -0
- package/src/storybook/stories/molecules/Search.stories.tsx +101 -0
- package/src/storybook/stories/molecules/SegmentedButton.stories.tsx +108 -0
- package/src/storybook/stories/molecules/Select.stories.tsx +103 -0
- package/src/storybook/stories/molecules/TableCell.stories.tsx +46 -0
- package/src/storybook/stories/molecules/TableHeaderCell.stories.tsx +34 -0
- package/src/storybook/stories/molecules/TextArea.stories.tsx +80 -0
- package/src/storybook/stories/molecules/Title.stories.tsx +76 -0
- package/src/storybook/stories/organisms/Accordion.stories.tsx +70 -0
- package/src/storybook/stories/organisms/Dialog.stories.tsx +103 -0
- package/src/storybook/stories/organisms/Navbar.stories.tsx +78 -0
- package/src/storybook/stories/organisms/Table.stories.tsx +154 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { PropsWithChildren } from 'react';
|
|
5
|
+
import { BACKGROUND_COLORS, OUTLINED_BORDER } from './segmentedButton.classes';
|
|
6
|
+
import cx from 'classnames';
|
|
7
|
+
import { SegmentedButtonType } from './segmentedButton.enums';
|
|
8
|
+
import { ButtonSegmentType } from '@/components/atoms';
|
|
9
|
+
|
|
10
|
+
interface SegmentedButtonProps {
|
|
11
|
+
/**
|
|
12
|
+
* The type of the button
|
|
13
|
+
*/
|
|
14
|
+
type?: SegmentedButtonType;
|
|
15
|
+
/**
|
|
16
|
+
* The shape of the button
|
|
17
|
+
*/
|
|
18
|
+
shape?: ButtonSegmentType;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function SegmentedButton({
|
|
22
|
+
type = SegmentedButtonType.Filled,
|
|
23
|
+
children,
|
|
24
|
+
shape = ButtonSegmentType.Rounded,
|
|
25
|
+
}: PropsWithChildren<SegmentedButtonProps>): React.JSX.Element {
|
|
26
|
+
const backgroundColors = BACKGROUND_COLORS[type];
|
|
27
|
+
const borderColors = type === SegmentedButtonType.Outlined ? OUTLINED_BORDER : '';
|
|
28
|
+
const borderShape = shape === ButtonSegmentType.Rounded ? 'rounded-full gap-1 p-xxs' : '';
|
|
29
|
+
const scrollable =
|
|
30
|
+
shape === ButtonSegmentType.Rounded ? 'flex-wrap' : 'flex-nowrap overflow-x-auto';
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={cx('flex flex-row', backgroundColors, borderColors, borderShape, scrollable)}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { SegmentedButtonType } from './segmentedButton.enums';
|
|
5
|
+
|
|
6
|
+
export const BACKGROUND_COLORS: Record<SegmentedButtonType, string> = {
|
|
7
|
+
[SegmentedButtonType.Outlined]: 'bg-transparent',
|
|
8
|
+
[SegmentedButtonType.Filled]: 'bg-neutral-96 dark:bg-neutral-10',
|
|
9
|
+
[SegmentedButtonType.Transparent]: 'bg-transparent',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const OUTLINED_BORDER = 'border border-neutral-70 dark:border-neutral-40';
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { TriangleDown } from '@iota/apps-ui-icons';
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
import { forwardRef, useEffect, useState } from 'react';
|
|
7
|
+
import { Dropdown } from '../dropdown/Dropdown';
|
|
8
|
+
import { SecondaryText } from '@/components/atoms/secondary-text';
|
|
9
|
+
import { InputWrapper, LabelHtmlTag } from '../input/InputWrapper';
|
|
10
|
+
import { ListItem, ButtonUnstyled } from '@/components/atoms';
|
|
11
|
+
import { DropdownPosition } from '../dropdown';
|
|
12
|
+
import { SelectSize } from './select.enums';
|
|
13
|
+
|
|
14
|
+
export type SelectOption =
|
|
15
|
+
| string
|
|
16
|
+
| { id: string; renderLabel: () => React.JSX.Element }
|
|
17
|
+
| { id: string; label: React.ReactNode };
|
|
18
|
+
|
|
19
|
+
interface SelectProps extends Pick<React.HTMLProps<HTMLSelectElement>, 'disabled'> {
|
|
20
|
+
/**
|
|
21
|
+
* The selected option value.
|
|
22
|
+
*/
|
|
23
|
+
value?: string;
|
|
24
|
+
/**
|
|
25
|
+
* The field label.
|
|
26
|
+
*/
|
|
27
|
+
label?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The field caption.
|
|
30
|
+
*/
|
|
31
|
+
caption?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The dropdown elements to render.
|
|
34
|
+
*/
|
|
35
|
+
options: SelectOption[];
|
|
36
|
+
/**
|
|
37
|
+
* The icon to show on the left of the field.
|
|
38
|
+
*/
|
|
39
|
+
leadingIcon?: React.ReactNode;
|
|
40
|
+
/**
|
|
41
|
+
* The supporting text to shown at the end of the selector.
|
|
42
|
+
*/
|
|
43
|
+
supportingText?: string;
|
|
44
|
+
/**
|
|
45
|
+
* The error message to show under the field.
|
|
46
|
+
*/
|
|
47
|
+
errorMessage?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Placeholder for the selector
|
|
50
|
+
*/
|
|
51
|
+
placeholder?: SelectOption;
|
|
52
|
+
/**
|
|
53
|
+
* The callback to call when the value changes.
|
|
54
|
+
*/
|
|
55
|
+
onValueChange?: (id: string) => void;
|
|
56
|
+
/**
|
|
57
|
+
* The callback to call when the option is clicked.
|
|
58
|
+
*/
|
|
59
|
+
onOptionClick?: (id: string) => void;
|
|
60
|
+
/**
|
|
61
|
+
* The dropdown position
|
|
62
|
+
*/
|
|
63
|
+
dropdownPosition?: DropdownPosition;
|
|
64
|
+
/**
|
|
65
|
+
* The size of the select.
|
|
66
|
+
*/
|
|
67
|
+
size?: SelectSize;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
|
71
|
+
(
|
|
72
|
+
{
|
|
73
|
+
disabled,
|
|
74
|
+
label,
|
|
75
|
+
leadingIcon,
|
|
76
|
+
supportingText,
|
|
77
|
+
errorMessage,
|
|
78
|
+
caption,
|
|
79
|
+
options,
|
|
80
|
+
placeholder,
|
|
81
|
+
onValueChange,
|
|
82
|
+
onOptionClick,
|
|
83
|
+
value,
|
|
84
|
+
dropdownPosition = DropdownPosition.Bottom,
|
|
85
|
+
size = SelectSize.Default,
|
|
86
|
+
},
|
|
87
|
+
ref,
|
|
88
|
+
) => {
|
|
89
|
+
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
90
|
+
const selectedValue = findValueByProps(value, options);
|
|
91
|
+
|
|
92
|
+
const selectorText = selectedValue || placeholder;
|
|
93
|
+
const selectPadding = size === SelectSize.Small ? 'px-sm' : 'px-md';
|
|
94
|
+
const textSize = size === SelectSize.Small ? 'text-body-md' : 'text-body-lg';
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (disabled && isOpen) {
|
|
97
|
+
closeDropdown();
|
|
98
|
+
}
|
|
99
|
+
}, [disabled, isOpen]);
|
|
100
|
+
|
|
101
|
+
function findValueByProps(value: SelectProps['value'], options: SelectOption[] = []) {
|
|
102
|
+
return (
|
|
103
|
+
options.find((option) =>
|
|
104
|
+
typeof option === 'string' ? option === value : option.id === value,
|
|
105
|
+
) ?? options[0]
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function onSelectorClick() {
|
|
110
|
+
setIsOpen((prev) => !prev);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function handleOptionClick(option: SelectOption) {
|
|
114
|
+
closeDropdown();
|
|
115
|
+
const clickedOption = typeof option === 'string' ? option : option.id;
|
|
116
|
+
onOptionClick?.(clickedOption);
|
|
117
|
+
|
|
118
|
+
if (option !== selectedValue) {
|
|
119
|
+
onValueChange?.(clickedOption);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function closeDropdown() {
|
|
124
|
+
setIsOpen(false);
|
|
125
|
+
}
|
|
126
|
+
return (
|
|
127
|
+
<InputWrapper
|
|
128
|
+
label={label}
|
|
129
|
+
caption={caption}
|
|
130
|
+
disabled={disabled}
|
|
131
|
+
errorMessage={errorMessage}
|
|
132
|
+
labelHtmlTag={LabelHtmlTag.Div}
|
|
133
|
+
>
|
|
134
|
+
<div className="relative flex w-full flex-col">
|
|
135
|
+
<ButtonUnstyled
|
|
136
|
+
ref={ref}
|
|
137
|
+
onClick={onSelectorClick}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
className={cx(
|
|
140
|
+
'flex flex-row items-center gap-x-3 rounded-lg border border-neutral-80 py-sm hover:enabled:border-neutral-50 focus-visible:enabled:border-primary-30 active:enabled:border-primary-30 disabled:cursor-not-allowed group-[.errored]:border-error-30 group-[.opened]:border-primary-30 dark:border-neutral-20 dark:hover:enabled:border-neutral-60 dark:group-[.errored]:border-error-80 dark:group-[.opened]:border-primary-80 [&:is(:focus,_:focus-visible,_:active)]:enabled:border-primary-30 dark:[&:is(:focus,_:focus-visible,_:active)]:enabled:border-primary-80 [&_svg]:h-5 [&_svg]:w-5',
|
|
141
|
+
selectPadding,
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
{leadingIcon && (
|
|
145
|
+
<span className="text-neutral-10 dark:text-neutral-92">
|
|
146
|
+
{leadingIcon}
|
|
147
|
+
</span>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
<div className="flex w-full flex-row items-baseline gap-x-3">
|
|
151
|
+
{selectorText && (
|
|
152
|
+
<div
|
|
153
|
+
className={cx(
|
|
154
|
+
'block w-full text-start text-neutral-10 dark:text-neutral-92',
|
|
155
|
+
textSize,
|
|
156
|
+
)}
|
|
157
|
+
>
|
|
158
|
+
<OptionLabel option={selectorText} />
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
|
|
162
|
+
{supportingText && (
|
|
163
|
+
<div className="ml-auto">
|
|
164
|
+
<SecondaryText>{supportingText}</SecondaryText>
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<TriangleDown
|
|
170
|
+
className={cx(
|
|
171
|
+
'text-neutral-10 transition-transform dark:text-neutral-92',
|
|
172
|
+
{
|
|
173
|
+
' rotate-180': isOpen,
|
|
174
|
+
},
|
|
175
|
+
)}
|
|
176
|
+
/>
|
|
177
|
+
</ButtonUnstyled>
|
|
178
|
+
|
|
179
|
+
{isOpen && (
|
|
180
|
+
<div
|
|
181
|
+
className="fixed left-0 top-0 z-[49] h-screen w-screen bg-transparent"
|
|
182
|
+
onClick={closeDropdown}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
<div
|
|
186
|
+
className={cx('absolute z-50 min-w-full', {
|
|
187
|
+
hidden: !isOpen,
|
|
188
|
+
'top-full':
|
|
189
|
+
!dropdownPosition || dropdownPosition === DropdownPosition.Bottom,
|
|
190
|
+
'bottom-full': dropdownPosition === DropdownPosition.Top,
|
|
191
|
+
})}
|
|
192
|
+
>
|
|
193
|
+
<Dropdown>
|
|
194
|
+
{options.map((option) => {
|
|
195
|
+
const optionIsString = typeof option === 'string';
|
|
196
|
+
return (
|
|
197
|
+
<ListItem
|
|
198
|
+
onClick={() => handleOptionClick(option)}
|
|
199
|
+
hideBottomBorder
|
|
200
|
+
key={optionIsString ? option : option.id}
|
|
201
|
+
>
|
|
202
|
+
<OptionLabel option={option} />
|
|
203
|
+
</ListItem>
|
|
204
|
+
);
|
|
205
|
+
})}
|
|
206
|
+
</Dropdown>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</InputWrapper>
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
function OptionLabel({ option }: { option: SelectOption }) {
|
|
215
|
+
if (typeof option === 'string') {
|
|
216
|
+
return option;
|
|
217
|
+
} else if ('renderLabel' in option) {
|
|
218
|
+
return option.renderLabel();
|
|
219
|
+
} else {
|
|
220
|
+
return option.label;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import type { PropsWithChildren } from 'react';
|
|
4
|
+
import cx from 'classnames';
|
|
5
|
+
import { Placeholder } from '@/components/atoms';
|
|
6
|
+
|
|
7
|
+
interface TableCellBaseProps {
|
|
8
|
+
/**
|
|
9
|
+
* The label of the cell.
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
/**
|
|
13
|
+
* If the cell is the last in the row and should not have a border.
|
|
14
|
+
*/
|
|
15
|
+
hasLastBorderNoneClass?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the cell content should be centered.
|
|
18
|
+
*/
|
|
19
|
+
isContentCentered?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function TableCellBase({
|
|
23
|
+
children,
|
|
24
|
+
hasLastBorderNoneClass,
|
|
25
|
+
isContentCentered,
|
|
26
|
+
}: PropsWithChildren<TableCellBaseProps>) {
|
|
27
|
+
return (
|
|
28
|
+
<td
|
|
29
|
+
className={cx(
|
|
30
|
+
'h-14 border-b border-shader-neutral-light-8 px-md dark:border-shader-neutral-dark-8',
|
|
31
|
+
{ 'last:border-none': hasLastBorderNoneClass },
|
|
32
|
+
{ 'flex items-center justify-center': isContentCentered },
|
|
33
|
+
)}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</td>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface TableCellTextProps {
|
|
41
|
+
supportingLabel?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function TableCellText({
|
|
45
|
+
children,
|
|
46
|
+
supportingLabel,
|
|
47
|
+
}: PropsWithChildren<TableCellTextProps>) {
|
|
48
|
+
return (
|
|
49
|
+
<div className="flex flex-row items-baseline gap-1">
|
|
50
|
+
<span>{children}</span>
|
|
51
|
+
{supportingLabel && (
|
|
52
|
+
<span className="text-body-sm text-neutral-60 dark:text-neutral-40">
|
|
53
|
+
{supportingLabel}
|
|
54
|
+
</span>
|
|
55
|
+
)}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function TableCellPlaceholder() {
|
|
61
|
+
return <Placeholder />;
|
|
62
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { SortByDown, SortByUp } from '@iota/apps-ui-icons';
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
import { Checkbox } from '@/components/atoms/checkbox';
|
|
7
|
+
import { TableHeaderCellSortOrder } from './tableHeaderCell.enums';
|
|
8
|
+
|
|
9
|
+
export interface TableHeaderCellProps {
|
|
10
|
+
/**
|
|
11
|
+
* The column key.
|
|
12
|
+
*/
|
|
13
|
+
columnKey: string | number;
|
|
14
|
+
/**
|
|
15
|
+
* The label of the Header cell.
|
|
16
|
+
*/
|
|
17
|
+
label?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Action component to be rendered on the left side.
|
|
20
|
+
*/
|
|
21
|
+
actionLeft?: React.ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Action component to be rendered on the right side.
|
|
24
|
+
*/
|
|
25
|
+
actionRight?: React.ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* Has Sort icon.
|
|
28
|
+
*/
|
|
29
|
+
hasSort?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* On Sort icon click.
|
|
32
|
+
*/
|
|
33
|
+
onSortClick?: (columnKey: string | number, sortOrder: TableHeaderCellSortOrder) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Has Checkbox.
|
|
36
|
+
*/
|
|
37
|
+
hasCheckbox?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Is Checkbox checked.
|
|
40
|
+
*/
|
|
41
|
+
isChecked?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Is Checkbox indeterminate.
|
|
44
|
+
*/
|
|
45
|
+
isIndeterminate?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* On Checkbox change.
|
|
48
|
+
*/
|
|
49
|
+
onCheckboxChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the cell content should be centered.
|
|
52
|
+
*/
|
|
53
|
+
isContentCentered?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Sort order when cell is initialized
|
|
56
|
+
*/
|
|
57
|
+
sortOrder?: TableHeaderCellSortOrder;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function TableHeaderCell({
|
|
61
|
+
label,
|
|
62
|
+
columnKey,
|
|
63
|
+
hasSort,
|
|
64
|
+
hasCheckbox,
|
|
65
|
+
isChecked,
|
|
66
|
+
isIndeterminate,
|
|
67
|
+
isContentCentered,
|
|
68
|
+
onSortClick,
|
|
69
|
+
onCheckboxChange,
|
|
70
|
+
sortOrder,
|
|
71
|
+
}: TableHeaderCellProps): JSX.Element {
|
|
72
|
+
const handleSort = () => {
|
|
73
|
+
const newSortOrder =
|
|
74
|
+
sortOrder === TableHeaderCellSortOrder.Asc
|
|
75
|
+
? TableHeaderCellSortOrder.Desc
|
|
76
|
+
: TableHeaderCellSortOrder.Asc;
|
|
77
|
+
if (onSortClick) {
|
|
78
|
+
onSortClick(columnKey, newSortOrder);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const textColorClass = 'text-neutral-10 dark:text-neutral-92';
|
|
83
|
+
const textSizeClass = 'text-label-lg';
|
|
84
|
+
|
|
85
|
+
const sortElement = (() => {
|
|
86
|
+
if (!hasSort) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (sortOrder === TableHeaderCellSortOrder.Asc) {
|
|
91
|
+
return <SortByUp className="shrink-0" />;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (sortOrder === TableHeaderCellSortOrder.Desc) {
|
|
95
|
+
return <SortByDown className="shrink-0" />;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return <SortByUp className="invisible shrink-0 group-hover:visible" />;
|
|
99
|
+
})();
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<th
|
|
103
|
+
onClick={hasSort ? handleSort : undefined}
|
|
104
|
+
className={cx(
|
|
105
|
+
'state-layer group relative h-14 border-b border-shader-neutral-light-8 px-md after:pointer-events-none dark:border-shader-neutral-dark-8',
|
|
106
|
+
{
|
|
107
|
+
'cursor-pointer': hasSort,
|
|
108
|
+
},
|
|
109
|
+
)}
|
|
110
|
+
>
|
|
111
|
+
<div
|
|
112
|
+
className={cx(
|
|
113
|
+
'flex flex-row items-center gap-1 [&_svg]:h-4 [&_svg]:w-4',
|
|
114
|
+
textColorClass,
|
|
115
|
+
textSizeClass,
|
|
116
|
+
{
|
|
117
|
+
'justify-center': isContentCentered,
|
|
118
|
+
},
|
|
119
|
+
)}
|
|
120
|
+
>
|
|
121
|
+
{hasCheckbox ? (
|
|
122
|
+
<Checkbox
|
|
123
|
+
isChecked={isChecked}
|
|
124
|
+
isIndeterminate={isIndeterminate}
|
|
125
|
+
onCheckedChange={onCheckboxChange}
|
|
126
|
+
/>
|
|
127
|
+
) : (
|
|
128
|
+
<span
|
|
129
|
+
className={cx({
|
|
130
|
+
'text-left': !isContentCentered,
|
|
131
|
+
})}
|
|
132
|
+
>
|
|
133
|
+
{label}
|
|
134
|
+
</span>
|
|
135
|
+
)}
|
|
136
|
+
{sortElement}
|
|
137
|
+
</div>
|
|
138
|
+
</th>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { TooltipPosition } from '@/components/atoms';
|
|
5
|
+
import { Tooltip } from '@/components/atoms';
|
|
6
|
+
import { Info } from '@iota/apps-ui-icons';
|
|
7
|
+
import { TitleSize } from './titleSize.enums';
|
|
8
|
+
import cx from 'classnames';
|
|
9
|
+
import { TITLE_PADDINGS, TITLE_SIZE } from './titleClasses.constants';
|
|
10
|
+
|
|
11
|
+
interface TitleProps {
|
|
12
|
+
/**
|
|
13
|
+
* The title of the component.
|
|
14
|
+
*/
|
|
15
|
+
title: string;
|
|
16
|
+
/**
|
|
17
|
+
* The subtitle of the component.
|
|
18
|
+
*/
|
|
19
|
+
subtitle?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The trailing element.
|
|
22
|
+
*/
|
|
23
|
+
trailingElement?: React.ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* The tooltip position.
|
|
26
|
+
*/
|
|
27
|
+
tooltipPosition?: TooltipPosition;
|
|
28
|
+
/**
|
|
29
|
+
* The tooltip text.
|
|
30
|
+
*/
|
|
31
|
+
tooltipText?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Supporting Element
|
|
34
|
+
*/
|
|
35
|
+
supportingElement?: React.ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* The size of the component
|
|
38
|
+
*/
|
|
39
|
+
size?: TitleSize;
|
|
40
|
+
/**
|
|
41
|
+
* The 'data-testid' attribute value (used in e2e tests)
|
|
42
|
+
*/
|
|
43
|
+
testId?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function Title({
|
|
47
|
+
title,
|
|
48
|
+
subtitle,
|
|
49
|
+
trailingElement,
|
|
50
|
+
tooltipText,
|
|
51
|
+
supportingElement,
|
|
52
|
+
tooltipPosition,
|
|
53
|
+
size = TitleSize.Medium,
|
|
54
|
+
testId,
|
|
55
|
+
}: TitleProps) {
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
className={cx('flex flex-row items-center justify-between', TITLE_PADDINGS[size])}
|
|
59
|
+
data-testid={testId}
|
|
60
|
+
>
|
|
61
|
+
<div className="flex flex-row items-center gap-x-xxxs">
|
|
62
|
+
<div className="flex flex-col justify-start">
|
|
63
|
+
<div className="flex flex-row items-center gap-x-0.5 text-neutral-10 dark:text-neutral-92">
|
|
64
|
+
<h4 className={cx(TITLE_SIZE[size])}>{title}</h4>
|
|
65
|
+
{tooltipText && (
|
|
66
|
+
<Tooltip text={tooltipText} position={tooltipPosition}>
|
|
67
|
+
<Info />
|
|
68
|
+
</Tooltip>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
<p className="text-label-md text-neutral-60 dark:text-neutral-40">{subtitle}</p>
|
|
72
|
+
</div>
|
|
73
|
+
{supportingElement}
|
|
74
|
+
</div>
|
|
75
|
+
{trailingElement}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { TitleSize } from './titleSize.enums';
|
|
5
|
+
|
|
6
|
+
export const TITLE_PADDINGS: Record<TitleSize, string> = {
|
|
7
|
+
[TitleSize.Small]: 'px-md py-sm--rs',
|
|
8
|
+
[TitleSize.Medium]: 'px-md--rs py-sm--rs',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const TITLE_SIZE: Record<TitleSize, string> = {
|
|
12
|
+
[TitleSize.Small]: 'text-title-md',
|
|
13
|
+
[TitleSize.Medium]: 'text-title-lg',
|
|
14
|
+
};
|