oneslash-design-system 1.1.34 → 1.2.1
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/components/menu.tsx +35 -0
- package/components/navigation.tsx +27 -0
- package/components/select.tsx +253 -0
- package/dist/components/menu.d.ts +9 -0
- package/dist/components/menu.jsx +13 -0
- package/dist/components/navigation.d.ts +7 -0
- package/dist/components/navigation.jsx +9 -0
- package/dist/components/select.d.ts +19 -0
- package/dist/components/select.jsx +235 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/output.css +80 -0
- package/index.ts +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
|
|
4
|
+
interface MenuProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
width?: number | string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Menu = forwardRef<HTMLDivElement, MenuProps>(
|
|
11
|
+
({ children, width, className = '' }, ref) => {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={`
|
|
16
|
+
bg-light-background-accent300 dark:bg-dark-background-accent300
|
|
17
|
+
rounded-[8px]
|
|
18
|
+
shadow-lg
|
|
19
|
+
overflow-hidden
|
|
20
|
+
${className}
|
|
21
|
+
`}
|
|
22
|
+
style={{ width: width || 'auto' }}
|
|
23
|
+
>
|
|
24
|
+
<div className="p-[10px]">
|
|
25
|
+
{children}
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
Menu.displayName = 'Menu';
|
|
33
|
+
|
|
34
|
+
export default Menu;
|
|
35
|
+
export { Menu };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface NavigationProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function Navigation({
|
|
10
|
+
children,
|
|
11
|
+
className = '',
|
|
12
|
+
}: NavigationProps) {
|
|
13
|
+
return (
|
|
14
|
+
<nav
|
|
15
|
+
className={`
|
|
16
|
+
bg-light-background-default dark:bg-dark-background-default
|
|
17
|
+
border-r border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled
|
|
18
|
+
p-[10px]
|
|
19
|
+
${className}
|
|
20
|
+
`}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
</nav>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Navigation };
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useState, useEffect, useRef, useCallback, SVGProps, JSX } from 'react';
|
|
3
|
+
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
|
4
|
+
import Menu from './menu';
|
|
5
|
+
import MenuItem from './menuItem';
|
|
6
|
+
|
|
7
|
+
type IconType = (props: SVGProps<SVGSVGElement>) => JSX.Element;
|
|
8
|
+
|
|
9
|
+
export interface SelectOption {
|
|
10
|
+
value: string;
|
|
11
|
+
label: string;
|
|
12
|
+
iconName?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface SelectProps {
|
|
16
|
+
value?: string | string[];
|
|
17
|
+
options: SelectOption[];
|
|
18
|
+
onChange?: (value: string | string[]) => void;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
decoIconName?: string;
|
|
22
|
+
width?: number | string;
|
|
23
|
+
multiple?: boolean;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function Select({
|
|
28
|
+
value,
|
|
29
|
+
options,
|
|
30
|
+
onChange,
|
|
31
|
+
disabled = false,
|
|
32
|
+
placeholder = 'Label',
|
|
33
|
+
decoIconName,
|
|
34
|
+
width,
|
|
35
|
+
multiple = false,
|
|
36
|
+
className = '',
|
|
37
|
+
}: SelectProps) {
|
|
38
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
39
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
40
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
41
|
+
const [DecoIcon, setDecoIcon] = useState<IconType | null>(null);
|
|
42
|
+
const [mounted, setMounted] = useState(false);
|
|
43
|
+
|
|
44
|
+
const selectRef = useRef<HTMLDivElement>(null);
|
|
45
|
+
const menuRef = useRef<HTMLDivElement>(null);
|
|
46
|
+
|
|
47
|
+
// Handle SSR
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setMounted(true);
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
// Load decoration icon
|
|
53
|
+
const loadIcon = useCallback(async (iconName?: string) => {
|
|
54
|
+
if (!iconName) return null;
|
|
55
|
+
try {
|
|
56
|
+
const module = await import('@heroicons/react/24/outline');
|
|
57
|
+
const IconComponent = module[iconName as keyof typeof module] as IconType;
|
|
58
|
+
return IconComponent || null;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(`Failed to load icon ${iconName}:`, error);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const fetchIcon = async () => {
|
|
67
|
+
if (decoIconName) {
|
|
68
|
+
setDecoIcon(await loadIcon(decoIconName));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
fetchIcon();
|
|
72
|
+
}, [decoIconName, loadIcon]);
|
|
73
|
+
|
|
74
|
+
// Close menu when clicking outside
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!mounted) return;
|
|
77
|
+
|
|
78
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
79
|
+
if (
|
|
80
|
+
selectRef.current &&
|
|
81
|
+
menuRef.current &&
|
|
82
|
+
!selectRef.current.contains(event.target as Node) &&
|
|
83
|
+
!menuRef.current.contains(event.target as Node)
|
|
84
|
+
) {
|
|
85
|
+
setIsOpen(false);
|
|
86
|
+
setIsFocused(false);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (isOpen) {
|
|
91
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
96
|
+
};
|
|
97
|
+
}, [isOpen, mounted]);
|
|
98
|
+
|
|
99
|
+
const handleToggle = () => {
|
|
100
|
+
if (disabled) return;
|
|
101
|
+
setIsOpen(!isOpen);
|
|
102
|
+
setIsFocused(!isOpen);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const handleSelect = (optionValue: string) => {
|
|
106
|
+
if (multiple) {
|
|
107
|
+
const currentValues = Array.isArray(value) ? value : [];
|
|
108
|
+
const newValues = currentValues.includes(optionValue)
|
|
109
|
+
? currentValues.filter(v => v !== optionValue)
|
|
110
|
+
: [...currentValues, optionValue];
|
|
111
|
+
onChange?.(newValues);
|
|
112
|
+
} else {
|
|
113
|
+
onChange?.(optionValue);
|
|
114
|
+
setIsOpen(false);
|
|
115
|
+
setIsFocused(false);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const getDisplayLabel = () => {
|
|
120
|
+
if (!value) return placeholder;
|
|
121
|
+
|
|
122
|
+
if (multiple && Array.isArray(value)) {
|
|
123
|
+
if (value.length === 0) return placeholder;
|
|
124
|
+
const labels = value
|
|
125
|
+
.map(v => options.find(opt => opt.value === v)?.label)
|
|
126
|
+
.filter(Boolean);
|
|
127
|
+
return labels.join(', ');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return options.find(opt => opt.value === value)?.label || placeholder;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const isSelected = (optionValue: string) => {
|
|
134
|
+
if (multiple && Array.isArray(value)) {
|
|
135
|
+
return value.includes(optionValue);
|
|
136
|
+
}
|
|
137
|
+
return value === optionValue;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Determine border styles based on state
|
|
141
|
+
const getBorderStyles = () => {
|
|
142
|
+
if (disabled) {
|
|
143
|
+
return 'border border-light-actionOutlinedBorder-disabled dark:border-dark-actionOutlinedBorder-disabled';
|
|
144
|
+
}
|
|
145
|
+
if (isFocused || isOpen) {
|
|
146
|
+
return 'border border-light-accent-main dark:border-dark-accent-main outline outline-1 outline-light-accent-main dark:outline-dark-accent-main outline-offset-0';
|
|
147
|
+
}
|
|
148
|
+
if (isHovered) {
|
|
149
|
+
return 'border border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled';
|
|
150
|
+
}
|
|
151
|
+
return 'border border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled';
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Determine background color
|
|
155
|
+
const getBackgroundColor = () => {
|
|
156
|
+
if (isHovered && !isOpen && !disabled) {
|
|
157
|
+
return 'bg-light-action-hover dark:bg-dark-action-hover';
|
|
158
|
+
}
|
|
159
|
+
return 'bg-light-background-default dark:bg-dark-background-default';
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Determine text color
|
|
163
|
+
const getTextColor = () => {
|
|
164
|
+
if (disabled) {
|
|
165
|
+
return 'text-light-text-disabled dark:text-dark-text-disabled';
|
|
166
|
+
}
|
|
167
|
+
return 'text-light-text-primary dark:text-dark-text-primary';
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Determine icon color
|
|
171
|
+
const getIconColor = () => {
|
|
172
|
+
if (disabled) {
|
|
173
|
+
return 'text-light-text-disabled dark:text-dark-text-disabled';
|
|
174
|
+
}
|
|
175
|
+
return 'text-light-text-secondary dark:text-dark-text-secondary';
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<div className={`relative ${className}`} style={{ width: width || '100%' }}>
|
|
180
|
+
{/* Select Button */}
|
|
181
|
+
<div
|
|
182
|
+
ref={selectRef}
|
|
183
|
+
className={`
|
|
184
|
+
rounded-[8px]
|
|
185
|
+
${getBorderStyles()}
|
|
186
|
+
${getBackgroundColor()}
|
|
187
|
+
${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
|
|
188
|
+
transition-all duration-200 ease-in-out
|
|
189
|
+
outline-none
|
|
190
|
+
`}
|
|
191
|
+
onClick={handleToggle}
|
|
192
|
+
onMouseEnter={() => !disabled && setIsHovered(true)}
|
|
193
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
194
|
+
tabIndex={disabled ? -1 : 0}
|
|
195
|
+
onKeyDown={(e) => {
|
|
196
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
handleToggle();
|
|
199
|
+
}
|
|
200
|
+
}}
|
|
201
|
+
>
|
|
202
|
+
{/* Inner Content Container with Padding */}
|
|
203
|
+
<div className={`flex items-center justify-between p-2 ${getTextColor()}`}>
|
|
204
|
+
{/* Content Container */}
|
|
205
|
+
<div className="flex items-center space-x-1 flex-1 overflow-hidden">
|
|
206
|
+
{/* Optional Decoration Icon */}
|
|
207
|
+
{DecoIcon && (
|
|
208
|
+
<DecoIcon className={`w-6 h-6 flex-shrink-0 ${getIconColor()}`} />
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
{/* Display Text */}
|
|
212
|
+
<span className="text-body1 truncate">
|
|
213
|
+
{getDisplayLabel()}
|
|
214
|
+
</span>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
{/* Chevron Icon */}
|
|
218
|
+
<ChevronDownIcon
|
|
219
|
+
className={`
|
|
220
|
+
w-6 h-6 flex-shrink-0 ml-1
|
|
221
|
+
${getIconColor()}
|
|
222
|
+
transition-transform duration-200
|
|
223
|
+
${isOpen ? 'transform rotate-180' : ''}
|
|
224
|
+
`}
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
{/* Dropdown Menu */}
|
|
230
|
+
{mounted && isOpen && (
|
|
231
|
+
<div
|
|
232
|
+
className="absolute z-50 mt-1 left-0"
|
|
233
|
+
style={{ width: width || '100%' }}
|
|
234
|
+
>
|
|
235
|
+
<Menu ref={menuRef} width={width || '100%'}>
|
|
236
|
+
{options.map((option) => (
|
|
237
|
+
<MenuItem
|
|
238
|
+
key={option.value}
|
|
239
|
+
label={option.label}
|
|
240
|
+
iconName={option.iconName}
|
|
241
|
+
isSelected={isSelected(option.value)}
|
|
242
|
+
onClick={() => handleSelect(option.value)}
|
|
243
|
+
className="w-full"
|
|
244
|
+
/>
|
|
245
|
+
))}
|
|
246
|
+
</Menu>
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export { Select };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface MenuProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
width?: number | string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const Menu: React.ForwardRefExoticComponent<MenuProps & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
export default Menu;
|
|
9
|
+
export { Menu };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
var Menu = forwardRef(function (_a, ref) {
|
|
4
|
+
var children = _a.children, width = _a.width, _b = _a.className, className = _b === void 0 ? '' : _b;
|
|
5
|
+
return (<div ref={ref} className={"\n bg-light-background-accent300 dark:bg-dark-background-accent300\n rounded-[8px]\n shadow-lg\n overflow-hidden\n ".concat(className, "\n ")} style={{ width: width || 'auto' }}>
|
|
6
|
+
<div className="p-[10px]">
|
|
7
|
+
{children}
|
|
8
|
+
</div>
|
|
9
|
+
</div>);
|
|
10
|
+
});
|
|
11
|
+
Menu.displayName = 'Menu';
|
|
12
|
+
export default Menu;
|
|
13
|
+
export { Menu };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export default function Navigation(_a) {
|
|
4
|
+
var children = _a.children, _b = _a.className, className = _b === void 0 ? '' : _b;
|
|
5
|
+
return (<nav className={"\n bg-light-background-default dark:bg-dark-background-default\n border-r border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled\n p-[10px]\n ".concat(className, "\n ")}>
|
|
6
|
+
{children}
|
|
7
|
+
</nav>);
|
|
8
|
+
}
|
|
9
|
+
export { Navigation };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
export interface SelectOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
iconName?: string;
|
|
6
|
+
}
|
|
7
|
+
interface SelectProps {
|
|
8
|
+
value?: string | string[];
|
|
9
|
+
options: SelectOption[];
|
|
10
|
+
onChange?: (value: string | string[]) => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
decoIconName?: string;
|
|
14
|
+
width?: number | string;
|
|
15
|
+
multiple?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export default function Select({ value, options, onChange, disabled, placeholder, decoIconName, width, multiple, className, }: SelectProps): JSX.Element;
|
|
19
|
+
export { Select };
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
47
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
48
|
+
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
|
49
|
+
import Menu from './menu';
|
|
50
|
+
import MenuItem from './menuItem';
|
|
51
|
+
export default function Select(_a) {
|
|
52
|
+
var _this = this;
|
|
53
|
+
var value = _a.value, options = _a.options, onChange = _a.onChange, _b = _a.disabled, disabled = _b === void 0 ? false : _b, _c = _a.placeholder, placeholder = _c === void 0 ? 'Label' : _c, decoIconName = _a.decoIconName, width = _a.width, _d = _a.multiple, multiple = _d === void 0 ? false : _d, _e = _a.className, className = _e === void 0 ? '' : _e;
|
|
54
|
+
var _f = useState(false), isOpen = _f[0], setIsOpen = _f[1];
|
|
55
|
+
var _g = useState(false), isFocused = _g[0], setIsFocused = _g[1];
|
|
56
|
+
var _h = useState(false), isHovered = _h[0], setIsHovered = _h[1];
|
|
57
|
+
var _j = useState(null), DecoIcon = _j[0], setDecoIcon = _j[1];
|
|
58
|
+
var _k = useState(false), mounted = _k[0], setMounted = _k[1];
|
|
59
|
+
var selectRef = useRef(null);
|
|
60
|
+
var menuRef = useRef(null);
|
|
61
|
+
// Handle SSR
|
|
62
|
+
useEffect(function () {
|
|
63
|
+
setMounted(true);
|
|
64
|
+
}, []);
|
|
65
|
+
// Load decoration icon
|
|
66
|
+
var loadIcon = useCallback(function (iconName) { return __awaiter(_this, void 0, void 0, function () {
|
|
67
|
+
var module_1, IconComponent, error_1;
|
|
68
|
+
return __generator(this, function (_a) {
|
|
69
|
+
switch (_a.label) {
|
|
70
|
+
case 0:
|
|
71
|
+
if (!iconName)
|
|
72
|
+
return [2 /*return*/, null];
|
|
73
|
+
_a.label = 1;
|
|
74
|
+
case 1:
|
|
75
|
+
_a.trys.push([1, 3, , 4]);
|
|
76
|
+
return [4 /*yield*/, import('@heroicons/react/24/outline')];
|
|
77
|
+
case 2:
|
|
78
|
+
module_1 = _a.sent();
|
|
79
|
+
IconComponent = module_1[iconName];
|
|
80
|
+
return [2 /*return*/, IconComponent || null];
|
|
81
|
+
case 3:
|
|
82
|
+
error_1 = _a.sent();
|
|
83
|
+
console.error("Failed to load icon ".concat(iconName, ":"), error_1);
|
|
84
|
+
return [2 /*return*/, null];
|
|
85
|
+
case 4: return [2 /*return*/];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}); }, []);
|
|
89
|
+
useEffect(function () {
|
|
90
|
+
var fetchIcon = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
91
|
+
var _a;
|
|
92
|
+
return __generator(this, function (_b) {
|
|
93
|
+
switch (_b.label) {
|
|
94
|
+
case 0:
|
|
95
|
+
if (!decoIconName) return [3 /*break*/, 2];
|
|
96
|
+
_a = setDecoIcon;
|
|
97
|
+
return [4 /*yield*/, loadIcon(decoIconName)];
|
|
98
|
+
case 1:
|
|
99
|
+
_a.apply(void 0, [_b.sent()]);
|
|
100
|
+
_b.label = 2;
|
|
101
|
+
case 2: return [2 /*return*/];
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}); };
|
|
105
|
+
fetchIcon();
|
|
106
|
+
}, [decoIconName, loadIcon]);
|
|
107
|
+
// Close menu when clicking outside
|
|
108
|
+
useEffect(function () {
|
|
109
|
+
if (!mounted)
|
|
110
|
+
return;
|
|
111
|
+
var handleClickOutside = function (event) {
|
|
112
|
+
if (selectRef.current &&
|
|
113
|
+
menuRef.current &&
|
|
114
|
+
!selectRef.current.contains(event.target) &&
|
|
115
|
+
!menuRef.current.contains(event.target)) {
|
|
116
|
+
setIsOpen(false);
|
|
117
|
+
setIsFocused(false);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
if (isOpen) {
|
|
121
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
122
|
+
}
|
|
123
|
+
return function () {
|
|
124
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
125
|
+
};
|
|
126
|
+
}, [isOpen, mounted]);
|
|
127
|
+
var handleToggle = function () {
|
|
128
|
+
if (disabled)
|
|
129
|
+
return;
|
|
130
|
+
setIsOpen(!isOpen);
|
|
131
|
+
setIsFocused(!isOpen);
|
|
132
|
+
};
|
|
133
|
+
var handleSelect = function (optionValue) {
|
|
134
|
+
if (multiple) {
|
|
135
|
+
var currentValues = Array.isArray(value) ? value : [];
|
|
136
|
+
var newValues = currentValues.includes(optionValue)
|
|
137
|
+
? currentValues.filter(function (v) { return v !== optionValue; })
|
|
138
|
+
: __spreadArray(__spreadArray([], currentValues, true), [optionValue], false);
|
|
139
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(newValues);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(optionValue);
|
|
143
|
+
setIsOpen(false);
|
|
144
|
+
setIsFocused(false);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var getDisplayLabel = function () {
|
|
148
|
+
var _a;
|
|
149
|
+
if (!value)
|
|
150
|
+
return placeholder;
|
|
151
|
+
if (multiple && Array.isArray(value)) {
|
|
152
|
+
if (value.length === 0)
|
|
153
|
+
return placeholder;
|
|
154
|
+
var labels = value
|
|
155
|
+
.map(function (v) { var _a; return (_a = options.find(function (opt) { return opt.value === v; })) === null || _a === void 0 ? void 0 : _a.label; })
|
|
156
|
+
.filter(Boolean);
|
|
157
|
+
return labels.join(', ');
|
|
158
|
+
}
|
|
159
|
+
return ((_a = options.find(function (opt) { return opt.value === value; })) === null || _a === void 0 ? void 0 : _a.label) || placeholder;
|
|
160
|
+
};
|
|
161
|
+
var isSelected = function (optionValue) {
|
|
162
|
+
if (multiple && Array.isArray(value)) {
|
|
163
|
+
return value.includes(optionValue);
|
|
164
|
+
}
|
|
165
|
+
return value === optionValue;
|
|
166
|
+
};
|
|
167
|
+
// Determine border styles based on state
|
|
168
|
+
var getBorderStyles = function () {
|
|
169
|
+
if (disabled) {
|
|
170
|
+
return 'border border-light-actionOutlinedBorder-disabled dark:border-dark-actionOutlinedBorder-disabled';
|
|
171
|
+
}
|
|
172
|
+
if (isFocused || isOpen) {
|
|
173
|
+
return 'border border-light-accent-main dark:border-dark-accent-main outline outline-1 outline-light-accent-main dark:outline-dark-accent-main outline-offset-0';
|
|
174
|
+
}
|
|
175
|
+
if (isHovered) {
|
|
176
|
+
return 'border border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled';
|
|
177
|
+
}
|
|
178
|
+
return 'border border-light-actionOutlinedBorder-enabled dark:border-dark-actionOutlinedBorder-enabled';
|
|
179
|
+
};
|
|
180
|
+
// Determine background color
|
|
181
|
+
var getBackgroundColor = function () {
|
|
182
|
+
if (isHovered && !isOpen && !disabled) {
|
|
183
|
+
return 'bg-light-action-hover dark:bg-dark-action-hover';
|
|
184
|
+
}
|
|
185
|
+
return 'bg-light-background-default dark:bg-dark-background-default';
|
|
186
|
+
};
|
|
187
|
+
// Determine text color
|
|
188
|
+
var getTextColor = function () {
|
|
189
|
+
if (disabled) {
|
|
190
|
+
return 'text-light-text-disabled dark:text-dark-text-disabled';
|
|
191
|
+
}
|
|
192
|
+
return 'text-light-text-primary dark:text-dark-text-primary';
|
|
193
|
+
};
|
|
194
|
+
// Determine icon color
|
|
195
|
+
var getIconColor = function () {
|
|
196
|
+
if (disabled) {
|
|
197
|
+
return 'text-light-text-disabled dark:text-dark-text-disabled';
|
|
198
|
+
}
|
|
199
|
+
return 'text-light-text-secondary dark:text-dark-text-secondary';
|
|
200
|
+
};
|
|
201
|
+
return (<div className={"relative ".concat(className)} style={{ width: width || '100%' }}>
|
|
202
|
+
{/* Select Button */}
|
|
203
|
+
<div ref={selectRef} className={"\n rounded-[8px]\n ".concat(getBorderStyles(), "\n ").concat(getBackgroundColor(), "\n ").concat(disabled ? 'cursor-not-allowed' : 'cursor-pointer', "\n transition-all duration-200 ease-in-out\n outline-none\n ")} onClick={handleToggle} onMouseEnter={function () { return !disabled && setIsHovered(true); }} onMouseLeave={function () { return setIsHovered(false); }} tabIndex={disabled ? -1 : 0} onKeyDown={function (e) {
|
|
204
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
handleToggle();
|
|
207
|
+
}
|
|
208
|
+
}}>
|
|
209
|
+
{/* Inner Content Container with Padding */}
|
|
210
|
+
<div className={"flex items-center justify-between p-2 ".concat(getTextColor())}>
|
|
211
|
+
{/* Content Container */}
|
|
212
|
+
<div className="flex items-center space-x-1 flex-1 overflow-hidden">
|
|
213
|
+
{/* Optional Decoration Icon */}
|
|
214
|
+
{DecoIcon && (<DecoIcon className={"w-6 h-6 flex-shrink-0 ".concat(getIconColor())}/>)}
|
|
215
|
+
|
|
216
|
+
{/* Display Text */}
|
|
217
|
+
<span className="text-body1 truncate">
|
|
218
|
+
{getDisplayLabel()}
|
|
219
|
+
</span>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
{/* Chevron Icon */}
|
|
223
|
+
<ChevronDownIcon className={"\n w-6 h-6 flex-shrink-0 ml-1\n ".concat(getIconColor(), "\n transition-transform duration-200\n ").concat(isOpen ? 'transform rotate-180' : '', "\n ")}/>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
{/* Dropdown Menu */}
|
|
228
|
+
{mounted && isOpen && (<div className="absolute z-50 mt-1 left-0" style={{ width: width || '100%' }}>
|
|
229
|
+
<Menu ref={menuRef} width={width || '100%'}>
|
|
230
|
+
{options.map(function (option) { return (<MenuItem key={option.value} label={option.label} iconName={option.iconName} isSelected={isSelected(option.value)} onClick={function () { return handleSelect(option.value); }} className="w-full"/>); })}
|
|
231
|
+
</Menu>
|
|
232
|
+
</div>)}
|
|
233
|
+
</div>);
|
|
234
|
+
}
|
|
235
|
+
export { Select };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,9 +6,12 @@ export * from './components/checkBox';
|
|
|
6
6
|
export * from './components/emptyBox';
|
|
7
7
|
export * from './components/iconButton';
|
|
8
8
|
export * from './components/loadingScreen';
|
|
9
|
+
export * from './components/menu';
|
|
9
10
|
export * from './components/menuItem';
|
|
10
11
|
export * from './components/modal';
|
|
12
|
+
export * from './components/navigation';
|
|
11
13
|
export * from './components/popover';
|
|
14
|
+
export * from './components/select';
|
|
12
15
|
export * from './components/tab';
|
|
13
16
|
export * from './components/tag';
|
|
14
17
|
export * from './components/textField';
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,12 @@ export * from './components/checkBox';
|
|
|
6
6
|
export * from './components/emptyBox';
|
|
7
7
|
export * from './components/iconButton';
|
|
8
8
|
export * from './components/loadingScreen';
|
|
9
|
+
export * from './components/menu';
|
|
9
10
|
export * from './components/menuItem';
|
|
10
11
|
export * from './components/modal';
|
|
12
|
+
export * from './components/navigation';
|
|
11
13
|
export * from './components/popover';
|
|
14
|
+
export * from './components/select';
|
|
12
15
|
export * from './components/tab';
|
|
13
16
|
export * from './components/tag';
|
|
14
17
|
export * from './components/textField';
|
package/dist/output.css
CHANGED
|
@@ -549,6 +549,9 @@ video {
|
|
|
549
549
|
left: 0px;
|
|
550
550
|
right: 0px;
|
|
551
551
|
}
|
|
552
|
+
.left-0 {
|
|
553
|
+
left: 0px;
|
|
554
|
+
}
|
|
552
555
|
.top-4 {
|
|
553
556
|
top: 1rem;
|
|
554
557
|
}
|
|
@@ -561,6 +564,9 @@ video {
|
|
|
561
564
|
.mb-1 {
|
|
562
565
|
margin-bottom: 0.25rem;
|
|
563
566
|
}
|
|
567
|
+
.ml-1 {
|
|
568
|
+
margin-left: 0.25rem;
|
|
569
|
+
}
|
|
564
570
|
.ml-2 {
|
|
565
571
|
margin-left: 0.5rem;
|
|
566
572
|
}
|
|
@@ -647,6 +653,13 @@ video {
|
|
|
647
653
|
.flex-1 {
|
|
648
654
|
flex: 1 1 0%;
|
|
649
655
|
}
|
|
656
|
+
.flex-shrink-0 {
|
|
657
|
+
flex-shrink: 0;
|
|
658
|
+
}
|
|
659
|
+
.rotate-180 {
|
|
660
|
+
--tw-rotate: 180deg;
|
|
661
|
+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
662
|
+
}
|
|
650
663
|
.transform {
|
|
651
664
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
|
652
665
|
}
|
|
@@ -746,6 +759,9 @@ video {
|
|
|
746
759
|
.border-4 {
|
|
747
760
|
border-width: 4px;
|
|
748
761
|
}
|
|
762
|
+
.border-r {
|
|
763
|
+
border-right-width: 1px;
|
|
764
|
+
}
|
|
749
765
|
.border-t {
|
|
750
766
|
border-top-width: 1px;
|
|
751
767
|
}
|
|
@@ -760,6 +776,14 @@ video {
|
|
|
760
776
|
--tw-border-opacity: 1;
|
|
761
777
|
border-color: rgb(238 174 3 / var(--tw-border-opacity));
|
|
762
778
|
}
|
|
779
|
+
.border-light-actionOutlinedBorder-disabled {
|
|
780
|
+
--tw-border-opacity: 1;
|
|
781
|
+
border-color: rgb(176 176 176 / var(--tw-border-opacity));
|
|
782
|
+
}
|
|
783
|
+
.border-light-actionOutlinedBorder-enabled {
|
|
784
|
+
--tw-border-opacity: 1;
|
|
785
|
+
border-color: rgb(136 136 136 / var(--tw-border-opacity));
|
|
786
|
+
}
|
|
763
787
|
.border-light-misc-divider {
|
|
764
788
|
--tw-border-opacity: 1;
|
|
765
789
|
border-color: rgb(209 209 209 / var(--tw-border-opacity));
|
|
@@ -798,6 +822,10 @@ video {
|
|
|
798
822
|
--tw-bg-opacity: 1;
|
|
799
823
|
background-color: rgb(238 174 3 / var(--tw-bg-opacity));
|
|
800
824
|
}
|
|
825
|
+
.bg-light-action-hover {
|
|
826
|
+
--tw-bg-opacity: 1;
|
|
827
|
+
background-color: rgb(243 243 243 / var(--tw-bg-opacity));
|
|
828
|
+
}
|
|
801
829
|
.bg-light-actionBackground-disabled {
|
|
802
830
|
--tw-bg-opacity: 1;
|
|
803
831
|
background-color: rgb(238 238 238 / var(--tw-bg-opacity));
|
|
@@ -867,6 +895,9 @@ video {
|
|
|
867
895
|
.p-6 {
|
|
868
896
|
padding: 1.5rem;
|
|
869
897
|
}
|
|
898
|
+
.p-\[10px\] {
|
|
899
|
+
padding: 10px;
|
|
900
|
+
}
|
|
870
901
|
.p-\[3px\] {
|
|
871
902
|
padding: 3px;
|
|
872
903
|
}
|
|
@@ -972,6 +1003,18 @@ video {
|
|
|
972
1003
|
outline: 2px solid transparent;
|
|
973
1004
|
outline-offset: 2px;
|
|
974
1005
|
}
|
|
1006
|
+
.outline {
|
|
1007
|
+
outline-style: solid;
|
|
1008
|
+
}
|
|
1009
|
+
.outline-1 {
|
|
1010
|
+
outline-width: 1px;
|
|
1011
|
+
}
|
|
1012
|
+
.outline-offset-0 {
|
|
1013
|
+
outline-offset: 0px;
|
|
1014
|
+
}
|
|
1015
|
+
.outline-light-accent-main {
|
|
1016
|
+
outline-color: #EEAE03;
|
|
1017
|
+
}
|
|
975
1018
|
.ring-2 {
|
|
976
1019
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
977
1020
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
@@ -998,11 +1041,24 @@ video {
|
|
|
998
1041
|
--tw-blur: blur(8px);
|
|
999
1042
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
1000
1043
|
}
|
|
1044
|
+
.filter {
|
|
1045
|
+
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
1046
|
+
}
|
|
1047
|
+
.transition-all {
|
|
1048
|
+
transition-property: all;
|
|
1049
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1050
|
+
transition-duration: 150ms;
|
|
1051
|
+
}
|
|
1001
1052
|
.transition-colors {
|
|
1002
1053
|
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
|
1003
1054
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1004
1055
|
transition-duration: 150ms;
|
|
1005
1056
|
}
|
|
1057
|
+
.transition-transform {
|
|
1058
|
+
transition-property: transform;
|
|
1059
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1060
|
+
transition-duration: 150ms;
|
|
1061
|
+
}
|
|
1006
1062
|
.duration-200 {
|
|
1007
1063
|
transition-duration: 200ms;
|
|
1008
1064
|
}
|
|
@@ -1056,6 +1112,21 @@ body {
|
|
|
1056
1112
|
|
|
1057
1113
|
@media (prefers-color-scheme: dark) {
|
|
1058
1114
|
|
|
1115
|
+
.dark\:border-dark-accent-main {
|
|
1116
|
+
--tw-border-opacity: 1;
|
|
1117
|
+
border-color: rgb(255 205 41 / var(--tw-border-opacity));
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
.dark\:border-dark-actionOutlinedBorder-disabled {
|
|
1121
|
+
--tw-border-opacity: 1;
|
|
1122
|
+
border-color: rgb(56 56 56 / var(--tw-border-opacity));
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
.dark\:border-dark-actionOutlinedBorder-enabled {
|
|
1126
|
+
--tw-border-opacity: 1;
|
|
1127
|
+
border-color: rgb(123 123 123 / var(--tw-border-opacity));
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1059
1130
|
.dark\:border-dark-misc-divider {
|
|
1060
1131
|
--tw-border-opacity: 1;
|
|
1061
1132
|
border-color: rgb(64 64 64 / var(--tw-border-opacity));
|
|
@@ -1080,6 +1151,11 @@ body {
|
|
|
1080
1151
|
background-color: rgb(255 205 41 / var(--tw-bg-opacity));
|
|
1081
1152
|
}
|
|
1082
1153
|
|
|
1154
|
+
.dark\:bg-dark-action-hover {
|
|
1155
|
+
--tw-bg-opacity: 1;
|
|
1156
|
+
background-color: rgb(61 61 61 / var(--tw-bg-opacity));
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1083
1159
|
.dark\:bg-dark-actionBackground-disabled {
|
|
1084
1160
|
--tw-bg-opacity: 1;
|
|
1085
1161
|
background-color: rgb(56 56 56 / var(--tw-bg-opacity));
|
|
@@ -1175,6 +1251,10 @@ body {
|
|
|
1175
1251
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
|
1176
1252
|
}
|
|
1177
1253
|
|
|
1254
|
+
.dark\:outline-dark-accent-main {
|
|
1255
|
+
outline-color: #FFCD29;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1178
1258
|
.dark\:ring-dark-accent-main {
|
|
1179
1259
|
--tw-ring-opacity: 1;
|
|
1180
1260
|
--tw-ring-color: rgb(255 205 41 / var(--tw-ring-opacity));
|
package/index.ts
CHANGED
|
@@ -7,9 +7,12 @@ export * from './components/checkBox';
|
|
|
7
7
|
export * from './components/emptyBox';
|
|
8
8
|
export * from './components/iconButton';
|
|
9
9
|
export * from './components/loadingScreen';
|
|
10
|
+
export * from './components/menu';
|
|
10
11
|
export * from './components/menuItem';
|
|
11
12
|
export * from './components/modal';
|
|
13
|
+
export * from './components/navigation';
|
|
12
14
|
export * from './components/popover';
|
|
15
|
+
export * from './components/select';
|
|
13
16
|
export * from './components/tab';
|
|
14
17
|
export * from './components/tag';
|
|
15
18
|
export * from './components/textField';
|