@justin_evo/evo-ui 1.2.0 → 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/LICENSE +21 -21
- package/README.md +70 -70
- package/dist/declarations.d.ts +6 -6
- package/package.json +52 -52
- package/src/Alert/Alert.tsx +49 -49
- package/src/AutoComplete/AutoComplete.tsx +810 -810
- package/src/Badge/Badge.tsx +53 -53
- package/src/Breadcrumb/Breadcrumb.tsx +53 -53
- package/src/Button/Button.tsx +125 -125
- package/src/Card/Card.tsx +257 -257
- package/src/Checkbox/Checkbox.tsx +59 -59
- package/src/CommandPalette/CommandPalette.tsx +185 -185
- package/src/Container/Container.tsx +31 -31
- package/src/Divider/Divider.tsx +31 -31
- package/src/Form/Form.tsx +185 -185
- package/src/Grid/Grid.tsx +66 -66
- package/src/ImageCropper/ImageCropper.tsx +911 -911
- package/src/Input/Input.tsx +74 -74
- package/src/Modal/Modal.tsx +77 -77
- package/src/Nav/Nav.tsx +708 -708
- package/src/Notification/Notification.tsx +1503 -1503
- package/src/Pagination/Pagination.tsx +76 -76
- package/src/Radio/Radio.tsx +69 -69
- package/src/RichTextArea/RichTextArea.tsx +886 -886
- package/src/Select/Select.tsx +515 -515
- package/src/Skeleton/Skeleton.tsx +70 -70
- package/src/Stack/Stack.tsx +52 -52
- package/src/Table/Table.tsx +335 -335
- package/src/Tabs/Tabs.tsx +90 -90
- package/src/Theme/ThemeProvider.tsx +253 -253
- package/src/Theme/ThemeToggle.tsx +79 -79
- package/src/Toggle/Toggle.tsx +48 -48
- package/src/Tooltip/Tooltip.tsx +38 -38
- package/src/TopNav/TopNav.tsx +1163 -1163
- package/src/TreeSelect/TreeSelect.tsx +825 -825
- package/src/css/alert.module.scss +93 -93
- package/src/css/autocomplete.module.scss +416 -416
- package/src/css/badge.module.scss +82 -82
- package/src/css/base/_color.scss +159 -159
- package/src/css/base/_theme.scss +237 -237
- package/src/css/base/_variables.scss +161 -161
- package/src/css/breadcrumb.module.scss +50 -50
- package/src/css/button.module.scss +385 -385
- package/src/css/card.module.scss +217 -217
- package/src/css/checkbox.module.scss +123 -123
- package/src/css/commandpalette.module.scss +211 -211
- package/src/css/container.module.scss +18 -18
- package/src/css/divider.module.scss +41 -41
- package/src/css/form.module.scss +245 -245
- package/src/css/imagecropper.module.scss +397 -397
- package/src/css/input.module.scss +89 -89
- package/src/css/modal.module.scss +105 -105
- package/src/css/nav.module.scss +494 -494
- package/src/css/notification.module.scss +691 -691
- package/src/css/pagination.module.scss +63 -63
- package/src/css/radio.module.scss +89 -89
- package/src/css/richtextarea.module.scss +307 -307
- package/src/css/select.module.scss +525 -525
- package/src/css/skeleton.module.scss +30 -30
- package/src/css/table.module.scss +386 -386
- package/src/css/tabs.module.scss +63 -63
- package/src/css/theme-toggle.module.scss +83 -83
- package/src/css/toggle.module.scss +54 -54
- package/src/css/tooltip.module.scss +97 -97
- package/src/css/topnav.module.scss +568 -568
- package/src/css/treeselect.module.scss +558 -558
- package/src/css/utilities/_borders.scss +111 -111
- package/src/css/utilities/_colors.scss +66 -66
- package/src/css/utilities/_effects.scss +216 -216
- package/src/css/utilities/_layout.scss +181 -181
- package/src/css/utilities/_position.scss +75 -75
- package/src/css/utilities/_sizing.scss +138 -138
- package/src/css/utilities/_spacing.scss +99 -99
- package/src/css/utilities/_typography.scss +121 -121
- package/src/css/utilities/index.scss +24 -24
- package/src/declarations.d.ts +6 -6
- package/src/index.ts +60 -60
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
-
import styles from '../css/commandpalette.module.scss';
|
|
3
|
-
|
|
4
|
-
export interface CommandPaletteItem {
|
|
5
|
-
label: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
group?: string;
|
|
8
|
-
icon?: React.ReactNode;
|
|
9
|
-
shortcut?: string[];
|
|
10
|
-
onSelect: () => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface EvoCommandPaletteProps {
|
|
14
|
-
items: CommandPaletteItem[];
|
|
15
|
-
placeholder?: string;
|
|
16
|
-
open?: boolean;
|
|
17
|
-
onClose?: () => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Detect Mac for shortcut display only — keyboard handler uses ctrlKey||metaKey for both
|
|
21
|
-
const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.userAgent);
|
|
22
|
-
|
|
23
|
-
const SearchIcon = () => (
|
|
24
|
-
<svg viewBox="0 0 16 16" fill="none" width="16" height="16">
|
|
25
|
-
<circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.5" />
|
|
26
|
-
<path d="M10.5 10.5L13 13" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
27
|
-
</svg>
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
export const EvoCommandPalette = ({
|
|
31
|
-
items,
|
|
32
|
-
placeholder = 'Search commands…',
|
|
33
|
-
open: controlledOpen,
|
|
34
|
-
onClose,
|
|
35
|
-
}: EvoCommandPaletteProps) => {
|
|
36
|
-
const [internalOpen, setInternalOpen] = useState(false);
|
|
37
|
-
const [query, setQuery] = useState('');
|
|
38
|
-
const [activeIdx, setActiveIdx] = useState(0);
|
|
39
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
40
|
-
const listRef = useRef<HTMLDivElement>(null);
|
|
41
|
-
|
|
42
|
-
const isControlled = controlledOpen !== undefined;
|
|
43
|
-
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
44
|
-
|
|
45
|
-
const close = useCallback(() => {
|
|
46
|
-
if (!isControlled) setInternalOpen(false);
|
|
47
|
-
onClose?.();
|
|
48
|
-
}, [isControlled, onClose]);
|
|
49
|
-
|
|
50
|
-
// Ctrl+K (Windows/Linux) / ⌘+K (Mac)
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
const handler = (e: KeyboardEvent) => {
|
|
53
|
-
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
54
|
-
e.preventDefault();
|
|
55
|
-
if (!isControlled) setInternalOpen(o => !o);
|
|
56
|
-
}
|
|
57
|
-
if (e.key === 'Escape' && isOpen) close();
|
|
58
|
-
};
|
|
59
|
-
document.addEventListener('keydown', handler);
|
|
60
|
-
return () => document.removeEventListener('keydown', handler);
|
|
61
|
-
}, [isControlled, isOpen, close]);
|
|
62
|
-
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (isOpen) {
|
|
65
|
-
setQuery('');
|
|
66
|
-
setActiveIdx(0);
|
|
67
|
-
// Small delay so the element is mounted before focus
|
|
68
|
-
const t = setTimeout(() => inputRef.current?.focus(), 30);
|
|
69
|
-
return () => clearTimeout(t);
|
|
70
|
-
}
|
|
71
|
-
}, [isOpen]);
|
|
72
|
-
|
|
73
|
-
const filtered = query.trim()
|
|
74
|
-
? items.filter(item =>
|
|
75
|
-
item.label.toLowerCase().includes(query.toLowerCase()) ||
|
|
76
|
-
item.description?.toLowerCase().includes(query.toLowerCase()) ||
|
|
77
|
-
item.group?.toLowerCase().includes(query.toLowerCase())
|
|
78
|
-
)
|
|
79
|
-
: items;
|
|
80
|
-
|
|
81
|
-
const grouped = filtered.reduce<Record<string, CommandPaletteItem[]>>((acc, item) => {
|
|
82
|
-
const g = item.group ?? 'Actions';
|
|
83
|
-
if (!acc[g]) acc[g] = [];
|
|
84
|
-
acc[g].push(item);
|
|
85
|
-
return acc;
|
|
86
|
-
}, {});
|
|
87
|
-
|
|
88
|
-
const flat = Object.values(grouped).flat();
|
|
89
|
-
|
|
90
|
-
const scrollActiveIntoView = (idx: number) => {
|
|
91
|
-
const el = listRef.current?.querySelector(`[data-idx="${idx}"]`) as HTMLElement | null;
|
|
92
|
-
el?.scrollIntoView({ block: 'nearest' });
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
96
|
-
if (e.key === 'ArrowDown') {
|
|
97
|
-
e.preventDefault();
|
|
98
|
-
setActiveIdx(i => {
|
|
99
|
-
const next = Math.min(i + 1, flat.length - 1);
|
|
100
|
-
scrollActiveIntoView(next);
|
|
101
|
-
return next;
|
|
102
|
-
});
|
|
103
|
-
} else if (e.key === 'ArrowUp') {
|
|
104
|
-
e.preventDefault();
|
|
105
|
-
setActiveIdx(i => {
|
|
106
|
-
const next = Math.max(i - 1, 0);
|
|
107
|
-
scrollActiveIntoView(next);
|
|
108
|
-
return next;
|
|
109
|
-
});
|
|
110
|
-
} else if (e.key === 'Enter' && flat[activeIdx]) {
|
|
111
|
-
flat[activeIdx].onSelect();
|
|
112
|
-
close();
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
if (!isOpen) return null;
|
|
117
|
-
|
|
118
|
-
let globalIdx = 0;
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div className={styles.overlay} onClick={close} role="dialog" aria-modal="true">
|
|
122
|
-
<div
|
|
123
|
-
className={styles.palette}
|
|
124
|
-
onClick={e => e.stopPropagation()}
|
|
125
|
-
onKeyDown={handleKeyDown}
|
|
126
|
-
>
|
|
127
|
-
<div className={styles.searchRow}>
|
|
128
|
-
<span className={styles.searchIconWrap}><SearchIcon /></span>
|
|
129
|
-
<input
|
|
130
|
-
ref={inputRef}
|
|
131
|
-
className={styles.searchInput}
|
|
132
|
-
placeholder={placeholder}
|
|
133
|
-
value={query}
|
|
134
|
-
onChange={e => { setQuery(e.target.value); setActiveIdx(0); }}
|
|
135
|
-
aria-label="Command search"
|
|
136
|
-
/>
|
|
137
|
-
<kbd className={styles.escBadge}>Esc</kbd>
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<div className={styles.results} ref={listRef}>
|
|
141
|
-
{flat.length === 0 && (
|
|
142
|
-
<div className={styles.empty}>No results for “{query}”</div>
|
|
143
|
-
)}
|
|
144
|
-
{Object.entries(grouped).map(([group, groupItems]) => (
|
|
145
|
-
<div key={group} className={styles.group}>
|
|
146
|
-
<div className={styles.groupLabel}>{group}</div>
|
|
147
|
-
{groupItems.map(item => {
|
|
148
|
-
const idx = globalIdx++;
|
|
149
|
-
return (
|
|
150
|
-
<button
|
|
151
|
-
key={item.label}
|
|
152
|
-
data-idx={idx}
|
|
153
|
-
className={[styles.resultItem, idx === activeIdx ? styles.resultActive : '']
|
|
154
|
-
.filter(Boolean)
|
|
155
|
-
.join(' ')}
|
|
156
|
-
onClick={() => { item.onSelect(); close(); }}
|
|
157
|
-
onMouseEnter={() => setActiveIdx(idx)}
|
|
158
|
-
>
|
|
159
|
-
{item.icon && <span className={styles.resultIcon}>{item.icon}</span>}
|
|
160
|
-
<span className={styles.resultLabel}>{item.label}</span>
|
|
161
|
-
{item.description && <span className={styles.resultDesc}>{item.description}</span>}
|
|
162
|
-
{item.shortcut && (
|
|
163
|
-
<span className={styles.resultShortcut}>
|
|
164
|
-
{item.shortcut.map((k, i) => <kbd key={i}>{k}</kbd>)}
|
|
165
|
-
</span>
|
|
166
|
-
)}
|
|
167
|
-
</button>
|
|
168
|
-
);
|
|
169
|
-
})}
|
|
170
|
-
</div>
|
|
171
|
-
))}
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<div className={styles.footer}>
|
|
175
|
-
<span><kbd>↑</kbd><kbd>↓</kbd> navigate</span>
|
|
176
|
-
<span><kbd>↵</kbd> select</span>
|
|
177
|
-
<span><kbd>Esc</kbd> close</span>
|
|
178
|
-
<span className={styles.footerRight}>
|
|
179
|
-
<kbd>{isMac ? '⌘' : 'Ctrl'}</kbd><kbd>K</kbd> toggle
|
|
180
|
-
</span>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
);
|
|
185
|
-
};
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import styles from '../css/commandpalette.module.scss';
|
|
3
|
+
|
|
4
|
+
export interface CommandPaletteItem {
|
|
5
|
+
label: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
group?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
shortcut?: string[];
|
|
10
|
+
onSelect: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface EvoCommandPaletteProps {
|
|
14
|
+
items: CommandPaletteItem[];
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
open?: boolean;
|
|
17
|
+
onClose?: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Detect Mac for shortcut display only — keyboard handler uses ctrlKey||metaKey for both
|
|
21
|
+
const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.userAgent);
|
|
22
|
+
|
|
23
|
+
const SearchIcon = () => (
|
|
24
|
+
<svg viewBox="0 0 16 16" fill="none" width="16" height="16">
|
|
25
|
+
<circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.5" />
|
|
26
|
+
<path d="M10.5 10.5L13 13" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const EvoCommandPalette = ({
|
|
31
|
+
items,
|
|
32
|
+
placeholder = 'Search commands…',
|
|
33
|
+
open: controlledOpen,
|
|
34
|
+
onClose,
|
|
35
|
+
}: EvoCommandPaletteProps) => {
|
|
36
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
37
|
+
const [query, setQuery] = useState('');
|
|
38
|
+
const [activeIdx, setActiveIdx] = useState(0);
|
|
39
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
40
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
41
|
+
|
|
42
|
+
const isControlled = controlledOpen !== undefined;
|
|
43
|
+
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
44
|
+
|
|
45
|
+
const close = useCallback(() => {
|
|
46
|
+
if (!isControlled) setInternalOpen(false);
|
|
47
|
+
onClose?.();
|
|
48
|
+
}, [isControlled, onClose]);
|
|
49
|
+
|
|
50
|
+
// Ctrl+K (Windows/Linux) / ⌘+K (Mac)
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const handler = (e: KeyboardEvent) => {
|
|
53
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
if (!isControlled) setInternalOpen(o => !o);
|
|
56
|
+
}
|
|
57
|
+
if (e.key === 'Escape' && isOpen) close();
|
|
58
|
+
};
|
|
59
|
+
document.addEventListener('keydown', handler);
|
|
60
|
+
return () => document.removeEventListener('keydown', handler);
|
|
61
|
+
}, [isControlled, isOpen, close]);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (isOpen) {
|
|
65
|
+
setQuery('');
|
|
66
|
+
setActiveIdx(0);
|
|
67
|
+
// Small delay so the element is mounted before focus
|
|
68
|
+
const t = setTimeout(() => inputRef.current?.focus(), 30);
|
|
69
|
+
return () => clearTimeout(t);
|
|
70
|
+
}
|
|
71
|
+
}, [isOpen]);
|
|
72
|
+
|
|
73
|
+
const filtered = query.trim()
|
|
74
|
+
? items.filter(item =>
|
|
75
|
+
item.label.toLowerCase().includes(query.toLowerCase()) ||
|
|
76
|
+
item.description?.toLowerCase().includes(query.toLowerCase()) ||
|
|
77
|
+
item.group?.toLowerCase().includes(query.toLowerCase())
|
|
78
|
+
)
|
|
79
|
+
: items;
|
|
80
|
+
|
|
81
|
+
const grouped = filtered.reduce<Record<string, CommandPaletteItem[]>>((acc, item) => {
|
|
82
|
+
const g = item.group ?? 'Actions';
|
|
83
|
+
if (!acc[g]) acc[g] = [];
|
|
84
|
+
acc[g].push(item);
|
|
85
|
+
return acc;
|
|
86
|
+
}, {});
|
|
87
|
+
|
|
88
|
+
const flat = Object.values(grouped).flat();
|
|
89
|
+
|
|
90
|
+
const scrollActiveIntoView = (idx: number) => {
|
|
91
|
+
const el = listRef.current?.querySelector(`[data-idx="${idx}"]`) as HTMLElement | null;
|
|
92
|
+
el?.scrollIntoView({ block: 'nearest' });
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
96
|
+
if (e.key === 'ArrowDown') {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
setActiveIdx(i => {
|
|
99
|
+
const next = Math.min(i + 1, flat.length - 1);
|
|
100
|
+
scrollActiveIntoView(next);
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
} else if (e.key === 'ArrowUp') {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
setActiveIdx(i => {
|
|
106
|
+
const next = Math.max(i - 1, 0);
|
|
107
|
+
scrollActiveIntoView(next);
|
|
108
|
+
return next;
|
|
109
|
+
});
|
|
110
|
+
} else if (e.key === 'Enter' && flat[activeIdx]) {
|
|
111
|
+
flat[activeIdx].onSelect();
|
|
112
|
+
close();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (!isOpen) return null;
|
|
117
|
+
|
|
118
|
+
let globalIdx = 0;
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className={styles.overlay} onClick={close} role="dialog" aria-modal="true">
|
|
122
|
+
<div
|
|
123
|
+
className={styles.palette}
|
|
124
|
+
onClick={e => e.stopPropagation()}
|
|
125
|
+
onKeyDown={handleKeyDown}
|
|
126
|
+
>
|
|
127
|
+
<div className={styles.searchRow}>
|
|
128
|
+
<span className={styles.searchIconWrap}><SearchIcon /></span>
|
|
129
|
+
<input
|
|
130
|
+
ref={inputRef}
|
|
131
|
+
className={styles.searchInput}
|
|
132
|
+
placeholder={placeholder}
|
|
133
|
+
value={query}
|
|
134
|
+
onChange={e => { setQuery(e.target.value); setActiveIdx(0); }}
|
|
135
|
+
aria-label="Command search"
|
|
136
|
+
/>
|
|
137
|
+
<kbd className={styles.escBadge}>Esc</kbd>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div className={styles.results} ref={listRef}>
|
|
141
|
+
{flat.length === 0 && (
|
|
142
|
+
<div className={styles.empty}>No results for “{query}”</div>
|
|
143
|
+
)}
|
|
144
|
+
{Object.entries(grouped).map(([group, groupItems]) => (
|
|
145
|
+
<div key={group} className={styles.group}>
|
|
146
|
+
<div className={styles.groupLabel}>{group}</div>
|
|
147
|
+
{groupItems.map(item => {
|
|
148
|
+
const idx = globalIdx++;
|
|
149
|
+
return (
|
|
150
|
+
<button
|
|
151
|
+
key={item.label}
|
|
152
|
+
data-idx={idx}
|
|
153
|
+
className={[styles.resultItem, idx === activeIdx ? styles.resultActive : '']
|
|
154
|
+
.filter(Boolean)
|
|
155
|
+
.join(' ')}
|
|
156
|
+
onClick={() => { item.onSelect(); close(); }}
|
|
157
|
+
onMouseEnter={() => setActiveIdx(idx)}
|
|
158
|
+
>
|
|
159
|
+
{item.icon && <span className={styles.resultIcon}>{item.icon}</span>}
|
|
160
|
+
<span className={styles.resultLabel}>{item.label}</span>
|
|
161
|
+
{item.description && <span className={styles.resultDesc}>{item.description}</span>}
|
|
162
|
+
{item.shortcut && (
|
|
163
|
+
<span className={styles.resultShortcut}>
|
|
164
|
+
{item.shortcut.map((k, i) => <kbd key={i}>{k}</kbd>)}
|
|
165
|
+
</span>
|
|
166
|
+
)}
|
|
167
|
+
</button>
|
|
168
|
+
);
|
|
169
|
+
})}
|
|
170
|
+
</div>
|
|
171
|
+
))}
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div className={styles.footer}>
|
|
175
|
+
<span><kbd>↑</kbd><kbd>↓</kbd> navigate</span>
|
|
176
|
+
<span><kbd>↵</kbd> select</span>
|
|
177
|
+
<span><kbd>Esc</kbd> close</span>
|
|
178
|
+
<span className={styles.footerRight}>
|
|
179
|
+
<kbd>{isMac ? '⌘' : 'Ctrl'}</kbd><kbd>K</kbd> toggle
|
|
180
|
+
</span>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
};
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import styles from '../css/container.module.scss';
|
|
3
|
-
|
|
4
|
-
type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
5
|
-
|
|
6
|
-
interface EvoContainerProps {
|
|
7
|
-
children: React.ReactNode;
|
|
8
|
-
size?: ContainerSize;
|
|
9
|
-
centered?: boolean;
|
|
10
|
-
className?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const EvoContainer = ({
|
|
14
|
-
children,
|
|
15
|
-
size = 'lg',
|
|
16
|
-
centered = true,
|
|
17
|
-
className = '',
|
|
18
|
-
}: EvoContainerProps) => (
|
|
19
|
-
<div
|
|
20
|
-
className={[
|
|
21
|
-
styles.container,
|
|
22
|
-
styles[size],
|
|
23
|
-
centered ? styles.centered : '',
|
|
24
|
-
className,
|
|
25
|
-
]
|
|
26
|
-
.filter(Boolean)
|
|
27
|
-
.join(' ')}
|
|
28
|
-
>
|
|
29
|
-
{children}
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../css/container.module.scss';
|
|
3
|
+
|
|
4
|
+
type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
5
|
+
|
|
6
|
+
interface EvoContainerProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
size?: ContainerSize;
|
|
9
|
+
centered?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const EvoContainer = ({
|
|
14
|
+
children,
|
|
15
|
+
size = 'lg',
|
|
16
|
+
centered = true,
|
|
17
|
+
className = '',
|
|
18
|
+
}: EvoContainerProps) => (
|
|
19
|
+
<div
|
|
20
|
+
className={[
|
|
21
|
+
styles.container,
|
|
22
|
+
styles[size],
|
|
23
|
+
centered ? styles.centered : '',
|
|
24
|
+
className,
|
|
25
|
+
]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(' ')}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
package/src/Divider/Divider.tsx
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import styles from '../css/divider.module.scss';
|
|
2
|
-
|
|
3
|
-
interface EvoDividerProps {
|
|
4
|
-
orientation?: 'horizontal' | 'vertical';
|
|
5
|
-
label?: string;
|
|
6
|
-
className?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const EvoDivider = ({ orientation = 'horizontal', label, className = '' }: EvoDividerProps) => {
|
|
10
|
-
if (label) {
|
|
11
|
-
return (
|
|
12
|
-
<div className={`${styles.labeled} ${className}`}>
|
|
13
|
-
<div className={styles.line} />
|
|
14
|
-
<span className={styles.labelText}>{label}</span>
|
|
15
|
-
<div className={styles.line} />
|
|
16
|
-
</div>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<div
|
|
22
|
-
className={[
|
|
23
|
-
styles.divider,
|
|
24
|
-
orientation === 'vertical' ? styles.vertical : styles.horizontal,
|
|
25
|
-
className,
|
|
26
|
-
]
|
|
27
|
-
.filter(Boolean)
|
|
28
|
-
.join(' ')}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
};
|
|
1
|
+
import styles from '../css/divider.module.scss';
|
|
2
|
+
|
|
3
|
+
interface EvoDividerProps {
|
|
4
|
+
orientation?: 'horizontal' | 'vertical';
|
|
5
|
+
label?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const EvoDivider = ({ orientation = 'horizontal', label, className = '' }: EvoDividerProps) => {
|
|
10
|
+
if (label) {
|
|
11
|
+
return (
|
|
12
|
+
<div className={`${styles.labeled} ${className}`}>
|
|
13
|
+
<div className={styles.line} />
|
|
14
|
+
<span className={styles.labelText}>{label}</span>
|
|
15
|
+
<div className={styles.line} />
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className={[
|
|
23
|
+
styles.divider,
|
|
24
|
+
orientation === 'vertical' ? styles.vertical : styles.horizontal,
|
|
25
|
+
className,
|
|
26
|
+
]
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.join(' ')}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|