@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.
Files changed (220) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/LICENSE +201 -0
  3. package/README.md +16 -0
  4. package/dist/index.d.ts +1726 -0
  5. package/dist/index.es.js +6923 -0
  6. package/dist/index.es.js.map +1 -0
  7. package/dist/index.umd.js +118 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/dist/style.css +1 -0
  10. package/package.json +75 -0
  11. package/src/lib/components/atoms/badge/Badge.tsx +37 -0
  12. package/src/lib/components/atoms/badge/badge.classes.ts +33 -0
  13. package/src/lib/components/atoms/badge/badge.enums.ts +11 -0
  14. package/src/lib/components/atoms/badge/index.ts +6 -0
  15. package/src/lib/components/atoms/button/Button.tsx +99 -0
  16. package/src/lib/components/atoms/button/button-variants/ButtonPill.tsx +23 -0
  17. package/src/lib/components/atoms/button/button-variants/ButtonUnstyled.tsx +27 -0
  18. package/src/lib/components/atoms/button/button-variants/buttonVariants.types.ts +11 -0
  19. package/src/lib/components/atoms/button/button-variants/index.ts +5 -0
  20. package/src/lib/components/atoms/button/button.classes.ts +53 -0
  21. package/src/lib/components/atoms/button/button.enums.ts +21 -0
  22. package/src/lib/components/atoms/button/index.ts +7 -0
  23. package/src/lib/components/atoms/button-segment/ButtonSegment.tsx +98 -0
  24. package/src/lib/components/atoms/button-segment/buttonSegment.classes.ts +45 -0
  25. package/src/lib/components/atoms/button-segment/buttonSegment.enums.ts +7 -0
  26. package/src/lib/components/atoms/button-segment/index.ts +5 -0
  27. package/src/lib/components/atoms/checkbox/Checkbox.tsx +114 -0
  28. package/src/lib/components/atoms/checkbox/index.ts +4 -0
  29. package/src/lib/components/atoms/divider/Divider.tsx +48 -0
  30. package/src/lib/components/atoms/divider/divider.classes.ts +11 -0
  31. package/src/lib/components/atoms/divider/divider.enums.ts +7 -0
  32. package/src/lib/components/atoms/divider/index.ts +6 -0
  33. package/src/lib/components/atoms/header/Header.tsx +73 -0
  34. package/src/lib/components/atoms/header/index.ts +4 -0
  35. package/src/lib/components/atoms/index.ts +23 -0
  36. package/src/lib/components/atoms/info-box/InfoBox.tsx +74 -0
  37. package/src/lib/components/atoms/info-box/index.ts +5 -0
  38. package/src/lib/components/atoms/info-box/infoBox.classes.ts +19 -0
  39. package/src/lib/components/atoms/info-box/infoBox.enums.ts +14 -0
  40. package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +157 -0
  41. package/src/lib/components/atoms/key-value-info/index.ts +6 -0
  42. package/src/lib/components/atoms/key-value-info/keyValue.enums.ts +7 -0
  43. package/src/lib/components/atoms/label-text/LabelText.tsx +94 -0
  44. package/src/lib/components/atoms/label-text/index.ts +5 -0
  45. package/src/lib/components/atoms/label-text/labelText.classes.ts +22 -0
  46. package/src/lib/components/atoms/label-text/labelText.enums.ts +8 -0
  47. package/src/lib/components/atoms/list-item/ListItem.tsx +89 -0
  48. package/src/lib/components/atoms/list-item/index.ts +4 -0
  49. package/src/lib/components/atoms/loading-indicator/LoadingIndicator.tsx +38 -0
  50. package/src/lib/components/atoms/loading-indicator/index.ts +4 -0
  51. package/src/lib/components/atoms/panel/Panel.tsx +30 -0
  52. package/src/lib/components/atoms/panel/index.ts +4 -0
  53. package/src/lib/components/atoms/placeholder/Placeholder.tsx +27 -0
  54. package/src/lib/components/atoms/placeholder/index.ts +4 -0
  55. package/src/lib/components/atoms/radio-button/RadioButton.tsx +68 -0
  56. package/src/lib/components/atoms/radio-button/index.ts +4 -0
  57. package/src/lib/components/atoms/secondary-text/SecondaryText.tsx +28 -0
  58. package/src/lib/components/atoms/secondary-text/index.ts +4 -0
  59. package/src/lib/components/atoms/skeleton/Skeleton.tsx +47 -0
  60. package/src/lib/components/atoms/skeleton/index.ts +4 -0
  61. package/src/lib/components/atoms/snackbar/Snackbar.tsx +69 -0
  62. package/src/lib/components/atoms/snackbar/index.ts +5 -0
  63. package/src/lib/components/atoms/snackbar/snackbar.classes.ts +18 -0
  64. package/src/lib/components/atoms/snackbar/snackbar.enums.tsx +9 -0
  65. package/src/lib/components/atoms/toggle/Toggle.tsx +140 -0
  66. package/src/lib/components/atoms/toggle/index.ts +6 -0
  67. package/src/lib/components/atoms/toggle/toggle.classes.ts +41 -0
  68. package/src/lib/components/atoms/toggle/toggle.enums.ts +12 -0
  69. package/src/lib/components/atoms/tooltip/Tooltip.tsx +138 -0
  70. package/src/lib/components/atoms/tooltip/index.ts +5 -0
  71. package/src/lib/components/atoms/tooltip/tooltip.classes.ts +11 -0
  72. package/src/lib/components/atoms/tooltip/tooltip.enums.ts +9 -0
  73. package/src/lib/components/atoms/visual-asset-card/VisualAssetCard.tsx +101 -0
  74. package/src/lib/components/atoms/visual-asset-card/index.ts +5 -0
  75. package/src/lib/components/atoms/visual-asset-card/visualAssetCard.enums.ts +7 -0
  76. package/src/lib/components/index.ts +8 -0
  77. package/src/lib/components/molecules/account/Account.tsx +192 -0
  78. package/src/lib/components/molecules/account/index.ts +4 -0
  79. package/src/lib/components/molecules/address/Address.tsx +101 -0
  80. package/src/lib/components/molecules/address/index.ts +4 -0
  81. package/src/lib/components/molecules/card/Card.tsx +70 -0
  82. package/src/lib/components/molecules/card/CardAction.tsx +80 -0
  83. package/src/lib/components/molecules/card/CardBody.tsx +72 -0
  84. package/src/lib/components/molecules/card/CardImage.tsx +43 -0
  85. package/src/lib/components/molecules/card/CardImagePlaceholder.tsx +146 -0
  86. package/src/lib/components/molecules/card/card.classes.ts +27 -0
  87. package/src/lib/components/molecules/card/card.enums.ts +26 -0
  88. package/src/lib/components/molecules/card/index.ts +8 -0
  89. package/src/lib/components/molecules/chip/Chip.tsx +105 -0
  90. package/src/lib/components/molecules/chip/chip.classes.ts +32 -0
  91. package/src/lib/components/molecules/chip/chip.enums.ts +7 -0
  92. package/src/lib/components/molecules/chip/index.ts +4 -0
  93. package/src/lib/components/molecules/display-stats/DisplayStats.tsx +142 -0
  94. package/src/lib/components/molecules/display-stats/displayStats.classes.ts +36 -0
  95. package/src/lib/components/molecules/display-stats/displayStats.enums.ts +13 -0
  96. package/src/lib/components/molecules/display-stats/index.ts +5 -0
  97. package/src/lib/components/molecules/dropdown/Dropdown.tsx +10 -0
  98. package/src/lib/components/molecules/dropdown/dropdownPosition.enums.ts +7 -0
  99. package/src/lib/components/molecules/dropdown/index.ts +5 -0
  100. package/src/lib/components/molecules/index.ts +17 -0
  101. package/src/lib/components/molecules/input/Input.tsx +246 -0
  102. package/src/lib/components/molecules/input/InputWrapper.tsx +97 -0
  103. package/src/lib/components/molecules/input/TextArea.tsx +150 -0
  104. package/src/lib/components/molecules/input/index.ts +8 -0
  105. package/src/lib/components/molecules/input/input.classes.ts +14 -0
  106. package/src/lib/components/molecules/input/input.enums.ts +14 -0
  107. package/src/lib/components/molecules/input/input.types.ts +29 -0
  108. package/src/lib/components/molecules/navbar-item/NavbarItem.tsx +48 -0
  109. package/src/lib/components/molecules/navbar-item/NavbarItemHorizontal.tsx +65 -0
  110. package/src/lib/components/molecules/navbar-item/NavbarItemVertical.tsx +54 -0
  111. package/src/lib/components/molecules/navbar-item/index.ts +5 -0
  112. package/src/lib/components/molecules/navbar-item/navbarItem.classes.ts +16 -0
  113. package/src/lib/components/molecules/navbar-item/navbarItem.enums.ts +7 -0
  114. package/src/lib/components/molecules/search/Search.tsx +216 -0
  115. package/src/lib/components/molecules/search/index.ts +5 -0
  116. package/src/lib/components/molecules/search/search.classes.ts +20 -0
  117. package/src/lib/components/molecules/search/search.enums.ts +7 -0
  118. package/src/lib/components/molecules/segmented-button/SegmentedButton.tsx +38 -0
  119. package/src/lib/components/molecules/segmented-button/index.ts +6 -0
  120. package/src/lib/components/molecules/segmented-button/segmentedButton.classes.ts +12 -0
  121. package/src/lib/components/molecules/segmented-button/segmentedButton.enums.ts +8 -0
  122. package/src/lib/components/molecules/select/Select.tsx +222 -0
  123. package/src/lib/components/molecules/select/index.ts +5 -0
  124. package/src/lib/components/molecules/select/select.enums.ts +7 -0
  125. package/src/lib/components/molecules/table-cell/TableCell.tsx +62 -0
  126. package/src/lib/components/molecules/table-cell/index.ts +4 -0
  127. package/src/lib/components/molecules/table-header-cell/TableHeaderCell.tsx +140 -0
  128. package/src/lib/components/molecules/table-header-cell/index.ts +5 -0
  129. package/src/lib/components/molecules/table-header-cell/tableHeaderCell.enums.ts +7 -0
  130. package/src/lib/components/molecules/title/Title.tsx +78 -0
  131. package/src/lib/components/molecules/title/index.ts +5 -0
  132. package/src/lib/components/molecules/title/titleClasses.constants.ts +14 -0
  133. package/src/lib/components/molecules/title/titleSize.enums.ts +7 -0
  134. package/src/lib/components/organisms/accordion/Accordion.tsx +109 -0
  135. package/src/lib/components/organisms/accordion/accordion.classes.ts +4 -0
  136. package/src/lib/components/organisms/accordion/index.ts +4 -0
  137. package/src/lib/components/organisms/dialog/Dialog.tsx +142 -0
  138. package/src/lib/components/organisms/dialog/dialog.enums.ts +7 -0
  139. package/src/lib/components/organisms/dialog/index.ts +5 -0
  140. package/src/lib/components/organisms/index.ts +7 -0
  141. package/src/lib/components/organisms/navbar/Navbar.tsx +101 -0
  142. package/src/lib/components/organisms/navbar/NavbarSlideout.tsx +59 -0
  143. package/src/lib/components/organisms/navbar/index.ts +5 -0
  144. package/src/lib/components/organisms/table/Table.tsx +234 -0
  145. package/src/lib/components/organisms/table/TableContext.tsx +56 -0
  146. package/src/lib/components/organisms/table/index.ts +4 -0
  147. package/src/lib/constants/colors.constants.ts +133 -0
  148. package/src/lib/constants/index.ts +4 -0
  149. package/src/lib/enums/index.ts +4 -0
  150. package/src/lib/enums/screenSize.enums.ts +9 -0
  151. package/src/lib/index.ts +8 -0
  152. package/src/lib/styles/fonts.css +5 -0
  153. package/src/lib/styles/index.css +149 -0
  154. package/src/lib/tailwind/base.presets.ts +49 -0
  155. package/src/lib/tailwind/constants/fontSizes.constants.ts +201 -0
  156. package/src/lib/tailwind/constants/index.ts +6 -0
  157. package/src/lib/tailwind/constants/scaling.constants.ts +41 -0
  158. package/src/lib/tailwind/constants/variableSpacing.constants.ts +66 -0
  159. package/src/lib/tailwind/helpers.ts +20 -0
  160. package/src/lib/tailwind/index.ts +5 -0
  161. package/src/lib/tailwind/plugins.ts +8 -0
  162. package/src/lib/tailwind/responsive.presets.ts +36 -0
  163. package/src/lib/tailwind/static.presets.ts +25 -0
  164. package/src/lib/tailwind/types.ts +6 -0
  165. package/src/lib/utils/format.ts +8 -0
  166. package/src/lib/utils/index.ts +4 -0
  167. package/src/storybook/blocks/Showcase.tsx +20 -0
  168. package/src/storybook/blocks/TypeSet.tsx +34 -0
  169. package/src/storybook/blocks/TypeSetItem.tsx +74 -0
  170. package/src/storybook/blocks/index.ts +6 -0
  171. package/src/storybook/constants/index.ts +5 -0
  172. package/src/storybook/constants/typeset.constants.ts +39 -0
  173. package/src/storybook/constants/variableSpacing.constants.ts +6 -0
  174. package/src/storybook/helpers/getFontSizeLabel.ts +15 -0
  175. package/src/storybook/helpers/index.ts +4 -0
  176. package/src/storybook/stories/atoms/Badge.stories.tsx +32 -0
  177. package/src/storybook/stories/atoms/Button.stories.tsx +45 -0
  178. package/src/storybook/stories/atoms/ButtonSegment.stories.tsx +45 -0
  179. package/src/storybook/stories/atoms/Checkbox.stories.tsx +34 -0
  180. package/src/storybook/stories/atoms/CustomScrollbar.stories.tsx +22 -0
  181. package/src/storybook/stories/atoms/Divider.stories.tsx +41 -0
  182. package/src/storybook/stories/atoms/Header.stories.tsx +58 -0
  183. package/src/storybook/stories/atoms/InfoBox.stories.tsx +67 -0
  184. package/src/storybook/stories/atoms/KeyValueInfo.stories.tsx +59 -0
  185. package/src/storybook/stories/atoms/LabelText.stories.tsx +55 -0
  186. package/src/storybook/stories/atoms/ListItem.stories.tsx +41 -0
  187. package/src/storybook/stories/atoms/LoadingIndicator.stories.tsx +32 -0
  188. package/src/storybook/stories/atoms/Panel.stories.tsx +36 -0
  189. package/src/storybook/stories/atoms/Placeholder.stories.tsx +33 -0
  190. package/src/storybook/stories/atoms/RadioButton.stories.tsx +51 -0
  191. package/src/storybook/stories/atoms/Skeleton.stories.tsx +33 -0
  192. package/src/storybook/stories/atoms/Snackbar.stories.tsx +43 -0
  193. package/src/storybook/stories/atoms/Toggle.stories.tsx +59 -0
  194. package/src/storybook/stories/atoms/Tooltip.stories.tsx +57 -0
  195. package/src/storybook/stories/atoms/VisualAssetCard.stories.tsx +56 -0
  196. package/src/storybook/stories/components/VariableSpacingShowcase.tsx +46 -0
  197. package/src/storybook/stories/components/index.ts +4 -0
  198. package/src/storybook/stories/design-tokens/colors.stories.mdx +23 -0
  199. package/src/storybook/stories/design-tokens/icons.stories.mdx +17 -0
  200. package/src/storybook/stories/design-tokens/typeset.stories.mdx +15 -0
  201. package/src/storybook/stories/design-tokens/variable-spacing.stories.mdx +10 -0
  202. package/src/storybook/stories/molecules/Account.stories.tsx +69 -0
  203. package/src/storybook/stories/molecules/Address.stories.tsx +39 -0
  204. package/src/storybook/stories/molecules/Card.stories.tsx +112 -0
  205. package/src/storybook/stories/molecules/Chip.stories.tsx +122 -0
  206. package/src/storybook/stories/molecules/DisplayStats.stories.tsx +63 -0
  207. package/src/storybook/stories/molecules/Dropdown.stories.tsx +38 -0
  208. package/src/storybook/stories/molecules/Input.stories.tsx +162 -0
  209. package/src/storybook/stories/molecules/NavbarItem.stories.tsx +45 -0
  210. package/src/storybook/stories/molecules/Search.stories.tsx +101 -0
  211. package/src/storybook/stories/molecules/SegmentedButton.stories.tsx +108 -0
  212. package/src/storybook/stories/molecules/Select.stories.tsx +103 -0
  213. package/src/storybook/stories/molecules/TableCell.stories.tsx +46 -0
  214. package/src/storybook/stories/molecules/TableHeaderCell.stories.tsx +34 -0
  215. package/src/storybook/stories/molecules/TextArea.stories.tsx +80 -0
  216. package/src/storybook/stories/molecules/Title.stories.tsx +76 -0
  217. package/src/storybook/stories/organisms/Accordion.stories.tsx +70 -0
  218. package/src/storybook/stories/organisms/Dialog.stories.tsx +103 -0
  219. package/src/storybook/stories/organisms/Navbar.stories.tsx +78 -0
  220. package/src/storybook/stories/organisms/Table.stories.tsx +154 -0
@@ -0,0 +1,142 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ReactNode } from 'react';
5
+ import type { TooltipPosition } from '@/components/atoms';
6
+ import { ButtonUnstyled, Tooltip } from '@/components/atoms';
7
+ import { Copy, Info } from '@iota/apps-ui-icons';
8
+ import { DisplayStatsType, DisplayStatsSize } from './displayStats.enums';
9
+ import cx from 'classnames';
10
+ import {
11
+ BACKGROUND_CLASSES,
12
+ SIZE_CLASSES,
13
+ TEXT_CLASSES,
14
+ VALUE_TEXT_CLASSES,
15
+ SUPPORTING_LABEL_TEXT_CLASSES,
16
+ LABEL_TEXT_CLASSES,
17
+ } from './displayStats.classes';
18
+
19
+ interface DisplayStatsProps {
20
+ /**
21
+ * The label of the stats.
22
+ */
23
+ label: ReactNode;
24
+ /**
25
+ * The tooltip position.
26
+ */
27
+ tooltipPosition?: TooltipPosition;
28
+ /**
29
+ * The tooltip text.
30
+ */
31
+ tooltipText?: string;
32
+ /**
33
+ * The value of the stats.
34
+ */
35
+ value: ReactNode;
36
+ /**
37
+ * The supporting label of the stats (optional).
38
+ */
39
+ supportingLabel?: string;
40
+ /**
41
+ * The background color of the stats.
42
+ */
43
+ type?: DisplayStatsType;
44
+ /**
45
+ * The size of the stats.
46
+ */
47
+ size?: DisplayStatsSize;
48
+ /**
49
+ * Add icon to the right of the label.
50
+ */
51
+ icon?: React.ReactNode;
52
+ /**
53
+ * Text that need to be copied (optional).
54
+ */
55
+ copyText?: string;
56
+ /**
57
+ * The onCopySuccess event of the KeyValue (optional).
58
+ */
59
+ onCopySuccess?: (e: React.MouseEvent<HTMLButtonElement>, text: string) => void;
60
+ /**
61
+ * The onCopyError event of the KeyValue (optional).
62
+ */
63
+ onCopyError?: (e: unknown, text: string) => void;
64
+ }
65
+
66
+ export function DisplayStats({
67
+ label,
68
+ tooltipPosition,
69
+ tooltipText,
70
+ value,
71
+ supportingLabel,
72
+ type = DisplayStatsType.Default,
73
+ size = DisplayStatsSize.Default,
74
+ icon,
75
+ copyText,
76
+ onCopySuccess,
77
+ onCopyError,
78
+ }: DisplayStatsProps): React.JSX.Element {
79
+ const backgroundClass = BACKGROUND_CLASSES[type];
80
+ const sizeClass = SIZE_CLASSES[size];
81
+ const textClass = TEXT_CLASSES[type];
82
+ const valueClass = VALUE_TEXT_CLASSES[size];
83
+ const labelClass = LABEL_TEXT_CLASSES[size];
84
+ const supportingLabelTextClass = SUPPORTING_LABEL_TEXT_CLASSES[size];
85
+
86
+ async function handleCopyClick(event: React.MouseEvent<HTMLButtonElement>) {
87
+ if (!navigator.clipboard) {
88
+ return;
89
+ }
90
+
91
+ if (copyText) {
92
+ try {
93
+ await navigator.clipboard.writeText(copyText);
94
+ onCopySuccess?.(event, copyText);
95
+ } catch (error) {
96
+ console.error('Failed to copy:', error);
97
+ onCopyError?.(error, copyText);
98
+ }
99
+ }
100
+ }
101
+ return (
102
+ <div
103
+ className={cx(
104
+ 'flex h-full w-full flex-col justify-between rounded-2xl p-md--rs',
105
+ backgroundClass,
106
+ sizeClass,
107
+ textClass,
108
+ )}
109
+ >
110
+ <div
111
+ className={cx('flex flex-row items-center', {
112
+ 'w-full justify-between': icon,
113
+ })}
114
+ >
115
+ <div className="flex flex-row items-center gap-xxs">
116
+ <span className={cx(labelClass, 'whitespace-pre-line')}>{label}</span>
117
+ {tooltipText && (
118
+ <Tooltip text={tooltipText} position={tooltipPosition}>
119
+ <Info className="opacity-40" />
120
+ </Tooltip>
121
+ )}
122
+ </div>
123
+ {icon && <span className="text-neutral-10 dark:text-neutral-92">{icon}</span>}
124
+ </div>
125
+ <div className="flex w-full flex-row items-baseline gap-xxs">
126
+ <span className={cx('break-all', valueClass)}>{value}</span>
127
+ {supportingLabel && (
128
+ <span className={cx('opacity-40', supportingLabelTextClass)}>
129
+ {supportingLabel}
130
+ </span>
131
+ )}
132
+ {copyText && (
133
+ <div className="self-center">
134
+ <ButtonUnstyled onClick={handleCopyClick}>
135
+ <Copy className="text-neutral-60 dark:text-neutral-40" />
136
+ </ButtonUnstyled>
137
+ </div>
138
+ )}
139
+ </div>
140
+ </div>
141
+ );
142
+ }
@@ -0,0 +1,36 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { DisplayStatsType, DisplayStatsSize } from './displayStats.enums';
5
+
6
+ export const BACKGROUND_CLASSES: Record<DisplayStatsType, string> = {
7
+ [DisplayStatsType.Default]: 'bg-neutral-96 dark:bg-neutral-10',
8
+ [DisplayStatsType.Highlight]: 'bg-primary-30 dark:bg-primary-80',
9
+ [DisplayStatsType.Secondary]: 'bg-secondary-90 dark:bg-secondary-10',
10
+ };
11
+
12
+ export const TEXT_CLASSES: Record<DisplayStatsType, string> = {
13
+ [DisplayStatsType.Default]: 'text-neutral-10 dark:text-neutral-92',
14
+ [DisplayStatsType.Highlight]: 'text-neutral-100 dark:text-primary-10',
15
+ [DisplayStatsType.Secondary]: 'text-neutral-10 dark:text-neutral-92',
16
+ };
17
+
18
+ export const SIZE_CLASSES: Record<DisplayStatsSize, string> = {
19
+ [DisplayStatsSize.Default]: 'gap-y-sm',
20
+ [DisplayStatsSize.Large]: 'gap-y-md',
21
+ };
22
+
23
+ export const VALUE_TEXT_CLASSES: Record<DisplayStatsSize, string> = {
24
+ [DisplayStatsSize.Default]: 'text-title-md',
25
+ [DisplayStatsSize.Large]: 'text-headline-sm',
26
+ };
27
+
28
+ export const SUPPORTING_LABEL_TEXT_CLASSES: Record<DisplayStatsSize, string> = {
29
+ [DisplayStatsSize.Default]: 'text-label-md',
30
+ [DisplayStatsSize.Large]: 'text-label-lg',
31
+ };
32
+
33
+ export const LABEL_TEXT_CLASSES: Record<DisplayStatsSize, string> = {
34
+ [DisplayStatsSize.Default]: 'text-label-sm',
35
+ [DisplayStatsSize.Large]: 'text-label-md',
36
+ };
@@ -0,0 +1,13 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export enum DisplayStatsType {
5
+ Default = 'default',
6
+ Highlight = 'highlight',
7
+ Secondary = 'secondary',
8
+ }
9
+
10
+ export enum DisplayStatsSize {
11
+ Default = 'default',
12
+ Large = 'large',
13
+ }
@@ -0,0 +1,5 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './DisplayStats';
5
+ export * from './displayStats.enums';
@@ -0,0 +1,10 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export function Dropdown({ children }: React.PropsWithChildren): React.JSX.Element {
5
+ return (
6
+ <ul className="list-none rounded-lg border border-neutral-80 bg-neutral-100 py-xs dark:border-neutral-20 dark:bg-neutral-6">
7
+ {children}
8
+ </ul>
9
+ );
10
+ }
@@ -0,0 +1,7 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export enum DropdownPosition {
5
+ Top = 'top',
6
+ Bottom = 'bottom',
7
+ }
@@ -0,0 +1,5 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './Dropdown';
5
+ export * from './dropdownPosition.enums';
@@ -0,0 +1,17 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './address';
5
+ export * from './chip';
6
+ export * from './segmented-button';
7
+ export * from './title';
8
+ export * from './input';
9
+ export * from './navbar-item';
10
+ export * from './account';
11
+ export * from './dropdown';
12
+ export * from './table-cell';
13
+ export * from './select';
14
+ export * from './table-header-cell';
15
+ export * from './search';
16
+ export * from './card';
17
+ export * from './display-stats';
@@ -0,0 +1,246 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { forwardRef, Fragment, useEffect, useRef, useState } from 'react';
5
+ import cx from 'classnames';
6
+ import type { InputWrapperProps } from './InputWrapper';
7
+ import { InputWrapper } from './InputWrapper';
8
+ import {
9
+ BORDER_CLASSES,
10
+ INPUT_CLASSES,
11
+ INPUT_TEXT_CLASSES,
12
+ INPUT_NUMBER_CLASSES,
13
+ INPUT_PLACEHOLDER_CLASSES,
14
+ } from './input.classes';
15
+ import { InputType } from './input.enums';
16
+ import { SecondaryText } from '@/components/atoms/secondary-text';
17
+ import { Close, VisibilityOff, VisibilityOn } from '@iota/apps-ui-icons';
18
+ import { ButtonUnstyled } from '@/components/atoms/button';
19
+ import type { InputPropsByType, NumericFormatInputProps } from './input.types';
20
+ import { NumericFormat } from 'react-number-format';
21
+
22
+ export interface BaseInputProps extends InputWrapperProps {
23
+ /**
24
+ * A leading icon that is shown before the input
25
+ */
26
+ leadingIcon?: React.JSX.Element;
27
+ /**
28
+ * Supporting text that is shown at the end of the input component.
29
+ */
30
+ supportingText?: string;
31
+ /**
32
+ * Amount counter that is shown at the side of the caption text.
33
+ */
34
+ amountCounter?: string | number;
35
+ /**
36
+ * Trailing element that is shown after the input
37
+ */
38
+ trailingElement?: React.JSX.Element;
39
+ /**
40
+ * Is the content of the input visible
41
+ */
42
+ isContentVisible?: boolean;
43
+ /**
44
+ * Value of the input
45
+ */
46
+ value?: string | number;
47
+ /**
48
+ * Default value of the input
49
+ */
50
+ defaultValue?: string | number;
51
+ /**
52
+ * onClearInput function that is called when the clear button is clicked
53
+ */
54
+ onClearInput?: () => void;
55
+ /**
56
+ * Shows toggle button to show/hide the content of the input field
57
+ */
58
+ isVisibilityToggleEnabled?: boolean;
59
+ }
60
+
61
+ export type InputProps = BaseInputProps & InputPropsByType;
62
+
63
+ export const Input = forwardRef<HTMLInputElement, InputProps>(function InputComponent(
64
+ {
65
+ label,
66
+ caption,
67
+ disabled,
68
+ errorMessage,
69
+ leadingIcon,
70
+ supportingText,
71
+ amountCounter,
72
+ trailingElement,
73
+ isContentVisible,
74
+ value,
75
+ defaultValue,
76
+ onClearInput,
77
+ isVisibilityToggleEnabled,
78
+ type,
79
+ ...inputProps
80
+ },
81
+ forwardRef,
82
+ ) {
83
+ isVisibilityToggleEnabled ??= type === InputType.Password;
84
+ const inputWrapperRef = useRef<HTMLDivElement | null>(null);
85
+
86
+ const [isInputContentVisible, setIsInputContentVisible] = useState<boolean>(
87
+ isContentVisible ?? type !== InputType.Password,
88
+ );
89
+
90
+ useEffect(() => {
91
+ setIsInputContentVisible(isContentVisible ?? type !== InputType.Password);
92
+ }, [type, isContentVisible]);
93
+
94
+ function onToggleButtonClick() {
95
+ setIsInputContentVisible((prev) => !prev);
96
+ }
97
+
98
+ function focusOnInput() {
99
+ if (inputWrapperRef.current) {
100
+ inputWrapperRef.current.querySelector('input')?.focus();
101
+ }
102
+ }
103
+
104
+ return (
105
+ <InputWrapper
106
+ label={label}
107
+ caption={caption}
108
+ disabled={disabled}
109
+ errorMessage={errorMessage}
110
+ amountCounter={amountCounter}
111
+ required={inputProps.required}
112
+ >
113
+ <div
114
+ className={cx('relative flex flex-row items-center gap-x-3', BORDER_CLASSES)}
115
+ onClick={focusOnInput}
116
+ ref={inputWrapperRef}
117
+ >
118
+ {leadingIcon && (
119
+ <span className="text-neutral-10 dark:text-neutral-92">{leadingIcon}</span>
120
+ )}
121
+ <InputElement
122
+ {...inputProps}
123
+ inputRef={forwardRef}
124
+ value={value}
125
+ type={
126
+ type === InputType.Password && isInputContentVisible ? InputType.Text : type
127
+ }
128
+ disabled={disabled}
129
+ className={cx(
130
+ INPUT_CLASSES,
131
+ INPUT_TEXT_CLASSES,
132
+ INPUT_PLACEHOLDER_CLASSES,
133
+ INPUT_NUMBER_CLASSES,
134
+ )}
135
+ />
136
+
137
+ {supportingText && <SecondaryText>{supportingText}</SecondaryText>}
138
+ <InputTrailingElement
139
+ value={value}
140
+ type={type}
141
+ onClearInput={onClearInput}
142
+ isContentVisible={isInputContentVisible}
143
+ trailingElement={trailingElement}
144
+ isVisibilityToggleEnabled={isVisibilityToggleEnabled}
145
+ onToggleButtonClick={onToggleButtonClick}
146
+ />
147
+ </div>
148
+ </InputWrapper>
149
+ );
150
+ });
151
+
152
+ function InputElement({
153
+ type,
154
+ inputRef,
155
+ ...inputProps
156
+ }: InputProps & {
157
+ inputRef: React.ForwardedRef<HTMLInputElement>;
158
+ className: string;
159
+ }) {
160
+ function preventScrollInputChange(e: React.WheelEvent<HTMLInputElement>) {
161
+ if (type === InputType.Number) {
162
+ const input = e.currentTarget;
163
+
164
+ input.blur();
165
+ e.stopPropagation();
166
+ setTimeout(() => {
167
+ input.focus({ preventScroll: true });
168
+ }, 0);
169
+ }
170
+ }
171
+ return type === InputType.NumericFormat ? (
172
+ <NumericFormatInput inputRef={inputRef} {...inputProps} type={type} />
173
+ ) : (
174
+ <input
175
+ ref={inputRef}
176
+ {...inputProps}
177
+ type={type}
178
+ onWheel={(e) => {
179
+ preventScrollInputChange(e);
180
+ inputProps.onWheel?.(e);
181
+ }}
182
+ />
183
+ );
184
+ }
185
+
186
+ function NumericFormatInput({
187
+ inputRef,
188
+ className,
189
+ type,
190
+ ...inputProps
191
+ }: NumericFormatInputProps &
192
+ InputProps & {
193
+ inputRef: React.ForwardedRef<HTMLInputElement>;
194
+ className: string;
195
+ value?: string | number;
196
+ }) {
197
+ return (
198
+ <NumericFormat
199
+ className={className}
200
+ valueIsNumericString
201
+ getInputRef={inputRef}
202
+ {...inputProps}
203
+ />
204
+ );
205
+ }
206
+
207
+ function InputTrailingElement({
208
+ value,
209
+ type,
210
+ onClearInput,
211
+ isContentVisible,
212
+ trailingElement,
213
+ onToggleButtonClick,
214
+ isVisibilityToggleEnabled,
215
+ }: BaseInputProps & {
216
+ onToggleButtonClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
217
+ type: InputPropsByType['type'];
218
+ }) {
219
+ const showClearInput = Boolean(type === InputType.Text && value && onClearInput);
220
+ const showPasswordToggle = Boolean(type === InputType.Password && isVisibilityToggleEnabled);
221
+ const showTrailingElement = Boolean(trailingElement && !showClearInput && !showPasswordToggle);
222
+
223
+ if (showClearInput) {
224
+ return (
225
+ <ButtonUnstyled
226
+ className="text-neutral-10 dark:text-neutral-92 [&_svg]:h-5 [&_svg]:w-5"
227
+ onClick={onClearInput}
228
+ tabIndex={-1}
229
+ >
230
+ <Close />
231
+ </ButtonUnstyled>
232
+ );
233
+ } else if (showPasswordToggle) {
234
+ return (
235
+ <ButtonUnstyled
236
+ onClick={onToggleButtonClick}
237
+ className="text-neutral-10 dark:text-neutral-92 [&_svg]:h-5 [&_svg]:w-5"
238
+ tabIndex={-1}
239
+ >
240
+ {isContentVisible ? <VisibilityOn /> : <VisibilityOff />}
241
+ </ButtonUnstyled>
242
+ );
243
+ } else if (showTrailingElement) {
244
+ return <Fragment>{trailingElement}</Fragment>;
245
+ }
246
+ }
@@ -0,0 +1,97 @@
1
+ // Copyright (c) 2024 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import cx from 'classnames';
5
+ import { SecondaryText } from '@/components/atoms/secondary-text';
6
+ import { LABEL_CLASSES } from './input.classes';
7
+ import { createElement } from 'react';
8
+
9
+ export enum LabelHtmlTag {
10
+ Label = 'label',
11
+ Div = 'div',
12
+ }
13
+
14
+ export interface InputWrapperProps {
15
+ /**
16
+ * Shows a label with the text above the input.
17
+ */
18
+ label?: string;
19
+ /**
20
+ * Shows a caption with the text below the input.
21
+ */
22
+ caption?: string;
23
+ /**
24
+ * Error Message. Overrides the caption.
25
+ */
26
+ errorMessage?: string;
27
+ /**
28
+ * Amount counter that is shown at the side of the caption text.
29
+ */
30
+ amountCounter?: string | number;
31
+ /**
32
+ * Is the input required
33
+ */
34
+ required?: boolean;
35
+ /**
36
+ * Is the input disabled
37
+ */
38
+ disabled?: boolean;
39
+ /**
40
+ * Use a div as a label instead of a label element
41
+ */
42
+ labelHtmlTag?: LabelHtmlTag;
43
+ }
44
+
45
+ export function InputWrapper({
46
+ label,
47
+ caption,
48
+ disabled,
49
+ errorMessage,
50
+ amountCounter,
51
+ required,
52
+ labelHtmlTag = LabelHtmlTag.Label,
53
+ children,
54
+ }: React.PropsWithChildren<InputWrapperProps>) {
55
+ return (
56
+ <div
57
+ className={cx('group flex w-full flex-col gap-y-2', {
58
+ 'cursor-not-allowed opacity-40': disabled,
59
+ errored: errorMessage,
60
+ enabled: !disabled,
61
+ required: required,
62
+ })}
63
+ >
64
+ {label ? (
65
+ <LabelWrapper labelHtmlTag={labelHtmlTag}>
66
+ {label}
67
+ {children}
68
+ </LabelWrapper>
69
+ ) : (
70
+ children
71
+ )}
72
+
73
+ {(errorMessage || caption || amountCounter) && (
74
+ <div
75
+ className={cx(
76
+ 'flex flex-row items-center',
77
+ caption || errorMessage ? 'justify-between' : 'justify-end',
78
+ )}
79
+ >
80
+ {(errorMessage || caption) && (
81
+ <SecondaryText hasErrorStyles>{errorMessage || caption}</SecondaryText>
82
+ )}
83
+ {amountCounter && <SecondaryText>{amountCounter}</SecondaryText>}
84
+ </div>
85
+ )}
86
+ </div>
87
+ );
88
+ }
89
+
90
+ function LabelWrapper({
91
+ labelHtmlTag,
92
+ children,
93
+ }: Required<Pick<InputWrapperProps, 'labelHtmlTag'>> & {
94
+ children: React.ReactNode;
95
+ }) {
96
+ return createElement(labelHtmlTag, { className: LABEL_CLASSES }, children);
97
+ }