oneslash-design-system 1.2.12 → 1.2.13

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 (42) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.eslintrc.json +3 -0
  3. package/components/alert.tsx +132 -0
  4. package/components/button.tsx +120 -0
  5. package/components/checkBox.tsx +60 -0
  6. package/components/emptyBox.tsx +33 -0
  7. package/components/iconButton.tsx +103 -0
  8. package/components/loadingScreen.tsx +30 -0
  9. package/components/menu.tsx +35 -0
  10. package/components/menuItem.tsx +117 -0
  11. package/components/modal.tsx +85 -0
  12. package/components/navigation.tsx +27 -0
  13. package/components/popover.tsx +69 -0
  14. package/components/radioGroup.tsx +50 -0
  15. package/components/select.tsx +253 -0
  16. package/components/tab.tsx +85 -0
  17. package/components/tableCell.tsx +15 -0
  18. package/components/tableContainer.tsx +15 -0
  19. package/components/tableHeader.tsx +15 -0
  20. package/components/tableHeaderCell.tsx +15 -0
  21. package/components/tableRow.tsx +15 -0
  22. package/components/tabsContainer.tsx +23 -0
  23. package/components/tag.tsx +81 -0
  24. package/components/textField.tsx +116 -0
  25. package/components/textarea.tsx +120 -0
  26. package/components/timeStamp.tsx +65 -0
  27. package/components/tooltip.tsx +66 -0
  28. package/components/userImage.tsx +64 -0
  29. package/designTokens.js +234 -0
  30. package/dist/components/loadingScreen.jsx +2 -2
  31. package/dist/components/menuItem.d.ts +2 -8
  32. package/dist/components/menuItem.jsx +14 -34
  33. package/dist/components/tag.d.ts +2 -1
  34. package/dist/components/tag.jsx +22 -22
  35. package/index.css +8 -0
  36. package/index.ts +21 -0
  37. package/next.config.mjs +4 -0
  38. package/package.json +4 -28
  39. package/postcss.config.mjs +8 -0
  40. package/tailwind.config.ts +232 -0
  41. package/tsconfig.json +37 -0
  42. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,85 @@
1
+ 'use client';
2
+ import React, { useEffect, useRef } from 'react';
3
+
4
+ interface ModalProps {
5
+ isOpen: boolean;
6
+ title?: string;
7
+ children: React.ReactNode;
8
+ onClose: () => void;
9
+ actions?: React.ReactNode;
10
+ size?: 'medium' | 'large';
11
+ }
12
+
13
+ export default function Modal({
14
+ isOpen,
15
+ title,
16
+ children,
17
+ onClose,
18
+ actions,
19
+ size = 'medium', // Default size is medium
20
+ }: ModalProps) {
21
+
22
+ if (!isOpen) return null;
23
+
24
+ // close modal by clicking elsewhere
25
+ const handleOverlayClick = (e: React.MouseEvent<HTMLDivElement>) => {
26
+ if (e.target === e.currentTarget) {
27
+ onClose();
28
+ }
29
+ };
30
+
31
+ // close modal by esc keypress
32
+ useEffect(() => {
33
+ const handleKeyDown = (e: KeyboardEvent) => {
34
+ if (e.key === 'Escape') {
35
+ onClose();
36
+ }
37
+ };
38
+ window.addEventListener('keydown', handleKeyDown);
39
+ return () => {
40
+ window.removeEventListener('keydown', handleKeyDown);
41
+ };
42
+ }, [onClose]);
43
+
44
+ // Determine width based on size prop
45
+ const modalWidth = size === 'large' ? 'w-[1200px]' : 'w-[600px]';
46
+ const maxWidth = size === 'large' ? '1200px' : '600px';
47
+
48
+
49
+
50
+ return (
51
+ <div
52
+ className="fixed inset-[-32px] bg-black bg-opacity-50 flex items-center justify-center z-50"
53
+ onClick={handleOverlayClick}
54
+ role="dialog"
55
+ aria-labelledby="modal-title"
56
+ aria-modal="true"
57
+ tabIndex={-1}
58
+ >
59
+ <div
60
+ className={`bg-light-background-default dark:bg-dark-background-default p-6 rounded-[8px] space-y-4 ${modalWidth}`}
61
+ style={{
62
+ maxWidth,
63
+ width: 'calc(100vw - 64px)',
64
+ maxHeight: '800px',
65
+ height: 'auto',
66
+ overflowY: 'auto',
67
+ }}
68
+ >
69
+ {title && (
70
+ <h2 id="modal-title" className="text-h6">
71
+ {title}
72
+ </h2>
73
+ )}
74
+ <div className="text-body1 space-y-4">
75
+ {children}
76
+ </div>
77
+ {actions && (
78
+ <div className="flex justify-between">
79
+ {actions}
80
+ </div>
81
+ )}
82
+ </div>
83
+ </div>
84
+ );
85
+ }
@@ -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-misc-divider dark:border-dark-misc-divider
18
+ p-[10px]
19
+ ${className}
20
+ `}
21
+ >
22
+ {children}
23
+ </nav>
24
+ );
25
+ }
26
+
27
+ export { Navigation };
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+ import React, { useState, useEffect } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { usePopper } from 'react-popper';
5
+
6
+ interface PopoverProps {
7
+ id?: string;
8
+ anchorEl?: HTMLElement | null;
9
+ open: boolean;
10
+ onClose: () => void;
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ export default function Popover({
15
+ id,
16
+ anchorEl,
17
+ open,
18
+ onClose,
19
+ children,
20
+ }: PopoverProps) {
21
+ const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null);
22
+ const [hasMounted, setHasMounted] = useState(false);
23
+
24
+ // Initialize Popper.js
25
+ const { styles, attributes } = usePopper(anchorEl, popoverElement, {
26
+ placement: 'bottom-start', // Default placement, can be customized
27
+ modifiers: [
28
+ { name: 'offset', options: { offset: [0, 8] } }, // Offset for spacing between anchor and popover
29
+ ],
30
+ });
31
+
32
+ // Handle outside clicks to close the popover
33
+ useEffect(() => {
34
+ const handleClickOutside = (event: MouseEvent) => {
35
+ if (popoverElement && !popoverElement.contains(event.target as Node) && anchorEl) {
36
+ onClose();
37
+ }
38
+ };
39
+
40
+ if (open) {
41
+ document.addEventListener('mousedown', handleClickOutside);
42
+ }
43
+ return () => {
44
+ document.removeEventListener('mousedown', handleClickOutside);
45
+ };
46
+ }, [open, anchorEl, popoverElement, onClose]);
47
+
48
+ // Ensure popover is only rendered after the component mounts
49
+ useEffect(() => {
50
+ setHasMounted(true);
51
+ }, []);
52
+
53
+ if (!open || !hasMounted || !anchorEl) return null;
54
+
55
+ // Render popover in a portal to prevent layout shifts and positioning issues
56
+ return createPortal(
57
+ <div
58
+ id={id}
59
+ ref={setPopoverElement}
60
+ style={{ ...styles.popper, display: open ? 'block' : 'none' }}
61
+ {...attributes.popper}
62
+ className="bg-light-background-accent300 dark:bg-dark-background-accent300 rounded-[8px] shadow-lg p-2"
63
+ role="dialog"
64
+ >
65
+ {children}
66
+ </div>,
67
+ document.body // Mounting the popover in the document body for isolation
68
+ );
69
+ }
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface RadioOption {
5
+ label: string;
6
+ value: string;
7
+ }
8
+
9
+ interface RadioGroupProps {
10
+ options: RadioOption[];
11
+ selectedValue: string;
12
+ onChange: (value: string) => void;
13
+ direction?: 'horizontal' | 'vertical';
14
+ }
15
+
16
+ export default function RadioGroup({
17
+ options,
18
+ selectedValue,
19
+ onChange,
20
+ direction = 'vertical',
21
+ }: RadioGroupProps) {
22
+ return (
23
+ <div
24
+ className={`flex ${ direction === 'horizontal' ? 'space-x-4' : 'flex-col space-y-2' }`}
25
+ >
26
+ {options.map((option) => (
27
+ <label
28
+ key={option.value}
29
+ className="flex items-center cursor-pointer"
30
+ onClick={() => onChange(option.value)}
31
+ >
32
+ {/* outer circle */}
33
+ <div
34
+ className={`relative flex justify-center items-center w-4 h-4 rounded-full border-2
35
+ ${selectedValue === option.value
36
+ ? 'border-light-text-primary dark:border-dark-text-primary'
37
+ : 'border-light-text-secondary dark:border-dark-text-secondary'}
38
+ `}
39
+ >
40
+ {/* Inner circle */}
41
+ {selectedValue === option.value && (
42
+ <div className='absolute w-2 h-2 rounded-full bg-light-text-primary dark:bg-dark-text-primary'/>
43
+ )}
44
+ </div>
45
+ <span className="ml-2 text-body1 text-light-text-primary dark:text-dark-text-primary">{option.label}</span>
46
+ </label>
47
+ ))}
48
+ </div>
49
+ );
50
+ }
@@ -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,85 @@
1
+ 'use client';
2
+ import React, { useState, useEffect, useCallback } from 'react';
3
+ import { useRouter, usePathname } from 'next/navigation';
4
+
5
+ type TabProps = {
6
+ label: string;
7
+ href?: string;
8
+ isSelected: boolean;
9
+ onClickTab: () => void;
10
+ onClickActionIcon?: any;
11
+ decoIcon?: string;
12
+ actionIcon?: string;
13
+ };
14
+
15
+ type IconType = React.ComponentType<React.SVGProps<SVGSVGElement>>;
16
+
17
+ export default function Tab({
18
+ label,
19
+ href,
20
+ isSelected,
21
+ onClickTab,
22
+ onClickActionIcon,
23
+ decoIcon,
24
+ actionIcon
25
+ }: TabProps) {
26
+ const router = useRouter();
27
+ const pathname = usePathname();
28
+
29
+ const [IconLeft, setIconLeft] = useState<IconType | null>(null);
30
+ const [IconRight, setIconRight] = useState<IconType | null>(null);
31
+
32
+ // Load icon dynamically
33
+ const loadIcon = useCallback(async (iconName?: string) => {
34
+ if (!iconName) return null;
35
+ try {
36
+ const module = await import('@heroicons/react/24/outline');
37
+ const Icon = module[iconName as keyof typeof module] as IconType;
38
+ return Icon || null;
39
+ } catch (error) {
40
+ console.error(`Failed to load icon ${iconName}:`, error);
41
+ return null;
42
+ }
43
+ }, []);
44
+
45
+ useEffect(() => {
46
+ const fetchIcons = async () => {
47
+ if (decoIcon) {
48
+ setIconLeft(await loadIcon(decoIcon));
49
+ }
50
+ if (actionIcon) {
51
+ setIconRight(await loadIcon(actionIcon));
52
+ }
53
+ };
54
+ fetchIcons();
55
+ }, [decoIcon, actionIcon, loadIcon]);
56
+
57
+ const handleClick = () => {
58
+ onClickTab();
59
+ if (href) {
60
+ router.push(href);
61
+ }
62
+ };
63
+
64
+ return (
65
+ <div
66
+ className={`
67
+ flex items-center space-x-1 py-1 px-[6px] rounded-[8px] cursor-pointer justify-start transition-colors duration-200 ease-in-out
68
+ ${isSelected
69
+ ? 'bg-light-primary-dark dark:bg-dark-primary-dark text-light-text-contrast dark:text-dark-text-contrast'
70
+ : 'hover:bg-light-background-accent200 dark:hover:bg-dark-background-accent200'}
71
+ `}
72
+ onClick={handleClick}
73
+ >
74
+ {IconLeft && <IconLeft className="w-6 h-6" />}
75
+ <span className="whitespace-nowrap text-body1 px-[6px]">
76
+ {label}
77
+ </span>
78
+ {IconRight && (
79
+ <div onClick={onClickActionIcon} className="cursor-pointer">
80
+ <IconRight className="w-6 h-6" />
81
+ </div>
82
+ )}
83
+ </div>
84
+ );
85
+ }
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TableCellProps{
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TableCell({children}: TableCellProps) {
9
+
10
+ return (
11
+ <div className="flex-1 p-2 text-body2 text-light-text-primary dark:text-dark-text-primary border-t border-light-misc-divider dark:border-dark-misc-divider">
12
+ {children}
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TableContainerProps{
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TableContainer({children}: TableContainerProps) {
9
+
10
+ return (
11
+ <div className="w-full overflow-x-auto bg-light-background-default dark:bg-dark-background-default">
12
+ {children}
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TableHeaderProps{
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TableHeader({children}: TableHeaderProps) {
9
+
10
+ return (
11
+ <div className="py-2 bg-light-background-default dark:bg-dark-background-default">
12
+ {children}
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TableHeaderCellProps{
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TableHeaderCell({children}: TableHeaderCellProps) {
9
+
10
+ return (
11
+ <div className="flex-1 p-2 text-body2 text-light-text-primary dark:text-dark-text-primary">
12
+ {children}
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TableRowProps{
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TableRow({children}: TableRowProps) {
9
+
10
+ return (
11
+ <div className="flex w-full">
12
+ {children}
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,23 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ interface TabsContainerProps {
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export default function TabsContainer({
9
+ children,
10
+ }: TabsContainerProps) {
11
+ const tabCount = React.Children.count(children);
12
+
13
+ return (
14
+ <div
15
+ className={`
16
+ flex space-x-2 p-1 rounded-[12px]
17
+ ${tabCount > 0 ? 'bg-light-background-accent100 dark:bg-dark-background-accent100' : 'bg-transparent'}
18
+ `}
19
+ >
20
+ {children}
21
+ </div>
22
+ );
23
+ }