@inceptionbg/iui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/package.json +40 -0
  2. package/src/Elements/Accordions/Accordions.tsx +64 -0
  3. package/src/Elements/Alert/Alert.tsx +31 -0
  4. package/src/Elements/Alert/alert.scss +36 -0
  5. package/src/Elements/Button/Button.tsx +55 -0
  6. package/src/Elements/Button/IconButton.tsx +42 -0
  7. package/src/Elements/Button/button.scss +97 -0
  8. package/src/Elements/Dialog/Dialog.tsx +175 -0
  9. package/src/Elements/Helper/Collapse.tsx +39 -0
  10. package/src/Elements/Helper/NoAccessInfo.tsx +195 -0
  11. package/src/Elements/Tooltip/Tooltip.tsx +116 -0
  12. package/src/Elements/Tooltip/tooltip.scss +46 -0
  13. package/src/Elements/Wrappers/ConditionalWrapper.tsx +10 -0
  14. package/src/Elements/Wrappers/FormWrapper.tsx +67 -0
  15. package/src/Elements/Wrappers/FullPageWrapper.tsx +87 -0
  16. package/src/Elements/Wrappers/PageWrapper.tsx +148 -0
  17. package/src/icons/duotone/faArrowLeftFromLine.ts +17 -0
  18. package/src/icons/duotone/faArrowRightToLine.ts +17 -0
  19. package/src/icons/duotone/faBell.ts +17 -0
  20. package/src/icons/duotone/faEye.ts +17 -0
  21. package/src/icons/duotone/faEyeSlash.ts +17 -0
  22. package/src/icons/duotone/faHouseHeart.ts +17 -0
  23. package/src/icons/duotone/faPlusCircle.ts +18 -0
  24. package/src/icons/duotone/faUser.ts +18 -0
  25. package/src/icons/duotone/index.ts +19 -0
  26. package/src/icons/light/faAngleDown.ts +15 -0
  27. package/src/icons/light/faArrowDownShortWide.ts +15 -0
  28. package/src/icons/light/faArrowDownWideShort.ts +15 -0
  29. package/src/icons/light/faArrowsToLine.ts +15 -0
  30. package/src/icons/light/faArrowsUpDown.ts +15 -0
  31. package/src/icons/light/faBell.ts +15 -0
  32. package/src/icons/light/faCheck.ts +15 -0
  33. package/src/icons/light/faClockRotateLeft.ts +15 -0
  34. package/src/icons/light/faEllipsisVertical.ts +15 -0
  35. package/src/icons/light/faXmark.ts +15 -0
  36. package/src/icons/light/index.ts +23 -0
  37. package/src/icons/regular/faArrowRightArrowLeft.ts +15 -0
  38. package/src/icons/regular/faCalendar.ts +15 -0
  39. package/src/icons/regular/faCircleCheck.ts +15 -0
  40. package/src/icons/regular/faCircleExclamation.ts +15 -0
  41. package/src/icons/regular/faCircleInfo.ts +15 -0
  42. package/src/icons/regular/faFileArrowDown.ts +15 -0
  43. package/src/icons/regular/faFilterCircleXmark.ts +15 -0
  44. package/src/icons/regular/faTriangleExclamation.ts +15 -0
  45. package/src/icons/solid/faAngleLeft.ts +15 -0
  46. package/src/icons/solid/faAngleRight.ts +15 -0
  47. package/src/icons/solid/faArrowDownWideShort.ts +15 -0
  48. package/src/icons/solid/faArrowLeft.ts +15 -0
  49. package/src/icons/solid/faEllipsisVertical.ts +15 -0
  50. package/src/icons/solid/faFilter.ts +15 -0
  51. package/src/icons/solid/faGripDotsVertical.ts +15 -0
  52. package/src/icons/solid/faListUl.ts +15 -0
  53. package/src/icons/solid/faMagnifyingGlass.ts +15 -0
  54. package/src/icons/solid/faPrint.ts +15 -0
  55. package/src/icons/solid/faRotateRight.ts +15 -0
  56. package/src/icons/solid/faXmark.ts +15 -0
  57. package/src/index.ts +186 -0
  58. package/src/styles/App.scss +25 -0
  59. package/src/styles/iui/common/_animations.scss +56 -0
  60. package/src/styles/iui/common/_typography.scss +76 -0
  61. package/src/styles/iui/common/_variables.scss +56 -0
  62. package/src/styles/iui/common/helpers/_base.scss +32 -0
  63. package/src/styles/iui/common/helpers/_color.scss +7 -0
  64. package/src/styles/iui/common/helpers/_display.scss +54 -0
  65. package/src/styles/iui/common/helpers/_size.scss +17 -0
  66. package/src/styles/iui/common/maps/_align.scss +24 -0
  67. package/src/styles/iui/common/maps/_spacing.scss +78 -0
  68. package/src/styles/iui/components/_accordions.scss +47 -0
  69. package/src/styles/iui/components/_badge.scss +52 -0
  70. package/src/styles/iui/components/_card.scss +24 -0
  71. package/src/styles/iui/components/_dialog.scss +75 -0
  72. package/src/styles/iui/components/_header.scss +22 -0
  73. package/src/styles/iui/components/_input.scss +225 -0
  74. package/src/styles/iui/components/_loader.scss +93 -0
  75. package/src/styles/iui/components/_menu.scss +44 -0
  76. package/src/styles/iui/components/_notifications.scss +86 -0
  77. package/src/styles/iui/components/_page.scss +50 -0
  78. package/src/styles/iui/components/_pagePrelogin.scss +66 -0
  79. package/src/styles/iui/components/_portal.scss +8 -0
  80. package/src/styles/iui/components/_print.scss +92 -0
  81. package/src/styles/iui/components/_scrollbar.scss +18 -0
  82. package/src/styles/iui/components/_selectInput.scss +15 -0
  83. package/src/styles/iui/components/_sidebar.scss +171 -0
  84. package/src/styles/iui/components/_smallComponents.scss +24 -0
  85. package/src/styles/iui/components/_table.scss +207 -0
  86. package/src/styles/iui/components/_tabs.scss +94 -0
  87. package/src/styles/iui.scss +28 -0
  88. package/src/styles/red-variables.scss +9 -0
  89. package/src/types/IBasic.ts +31 -0
  90. package/src/types/IError.ts +4 -0
  91. package/src/types/IHeaderAction.ts +12 -0
  92. package/src/types/ISelect.ts +6 -0
  93. package/src/types/ISidebar.ts +29 -0
  94. package/src/types/ITab.ts +10 -0
  95. package/src/types/ITable.ts +210 -0
  96. package/src/types/custom.d.ts +9 -0
  97. package/src/utils/DateUtils.ts +30 -0
  98. package/src/utils/NumberUtils.ts +21 -0
  99. package/src/utils/ObjectUtils.ts +49 -0
  100. package/src/utils/StringUtils.ts +2 -0
  101. package/src/utils/Toasts.ts +6 -0
  102. package/src/utils/icons.ts +11 -0
  103. package/src/utils/index.ts +41 -0
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@inceptionbg/iui",
3
+ "version": "1.0.0",
4
+ "description": "UI components, elements & utils for Inception ecosystem",
5
+ "files": [
6
+ "src"
7
+ ],
8
+ "main": "src/index.ts",
9
+ "scripts": {
10
+ "build": "rollup -c"
11
+ },
12
+ "author": "Aleksandar Sadzak",
13
+ "license": "ISC",
14
+ "dependencies": {
15
+ "@fortawesome/react-fontawesome": "^0.2.0",
16
+ "clsx": "^1.2.1",
17
+ "moment": "^2.29.4",
18
+ "react-toastify": "^9.1.3",
19
+ "rollup-plugin-postcss": "^4.0.2"
20
+ },
21
+ "devDependencies": {
22
+ "@rollup/plugin-commonjs": "^25.0.2",
23
+ "@rollup/plugin-node-resolve": "^15.1.0",
24
+ "@rollup/plugin-terser": "^0.4.3",
25
+ "@rollup/plugin-typescript": "^11.1.2",
26
+ "rollup": "^3.26.0",
27
+ "rollup-plugin-delete": "^2.0.0",
28
+ "rollup-plugin-dts": "^5.3.0",
29
+ "rollup-plugin-peer-deps-external": "^2.2.4"
30
+ },
31
+ "peerDependencies": {
32
+ "@types/react": "^18.2.14",
33
+ "@types/react-dom": "^18.2.6",
34
+ "@types/react-router-dom": "^5.3.3",
35
+ "react": "^18.2.0",
36
+ "react-dom": "^18.2.0",
37
+ "react-router-dom": "^6.14.1",
38
+ "sass": "^1.63.6"
39
+ }
40
+ }
@@ -0,0 +1,64 @@
1
+ import { FC, useState } from "react";
2
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
+ import clsx from "clsx";
4
+ import { ITab } from "types/ITab";
5
+ import { faArrowsToLine } from "icons/light/faArrowsToLine";
6
+ import { faArrowsUpDown } from "icons/light/faArrowsUpDown";
7
+ import { Collapse } from "Elements/Helper/Collapse";
8
+
9
+ interface Props {
10
+ tabs: ITab[];
11
+ initialValue?: string;
12
+ compact?: boolean;
13
+ className?: string;
14
+ }
15
+ export const Accordions: FC<Props> = ({
16
+ tabs: allTabs,
17
+ initialValue,
18
+ compact,
19
+ className,
20
+ }) => {
21
+ const tabs = allTabs.filter((tab) => !tab.hidden);
22
+ const [selected, setSelected] = useState(initialValue || "");
23
+
24
+ return !!tabs.length ? (
25
+ <div className={className}>
26
+ <div className="iui-accordions">
27
+ {tabs.map((tab) => (
28
+ <div
29
+ key={tab.value}
30
+ className={clsx("iui-accordion", {
31
+ selected: selected === tab.value,
32
+ compact,
33
+ })}
34
+ >
35
+ <div
36
+ className={clsx("summary clickable", {
37
+ disabled: tab.disabled,
38
+ })}
39
+ onClick={
40
+ tab.disabled
41
+ ? undefined
42
+ : () => setSelected(selected === tab.value ? "" : tab.value)
43
+ }
44
+ >
45
+ <div className="flex center">
46
+ {tab.icon && (
47
+ <FontAwesomeIcon icon={tab.icon} className="iui-icon" />
48
+ )}
49
+ {tab.label}
50
+ </div>
51
+ <FontAwesomeIcon
52
+ icon={tab.value === selected ? faArrowsToLine : faArrowsUpDown}
53
+ className="collapse-icon"
54
+ />
55
+ </div>
56
+ <Collapse isOpen={selected === tab.value}>
57
+ <div className="p-4">{tab.component}</div>
58
+ </Collapse>
59
+ </div>
60
+ ))}
61
+ </div>
62
+ </div>
63
+ ) : null;
64
+ };
@@ -0,0 +1,31 @@
1
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
2
+ import clsx from "clsx";
3
+ import { FC, ReactNode } from "react";
4
+ import "./alert.scss";
5
+ import { infoIcons } from "utils/icons";
6
+
7
+ interface Props {
8
+ text?: string;
9
+ severity: "success" | "info" | "warning" | "error";
10
+ fitContent?: boolean;
11
+ className?: string;
12
+ children?: ReactNode;
13
+ }
14
+
15
+ export const Alert: FC<Props> = ({
16
+ text,
17
+ severity,
18
+ fitContent,
19
+ className,
20
+ children,
21
+ }) => (
22
+ <div
23
+ className={clsx("iui-alert", severity, className, {
24
+ "width-fit": fitContent,
25
+ })}
26
+ >
27
+ <FontAwesomeIcon icon={infoIcons[severity]} />
28
+ {text}
29
+ {children}
30
+ </div>
31
+ );
@@ -0,0 +1,36 @@
1
+ .iui-alert {
2
+ border-radius: 25px;
3
+ display: flex;
4
+ align-items: center;
5
+ padding: 16px;
6
+ font-size: 13px;
7
+ svg {
8
+ font-size: 18px;
9
+ opacity: 0.9;
10
+ margin-right: 12px;
11
+ }
12
+ &.success {
13
+ background: var(--success01);
14
+ svg {
15
+ color: var(--success);
16
+ }
17
+ }
18
+ &.info {
19
+ background: var(--info01);
20
+ svg {
21
+ color: var(--info);
22
+ }
23
+ }
24
+ &.warning {
25
+ background: var(--warning01);
26
+ svg {
27
+ color: var(--warning);
28
+ }
29
+ }
30
+ &.error {
31
+ background: var(--error01);
32
+ svg {
33
+ color: var(--error);
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,55 @@
1
+ import { ButtonHTMLAttributes, forwardRef, MouseEventHandler } from "react";
2
+ import clsx from "clsx";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
5
+ import "./button.scss";
6
+
7
+ interface Props {
8
+ label: string;
9
+ icon?: IconDefinition;
10
+ iconEnd?: IconDefinition;
11
+ onClick?: MouseEventHandler<HTMLButtonElement>;
12
+ disabled?: boolean;
13
+ primary?: boolean;
14
+ outlined?: boolean;
15
+ active?: boolean;
16
+ className?: string;
17
+ size?: "xs" | "s" | "m" | "l";
18
+ buttonProps?: ButtonHTMLAttributes<HTMLButtonElement>;
19
+ }
20
+
21
+ export const Button = forwardRef<HTMLButtonElement, Props>(
22
+ (
23
+ {
24
+ label,
25
+ icon,
26
+ iconEnd,
27
+ onClick,
28
+ disabled,
29
+ primary,
30
+ outlined,
31
+ active,
32
+ className,
33
+ size = "m",
34
+ buttonProps,
35
+ },
36
+ ref
37
+ ) => (
38
+ <button
39
+ ref={ref}
40
+ disabled={disabled}
41
+ className={clsx("iui-btn", className, size, {
42
+ primary,
43
+ outlined,
44
+ active,
45
+ })}
46
+ onClick={onClick}
47
+ type={buttonProps?.type || onClick ? "button" : "submit"}
48
+ {...buttonProps}
49
+ >
50
+ {icon && <FontAwesomeIcon icon={icon} />}
51
+ <div className="iui-btn-label">{label}</div>
52
+ {iconEnd && <FontAwesomeIcon icon={iconEnd} />}
53
+ </button>
54
+ )
55
+ );
@@ -0,0 +1,42 @@
1
+ import { ButtonHTMLAttributes, forwardRef, MouseEventHandler } from "react";
2
+ import clsx from "clsx";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
5
+
6
+ interface Props {
7
+ icon: IconDefinition;
8
+ onClick?: MouseEventHandler<HTMLButtonElement>;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ active?: boolean;
12
+ buttonProps?: ButtonHTMLAttributes<HTMLButtonElement>;
13
+ // outlined?: boolean;
14
+ // size?: "s" | "m" | "l";
15
+ }
16
+
17
+ export const IconButton = forwardRef<HTMLButtonElement, Props>(
18
+ (
19
+ {
20
+ icon,
21
+ onClick,
22
+ disabled,
23
+ className,
24
+ active,
25
+ buttonProps,
26
+ // outlined,
27
+ // size = "m",
28
+ },
29
+ ref
30
+ ) => (
31
+ <button
32
+ ref={ref}
33
+ disabled={disabled}
34
+ className={clsx("iui-btn iui-icon-btn", className, { active })}
35
+ onClick={onClick}
36
+ type={buttonProps?.type || onClick ? "button" : "submit"}
37
+ {...buttonProps}
38
+ >
39
+ <FontAwesomeIcon icon={icon} />
40
+ </button>
41
+ )
42
+ );
@@ -0,0 +1,97 @@
1
+ .iui-btn {
2
+ cursor: pointer;
3
+ user-select: none;
4
+ background: none;
5
+ border: none;
6
+ display: inline-flex;
7
+ align-items: center;
8
+ letter-spacing: 0.4px;
9
+ font-weight: 500;
10
+ transition: background-color 250ms;
11
+ border-radius: 8px;
12
+ color: var(--primary-dark);
13
+ svg {
14
+ font-size: 16px;
15
+ margin: 0 4px;
16
+ }
17
+ &.primary {
18
+ background-color: var(--primary);
19
+ color: white;
20
+ }
21
+ &.outlined {
22
+ border: 2px solid var(--primary-o25);
23
+ }
24
+ &:disabled {
25
+ opacity: 0.4;
26
+ cursor: default;
27
+ }
28
+ &:hover:not(:disabled):not(.primary),
29
+ &:active:not(:disabled):not(.primary),
30
+ &.active:not(:disabled):not(.primary) {
31
+ background-color: var(--primary-o25);
32
+ }
33
+ &.primary:hover:not(:disabled),
34
+ &.primary:active:not(:disabled),
35
+ &.primary.active:not(:disabled) {
36
+ background-color: var(--primary-dark);
37
+ }
38
+ &:active:not(:disabled) {
39
+ transform: translateY(2px);
40
+ }
41
+ // Sizes
42
+ &.xs {
43
+ font-size: 10px;
44
+ padding: 4px;
45
+ height: 23px;
46
+ &.outlined {
47
+ padding: 3px;
48
+ border-width: 1px;
49
+ }
50
+ svg {
51
+ font-size: 10px;
52
+ margin-right: 0px;
53
+ }
54
+ }
55
+ &.s {
56
+ font-size: 12px;
57
+ padding: 6px;
58
+ &.outlined {
59
+ padding: 4px;
60
+ }
61
+ svg {
62
+ font-size: 14px;
63
+ }
64
+ }
65
+ &.m {
66
+ font-size: 13px;
67
+ padding: 10px;
68
+ height: 38px;
69
+ &.outlined {
70
+ padding: 8px;
71
+ }
72
+ }
73
+ &.l {
74
+ font-size: 15px;
75
+ padding: 12px;
76
+ &.outlined {
77
+ padding: 10px;
78
+ }
79
+ svg {
80
+ font-size: 18px;
81
+ }
82
+ }
83
+ }
84
+
85
+ .iui-btn-label {
86
+ margin: 0 4px;
87
+ }
88
+
89
+ .iui-icon-btn {
90
+ padding: 6px;
91
+ border-radius: 50%;
92
+ svg {
93
+ margin: 0 !important;
94
+ height: 20px;
95
+ width: 20px;
96
+ }
97
+ }
@@ -0,0 +1,175 @@
1
+ import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
+ import clsx from "clsx";
4
+ import { FC, ReactNode, useCallback, useEffect, useRef } from "react";
5
+ import { createPortal } from "react-dom";
6
+ import { faTriangleExclamation } from "icons/regular/faTriangleExclamation";
7
+ import { ConditionalWrapper } from "Elements/Wrappers/ConditionalWrapper";
8
+ import { faCircleInfo } from "icons/regular/faCircleInfo";
9
+ import { Button } from "Elements/Button/Button";
10
+
11
+ interface Props {
12
+ title?: string;
13
+ titleEl?: ReactNode;
14
+ desc?: string;
15
+ descEl?: ReactNode;
16
+ isOpen: boolean;
17
+ onClose: () => void;
18
+ confirmButton?: {
19
+ label?: string;
20
+ icon?: IconDefinition;
21
+ onClick?: () => void;
22
+ onFormSubmit?: () => void;
23
+ disabled?: boolean;
24
+ keepOpen?: boolean;
25
+ };
26
+ cancelButton?: {
27
+ label?: string;
28
+ icon?: IconDefinition;
29
+ onClick?: () => void;
30
+ };
31
+ additionalButton?: {
32
+ label: string;
33
+ icon?: IconDefinition;
34
+ onClick?: () => void;
35
+ disabled?: boolean;
36
+ };
37
+ noBackgroundClick?: boolean;
38
+ noOverflow?: boolean;
39
+ type?: "info" | "error";
40
+ size?: "m" | "l" | "xl";
41
+ noPadding?: boolean;
42
+ className?: string;
43
+ children?: ReactNode;
44
+ }
45
+
46
+ const typeIcon = {
47
+ info: faCircleInfo,
48
+ error: faTriangleExclamation,
49
+ };
50
+
51
+ export const Dialog: FC<Props> = ({
52
+ title,
53
+ titleEl,
54
+ desc,
55
+ descEl,
56
+ isOpen,
57
+ onClose,
58
+ confirmButton,
59
+ cancelButton,
60
+ additionalButton,
61
+ noBackgroundClick,
62
+ noOverflow,
63
+ type,
64
+ size,
65
+ noPadding,
66
+ className,
67
+ children,
68
+ }) => {
69
+ const dialogRef = useRef<HTMLDivElement>(null);
70
+
71
+ const handleClose = useCallback(() => {
72
+ dialogRef.current?.classList.add("closing");
73
+ setTimeout(onClose, 200);
74
+ }, [dialogRef, onClose]);
75
+
76
+ useEffect(() => {
77
+ if (!noBackgroundClick) {
78
+ const handleClick = (ev: MouseEvent) =>
79
+ ev.target === dialogRef.current && handleClose();
80
+ window.addEventListener("click", handleClick);
81
+ return () => window.removeEventListener("click", handleClick);
82
+ }
83
+ }, [noBackgroundClick, handleClose]);
84
+
85
+ return isOpen
86
+ ? createPortal(
87
+ <div ref={dialogRef} className="iui-dialog">
88
+ <ConditionalWrapper
89
+ condition={!!confirmButton?.onFormSubmit}
90
+ wrapper={(children) => (
91
+ <form
92
+ onSubmit={(e) => {
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+ confirmButton!.onFormSubmit!();
96
+ !confirmButton!.keepOpen && handleClose();
97
+ }}
98
+ >
99
+ {children}
100
+ </form>
101
+ )}
102
+ >
103
+ <div
104
+ className={clsx("iui-dialog-container", size, type, className)}
105
+ >
106
+ {title && <h1>{title}</h1>}
107
+ {titleEl}
108
+ <div
109
+ className={clsx("iui-dialog-content", {
110
+ padding: !noPadding,
111
+ "no-overflow": noOverflow,
112
+ })}
113
+ >
114
+ {type && <FontAwesomeIcon icon={typeIcon[type]} />}
115
+ {desc && <p>{desc}</p>}
116
+ {descEl}
117
+ {children}
118
+ </div>
119
+ <div className="iui-dialog-actions">
120
+ <Button
121
+ label={
122
+ cancelButton?.label || (confirmButton ? "Otkaži" : "Ok")
123
+ }
124
+ icon={cancelButton?.icon}
125
+ primary={!confirmButton}
126
+ onClick={(e) => {
127
+ e.stopPropagation();
128
+ cancelButton?.onClick
129
+ ? cancelButton.onClick()
130
+ : handleClose();
131
+ }}
132
+ />
133
+ {additionalButton && (
134
+ <Button
135
+ label={additionalButton.label}
136
+ icon={additionalButton.icon}
137
+ className="ml-2"
138
+ onClick={
139
+ !!additionalButton.onClick
140
+ ? (e) => {
141
+ e.stopPropagation();
142
+ additionalButton.onClick!();
143
+ handleClose();
144
+ }
145
+ : undefined
146
+ }
147
+ disabled={additionalButton.disabled}
148
+ />
149
+ )}
150
+ {confirmButton && (
151
+ <Button
152
+ label={confirmButton.label || "Potvrdi"}
153
+ icon={confirmButton.icon}
154
+ primary
155
+ className="ml-2"
156
+ onClick={
157
+ !!confirmButton.onClick
158
+ ? (e) => {
159
+ e.stopPropagation();
160
+ confirmButton.onClick!();
161
+ !confirmButton.keepOpen && handleClose();
162
+ }
163
+ : undefined
164
+ }
165
+ disabled={confirmButton.disabled}
166
+ />
167
+ )}
168
+ </div>
169
+ </div>
170
+ </ConditionalWrapper>
171
+ </div>,
172
+ document.body
173
+ )
174
+ : null;
175
+ };
@@ -0,0 +1,39 @@
1
+ import clsx from "clsx";
2
+ import { FC, ReactNode, useEffect, useRef, useState } from "react";
3
+
4
+ interface Props {
5
+ isOpen: boolean;
6
+ className?: string;
7
+ children?: ReactNode;
8
+ }
9
+
10
+ export const Collapse: FC<Props> = ({ isOpen, className, children }) => {
11
+ const [height, setHeight] = useState<number>();
12
+ const ref = useRef<HTMLDivElement>(null);
13
+
14
+ useEffect(() => {
15
+ const observer = new ResizeObserver((entries) => {
16
+ const newHeight = Math.ceil(entries[0].contentRect.height);
17
+ setHeight(newHeight);
18
+ });
19
+
20
+ let observerRefValue: HTMLDivElement;
21
+ if (ref.current) {
22
+ observerRefValue = ref.current;
23
+ observer.observe(observerRefValue);
24
+ }
25
+
26
+ return () => {
27
+ observerRefValue && observer.unobserve(observerRefValue);
28
+ };
29
+ }, [ref]);
30
+
31
+ return (
32
+ <div
33
+ className={clsx("iui-colapse", className)}
34
+ style={{ maxHeight: isOpen ? height : 0 }}
35
+ >
36
+ <div ref={ref}>{children}</div>
37
+ </div>
38
+ );
39
+ };