@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.3 → 0.1.5
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/CHANGELOG.md +1 -1
- package/dist/index.d.ts +131 -131
- package/dist/index.esm.js +148 -148
- package/dist/index.js +148 -148
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ui/accessibility-demo.tsx +271 -0
- package/src/components/ui/advanced-component-architecture-demo.tsx +916 -0
- package/src/components/ui/advanced-transition-system-demo.tsx +670 -0
- package/src/components/ui/advanced-transition-system.tsx +395 -0
- package/src/components/ui/animation/animated-container.tsx +166 -0
- package/src/components/ui/animation/index.ts +19 -0
- package/src/components/ui/animation/staggered-container.tsx +68 -0
- package/src/components/ui/animation-demo.tsx +250 -0
- package/src/components/ui/badge.tsx +33 -0
- package/src/components/ui/battery-conscious-animation-demo.tsx +568 -0
- package/src/components/ui/border-radius-shadow-demo.tsx +187 -0
- package/src/components/ui/button.tsx +36 -0
- package/src/components/ui/card.tsx +207 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/color-preview.tsx +411 -0
- package/src/components/ui/data-display/chart.tsx +653 -0
- package/src/components/ui/data-display/data-grid-simple.tsx +76 -0
- package/src/components/ui/data-display/data-grid.tsx +680 -0
- package/src/components/ui/data-display/list.tsx +456 -0
- package/src/components/ui/data-display/table.tsx +482 -0
- package/src/components/ui/data-display/timeline.tsx +441 -0
- package/src/components/ui/data-display/tree.tsx +602 -0
- package/src/components/ui/data-display/types.ts +536 -0
- package/src/components/ui/enterprise-mobile-experience-demo.tsx +749 -0
- package/src/components/ui/enterprise-mobile-experience.tsx +464 -0
- package/src/components/ui/feedback/alert.tsx +157 -0
- package/src/components/ui/feedback/progress.tsx +292 -0
- package/src/components/ui/feedback/skeleton.tsx +185 -0
- package/src/components/ui/feedback/toast.tsx +280 -0
- package/src/components/ui/feedback/types.ts +125 -0
- package/src/components/ui/font-preview.tsx +288 -0
- package/src/components/ui/form-demo.tsx +553 -0
- package/src/components/ui/hardware-acceleration-demo.tsx +547 -0
- package/src/components/ui/input.tsx +35 -0
- package/src/components/ui/label.tsx +16 -0
- package/src/components/ui/layout-demo.tsx +367 -0
- package/src/components/ui/layouts/adaptive-layout.tsx +139 -0
- package/src/components/ui/layouts/desktop-layout.tsx +224 -0
- package/src/components/ui/layouts/index.ts +10 -0
- package/src/components/ui/layouts/mobile-layout.tsx +162 -0
- package/src/components/ui/layouts/tablet-layout.tsx +197 -0
- package/src/components/ui/mobile-form-validation.tsx +451 -0
- package/src/components/ui/mobile-input-demo.tsx +201 -0
- package/src/components/ui/mobile-input.tsx +281 -0
- package/src/components/ui/mobile-skeleton-loading-demo.tsx +638 -0
- package/src/components/ui/navigation/breadcrumb.tsx +158 -0
- package/src/components/ui/navigation/index.ts +36 -0
- package/src/components/ui/navigation/menu.tsx +374 -0
- package/src/components/ui/navigation/navigation-demo.tsx +324 -0
- package/src/components/ui/navigation/pagination.tsx +272 -0
- package/src/components/ui/navigation/sidebar.tsx +383 -0
- package/src/components/ui/navigation/stepper.tsx +303 -0
- package/src/components/ui/navigation/tabs.tsx +205 -0
- package/src/components/ui/navigation/types.ts +299 -0
- package/src/components/ui/overlay/backdrop.tsx +81 -0
- package/src/components/ui/overlay/focus-manager.tsx +143 -0
- package/src/components/ui/overlay/index.ts +36 -0
- package/src/components/ui/overlay/modal.tsx +270 -0
- package/src/components/ui/overlay/overlay-manager.tsx +110 -0
- package/src/components/ui/overlay/popover.tsx +462 -0
- package/src/components/ui/overlay/portal.tsx +79 -0
- package/src/components/ui/overlay/tooltip.tsx +303 -0
- package/src/components/ui/overlay/types.ts +196 -0
- package/src/components/ui/performance-demo.tsx +596 -0
- package/src/components/ui/semantic-input-system-demo.tsx +502 -0
- package/src/components/ui/semantic-input-system-demo.tsx.disabled +873 -0
- package/src/components/ui/tablet-layout.tsx +192 -0
- package/src/components/ui/theme-customizer.tsx +386 -0
- package/src/components/ui/theme-preview.tsx +310 -0
- package/src/components/ui/theme-switcher.tsx +264 -0
- package/src/components/ui/theme-toggle.tsx +38 -0
- package/src/components/ui/token-demo.tsx +195 -0
- package/src/components/ui/touch-demo.tsx +462 -0
- package/src/components/ui/touch-friendly-interface-demo.tsx +519 -0
- package/src/components/ui/touch-friendly-interface.tsx +296 -0
- package/src/hooks/index.ts +190 -0
- package/src/hooks/use-accessibility-support.ts +518 -0
- package/src/hooks/use-adaptive-layout.ts +289 -0
- package/src/hooks/use-advanced-patterns.ts +294 -0
- package/src/hooks/use-advanced-transition-system.ts +393 -0
- package/src/hooks/use-animation-profile.ts +288 -0
- package/src/hooks/use-battery-animations.ts +384 -0
- package/src/hooks/use-battery-conscious-loading.ts +475 -0
- package/src/hooks/use-battery-optimization.ts +330 -0
- package/src/hooks/use-battery-status.ts +299 -0
- package/src/hooks/use-component-performance.ts +344 -0
- package/src/hooks/use-device-loading-states.ts +459 -0
- package/src/hooks/use-device.tsx +110 -0
- package/src/hooks/use-enterprise-mobile-experience.ts +488 -0
- package/src/hooks/use-form-feedback.ts +403 -0
- package/src/hooks/use-form-performance.ts +513 -0
- package/src/hooks/use-frame-rate.ts +251 -0
- package/src/hooks/use-gestures.ts +338 -0
- package/src/hooks/use-hardware-acceleration.ts +341 -0
- package/src/hooks/use-input-accessibility.ts +455 -0
- package/src/hooks/use-input-performance.ts +506 -0
- package/src/hooks/use-layout-performance.ts +319 -0
- package/src/hooks/use-loading-accessibility.ts +535 -0
- package/src/hooks/use-loading-performance.ts +473 -0
- package/src/hooks/use-memory-usage.ts +287 -0
- package/src/hooks/use-mobile-form-layout.ts +464 -0
- package/src/hooks/use-mobile-form-validation.ts +518 -0
- package/src/hooks/use-mobile-keyboard-optimization.ts +472 -0
- package/src/hooks/use-mobile-layout.ts +302 -0
- package/src/hooks/use-mobile-optimization.ts +406 -0
- package/src/hooks/use-mobile-skeleton.ts +402 -0
- package/src/hooks/use-mobile-touch.ts +414 -0
- package/src/hooks/use-performance-throttling.ts +348 -0
- package/src/hooks/use-performance.ts +316 -0
- package/src/hooks/use-reusable-architecture.ts +414 -0
- package/src/hooks/use-semantic-input-types.ts +357 -0
- package/src/hooks/use-semantic-input.ts +565 -0
- package/src/hooks/use-tablet-layout.ts +384 -0
- package/src/hooks/use-touch-friendly-input.ts +524 -0
- package/src/hooks/use-touch-friendly-interface.ts +331 -0
- package/src/hooks/use-touch-optimization.ts +375 -0
- package/src/index.ts +279 -279
- package/src/lib/utils.ts +6 -0
- package/src/themes/README.md +272 -0
- package/src/themes/ThemeContext.tsx +31 -0
- package/src/themes/ThemeProvider.tsx +232 -0
- package/src/themes/accessibility/index.ts +27 -0
- package/src/themes/accessibility.ts +259 -0
- package/src/themes/aria-patterns.ts +420 -0
- package/src/themes/base-themes.ts +55 -0
- package/src/themes/colorManager.ts +380 -0
- package/src/themes/examples/dark-theme.ts +154 -0
- package/src/themes/examples/minimal-theme.ts +108 -0
- package/src/themes/focus-management.ts +701 -0
- package/src/themes/fontLoader.ts +201 -0
- package/src/themes/high-contrast.ts +621 -0
- package/src/themes/index.ts +19 -0
- package/src/themes/inheritance.ts +227 -0
- package/src/themes/keyboard-navigation.ts +550 -0
- package/src/themes/motion-reduction.ts +662 -0
- package/src/themes/navigation.ts +238 -0
- package/src/themes/screen-reader.ts +645 -0
- package/src/themes/systemThemeDetector.ts +182 -0
- package/src/themes/themeCSSUpdater.ts +262 -0
- package/src/themes/themePersistence.ts +238 -0
- package/src/themes/themes/default.ts +586 -0
- package/src/themes/themes/harvey.ts +554 -0
- package/src/themes/themes/stan-design.ts +683 -0
- package/src/themes/types.ts +460 -0
- package/src/themes/useSystemTheme.ts +48 -0
- package/src/themes/useTheme.ts +87 -0
- package/src/themes/validation.ts +462 -0
- package/src/tokens/index.ts +34 -0
- package/src/tokens/tokenExporter.ts +397 -0
- package/src/tokens/tokenGenerator.ts +276 -0
- package/src/tokens/tokenManager.ts +248 -0
- package/src/tokens/tokenValidator.ts +543 -0
- package/src/tokens/types.ts +78 -0
- package/src/utils/bundle-analyzer.ts +260 -0
- package/src/utils/bundle-splitting.ts +483 -0
- package/src/utils/lazy-loading.ts +441 -0
- package/src/utils/performance-monitor.ts +513 -0
- package/src/utils/tree-shaking.ts +274 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import { ToastProps, ToastAction, ToastContainerProps } from './types';
|
|
3
|
+
|
|
4
|
+
// Simple icon components
|
|
5
|
+
const CheckCircleIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
|
|
6
|
+
<svg className={className} fill="currentColor" viewBox="0 0 20 20">
|
|
7
|
+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
|
8
|
+
</svg>
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const ExclamationTriangleIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
|
|
12
|
+
<svg className={className} fill="currentColor" viewBox="0 0 20 20">
|
|
13
|
+
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const XCircleIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
|
|
18
|
+
<svg className={className} fill="currentColor" viewBox="0 0 20 20">
|
|
19
|
+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const InformationCircleIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
|
|
24
|
+
<svg className={className} fill="currentColor" viewBox="0 0 20 20">
|
|
25
|
+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const XMarkIcon: React.FC<{ className?: string }> = ({ className = '' }) => (
|
|
30
|
+
<svg className={className} fill="currentColor" viewBox="0 0 20 20">
|
|
31
|
+
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Get icon for toast type
|
|
36
|
+
const getToastIcon = (type: ToastProps['type'], className: string) => {
|
|
37
|
+
switch (type) {
|
|
38
|
+
case 'success':
|
|
39
|
+
return <CheckCircleIcon className={className} />;
|
|
40
|
+
case 'warning':
|
|
41
|
+
return <ExclamationTriangleIcon className={className} />;
|
|
42
|
+
case 'error':
|
|
43
|
+
return <XCircleIcon className={className} />;
|
|
44
|
+
case 'info':
|
|
45
|
+
return <InformationCircleIcon className={className} />;
|
|
46
|
+
default:
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Note: getToastColors function removed as we're using semantic CSS classes
|
|
52
|
+
/*
|
|
53
|
+
const getToastColors = (type: ToastProps['type'], colors: any) => {
|
|
54
|
+
switch (type) {
|
|
55
|
+
case 'success':
|
|
56
|
+
return {
|
|
57
|
+
background: colors.semantic.success + '10',
|
|
58
|
+
border: colors.semantic.success + '30',
|
|
59
|
+
text: colors.semantic.success,
|
|
60
|
+
icon: colors.semantic.success
|
|
61
|
+
};
|
|
62
|
+
case 'warning':
|
|
63
|
+
return {
|
|
64
|
+
background: colors.semantic.warning + '10',
|
|
65
|
+
border: colors.semantic.warning + '30',
|
|
66
|
+
text: colors.semantic.warning,
|
|
67
|
+
icon: colors.semantic.warning
|
|
68
|
+
};
|
|
69
|
+
case 'error':
|
|
70
|
+
return {
|
|
71
|
+
background: colors.semantic.error + '10',
|
|
72
|
+
border: colors.semantic.error + '30',
|
|
73
|
+
text: colors.semantic.error,
|
|
74
|
+
icon: colors.semantic.error
|
|
75
|
+
};
|
|
76
|
+
case 'info':
|
|
77
|
+
return {
|
|
78
|
+
background: colors.semantic.info + '10',
|
|
79
|
+
border: colors.semantic.info + '30',
|
|
80
|
+
text: colors.semantic.info,
|
|
81
|
+
icon: colors.semantic.info
|
|
82
|
+
};
|
|
83
|
+
default:
|
|
84
|
+
return {
|
|
85
|
+
background: colors.surface.surface,
|
|
86
|
+
border: colors.surface.border,
|
|
87
|
+
text: colors.text.primary,
|
|
88
|
+
icon: colors.text.secondary
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
// Toast Action Button Component
|
|
95
|
+
const ToastActionButton: React.FC<ToastAction> = ({
|
|
96
|
+
label,
|
|
97
|
+
action,
|
|
98
|
+
variant = 'primary'
|
|
99
|
+
}) => {
|
|
100
|
+
return (
|
|
101
|
+
<button
|
|
102
|
+
type="button"
|
|
103
|
+
className={`toast__action-button toast__action-button--${variant}`}
|
|
104
|
+
onClick={() => action}
|
|
105
|
+
>
|
|
106
|
+
{label}
|
|
107
|
+
</button>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Individual Toast Component
|
|
112
|
+
export const Toast: React.FC<ToastProps> = ({
|
|
113
|
+
title,
|
|
114
|
+
message,
|
|
115
|
+
type = 'default',
|
|
116
|
+
duration = 5000,
|
|
117
|
+
onClose,
|
|
118
|
+
actions = [],
|
|
119
|
+
icon,
|
|
120
|
+
showIcon = true,
|
|
121
|
+
closable = true,
|
|
122
|
+
autoClose = true,
|
|
123
|
+
pauseOnHover = true,
|
|
124
|
+
progress = false,
|
|
125
|
+
size = 'md',
|
|
126
|
+
variant = 'default',
|
|
127
|
+
className = '',
|
|
128
|
+
}) => {
|
|
129
|
+
// Note: theme and colors not needed as we're using semantic CSS classes
|
|
130
|
+
|
|
131
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
132
|
+
const [progressValue, setProgressValue] = useState(100);
|
|
133
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
134
|
+
const progressRef = useRef<NodeJS.Timeout | null>(null);
|
|
135
|
+
|
|
136
|
+
const handleClose = useCallback(() => {
|
|
137
|
+
setIsVisible(false);
|
|
138
|
+
if (onClose) {
|
|
139
|
+
onClose();
|
|
140
|
+
}
|
|
141
|
+
}, [onClose]);
|
|
142
|
+
|
|
143
|
+
const handleMouseEnter = useCallback(() => {
|
|
144
|
+
if (pauseOnHover && autoClose) {
|
|
145
|
+
if (timeoutRef.current) {
|
|
146
|
+
clearTimeout(timeoutRef.current);
|
|
147
|
+
}
|
|
148
|
+
if (progressRef.current) {
|
|
149
|
+
clearInterval(progressRef.current);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}, [pauseOnHover, autoClose]);
|
|
153
|
+
|
|
154
|
+
const handleMouseLeave = useCallback(() => {
|
|
155
|
+
if (pauseOnHover && autoClose) {
|
|
156
|
+
startAutoClose();
|
|
157
|
+
}
|
|
158
|
+
}, [pauseOnHover, autoClose]);
|
|
159
|
+
|
|
160
|
+
const startAutoClose = useCallback(() => {
|
|
161
|
+
if (duration > 0 && autoClose) {
|
|
162
|
+
timeoutRef.current = setTimeout(() => {
|
|
163
|
+
handleClose();
|
|
164
|
+
}, duration);
|
|
165
|
+
|
|
166
|
+
if (progress) {
|
|
167
|
+
const startTime = Date.now();
|
|
168
|
+
const endTime = startTime + duration;
|
|
169
|
+
|
|
170
|
+
progressRef.current = setInterval(() => {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
const remaining = Math.max(0, endTime - now);
|
|
173
|
+
const newProgress = (remaining / duration) * 100;
|
|
174
|
+
setProgressValue(newProgress);
|
|
175
|
+
|
|
176
|
+
if (remaining <= 0) {
|
|
177
|
+
if (progressRef.current) {
|
|
178
|
+
clearInterval(progressRef.current);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}, 10);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}, [duration, autoClose, progress, handleClose]);
|
|
185
|
+
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
startAutoClose();
|
|
188
|
+
|
|
189
|
+
return () => {
|
|
190
|
+
if (timeoutRef.current) {
|
|
191
|
+
clearTimeout(timeoutRef.current);
|
|
192
|
+
}
|
|
193
|
+
if (progressRef.current) {
|
|
194
|
+
clearInterval(progressRef.current);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}, [startAutoClose]);
|
|
198
|
+
|
|
199
|
+
if (!isVisible) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const shouldShowIcon = showIcon && (icon || type);
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div
|
|
207
|
+
className={`toast__container toast__container--${size} toast__container--${variant} toast__container--${type} ${className}`}
|
|
208
|
+
role="alert"
|
|
209
|
+
aria-live="polite"
|
|
210
|
+
onMouseEnter={handleMouseEnter}
|
|
211
|
+
onMouseLeave={handleMouseLeave}
|
|
212
|
+
>
|
|
213
|
+
{progress && (
|
|
214
|
+
<div className="toast__progress">
|
|
215
|
+
<div
|
|
216
|
+
className={`toast__progress-bar toast__progress-bar--${type}`}
|
|
217
|
+
style={{ width: `${progressValue}%` }}
|
|
218
|
+
/>
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
221
|
+
|
|
222
|
+
{shouldShowIcon && (
|
|
223
|
+
<div className={`toast__icon toast__icon--${type}`}>
|
|
224
|
+
{icon || getToastIcon(type, 'toast__icon')}
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
|
|
228
|
+
<div className="toast__content">
|
|
229
|
+
{title && (
|
|
230
|
+
<h3 className="toast__title">
|
|
231
|
+
{title}
|
|
232
|
+
</h3>
|
|
233
|
+
)}
|
|
234
|
+
|
|
235
|
+
<div className={`toast__message ${!title ? 'toast__message--only' : ''}`}>
|
|
236
|
+
{message}
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
{actions.length > 0 && (
|
|
240
|
+
<div className="toast__actions">
|
|
241
|
+
{actions.map((action, index) => (
|
|
242
|
+
<ToastActionButton
|
|
243
|
+
key={index}
|
|
244
|
+
{...action}
|
|
245
|
+
/>
|
|
246
|
+
))}
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{closable && (
|
|
252
|
+
<button
|
|
253
|
+
type="button"
|
|
254
|
+
className="toast__close-button"
|
|
255
|
+
onClick={handleClose}
|
|
256
|
+
aria-label="Close toast"
|
|
257
|
+
>
|
|
258
|
+
<XMarkIcon className="toast__close-icon" />
|
|
259
|
+
</button>
|
|
260
|
+
)}
|
|
261
|
+
</div>
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Toast Container Component
|
|
266
|
+
export const ToastContainer: React.FC<ToastContainerProps & { children: React.ReactNode }> = ({
|
|
267
|
+
position = 'top-right',
|
|
268
|
+
className = '',
|
|
269
|
+
children
|
|
270
|
+
}) => {
|
|
271
|
+
return (
|
|
272
|
+
<div className={`toast-container toast-container--${position} ${className}`}>
|
|
273
|
+
<div className="toast-container__list">
|
|
274
|
+
{children}
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export default Toast;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// Base props for all feedback components
|
|
4
|
+
export interface FeedbackBaseProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
theme?: 'stan-design' | 'harvey';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Alert Component Types
|
|
10
|
+
export interface AlertProps extends FeedbackBaseProps {
|
|
11
|
+
title?: string;
|
|
12
|
+
message: string;
|
|
13
|
+
type: 'success' | 'warning' | 'error' | 'info';
|
|
14
|
+
dismissible?: boolean;
|
|
15
|
+
onDismiss?: () => void;
|
|
16
|
+
icon?: React.ReactNode;
|
|
17
|
+
actions?: AlertAction[];
|
|
18
|
+
showIcon?: boolean;
|
|
19
|
+
closable?: boolean;
|
|
20
|
+
persistent?: boolean;
|
|
21
|
+
size?: 'sm' | 'md' | 'lg';
|
|
22
|
+
variant?: 'default' | 'bordered' | 'filled';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface AlertAction {
|
|
26
|
+
label: string;
|
|
27
|
+
onClick: () => void;
|
|
28
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
29
|
+
size?: 'sm' | 'md' | 'lg';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Toast Component Types
|
|
33
|
+
export interface ToastProps extends FeedbackBaseProps {
|
|
34
|
+
id: string;
|
|
35
|
+
title?: string;
|
|
36
|
+
message: string;
|
|
37
|
+
type: 'success' | 'warning' | 'error' | 'info' | 'default';
|
|
38
|
+
duration?: number; // milliseconds, 0 = persistent
|
|
39
|
+
onClose?: () => void;
|
|
40
|
+
onAction?: (action: string) => void;
|
|
41
|
+
actions?: ToastAction[];
|
|
42
|
+
icon?: React.ReactNode;
|
|
43
|
+
showIcon?: boolean;
|
|
44
|
+
closable?: boolean;
|
|
45
|
+
position?: 'top-left' | 'top-right' | 'top-center' | 'bottom-left' | 'bottom-right' | 'bottom-center';
|
|
46
|
+
autoClose?: boolean;
|
|
47
|
+
pauseOnHover?: boolean;
|
|
48
|
+
draggable?: boolean;
|
|
49
|
+
progress?: boolean;
|
|
50
|
+
size?: 'sm' | 'md' | 'lg';
|
|
51
|
+
variant?: 'default' | 'bordered' | 'filled';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ToastAction {
|
|
55
|
+
label: string;
|
|
56
|
+
action: string;
|
|
57
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ToastContainerProps {
|
|
61
|
+
position?: ToastProps['position'];
|
|
62
|
+
maxToasts?: number;
|
|
63
|
+
autoClose?: boolean;
|
|
64
|
+
pauseOnHover?: boolean;
|
|
65
|
+
draggable?: boolean;
|
|
66
|
+
progress?: boolean;
|
|
67
|
+
className?: string;
|
|
68
|
+
theme?: 'stan-design' | 'harvey';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Progress Component Types
|
|
72
|
+
export interface ProgressProps extends FeedbackBaseProps {
|
|
73
|
+
value: number; // 0-100
|
|
74
|
+
max?: number;
|
|
75
|
+
min?: number;
|
|
76
|
+
label?: string;
|
|
77
|
+
showLabel?: boolean;
|
|
78
|
+
showValue?: boolean;
|
|
79
|
+
showPercentage?: boolean;
|
|
80
|
+
animated?: boolean;
|
|
81
|
+
striped?: boolean;
|
|
82
|
+
color?: string;
|
|
83
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
84
|
+
variant?: 'linear' | 'circular' | 'steps';
|
|
85
|
+
thickness?: number;
|
|
86
|
+
trackColor?: string;
|
|
87
|
+
progressColor?: string;
|
|
88
|
+
indeterminate?: boolean;
|
|
89
|
+
onComplete?: () => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ProgressStep {
|
|
93
|
+
label: string;
|
|
94
|
+
value: number;
|
|
95
|
+
status: 'pending' | 'active' | 'completed' | 'error';
|
|
96
|
+
description?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Skeleton Component Types
|
|
100
|
+
export interface SkeletonProps extends FeedbackBaseProps {
|
|
101
|
+
width?: string | number;
|
|
102
|
+
height?: string | number;
|
|
103
|
+
variant?: 'text' | 'circular' | 'rectangular' | 'rounded';
|
|
104
|
+
animation?: 'pulse' | 'wave' | 'none';
|
|
105
|
+
rows?: number;
|
|
106
|
+
spacing?: number;
|
|
107
|
+
show?: boolean;
|
|
108
|
+
className?: string;
|
|
109
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface SkeletonTextProps extends SkeletonProps {
|
|
113
|
+
lines?: number;
|
|
114
|
+
lineHeight?: string | number;
|
|
115
|
+
lastLineWidth?: string | number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface SkeletonAvatarProps extends SkeletonProps {
|
|
119
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
120
|
+
shape?: 'circular' | 'square' | 'rounded';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SkeletonButtonProps extends SkeletonProps {
|
|
124
|
+
fullWidth?: boolean;
|
|
125
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './card';
|
|
3
|
+
import { Badge } from './badge';
|
|
4
|
+
import { useTheme } from '../../themes';
|
|
5
|
+
import { FontConfig } from '../../themes/types';
|
|
6
|
+
|
|
7
|
+
export interface FontPreviewProps {
|
|
8
|
+
fontConfig?: FontConfig;
|
|
9
|
+
fontType?: 'primary' | 'secondary' | 'display' | 'body' | 'mono';
|
|
10
|
+
showAllVariations?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const FontPreview: React.FC<FontPreviewProps> = ({
|
|
15
|
+
fontConfig,
|
|
16
|
+
fontType = 'primary',
|
|
17
|
+
showAllVariations = false,
|
|
18
|
+
className = ''
|
|
19
|
+
}) => {
|
|
20
|
+
const { currentThemeConfig } = useTheme();
|
|
21
|
+
|
|
22
|
+
// Use provided fontConfig or get from current theme
|
|
23
|
+
const config = fontConfig || currentThemeConfig?.fonts[fontType];
|
|
24
|
+
|
|
25
|
+
if (!config) {
|
|
26
|
+
return (
|
|
27
|
+
<Card className={className}>
|
|
28
|
+
<CardContent className="p-4">
|
|
29
|
+
<p className="text-sm text-muted-foreground">Font configuration not available</p>
|
|
30
|
+
</CardContent>
|
|
31
|
+
</Card>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { family, weights, sizes, lineHeights, letterSpacing, fallbacks, source } = config;
|
|
36
|
+
|
|
37
|
+
// Build full font family string with fallbacks
|
|
38
|
+
const fullFontFamily = fallbacks
|
|
39
|
+
? `${family}, ${fallbacks.join(', ')}`
|
|
40
|
+
: family;
|
|
41
|
+
|
|
42
|
+
// Sample text for preview
|
|
43
|
+
const sampleText = "The quick brown fox jumps over the lazy dog";
|
|
44
|
+
const sampleNumbers = "1234567890";
|
|
45
|
+
const sampleSpecial = "!@#$%^&*()_+-={}[]|\\:;\"'<>,.?/";
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Card className={className}>
|
|
49
|
+
<CardHeader>
|
|
50
|
+
<CardTitle className="flex items-center justify-between">
|
|
51
|
+
<span className="capitalize">{fontType} Font</span>
|
|
52
|
+
<div className="flex gap-2">
|
|
53
|
+
{source && (
|
|
54
|
+
<Badge variant="outline" className="text-xs">
|
|
55
|
+
{source.type}
|
|
56
|
+
</Badge>
|
|
57
|
+
)}
|
|
58
|
+
<Badge variant="secondary" className="text-xs">
|
|
59
|
+
{weights?.length || 0} weights
|
|
60
|
+
</Badge>
|
|
61
|
+
</div>
|
|
62
|
+
</CardTitle>
|
|
63
|
+
<CardDescription>
|
|
64
|
+
<span className="font-mono text-xs">{family}</span>
|
|
65
|
+
{fallbacks && fallbacks.length > 0 && (
|
|
66
|
+
<div className="mt-1 text-xs text-muted-foreground">
|
|
67
|
+
Fallbacks: {fallbacks.slice(0, 3).join(', ')}
|
|
68
|
+
{fallbacks.length > 3 && ` (+${fallbacks.length - 3} more)`}
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
</CardDescription>
|
|
72
|
+
</CardHeader>
|
|
73
|
+
|
|
74
|
+
<CardContent className="space-y-6">
|
|
75
|
+
{/* Font Weights Preview */}
|
|
76
|
+
<div>
|
|
77
|
+
<h4 className="text-sm font-medium mb-3">Font Weights</h4>
|
|
78
|
+
<div className="space-y-2">
|
|
79
|
+
{weights?.map(weight => (
|
|
80
|
+
<div key={weight} className="flex items-center gap-4">
|
|
81
|
+
<Badge variant="outline" className="text-xs w-12 justify-center">
|
|
82
|
+
{weight}
|
|
83
|
+
</Badge>
|
|
84
|
+
<p
|
|
85
|
+
style={{
|
|
86
|
+
fontFamily: fullFontFamily,
|
|
87
|
+
fontWeight: weight,
|
|
88
|
+
fontSize: sizes?.md || '1rem'
|
|
89
|
+
}}
|
|
90
|
+
className="flex-1"
|
|
91
|
+
>
|
|
92
|
+
{sampleText}
|
|
93
|
+
</p>
|
|
94
|
+
</div>
|
|
95
|
+
))}
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{showAllVariations && (
|
|
100
|
+
<>
|
|
101
|
+
{/* Font Sizes Preview */}
|
|
102
|
+
<div>
|
|
103
|
+
<h4 className="text-sm font-medium mb-3">Font Sizes</h4>
|
|
104
|
+
<div className="space-y-2">
|
|
105
|
+
{Object.entries(sizes || {}).map(([size, value]) => (
|
|
106
|
+
<div key={size} className="flex items-center gap-4">
|
|
107
|
+
<Badge variant="outline" className="text-xs w-12 justify-center">
|
|
108
|
+
{size}
|
|
109
|
+
</Badge>
|
|
110
|
+
<span className="text-xs text-muted-foreground w-16">{value}</span>
|
|
111
|
+
<p
|
|
112
|
+
style={{
|
|
113
|
+
fontFamily: fullFontFamily,
|
|
114
|
+
fontSize: value,
|
|
115
|
+
fontWeight: weights?.[0] || 400
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
Sample text
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
))}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* Line Heights Preview */}
|
|
126
|
+
<div>
|
|
127
|
+
<h4 className="text-sm font-medium mb-3">Line Heights</h4>
|
|
128
|
+
<div className="space-y-4">
|
|
129
|
+
{Object.entries(lineHeights || {}).map(([height, value]) => (
|
|
130
|
+
<div key={height} className="space-y-2">
|
|
131
|
+
<div className="flex items-center gap-2">
|
|
132
|
+
<Badge variant="outline" className="text-xs">
|
|
133
|
+
{height}
|
|
134
|
+
</Badge>
|
|
135
|
+
<span className="text-xs text-muted-foreground">{value}</span>
|
|
136
|
+
</div>
|
|
137
|
+
<p
|
|
138
|
+
style={{
|
|
139
|
+
fontFamily: fullFontFamily,
|
|
140
|
+
fontSize: sizes?.md || '1rem',
|
|
141
|
+
lineHeight: value,
|
|
142
|
+
fontWeight: weights?.[0] || 400
|
|
143
|
+
}}
|
|
144
|
+
className="text-sm border-l-2 border-muted pl-4"
|
|
145
|
+
>
|
|
146
|
+
This is a multiline text example to demonstrate how line height affects the spacing between lines of text.
|
|
147
|
+
The line height setting controls the vertical space between each line, which is crucial for readability and
|
|
148
|
+
overall typography appearance.
|
|
149
|
+
</p>
|
|
150
|
+
</div>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
{/* Letter Spacing Preview */}
|
|
156
|
+
<div>
|
|
157
|
+
<h4 className="text-sm font-medium mb-3">Letter Spacing</h4>
|
|
158
|
+
<div className="space-y-2">
|
|
159
|
+
{Object.entries(letterSpacing || {}).map(([spacing, value]) => (
|
|
160
|
+
<div key={spacing} className="flex items-center gap-4">
|
|
161
|
+
<Badge variant="outline" className="text-xs w-16 justify-center">
|
|
162
|
+
{spacing}
|
|
163
|
+
</Badge>
|
|
164
|
+
<span className="text-xs text-muted-foreground w-16">{value}</span>
|
|
165
|
+
<p
|
|
166
|
+
style={{
|
|
167
|
+
fontFamily: fullFontFamily,
|
|
168
|
+
fontSize: sizes?.md || '1rem',
|
|
169
|
+
letterSpacing: value,
|
|
170
|
+
fontWeight: weights?.[0] || 400
|
|
171
|
+
}}
|
|
172
|
+
className="flex-1"
|
|
173
|
+
>
|
|
174
|
+
Letter spacing example
|
|
175
|
+
</p>
|
|
176
|
+
</div>
|
|
177
|
+
))}
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</>
|
|
181
|
+
)}
|
|
182
|
+
|
|
183
|
+
{/* Character Set Preview */}
|
|
184
|
+
<div>
|
|
185
|
+
<h4 className="text-sm font-medium mb-3">Character Support</h4>
|
|
186
|
+
<div className="space-y-3">
|
|
187
|
+
<div>
|
|
188
|
+
<span className="text-xs text-muted-foreground block mb-1">Alphabet</span>
|
|
189
|
+
<p
|
|
190
|
+
style={{
|
|
191
|
+
fontFamily: fullFontFamily,
|
|
192
|
+
fontSize: sizes?.md || '1rem',
|
|
193
|
+
fontWeight: weights?.[0] || 400
|
|
194
|
+
}}
|
|
195
|
+
className="text-sm"
|
|
196
|
+
>
|
|
197
|
+
{sampleText}
|
|
198
|
+
</p>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div>
|
|
202
|
+
<span className="text-xs text-muted-foreground block mb-1">Numbers</span>
|
|
203
|
+
<p
|
|
204
|
+
style={{
|
|
205
|
+
fontFamily: fullFontFamily,
|
|
206
|
+
fontSize: sizes?.lg || '1.125rem',
|
|
207
|
+
fontWeight: weights?.[0] || 400,
|
|
208
|
+
letterSpacing: letterSpacing?.wide || '0.025em'
|
|
209
|
+
}}
|
|
210
|
+
className="text-sm"
|
|
211
|
+
>
|
|
212
|
+
{sampleNumbers}
|
|
213
|
+
</p>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<div>
|
|
217
|
+
<span className="text-xs text-muted-foreground block mb-1">Special Characters</span>
|
|
218
|
+
<p
|
|
219
|
+
style={{
|
|
220
|
+
fontFamily: fullFontFamily,
|
|
221
|
+
fontSize: sizes?.sm || '0.875rem',
|
|
222
|
+
fontWeight: weights?.[0] || 400
|
|
223
|
+
}}
|
|
224
|
+
className="text-sm"
|
|
225
|
+
>
|
|
226
|
+
{sampleSpecial}
|
|
227
|
+
</p>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
{/* Font Loading Information */}
|
|
233
|
+
{source && (
|
|
234
|
+
<div className="pt-4 border-t">
|
|
235
|
+
<h4 className="text-sm font-medium mb-2">Font Loading</h4>
|
|
236
|
+
<div className="space-y-1 text-xs text-muted-foreground">
|
|
237
|
+
<div>Source: <span className="capitalize">{source.type}</span></div>
|
|
238
|
+
{source.url && <div>URL: {source.url}</div>}
|
|
239
|
+
{source.files && (
|
|
240
|
+
<div>
|
|
241
|
+
Files: {Object.keys(source.files).join(', ')}
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
{config.display && (
|
|
245
|
+
<div>Display: {config.display}</div>
|
|
246
|
+
)}
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
250
|
+
</CardContent>
|
|
251
|
+
</Card>
|
|
252
|
+
);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Multi-font preview component
|
|
256
|
+
export interface FontShowcaseProps {
|
|
257
|
+
showAllVariations?: boolean;
|
|
258
|
+
className?: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const FontShowcase: React.FC<FontShowcaseProps> = ({
|
|
262
|
+
showAllVariations = false,
|
|
263
|
+
className = ''
|
|
264
|
+
}) => {
|
|
265
|
+
const { currentThemeConfig } = useTheme();
|
|
266
|
+
|
|
267
|
+
if (!currentThemeConfig?.fonts) {
|
|
268
|
+
return (
|
|
269
|
+
<div className={className}>
|
|
270
|
+
<p className="text-sm text-muted-foreground">No font configuration available</p>
|
|
271
|
+
</div>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const fontTypes: Array<keyof typeof currentThemeConfig.fonts> = ['primary', 'secondary', 'display', 'body', 'mono'];
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<div className={`space-y-6 ${className}`}>
|
|
279
|
+
{fontTypes.map(fontType => (
|
|
280
|
+
<FontPreview
|
|
281
|
+
key={fontType}
|
|
282
|
+
fontType={fontType}
|
|
283
|
+
showAllVariations={showAllVariations}
|
|
284
|
+
/>
|
|
285
|
+
))}
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
};
|