@aristobyte-ui/dropdown 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 (81) hide show
  1. package/@types/index.d.ts +4 -0
  2. package/@types/styles/scss-modules.d.ts +4 -0
  3. package/assets/svg/i_Copy.svg +1 -0
  4. package/assets/svg/i_Error.svg +1 -0
  5. package/assets/svg/i_Info.svg +1 -0
  6. package/assets/svg/i_Success.svg +1 -0
  7. package/assets/svg/i_Warning.svg +1 -0
  8. package/components/Dropdown/Dropdown.module.scss +41 -0
  9. package/components/Dropdown/index.tsx +175 -0
  10. package/components/DropdownOption/DropdownOption.module.scss +24 -0
  11. package/components/DropdownOption/index.tsx +33 -0
  12. package/components/index.ts +2 -0
  13. package/dist/components/Anchor/index.js +28 -0
  14. package/dist/components/Button/index.js +35 -0
  15. package/dist/components/ButtonGroup/index.js +16 -0
  16. package/dist/components/CodeBlock/index.js +33 -0
  17. package/dist/components/CodeBlock/types.js +1 -0
  18. package/dist/components/Dropdown/index.js +73 -0
  19. package/dist/components/DropdownOption/index.js +13 -0
  20. package/dist/components/MessageBox/index.js +19 -0
  21. package/dist/components/Radio/index.js +10 -0
  22. package/dist/components/RadioGroup/index.js +21 -0
  23. package/dist/components/Spinner/index.js +6 -0
  24. package/dist/components/Switch/index.js +15 -0
  25. package/dist/components/TabSwitchWithSlidingIndicator/index.js +10 -0
  26. package/dist/components/index.js +2 -0
  27. package/dist/index.js +1 -0
  28. package/dist/tsconfig.tsbuildinfo +1 -0
  29. package/dist/types/components/Anchor/index.d.ts +6 -0
  30. package/dist/types/components/Anchor/index.d.ts.map +1 -0
  31. package/dist/types/components/Button/index.d.ts +15 -0
  32. package/dist/types/components/Button/index.d.ts.map +1 -0
  33. package/dist/types/components/ButtonGroup/index.d.ts +13 -0
  34. package/dist/types/components/ButtonGroup/index.d.ts.map +1 -0
  35. package/dist/types/components/CodeBlock/index.d.ts +11 -0
  36. package/dist/types/components/CodeBlock/index.d.ts.map +1 -0
  37. package/dist/types/components/CodeBlock/types.d.ts +3 -0
  38. package/dist/types/components/CodeBlock/types.d.ts.map +1 -0
  39. package/dist/types/components/Dropdown/index.d.ts +14 -0
  40. package/dist/types/components/Dropdown/index.d.ts.map +1 -0
  41. package/dist/types/components/DropdownOption/index.d.ts +12 -0
  42. package/dist/types/components/DropdownOption/index.d.ts.map +1 -0
  43. package/dist/types/components/MessageBox/index.d.ts +14 -0
  44. package/dist/types/components/MessageBox/index.d.ts.map +1 -0
  45. package/dist/types/components/Radio/index.d.ts +17 -0
  46. package/dist/types/components/Radio/index.d.ts.map +1 -0
  47. package/dist/types/components/RadioGroup/index.d.ts +18 -0
  48. package/dist/types/components/RadioGroup/index.d.ts.map +1 -0
  49. package/dist/types/components/Spinner/index.d.ts +9 -0
  50. package/dist/types/components/Spinner/index.d.ts.map +1 -0
  51. package/dist/types/components/Switch/index.d.ts +18 -0
  52. package/dist/types/components/Switch/index.d.ts.map +1 -0
  53. package/dist/types/components/TabSwitchWithSlidingIndicator/index.d.ts +9 -0
  54. package/dist/types/components/TabSwitchWithSlidingIndicator/index.d.ts.map +1 -0
  55. package/dist/types/components/index.d.ts +3 -0
  56. package/dist/types/components/index.d.ts.map +1 -0
  57. package/dist/types/index.d.ts +2 -0
  58. package/dist/types/index.d.ts.map +1 -0
  59. package/dist/types/utils/Portal.d.ts +5 -0
  60. package/dist/types/utils/Portal.d.ts.map +1 -0
  61. package/dist/types/utils/icons.d.ts +8 -0
  62. package/dist/types/utils/icons.d.ts.map +1 -0
  63. package/dist/types/utils/index.d.ts +3 -0
  64. package/dist/types/utils/index.d.ts.map +1 -0
  65. package/dist/types/utils/ripple.d.ts +9 -0
  66. package/dist/types/utils/ripple.d.ts.map +1 -0
  67. package/dist/utils/Portal.js +12 -0
  68. package/dist/utils/icons.js +12 -0
  69. package/dist/utils/index.js +2 -0
  70. package/dist/utils/ripple.js +38 -0
  71. package/eslint.config.mjs +2 -0
  72. package/index.ts +1 -0
  73. package/package.json +44 -0
  74. package/styles/_settings.scss +179 -0
  75. package/tsconfig.json +11 -0
  76. package/turbo/generators/config.ts +30 -0
  77. package/turbo/generators/templates/component.hbs +8 -0
  78. package/utils/Portal.tsx +17 -0
  79. package/utils/icons.ts +13 -0
  80. package/utils/index.ts +2 -0
  81. package/utils/ripple.tsx +54 -0
@@ -0,0 +1,4 @@
1
+ declare module "*.svg" {
2
+ const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
3
+ export default content;
4
+ }
@@ -0,0 +1,4 @@
1
+ declare module "*.module.scss" {
2
+ const classes: { [key: string]: string };
3
+ export default classes;
4
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy-icon lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-octagon-x-icon lucide-octagon-x"><path d="m15 9-6 6"/><path d="M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z"/><path d="m9 9 6 6"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info-icon lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-octagon-alert-icon lucide-octagon-alert"><path d="M12 16h.01"/><path d="M12 8v4"/><path d="M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z"/></svg>
@@ -0,0 +1,41 @@
1
+ @use "../../styles/settings" as *;
2
+
3
+ .dropdown {
4
+ width: max-content;
5
+
6
+ &__button {
7
+ width: max-content;
8
+ }
9
+
10
+ &__box {
11
+ &-overlay {
12
+ backdrop-filter: blur(12px);
13
+ height: 100%;
14
+ left: 0;
15
+ position: fixed;
16
+ top: 0;
17
+ width: 100%;
18
+ z-index: 99999999999;
19
+ }
20
+
21
+ &-options {
22
+ align-items: flex-start;
23
+ background-color: $color-default;
24
+ border-radius: 8px; //TODO: change to dynamic
25
+ box-shadow:
26
+ 0 4px 6px rgba(0, 0, 0, 0.04),
27
+ 0 12px 24px rgba(0, 0, 0, 0.1);
28
+ display: flex;
29
+ flex-direction: column;
30
+ opacity: 1;
31
+ min-width: 300px;
32
+ padding: 4px;
33
+ position: absolute;
34
+ transition:
35
+ transform 200ms $cubic-bezier-secondary,
36
+ opacity 150ms ease;
37
+ width: 100%;
38
+ z-index: 99999999999;
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,175 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { DropdownOption, type IDropdownOption } from "../DropdownOption";
5
+
6
+ import { AnimatePresence, motion } from "framer-motion";
7
+
8
+ import { Button } from "@aristobyte-ui/button";
9
+ import { Portal } from "../../utils/Portal";
10
+
11
+ import styles from "./Dropdown.module.scss";
12
+
13
+ export interface IDropdown {
14
+ children:
15
+ | React.ReactElement<IDropdownOption>
16
+ | React.ReactElement<IDropdownOption>[];
17
+ value: string;
18
+ appearance?:
19
+ | "solid"
20
+ | "outline"
21
+ | "outline-dashed"
22
+ | "no-outline"
23
+ | "glowing";
24
+ onChange?: (newValue: string) => void;
25
+ initiallyOpened?: boolean;
26
+ placeholder?: string;
27
+ disabled?: boolean;
28
+ className?: string;
29
+ }
30
+
31
+ type PositionType = {
32
+ top: 0;
33
+ left: 0;
34
+ width: 0;
35
+ };
36
+
37
+ export const Dropdown: React.FC<IDropdown> = ({
38
+ children,
39
+ value,
40
+ onChange,
41
+ appearance = "outline",
42
+ placeholder = "Select",
43
+ className = "",
44
+ initiallyOpened = false,
45
+ disabled = false,
46
+ }) => {
47
+ const [isOpened, setIsOpened] = React.useState<boolean>(initiallyOpened);
48
+ const [selected, setSelected] = React.useState<string>(value);
49
+ const [position, setPosition] = React.useState<PositionType>({
50
+ top: 0,
51
+ left: 0,
52
+ width: 0,
53
+ });
54
+ const [dropdownHeight, setDropdownHeight] = React.useState(0);
55
+ const [buttonHeight, setButtonHeight] = React.useState(0);
56
+ const buttonRef = React.useRef<HTMLButtonElement>(null);
57
+ const boxRef = React.useRef<HTMLDivElement>(null);
58
+ const uniqueId = React.useId();
59
+
60
+ React.useLayoutEffect(() => {
61
+ if (!isOpened) {
62
+ return;
63
+ }
64
+
65
+ if (boxRef.current) {
66
+ setDropdownHeight(boxRef.current.getBoundingClientRect().height);
67
+ }
68
+
69
+ if (buttonRef.current) {
70
+ setButtonHeight(buttonRef.current.getBoundingClientRect().height);
71
+ }
72
+ }, [isOpened]);
73
+
74
+ const options = React.Children.toArray(children).filter(
75
+ (child): child is React.ReactElement<IDropdownOption> =>
76
+ React.isValidElement(child) && child.type === DropdownOption
77
+ );
78
+
79
+ const isValidValue = () => {
80
+ return !!options.find(({ props }) => props.value === value);
81
+ };
82
+
83
+ const handleChange = (currentRadioValue: string) => {
84
+ onChange?.(currentRadioValue);
85
+ setSelected(currentRadioValue);
86
+ setIsOpened(false);
87
+ };
88
+
89
+ const handleToggle = () => {
90
+ if (disabled) return;
91
+
92
+ const rect = buttonRef.current?.getBoundingClientRect();
93
+ if (!rect) return;
94
+
95
+ const spaceBelow = window.innerHeight - rect.bottom;
96
+ const spaceAbove = rect.top;
97
+
98
+ const shouldOpenUpwards =
99
+ dropdownHeight > 0 &&
100
+ spaceBelow < dropdownHeight &&
101
+ spaceAbove > dropdownHeight;
102
+
103
+ const finalPosition = {
104
+ top: shouldOpenUpwards
105
+ ? rect.top + window.scrollY - dropdownHeight - buttonHeight / 2
106
+ : rect.top + window.scrollY + buttonHeight + 6,
107
+ left: rect.left + window.scrollX,
108
+ width: rect.width,
109
+ } as PositionType;
110
+
111
+ setPosition(finalPosition);
112
+ setIsOpened((prev) => !prev);
113
+ };
114
+
115
+ if (!isValidValue()) {
116
+ throw new Error(
117
+ 'The "value" prop did not match with any of the DropdownOption "value" prop'
118
+ );
119
+ }
120
+
121
+ return (
122
+ <>
123
+ <div className={`${styles["dropdown"]} ${className}`}>
124
+ <Button
125
+ {...{ ref: buttonRef }}
126
+ className={styles["dropdown__button"]}
127
+ appearance={appearance}
128
+ onClick={handleToggle}
129
+ disabled={disabled}
130
+ >
131
+ {placeholder}
132
+ </Button>
133
+ </div>
134
+
135
+ <Portal>
136
+ <AnimatePresence>
137
+ {isOpened && (
138
+ <div className={styles["dropdown__box"]}>
139
+ <motion.div
140
+ className={styles["dropdown__box-overlay"]}
141
+ initial={{ opacity: 0 }}
142
+ animate={{ opacity: 1 }}
143
+ exit={{ opacity: 0 }}
144
+ transition={{ duration: 0.3, ease: "easeIn" }}
145
+ onClick={() => setIsOpened(false)}
146
+ />
147
+ <motion.div
148
+ ref={boxRef}
149
+ className={styles["dropdown__box-options"]}
150
+ initial={{ opacity: 0, y: 20, scale: 0.95 }}
151
+ animate={{ opacity: 1, y: 0, scale: 1 }}
152
+ exit={{ opacity: 0, y: 20, scale: 0.95 }}
153
+ transition={{ duration: 0.2, ease: "easeIn" }}
154
+ style={{
155
+ top: position.top,
156
+ left: position.left,
157
+ width: position.width,
158
+ }}
159
+ >
160
+ {options.map(({ props }) => (
161
+ <DropdownOption
162
+ {...props}
163
+ key={`${props.value}-${uniqueId}`}
164
+ selectedValue={selected}
165
+ onChange={() => handleChange(props.value)}
166
+ />
167
+ ))}
168
+ </motion.div>
169
+ </div>
170
+ )}
171
+ </AnimatePresence>
172
+ </Portal>
173
+ </>
174
+ );
175
+ };
@@ -0,0 +1,24 @@
1
+ @use "../../styles/settings" as *;
2
+
3
+ .dropdown-option {
4
+ border-radius: 8px; //TODO: change to dynamic
5
+ color: $white;
6
+ font-size: 14px;
7
+ font-weight: 500;
8
+ padding: 10px 16px;
9
+ text-align: left;
10
+ transition: all 120ms ease-out;
11
+ width: 100%;
12
+
13
+ &:hover {
14
+ background-color: $color-default-hover;
15
+ }
16
+
17
+ &__title {
18
+ color: $white;
19
+ }
20
+
21
+ &__description {
22
+ color: rgba($white, 0.6);
23
+ }
24
+ }
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+
3
+ import styles from "./DropdownOption.module.scss";
4
+
5
+ export interface IDropdownOption {
6
+ children: string;
7
+ value: string;
8
+ onChange?: () => void;
9
+ selectedValue?: string;
10
+ description?: string;
11
+ icon?: string;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ export const DropdownOption: React.FC<IDropdownOption> = ({
16
+ children,
17
+ // value,
18
+ // selectedValue,
19
+ onChange,
20
+ // icon,
21
+ description,
22
+ // disabled,
23
+ }) => {
24
+ // const isSelected = selectedValue === value;
25
+ return (
26
+ <button className={styles["dropdown-option"]} onClick={onChange}>
27
+ <div className={styles["dropdown-option__content"]}>
28
+ <h3 className={styles["dropdown-option__title"]}>{children}</h3>
29
+ <p className={styles["dropdown-option__description"]}>{description}</p>
30
+ </div>
31
+ </button>
32
+ );
33
+ };
@@ -0,0 +1,2 @@
1
+ export { Dropdown } from "./Dropdown";
2
+ export { DropdownOption } from "./DropdownOption";
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import { renderRipple } from "../../utils";
16
+ import styles from "./Anchor.module.scss";
17
+ export const Anchor = (_a) => {
18
+ var { href, variant = "default", className = "", children, onClick } = _a, props = __rest(_a, ["href", "variant", "className", "children", "onClick"]);
19
+ const ref = React.useRef(null);
20
+ const handleClick = (e) => {
21
+ const { clientX, clientY } = e;
22
+ renderRipple({ ref, clientX, clientY });
23
+ if (onClick) {
24
+ onClick(e);
25
+ }
26
+ };
27
+ return (_jsx("a", Object.assign({}, props, { ref: ref, href: href, className: `anchor ${styles["anchor"]} ${styles[`anchor--${variant}`]} ${className}`, onClick: handleClick, children: children })));
28
+ };
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import { Spinner } from "../Spinner";
16
+ import { renderRipple } from "../../utils";
17
+ import styles from "./Button.module.scss";
18
+ export const Button = (_a) => {
19
+ var { onClick, children, variant = "default", appearance = "solid", size = "md", radius = "md", icon, spinnerType = "default", isLoading = false, disabled, className = "", dangerouslySetInnerHTML } = _a, restProps = __rest(_a, ["onClick", "children", "variant", "appearance", "size", "radius", "icon", "spinnerType", "isLoading", "disabled", "className", "dangerouslySetInnerHTML"]);
20
+ const ref = React.useRef(null);
21
+ const handleClick = (e) => {
22
+ const { clientX, clientY } = e;
23
+ renderRipple({ ref, clientX, clientY });
24
+ if (onClick) {
25
+ onClick(e);
26
+ }
27
+ };
28
+ const Children = () => {
29
+ var _a;
30
+ return (_jsxs(_Fragment, { children: [isLoading && (_jsx(Spinner, { size: size, variant: variant, type: spinnerType, className: styles["spinner"] })), icon && (_jsx("span", { className: `${styles["icon"]} ${styles[`icon--${(_a = icon.align) !== null && _a !== void 0 ? _a : "left"}`]}`, children: React.createElement(icon.component) })), children] }));
31
+ };
32
+ return (_jsx("button", Object.assign({ ref: ref, disabled: disabled || isLoading, className: `${styles["button"]} ${styles[`button-variant--${variant}`]} ${styles[`button-appearance--${appearance}`]} ${styles[`button-size--${size}`]} ${styles[`button-radius--${radius}`]} ${isLoading ? styles["button--loading"] : ""} ${className}`, onClick: handleClick }, (dangerouslySetInnerHTML
33
+ ? { dangerouslySetInnerHTML }
34
+ : { children: _jsx(Children, {}) }), restProps)));
35
+ };
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Button } from "../Button";
5
+ import styles from "./ButtonGroup.module.scss";
6
+ export const ButtonGroup = ({ children, align = "horizontal", variant = "default", size = "md", radius = "md", disabled, className = "", }) => {
7
+ return (_jsx("div", { className: `${styles["button-group"]} ${styles[`button-group-variant--${variant}`]} ${styles[`button-group-size--${size}`]} ${styles[`button-group-radius--${radius}`]} ${styles[`button-group-align--${align}`]} ${className}`, children: React.Children.toArray(children)
8
+ .filter((child) => React.isValidElement(child) && child.type === Button)
9
+ .map((child, index) => React.cloneElement(child, {
10
+ key: index || child.key,
11
+ size: size || child.props.size,
12
+ disabled: disabled || child.props.disabled,
13
+ variant: variant || child.props.variant,
14
+ radius: "none",
15
+ })) }));
16
+ };
@@ -0,0 +1,33 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ import * as React from "react";
12
+ import { getSingletonHighlighter } from "shiki";
13
+ import { Button } from "../Button";
14
+ import { Icons } from "../../utils";
15
+ import styles from "./CodeBlock.module.scss";
16
+ export const CodeBlock = ({ code, lang = "tsx", theme = "nord", className = "", }) => {
17
+ const [html, setHtml] = React.useState("");
18
+ React.useEffect(() => {
19
+ (() => __awaiter(void 0, void 0, void 0, function* () {
20
+ setHtml((yield getSingletonHighlighter({
21
+ themes: [theme],
22
+ langs: [lang],
23
+ })).codeToHtml(code, {
24
+ lang,
25
+ theme,
26
+ }));
27
+ }))();
28
+ }, [code, lang, theme]);
29
+ const copyToClipboard = () => __awaiter(void 0, void 0, void 0, function* () {
30
+ yield navigator.clipboard.writeText(code);
31
+ });
32
+ return (_jsxs("div", { className: `code-block ${styles["code-block"]} ${className}`, children: [_jsx("div", { className: styles["code-block__container"], dangerouslySetInnerHTML: { __html: html } }), _jsx(Button, { onClick: copyToClipboard, className: styles["code-block__button"], dangerouslySetInnerHTML: { __html: Icons.Copy } })] }));
33
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { createElement as _createElement } from "react";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
+ import * as React from "react";
5
+ import { DropdownOption } from "../DropdownOption";
6
+ import { AnimatePresence, motion } from "framer-motion";
7
+ import { Button } from "@aristobyte-ui/button";
8
+ import { Portal } from "../../utils/Portal";
9
+ import styles from "./Dropdown.module.scss";
10
+ export const Dropdown = ({ children, value, onChange, appearance = "outline", placeholder = "Select", className = "", initiallyOpened = false, disabled = false, }) => {
11
+ const [isOpened, setIsOpened] = React.useState(initiallyOpened);
12
+ const [selected, setSelected] = React.useState(value);
13
+ const [position, setPosition] = React.useState({
14
+ top: 0,
15
+ left: 0,
16
+ width: 0,
17
+ });
18
+ const [dropdownHeight, setDropdownHeight] = React.useState(0);
19
+ const [buttonHeight, setButtonHeight] = React.useState(0);
20
+ const buttonRef = React.useRef(null);
21
+ const boxRef = React.useRef(null);
22
+ const uniqueId = React.useId();
23
+ React.useLayoutEffect(() => {
24
+ if (!isOpened) {
25
+ return;
26
+ }
27
+ if (boxRef.current) {
28
+ setDropdownHeight(boxRef.current.getBoundingClientRect().height);
29
+ }
30
+ if (buttonRef.current) {
31
+ setButtonHeight(buttonRef.current.getBoundingClientRect().height);
32
+ }
33
+ }, [isOpened]);
34
+ const options = React.Children.toArray(children).filter((child) => React.isValidElement(child) && child.type === DropdownOption);
35
+ const isValidValue = () => {
36
+ return !!options.find(({ props }) => props.value === value);
37
+ };
38
+ const handleChange = (currentRadioValue) => {
39
+ onChange === null || onChange === void 0 ? void 0 : onChange(currentRadioValue);
40
+ setSelected(currentRadioValue);
41
+ setIsOpened(false);
42
+ };
43
+ const handleToggle = () => {
44
+ var _a;
45
+ if (disabled)
46
+ return;
47
+ const rect = (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
48
+ if (!rect)
49
+ return;
50
+ const spaceBelow = window.innerHeight - rect.bottom;
51
+ const spaceAbove = rect.top;
52
+ const shouldOpenUpwards = dropdownHeight > 0 &&
53
+ spaceBelow < dropdownHeight &&
54
+ spaceAbove > dropdownHeight;
55
+ const finalPosition = {
56
+ top: shouldOpenUpwards
57
+ ? rect.top + window.scrollY - dropdownHeight - buttonHeight / 2
58
+ : rect.top + window.scrollY + buttonHeight + 6,
59
+ left: rect.left + window.scrollX,
60
+ width: rect.width,
61
+ };
62
+ setPosition(finalPosition);
63
+ setIsOpened((prev) => !prev);
64
+ };
65
+ if (!isValidValue()) {
66
+ throw new Error('The "value" prop did not match with any of the DropdownOption "value" prop');
67
+ }
68
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles["dropdown"]} ${className}`, children: _jsx(Button, { ref: buttonRef, className: styles["dropdown__button"], appearance: appearance, onClick: handleToggle, disabled: disabled, children: placeholder }) }), _jsx(Portal, { children: _jsx(AnimatePresence, { children: isOpened && (_jsxs("div", { className: styles["dropdown__box"], children: [_jsx(motion.div, { className: styles["dropdown__box-overlay"], initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.3, ease: "easeIn" }, onClick: () => setIsOpened(false) }), _jsx(motion.div, { ref: boxRef, className: styles["dropdown__box-options"], initial: { opacity: 0, y: 20, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: 20, scale: 0.95 }, transition: { duration: 0.2, ease: "easeIn" }, style: {
69
+ top: position.top,
70
+ left: position.left,
71
+ width: position.width,
72
+ }, children: options.map(({ props }) => (_createElement(DropdownOption, Object.assign({}, props, { key: `${props.value}-${uniqueId}`, selectedValue: selected, onChange: () => handleChange(props.value) })))) })] })) }) })] }));
73
+ };
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styles from "./DropdownOption.module.scss";
3
+ export const DropdownOption = ({ children,
4
+ // value,
5
+ // selectedValue,
6
+ onChange,
7
+ // icon,
8
+ description,
9
+ // disabled,
10
+ }) => {
11
+ // const isSelected = selectedValue === value;
12
+ return (_jsx("button", { className: styles["dropdown-option"], onClick: onChange, children: _jsxs("div", { className: styles["dropdown-option__content"], children: [_jsx("h3", { className: styles["dropdown-option__title"], children: children }), _jsx("p", { className: styles["dropdown-option__description"], children: description })] }) }));
13
+ };
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icons } from "../../utils";
3
+ import styles from "./MessageBox.module.scss";
4
+ const renderIcon = (variant) => {
5
+ switch (variant) {
6
+ case "warning":
7
+ return Icons.Warning;
8
+ case "success":
9
+ return Icons.Success;
10
+ case "error":
11
+ return Icons.Error;
12
+ case "info":
13
+ default:
14
+ return Icons.Info;
15
+ }
16
+ };
17
+ export const MessageBox = ({ children, className = "", variant = "default", withIcon = false, customIcon = null, radius = "md", type = "outline", }) => (_jsxs("div", { className: `message-box ${styles["message-box"]} ${styles[`message-box-type--${type}`]} ${styles[`message-box-radius--${radius}`]} ${styles[`message-box--${variant}`]} ${className}`, children: [withIcon && (_jsx("span", { className: `${styles["message-box__icon"]} ${styles[`message-box__icon--${variant}`]}`, dangerouslySetInnerHTML: {
18
+ __html: customIcon ? customIcon : renderIcon(variant),
19
+ } })), _jsx("p", { className: `${styles["message-box__content"]}`, dangerouslySetInnerHTML: { __html: children || "" } })] }));
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styles from "./Radio.module.scss";
3
+ export const Radio = ({ children, value, checked, name, disabled = false, highlightLabel = false, className = "", size = "md", variant = "default", appearance = "default", alignLabel = "right", onChange, }) => {
4
+ const handleChange = () => {
5
+ if (!disabled && onChange) {
6
+ onChange(value);
7
+ }
8
+ };
9
+ return (_jsxs("label", { className: `${styles["radio"]} ${styles[`radio-align-label--${alignLabel}`]} ${styles[`radio-appearance--${appearance}`]} ${styles[`radio-variant--${variant}`]} ${styles[`radio-size--${size}`]} ${disabled ? styles["radio--disabled"] : ""} ${className}`, children: [_jsx("input", { type: "radio", name: name, value: value, checked: checked, disabled: disabled, onChange: handleChange, className: styles["radio__input"] }), _jsx("span", { className: styles["radio__control"] }), children && (_jsx("span", { className: `${styles["radio__label"]} ${highlightLabel ? styles["radio__label--highlight-label"] : ""}`, children: children }))] }));
10
+ };
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createElement as _createElement } from "react";
4
+ import * as React from "react";
5
+ import { Radio } from "../Radio";
6
+ import styles from "./RadioGroup.module.scss";
7
+ export const RadioGroup = ({ name, value, onChange, children, disabled = false, highlightLabel = false, className = "", size = "md", variant = "default", appearance = "outline", align = "horizontal", alignLabel = "right", }) => {
8
+ const uniqueId = React.useId();
9
+ const [currentValue, setCurrentValue] = React.useState(value);
10
+ const radios = React.Children.toArray(children).filter((child) => React.isValidElement(child) && child.type === Radio);
11
+ const handleChange = (currentRadioValue) => {
12
+ if (onChange) {
13
+ onChange(currentRadioValue);
14
+ }
15
+ setCurrentValue(currentRadioValue);
16
+ };
17
+ return (_jsx("div", { className: `${styles["radio-group"]} ${styles[`radio-group--${align}`]} ${className}`, children: radios.map(({ props }) => {
18
+ var _a, _b, _c, _d, _e, _f;
19
+ return (_createElement(Radio, Object.assign({}, props, { key: `${name}-${props.value}-${uniqueId}`, name: `${name}-${props.value}-${uniqueId}`, checked: props.value === currentValue, onChange: () => handleChange(props.value), disabled: (_a = props.disabled) !== null && _a !== void 0 ? _a : disabled, size: (_b = props.size) !== null && _b !== void 0 ? _b : size, variant: (_c = props.variant) !== null && _c !== void 0 ? _c : variant, appearance: (_d = props.appearance) !== null && _d !== void 0 ? _d : appearance, highlightLabel: (_e = props.highlightLabel) !== null && _e !== void 0 ? _e : highlightLabel, alignLabel: (_f = props.alignLabel) !== null && _f !== void 0 ? _f : alignLabel })));
20
+ }) }, uniqueId));
21
+ };
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import styles from "./Spinner.module.scss";
4
+ export const Spinner = ({ type = "default", variant = "default", size = "md", className = "", }) => {
5
+ return (_jsx("div", { className: `spinner ${styles[`spinner-type--${type}`]} ${styles[`spinner-variant--${variant}`]} ${styles[`spinner-size--${size}`]} ${className}` }));
6
+ };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import styles from "./Switch.module.scss";
5
+ //@TODO: Fix the the switch styling, which is breaking when continuously clicking on the component
6
+ export const Switch = ({ label, alignLabel = "vertical", checked, switchSize = "md", variant = "default", disabled = false, trackIcon, thumbIcon, className = "", onChange, }) => {
7
+ const id = React.useId();
8
+ const [isChecked, setIsChecked] = React.useState(!!checked);
9
+ const handleChange = () => {
10
+ setIsChecked((prev) => !prev);
11
+ if (onChange)
12
+ onChange();
13
+ };
14
+ return (_jsxs("label", { htmlFor: id, className: `${styles["switch"]} ${styles[`switch-size--${switchSize}`]} ${styles[`switch-variant--${variant}`]} ${styles[`switch-align-label--${alignLabel}`]} ${disabled ? styles["switch--disabled"] : ""} ${className}`, children: [_jsx("input", { id: id, type: "checkbox", disabled: disabled, checked: isChecked, onChange: handleChange }), _jsxs("span", { className: styles["switch__track"], children: [trackIcon && trackIcon.checked && (_jsx("span", { className: `${styles["switch__track-icon"]} ${styles["switch__track-icon--checked"]}`, children: React.createElement(trackIcon.checked) })), _jsx("span", { className: styles["switch__thumb"], children: thumbIcon && (_jsx("span", { className: styles["switch__thumb-icon"], children: React.createElement(thumbIcon) })) }), trackIcon && trackIcon.unchecked && (_jsx("span", { className: `${styles["switch__track-icon"]} ${styles["switch__track-icon--unchecked"]}`, children: React.createElement(trackIcon.unchecked) }))] }), label && _jsx("span", { className: styles["switch__label"], children: label })] }));
15
+ };
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import styles from "./TabSwitchWithSlidingIndicator.module.scss";
4
+ export const TabSwitchWithSlidingIndicator = ({ tabs }) => {
5
+ const [activeIndex, setActiveIndex] = React.useState(0);
6
+ const currentIndex = tabs.findIndex((_, i) => i === activeIndex);
7
+ return (_jsxs("div", { className: `tab-switch-with-sliding-indicator ${styles["tab-switch-with-sliding-indicator"]}`, children: [_jsxs("div", { className: styles["tab-switch-with-sliding-indicator__tabs"], children: [tabs.map(({ buttonContent }, index) => (_jsx("button", { className: `${styles["tab-switch-with-sliding-indicator__tab"]} ${activeIndex === index ? styles[" tab-switch-with-sliding-indicator__tab--active"] : ""}`, onClick: () => setActiveIndex(index), children:
8
+ // @TODO: This should be fixed: from consumer level we should be able to pass only string not components - once this is resolved the active tab should have text color white. Since we pass a whole component from consumer level it's hard to identify the most inner component which contains text, so we can change the color of it in different scenarios
9
+ buttonContent || index }, index))), _jsx("span", { className: styles["tab-switch-with-sliding-indicator__bar"], style: { left: `${currentIndex * 80}px` } })] }), _jsx("div", { className: styles["tab-switch-with-sliding-indicator__content"], children: tabs[currentIndex].content })] }));
10
+ };
@@ -0,0 +1,2 @@
1
+ export { Dropdown } from "./Dropdown";
2
+ export { DropdownOption } from "./DropdownOption";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { Dropdown, DropdownOption } from "./components";