@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,150 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { forwardRef, useEffect, useState } from 'react';
|
|
5
|
+
import type { InputWrapperProps } from './InputWrapper';
|
|
6
|
+
import { InputWrapper } from './InputWrapper';
|
|
7
|
+
import {
|
|
8
|
+
BORDER_CLASSES,
|
|
9
|
+
INPUT_CLASSES,
|
|
10
|
+
INPUT_TEXT_CLASSES,
|
|
11
|
+
INPUT_PLACEHOLDER_CLASSES,
|
|
12
|
+
} from './input.classes';
|
|
13
|
+
import cx from 'classnames';
|
|
14
|
+
import { ButtonUnstyled } from '@/components/atoms/button';
|
|
15
|
+
import { VisibilityOff, VisibilityOn } from '@iota/apps-ui-icons';
|
|
16
|
+
|
|
17
|
+
type TextAreaProps = Omit<
|
|
18
|
+
React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
|
19
|
+
'cols' | 'resize' | 'className'
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
interface TextFieldBaseProps extends TextAreaProps, InputWrapperProps {
|
|
23
|
+
/**
|
|
24
|
+
* Shows a label with the text above the input field.
|
|
25
|
+
*/
|
|
26
|
+
label?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Shows a caption with the text below the input field.
|
|
29
|
+
*/
|
|
30
|
+
caption?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Error Message. Overrides the caption.
|
|
33
|
+
*/
|
|
34
|
+
errorMessage?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Amount counter that is shown at the side of the caption text.
|
|
37
|
+
*/
|
|
38
|
+
amountCounter?: string | number;
|
|
39
|
+
/**
|
|
40
|
+
* Shows toggle button to show/hide the content of the input field
|
|
41
|
+
*/
|
|
42
|
+
isVisibilityToggleEnabled?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Is the content of the input visible
|
|
45
|
+
*/
|
|
46
|
+
isContentVisible?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* If true the textarea is resizable vertically
|
|
49
|
+
*/
|
|
50
|
+
isResizeEnabled?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const TextArea = forwardRef<HTMLTextAreaElement, TextFieldBaseProps>(function TextArea(
|
|
54
|
+
{
|
|
55
|
+
label,
|
|
56
|
+
caption,
|
|
57
|
+
disabled,
|
|
58
|
+
errorMessage,
|
|
59
|
+
value,
|
|
60
|
+
amountCounter,
|
|
61
|
+
isVisibilityToggleEnabled,
|
|
62
|
+
isResizeEnabled,
|
|
63
|
+
required,
|
|
64
|
+
isContentVisible,
|
|
65
|
+
...textareaProps
|
|
66
|
+
},
|
|
67
|
+
ref,
|
|
68
|
+
) {
|
|
69
|
+
const [isInputContentVisible, setIsInputContentVisible] = useState<boolean>(
|
|
70
|
+
isContentVisible ?? true,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
setIsInputContentVisible(isContentVisible ?? true);
|
|
75
|
+
}, [isContentVisible]);
|
|
76
|
+
|
|
77
|
+
function onToggleButtonClick() {
|
|
78
|
+
setIsInputContentVisible((prev) => !prev);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<InputWrapper
|
|
83
|
+
label={label}
|
|
84
|
+
caption={caption}
|
|
85
|
+
disabled={disabled || !isInputContentVisible}
|
|
86
|
+
errorMessage={errorMessage}
|
|
87
|
+
amountCounter={amountCounter}
|
|
88
|
+
required={required}
|
|
89
|
+
>
|
|
90
|
+
<div className="relative">
|
|
91
|
+
<textarea
|
|
92
|
+
disabled={disabled || !isInputContentVisible}
|
|
93
|
+
required={required}
|
|
94
|
+
ref={ref}
|
|
95
|
+
className={cx(
|
|
96
|
+
'peer block min-h-[50px]',
|
|
97
|
+
BORDER_CLASSES,
|
|
98
|
+
INPUT_CLASSES,
|
|
99
|
+
INPUT_TEXT_CLASSES,
|
|
100
|
+
INPUT_PLACEHOLDER_CLASSES,
|
|
101
|
+
isInputContentVisible && isResizeEnabled ? 'resize-y' : 'resize-none',
|
|
102
|
+
!isInputContentVisible &&
|
|
103
|
+
'not-visible select-none text-transparent dark:text-transparent',
|
|
104
|
+
)}
|
|
105
|
+
value={isInputContentVisible ? value : ''}
|
|
106
|
+
{...textareaProps}
|
|
107
|
+
/>
|
|
108
|
+
{!isInputContentVisible && (
|
|
109
|
+
<div className="absolute left-0 top-0 flex h-full w-full flex-col items-stretch gap-y-2 px-md py-sm peer-[.not-visible]:select-none">
|
|
110
|
+
<VisibilityOffBar rows={3} halfWidthRow={3} />
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
{isVisibilityToggleEnabled && (
|
|
115
|
+
<span className="absolute bottom-4 right-4 flex">
|
|
116
|
+
<ButtonUnstyled
|
|
117
|
+
onClick={onToggleButtonClick}
|
|
118
|
+
className="text-neutral-10 dark:text-neutral-92 [&_svg]:h-5 [&_svg]:w-5"
|
|
119
|
+
tabIndex={-1}
|
|
120
|
+
>
|
|
121
|
+
{isInputContentVisible ? <VisibilityOn /> : <VisibilityOff />}
|
|
122
|
+
</ButtonUnstyled>
|
|
123
|
+
</span>
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
</InputWrapper>
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
interface VisibilityOffBarProps {
|
|
131
|
+
rows: number;
|
|
132
|
+
halfWidthRow?: number;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function VisibilityOffBar({ rows, halfWidthRow }: VisibilityOffBarProps) {
|
|
136
|
+
return (
|
|
137
|
+
<>
|
|
138
|
+
{Array.from({ length: rows }).map((_, index) => {
|
|
139
|
+
const isHalfWidth = halfWidthRow === index + 1;
|
|
140
|
+
const width = isHalfWidth ? 'w-1/2' : 'w-full';
|
|
141
|
+
return (
|
|
142
|
+
<div
|
|
143
|
+
key={index}
|
|
144
|
+
className={`h-2.5 rounded bg-neutral-92/60 dark:bg-neutral-10/60 ${width}`}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
})}
|
|
148
|
+
</>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export const INPUT_CLASSES =
|
|
5
|
+
'w-full bg-transparent text-body-lg caret-primary-30 dark:caret-primary-80 focus:outline-none focus-visible:outline-none disabled:cursor-not-allowed';
|
|
6
|
+
export const INPUT_TEXT_CLASSES = 'text-neutral-10 dark:text-neutral-92';
|
|
7
|
+
export const INPUT_PLACEHOLDER_CLASSES =
|
|
8
|
+
'enabled:placeholder:text-neutral-40/40 dark:placeholder:text-neutral-60/40 enabled:dark:placeholder:text-neutral-60/40';
|
|
9
|
+
export const BORDER_CLASSES =
|
|
10
|
+
'px-md py-sm rounded-lg border border-neutral-80 group-[.enabled]:cursor-text group-[.errored]:border-error-30 hover:group-[.enabled]:border-neutral-50 dark:border-neutral-20 dark:hover:border-neutral-60 dark:group-[.errored]:border-error-80 [&:has(input:focus)]:!border-primary-30 [&:has(input:focus)]:dark:!border-primary-80';
|
|
11
|
+
export const INPUT_NUMBER_CLASSES =
|
|
12
|
+
'[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none disabled:cursor-not-allowed';
|
|
13
|
+
export const LABEL_CLASSES =
|
|
14
|
+
'flex flex-col gap-y-2 text-label-lg text-neutral-40 dark:text-neutral-60';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export enum InputType {
|
|
5
|
+
Text = 'text',
|
|
6
|
+
Password = 'password',
|
|
7
|
+
Number = 'number',
|
|
8
|
+
NumericFormat = 'numericFormat',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export enum Resize {
|
|
12
|
+
None = 'none',
|
|
13
|
+
Vertical = 'vertical',
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { ComponentProps } from 'react';
|
|
5
|
+
import type { InputType } from '.';
|
|
6
|
+
import type { NumericFormat } from 'react-number-format';
|
|
7
|
+
|
|
8
|
+
type InputElementProps = Omit<
|
|
9
|
+
React.ComponentProps<'input'>,
|
|
10
|
+
'type' | 'className' | 'ref' | 'value' | 'defaultValue'
|
|
11
|
+
>;
|
|
12
|
+
|
|
13
|
+
type GenericInputProps = {
|
|
14
|
+
type: InputType.Text | InputType.Password | InputType.Number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type NumericFormatProps = ComponentProps<typeof NumericFormat>;
|
|
18
|
+
|
|
19
|
+
export type NumericFormatInputProps = {
|
|
20
|
+
type: InputType.NumericFormat;
|
|
21
|
+
suffix?: NumericFormatProps['suffix'];
|
|
22
|
+
prefix?: NumericFormatProps['prefix'];
|
|
23
|
+
decimalScale?: NumericFormatProps['decimalScale'];
|
|
24
|
+
allowNegative?: NumericFormatProps['allowNegative'];
|
|
25
|
+
thousandSeparator?: NumericFormatProps['thousandSeparator'];
|
|
26
|
+
onValueChange?: NumericFormatProps['onValueChange'];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type InputPropsByType = InputElementProps & (NumericFormatInputProps | GenericInputProps);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { NavbarItemHorizontal } from './NavbarItemHorizontal';
|
|
5
|
+
import { NavbarItemVertical } from './NavbarItemVertical';
|
|
6
|
+
import { NavbarItemType } from './navbarItem.enums';
|
|
7
|
+
|
|
8
|
+
export interface NavbarItemProps {
|
|
9
|
+
/**
|
|
10
|
+
* The type of the navbar item.
|
|
11
|
+
*/
|
|
12
|
+
type?: NavbarItemType;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The icon of the navbar item.
|
|
16
|
+
*/
|
|
17
|
+
icon: React.ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* The text of the navbar item.
|
|
20
|
+
*/
|
|
21
|
+
text?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Indicates if the navbar item is selected.
|
|
24
|
+
*/
|
|
25
|
+
isSelected?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Indicates if the navbar item has a badge.
|
|
28
|
+
*/
|
|
29
|
+
hasBadge?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The onClick event of the navbar item.
|
|
32
|
+
*/
|
|
33
|
+
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Indicates if the navbar item is disabled.
|
|
36
|
+
*/
|
|
37
|
+
isDisabled?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function NavbarItem(props: NavbarItemProps): React.JSX.Element {
|
|
41
|
+
const { type, text } = props;
|
|
42
|
+
|
|
43
|
+
if (type === NavbarItemType.Vertical && !!text) {
|
|
44
|
+
return <NavbarItemVertical {...props} />;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return <NavbarItemHorizontal {...props} />;
|
|
48
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import cx from 'classnames';
|
|
5
|
+
import {
|
|
6
|
+
BADGE_WITH_TEXT,
|
|
7
|
+
BADGE_WITHOUT_TEXT,
|
|
8
|
+
PADDING_WITH_TEXT,
|
|
9
|
+
PADDING_WITHOUT_TEXT,
|
|
10
|
+
SELECTED_BACKGROUND,
|
|
11
|
+
SELECTED_ICON,
|
|
12
|
+
SELECTED_TEXT,
|
|
13
|
+
UNSELECTED_ICON,
|
|
14
|
+
UNSELECTED_TEXT,
|
|
15
|
+
} from './navbarItem.classes';
|
|
16
|
+
import { Badge, BadgeType } from '@/components/atoms';
|
|
17
|
+
import type { NavbarItemProps } from './NavbarItem';
|
|
18
|
+
|
|
19
|
+
export function NavbarItemHorizontal({
|
|
20
|
+
icon,
|
|
21
|
+
text,
|
|
22
|
+
isSelected,
|
|
23
|
+
hasBadge,
|
|
24
|
+
onClick,
|
|
25
|
+
isDisabled = false,
|
|
26
|
+
}: Omit<NavbarItemProps, 'type'>): React.JSX.Element {
|
|
27
|
+
const fillClasses = isSelected ? SELECTED_ICON : UNSELECTED_ICON;
|
|
28
|
+
const paddingClasses = text ? PADDING_WITH_TEXT : PADDING_WITHOUT_TEXT;
|
|
29
|
+
const backgroundColors = isSelected && SELECTED_BACKGROUND;
|
|
30
|
+
const badgePositionClasses = text ? BADGE_WITH_TEXT : BADGE_WITHOUT_TEXT;
|
|
31
|
+
const textClasses = isSelected ? SELECTED_TEXT : UNSELECTED_TEXT;
|
|
32
|
+
const disabledClasses = isDisabled ? 'cursor-not-allowed opacity-60' : 'state-layer';
|
|
33
|
+
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
34
|
+
if (isDisabled) {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
onClick?.(e);
|
|
39
|
+
};
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
onClick={handleClick}
|
|
43
|
+
className={cx(
|
|
44
|
+
'inline-flex cursor-pointer flex-col items-center justify-center space-y-1',
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
<div
|
|
48
|
+
className={cx(
|
|
49
|
+
'relative inline-flex rounded-full',
|
|
50
|
+
paddingClasses,
|
|
51
|
+
backgroundColors,
|
|
52
|
+
disabledClasses,
|
|
53
|
+
)}
|
|
54
|
+
>
|
|
55
|
+
<div className={cx('inline-flex [&_svg]:h-6 [&_svg]:w-6', fillClasses)}>{icon}</div>
|
|
56
|
+
{hasBadge && (
|
|
57
|
+
<div className={cx('absolute', badgePositionClasses)}>
|
|
58
|
+
<Badge type={BadgeType.PrimarySolid} />
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
{text && <span className={cx('text-center text-label-md', textClasses)}>{text}</span>}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import cx from 'classnames';
|
|
5
|
+
import {
|
|
6
|
+
SELECTED_BACKGROUND,
|
|
7
|
+
SELECTED_ICON,
|
|
8
|
+
SELECTED_TEXT,
|
|
9
|
+
UNSELECTED_ICON,
|
|
10
|
+
UNSELECTED_TEXT,
|
|
11
|
+
} from './navbarItem.classes';
|
|
12
|
+
import { Badge, BadgeType } from '@/components/atoms';
|
|
13
|
+
import type { NavbarItemProps } from './NavbarItem';
|
|
14
|
+
|
|
15
|
+
export function NavbarItemVertical({
|
|
16
|
+
icon,
|
|
17
|
+
text,
|
|
18
|
+
isSelected,
|
|
19
|
+
hasBadge,
|
|
20
|
+
onClick,
|
|
21
|
+
isDisabled = false,
|
|
22
|
+
}: Omit<NavbarItemProps, 'type'>): React.JSX.Element {
|
|
23
|
+
const fillClasses = isSelected ? SELECTED_ICON : UNSELECTED_ICON;
|
|
24
|
+
const backgroundColors = isSelected && SELECTED_BACKGROUND;
|
|
25
|
+
const textClasses = isSelected ? SELECTED_TEXT : UNSELECTED_TEXT;
|
|
26
|
+
const disabledClasses = isDisabled
|
|
27
|
+
? 'cursor-not-allowed opacity-60'
|
|
28
|
+
: 'state-layer cursor-pointer ';
|
|
29
|
+
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
30
|
+
if (isDisabled) {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
onClick?.(e);
|
|
35
|
+
};
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
onClick={handleClick}
|
|
39
|
+
className={cx(
|
|
40
|
+
'relative inline-flex w-full flex-row items-center justify-between rounded-full p-sm',
|
|
41
|
+
backgroundColors,
|
|
42
|
+
disabledClasses,
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
<div className="flex items-center gap-3">
|
|
46
|
+
<div className={cx('inline-flex [&_svg]:h-6 [&_svg]:w-6', fillClasses)}>{icon}</div>
|
|
47
|
+
{text && (
|
|
48
|
+
<span className={cx('text-center text-label-lg', textClasses)}>{text}</span>
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
{hasBadge && <Badge type={BadgeType.PrimarySolid} />}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export const SELECTED_ICON = 'text-neutral-10 dark:text-neutral-92';
|
|
5
|
+
export const UNSELECTED_ICON = 'text-neutral-40 dark:text-neutral-60';
|
|
6
|
+
|
|
7
|
+
export const PADDING_WITH_TEXT = 'py-xxs px-sm';
|
|
8
|
+
export const PADDING_WITHOUT_TEXT = 'p-sm';
|
|
9
|
+
|
|
10
|
+
export const SELECTED_BACKGROUND = 'bg-shader-primary-light-12 dark:bg-shader-primary-dark-12';
|
|
11
|
+
|
|
12
|
+
export const BADGE_WITH_TEXT = '-top-3 right-3';
|
|
13
|
+
export const BADGE_WITHOUT_TEXT = '-top-1 right-3';
|
|
14
|
+
|
|
15
|
+
export const SELECTED_TEXT = 'text-neutral-10 dark:text-neutral-92';
|
|
16
|
+
export const UNSELECTED_TEXT = 'text-neutral-60 dark:text-neutral-40';
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import cx from 'classnames';
|
|
6
|
+
import { Loader, Search as SearchIcon } from '@iota/apps-ui-icons';
|
|
7
|
+
import { Divider } from '@/components/atoms';
|
|
8
|
+
import { SearchBarType } from './search.enums';
|
|
9
|
+
import {
|
|
10
|
+
BACKGROUND_COLORS,
|
|
11
|
+
SUGGESTIONS_WRAPPER_STYLE,
|
|
12
|
+
SEARCH_WRAPPER_STYLE,
|
|
13
|
+
} from './search.classes';
|
|
14
|
+
|
|
15
|
+
export interface Suggestion {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
supportingText?: string;
|
|
19
|
+
type?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SearchProps {
|
|
23
|
+
/**
|
|
24
|
+
* The value of the search input.
|
|
25
|
+
*/
|
|
26
|
+
searchValue: string;
|
|
27
|
+
/**
|
|
28
|
+
* Callback when the search input value changes.
|
|
29
|
+
*/
|
|
30
|
+
onSearchValueChange: (value: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* List of suggestions to display (optional).
|
|
33
|
+
*/
|
|
34
|
+
suggestions?: Suggestion[];
|
|
35
|
+
/**
|
|
36
|
+
* Callback when a suggestion is clicked.
|
|
37
|
+
*/
|
|
38
|
+
onSuggestionClick?: (suggestion: Suggestion) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Placeholder text for the search input.
|
|
41
|
+
*/
|
|
42
|
+
placeholder: string;
|
|
43
|
+
/**
|
|
44
|
+
* Are the suggestions loading.
|
|
45
|
+
*/
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The type of the search bar. Can be 'outlined' or 'filled'.
|
|
49
|
+
*/
|
|
50
|
+
type?: SearchBarType;
|
|
51
|
+
/**
|
|
52
|
+
* Render suggestion.
|
|
53
|
+
*/
|
|
54
|
+
renderSuggestion?: (suggestion: Suggestion, index: number) => React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function Search({
|
|
58
|
+
searchValue,
|
|
59
|
+
suggestions,
|
|
60
|
+
onSearchValueChange,
|
|
61
|
+
onSuggestionClick,
|
|
62
|
+
placeholder,
|
|
63
|
+
isLoading = false,
|
|
64
|
+
type = SearchBarType.Outlined,
|
|
65
|
+
renderSuggestion,
|
|
66
|
+
}: SearchProps): React.JSX.Element {
|
|
67
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
68
|
+
const suggestionsListRef = useRef<HTMLDivElement>(null);
|
|
69
|
+
const [isSuggestionsVisible, setIsSuggestionsVisible] = useState(true);
|
|
70
|
+
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
|
|
71
|
+
|
|
72
|
+
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
|
|
73
|
+
const value = event.target.value;
|
|
74
|
+
onSearchValueChange(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Hide suggestions on escape key press
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const handler = (e: KeyboardEvent) => {
|
|
80
|
+
if (e.key === 'Escape') {
|
|
81
|
+
setIsSuggestionsVisible(false);
|
|
82
|
+
inputRef.current?.blur();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
document.addEventListener('keydown', handler);
|
|
87
|
+
|
|
88
|
+
return () => {
|
|
89
|
+
document.removeEventListener('keydown', handler);
|
|
90
|
+
};
|
|
91
|
+
}, []);
|
|
92
|
+
|
|
93
|
+
// Hide suggestions on click outside
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
const listener = (event: MouseEvent | TouchEvent) => {
|
|
96
|
+
const el = inputRef?.current;
|
|
97
|
+
if (!el || el.contains(event?.target as Node)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (suggestionsListRef.current?.contains(event.target as Node)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
setIsSuggestionsVisible(false);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
document.addEventListener('click', listener, true);
|
|
108
|
+
document.addEventListener('touchstart', listener, true);
|
|
109
|
+
|
|
110
|
+
return () => {
|
|
111
|
+
document.removeEventListener('click', listener, true);
|
|
112
|
+
document.removeEventListener('touchstart', listener, true);
|
|
113
|
+
};
|
|
114
|
+
}, [inputRef]);
|
|
115
|
+
|
|
116
|
+
const showSuggestions = isSuggestionsVisible && suggestions && suggestions.length > 0;
|
|
117
|
+
|
|
118
|
+
const roundedStyleWithSuggestions = showSuggestions
|
|
119
|
+
? 'rounded-t-3xl border-b border-b-transparent'
|
|
120
|
+
: type === SearchBarType.Outlined
|
|
121
|
+
? 'rounded-3xl border-b'
|
|
122
|
+
: 'rounded-full';
|
|
123
|
+
const searchTypeClass = SEARCH_WRAPPER_STYLE[type];
|
|
124
|
+
const backgroundColorClass = BACKGROUND_COLORS[type];
|
|
125
|
+
const suggestionsStyle = SUGGESTIONS_WRAPPER_STYLE[type];
|
|
126
|
+
|
|
127
|
+
const handleOnSuggestionClick = (suggestion: Suggestion) => {
|
|
128
|
+
onSuggestionClick?.(suggestion);
|
|
129
|
+
onSearchValueChange('');
|
|
130
|
+
setIsSuggestionsVisible(false);
|
|
131
|
+
setSelectedIndex(null);
|
|
132
|
+
inputRef.current?.blur();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
136
|
+
if (suggestions && suggestions?.length > 0) {
|
|
137
|
+
if (event.key === 'ArrowDown') {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
setSelectedIndex((prev) =>
|
|
140
|
+
prev === null || prev >= suggestions.length - 1 ? 0 : prev + 1,
|
|
141
|
+
);
|
|
142
|
+
} else if (event.key === 'ArrowUp') {
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
setSelectedIndex((prev) =>
|
|
145
|
+
prev === null || prev <= 0 ? suggestions.length - 1 : prev - 1,
|
|
146
|
+
);
|
|
147
|
+
} else if (event.key === 'Enter') {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
if (selectedIndex !== null && suggestions[selectedIndex]) {
|
|
150
|
+
handleOnSuggestionClick(suggestions[selectedIndex]);
|
|
151
|
+
} else if (suggestions.length === 1) {
|
|
152
|
+
handleOnSuggestionClick(suggestions[0]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<div className="relative w-full">
|
|
160
|
+
<div
|
|
161
|
+
className={cx(
|
|
162
|
+
'flex items-center overflow-hidden px-md py-sm text-neutral-10 dark:text-neutral-92 [&_svg]:h-6 [&_svg]:w-6',
|
|
163
|
+
roundedStyleWithSuggestions,
|
|
164
|
+
searchTypeClass,
|
|
165
|
+
)}
|
|
166
|
+
>
|
|
167
|
+
<input
|
|
168
|
+
ref={inputRef}
|
|
169
|
+
type="text"
|
|
170
|
+
value={searchValue}
|
|
171
|
+
onChange={handleChange}
|
|
172
|
+
onKeyDown={handleKeyDown}
|
|
173
|
+
onFocus={() => setIsSuggestionsVisible(true)}
|
|
174
|
+
placeholder={placeholder}
|
|
175
|
+
className={cx(
|
|
176
|
+
'w-full flex-1 outline-none placeholder:text-neutral-40 placeholder:dark:text-neutral-60',
|
|
177
|
+
backgroundColorClass,
|
|
178
|
+
)}
|
|
179
|
+
/>
|
|
180
|
+
<SearchIcon />
|
|
181
|
+
</div>
|
|
182
|
+
{showSuggestions && renderSuggestion && (
|
|
183
|
+
<div
|
|
184
|
+
ref={suggestionsListRef}
|
|
185
|
+
className={cx(
|
|
186
|
+
'absolute left-0 top-full flex w-full flex-col items-center overflow-hidden bg-neutral-100 dark:bg-neutral-10',
|
|
187
|
+
suggestionsStyle,
|
|
188
|
+
)}
|
|
189
|
+
>
|
|
190
|
+
<Divider width="w-11/12" />
|
|
191
|
+
{isLoading ? (
|
|
192
|
+
<div className="px-md py-sm">
|
|
193
|
+
<Loader className="animate-spin" />
|
|
194
|
+
</div>
|
|
195
|
+
) : (
|
|
196
|
+
suggestions.map((suggestion, index) => (
|
|
197
|
+
<div
|
|
198
|
+
key={suggestion.id}
|
|
199
|
+
onClick={() => handleOnSuggestionClick(suggestion)}
|
|
200
|
+
onMouseEnter={() => setSelectedIndex(index)}
|
|
201
|
+
className={cx(
|
|
202
|
+
'w-full cursor-pointer px-md py-sm',
|
|
203
|
+
selectedIndex === index
|
|
204
|
+
? 'bg-shader-primary-dark-16 dark:bg-shader-inverted-dark-16'
|
|
205
|
+
: '',
|
|
206
|
+
)}
|
|
207
|
+
>
|
|
208
|
+
{renderSuggestion(suggestion, index)}
|
|
209
|
+
</div>
|
|
210
|
+
))
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright (c) 2024 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { SearchBarType } from './search.enums';
|
|
5
|
+
|
|
6
|
+
export const BACKGROUND_COLORS: Record<SearchBarType, string> = {
|
|
7
|
+
[SearchBarType.Outlined]: 'bg-transparent',
|
|
8
|
+
[SearchBarType.Filled]: 'bg-neutral-92 dark:bg-neutral-12',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const SEARCH_WRAPPER_STYLE: Record<SearchBarType, string> = {
|
|
12
|
+
[SearchBarType.Outlined]: 'border-l border-r border-t border-neutral-70 dark:border-neutral-40',
|
|
13
|
+
[SearchBarType.Filled]: 'bg-neutral-92 dark:bg-neutral-12',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const SUGGESTIONS_WRAPPER_STYLE: Record<SearchBarType, string> = {
|
|
17
|
+
[SearchBarType.Outlined]:
|
|
18
|
+
'rounded-b-3xl border-b border-l border-r border-neutral-70 dark:border-neutral-40',
|
|
19
|
+
[SearchBarType.Filled]: 'rounded-b-3xl bg-neutral-92 dark:bg-neutral-12',
|
|
20
|
+
};
|