Skip to content

Commit c4f859a

Browse files
committed
fix style
1 parent cf5a834 commit c4f859a

File tree

4 files changed

+247
-14
lines changed

4 files changed

+247
-14
lines changed

src/ObjectView/ObjectRouter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const ObjectRouter: React.FC<Omit<JSONViewProps, 'currentField' | 'curren
2121
const currentType = typeof value;
2222

2323

24-
if (!value || value === true) {
24+
if ((!value && value !== 0 && value !== "") || value === true) {
2525
return <KeywordValueView {...props} {...{ currentField, currentType }} />;
2626
}
2727

src/Test.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
/* Custom demo styles */
3+
.custom-user-view {
4+
display: inline-block;
5+
margin: 2px 0;
6+
}
7+
8+
.custom-user-view:hover {
9+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
10+
}
11+
12+
/* Demo feature highlight */
13+
.demo-highlight {
14+
position: relative;
15+
}
16+
17+
.demo-highlight::after {
18+
content: "🆕";
19+
position: absolute;
20+
top: -8px;
21+
right: -8px;
22+
font-size: 12px;
23+
}

src/Test.tsx

Lines changed: 223 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,127 @@
33
import React, { useState } from 'react';
44
import { ObjectView } from './ObjectView/ObjectView';
55
import { allExamples, quickExamples, performanceTestData } from './exampleData';
6+
import { JSONViewProps, Constructor } from './ObjectView/JSONViewProps';
67
import './style.css';
8+
import "./Test.css";
9+
// Custom classes for demonstration
10+
class User {
11+
constructor(public name: string, public email: string, public role: string = 'user') { }
12+
}
13+
14+
class APIEndpoint {
15+
constructor(
16+
public method: string,
17+
public url: string,
18+
public status: number,
19+
public responseTime: number,
20+
public data?: any
21+
) { }
22+
}
23+
24+
// Custom renderer for User class
25+
const UserRenderer: React.FC<JSONViewProps> = ({ value, name, displayName, seperator = ":" }) => (
26+
<div className="custom-user-view" style={{
27+
padding: '4px 8px',
28+
borderRadius: '4px',
29+
backgroundColor: '#f0f8ff',
30+
border: '1px solid #e0e8f0'
31+
}}>
32+
{displayName && <span className="jv-name">{name}</span>}
33+
{displayName && <span>{seperator}</span>}
34+
<span style={{ marginRight: '8px' }}>👤</span>
35+
<strong>{value.name}</strong>
36+
<span style={{ color: '#666', marginLeft: '8px' }}>({value.email})</span>
37+
{value.role !== 'user' && (
38+
<span style={{
39+
backgroundColor: '#ffd700',
40+
padding: '2px 6px',
41+
borderRadius: '3px',
42+
fontSize: '10px',
43+
marginLeft: '8px',
44+
textTransform: 'uppercase'
45+
}}>
46+
{value.role}
47+
</span>
48+
)}
49+
</div>
50+
);
51+
52+
// Custom renderer for API endpoints
53+
const APIRenderer: React.FC<JSONViewProps> = ({ value, name, displayName, seperator = ":" }) => {
54+
const getStatusColor = (status: number) => {
55+
if (status < 300) return '#28a745';
56+
if (status < 400) return '#ffc107';
57+
return '#dc3545';
58+
};
59+
60+
const getMethodColor = (method: string) => {
61+
switch (method) {
62+
case 'GET': return '#007bff';
63+
case 'POST': return '#28a745';
64+
case 'PUT': return '#ffc107';
65+
case 'DELETE': return '#dc3545';
66+
default: return '#6c757d';
67+
}
68+
};
69+
70+
return (
71+
<div style={{
72+
padding: '6px 10px',
73+
borderRadius: '4px',
74+
backgroundColor: '#f8f9fa',
75+
border: '1px solid #dee2e6',
76+
fontFamily: 'monospace'
77+
}}>
78+
{displayName && <span className="jv-name">{name}</span>}
79+
{displayName && <span>{seperator}</span>}
80+
<span style={{
81+
backgroundColor: getMethodColor(value.method),
82+
color: 'white',
83+
padding: '2px 6px',
84+
borderRadius: '3px',
85+
fontSize: '11px',
86+
marginRight: '8px'
87+
}}>
88+
{value.method}
89+
</span>
90+
<span style={{ marginRight: '8px' }}>{value.url}</span>
91+
<span style={{
92+
color: getStatusColor(value.status),
93+
fontWeight: 'bold',
94+
marginRight: '8px'
95+
}}>
96+
{value.status}
97+
</span>
98+
<span style={{ color: '#666', fontSize: '12px' }}>
99+
{value.responseTime}ms
100+
</span>
101+
</div>
102+
);
103+
};
104+
105+
// Create custom data with new classes
106+
const createCustomExampleData = () => ({
107+
users: {
108+
admin: new User("Admin User", "admin@example.com", "admin"),
109+
moderator: new User("Mod User", "mod@example.com", "moderator"),
110+
regular: new User("John Doe", "john@example.com")
111+
},
112+
apiCalls: {
113+
getUsersAPI: new APIEndpoint('GET', '/api/users', 200, 145),
114+
loginAPI: new APIEndpoint('POST', '/api/auth/login', 401, 89),
115+
createUserAPI: new APIEndpoint('POST', '/api/users', 201, 234),
116+
deleteUserAPI: new APIEndpoint('DELETE', '/api/users/123', 204, 156)
117+
},
118+
keywordDemo: {
119+
isActive: true,
120+
isDisabled: false,
121+
data: null,
122+
config: undefined,
123+
emptyString: "",
124+
zeroNumber: 0
125+
}
126+
});
7127

8128
// Create a flat list of all available test data for the dropdown
9129
const testDataOptions = [
@@ -12,6 +132,16 @@ const testDataOptions = [
12132
{ label: 'Quick - Moderate Nested', value: quickExamples.moderate, category: 'Quick' },
13133
{ label: 'Quick - Complex Mixed Types', value: quickExamples.complex, category: 'Quick' },
14134

135+
// NEW: Custom renderer demos
136+
{ label: 'Demo - Custom Renderers', value: createCustomExampleData(), category: 'Demo' },
137+
{
138+
label: 'Demo - Keyword Styling', value: {
139+
booleans: { isTrue: true, isFalse: false },
140+
nullish: { nullValue: null, undefinedValue: undefined },
141+
emptyValues: { emptyString: "", zeroNumber: 0, emptyArray: [], emptyObject: {} }
142+
}, category: 'Demo'
143+
},
144+
15145
// Primitives
16146
{
17147
label: 'Primitives - Basic Types', value: {
@@ -70,6 +200,18 @@ export const Test = () => {
70200
const [customDataParsed, setCustomDataParsed] = useState<any>(null);
71201
const [parseError, setParseError] = useState<string>('');
72202

203+
// NEW: State for new features
204+
const [enableCustomRenderers, setEnableCustomRenderers] = useState(true);
205+
const [enableHighlighting, setEnableHighlighting] = useState(true);
206+
const [objectGrouped, setObjectGrouped] = useState(25);
207+
const [arrayGrouped, setArrayGrouped] = useState(10);
208+
209+
// Create custom renderer map
210+
const customRenderers = enableCustomRenderers ? new Map<Constructor, React.FC<JSONViewProps>>([
211+
[User as Constructor, UserRenderer],
212+
[APIEndpoint as Constructor, APIRenderer]
213+
]) : undefined;
214+
73215
const handleDataChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
74216
const selectedIndex = parseInt(event.target.value);
75217
setSelectedData(testDataOptions[selectedIndex]);
@@ -143,6 +285,20 @@ export const Test = () => {
143285
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
144286
<h1>ObjectView Test Interface</h1>
145287

288+
<div style={{
289+
marginBottom: '20px',
290+
padding: '15px',
291+
backgroundColor: '#e8f4fd',
292+
borderRadius: '8px',
293+
border: '1px solid #bee5eb'
294+
}}>
295+
<h3 style={{ margin: '0 0 10px 0', color: '#0c5460' }}>🆕 New Features Demo</h3>
296+
<p style={{ margin: '0', fontSize: '14px', color: '#0c5460' }}>
297+
This demo showcases the latest features: Custom Renderers, Keyword Styling, and Configurable Highlighting.
298+
Try selecting "Demo - Custom Renderers" to see custom User and API endpoint visualizations!
299+
</p>
300+
</div>
301+
146302
<div style={{ marginBottom: '20px', display: 'flex', gap: '20px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
147303
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', flexWrap: 'wrap' }}>
148304
<div>
@@ -206,6 +362,65 @@ export const Test = () => {
206362
</div>
207363
</div>
208364

365+
{/* NEW: Additional controls for new features */}
366+
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', flexWrap: 'wrap' }}>
367+
<div>
368+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
369+
🎨 Features:
370+
</label>
371+
<div style={{ display: 'flex', gap: '15px', flexWrap: 'wrap' }}>
372+
<label style={{ display: 'flex', alignItems: 'center' }}>
373+
<input
374+
type="checkbox"
375+
checked={enableCustomRenderers}
376+
onChange={(e) => setEnableCustomRenderers(e.target.checked)}
377+
style={{ marginRight: '6px' }}
378+
/>
379+
Custom Renderers
380+
</label>
381+
<label style={{ display: 'flex', alignItems: 'center' }}>
382+
<input
383+
type="checkbox"
384+
checked={enableHighlighting}
385+
onChange={(e) => setEnableHighlighting(e.target.checked)}
386+
style={{ marginRight: '6px' }}
387+
/>
388+
Change Highlighting
389+
</label>
390+
</div>
391+
</div>
392+
393+
<div>
394+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
395+
📦 Grouping:
396+
</label>
397+
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
398+
<label style={{ fontSize: '12px' }}>
399+
Objects:
400+
<input
401+
type="number"
402+
value={objectGrouped}
403+
onChange={(e) => setObjectGrouped(parseInt(e.target.value) || 25)}
404+
style={{ width: '50px', marginLeft: '4px', padding: '2px' }}
405+
min="1"
406+
max="100"
407+
/>
408+
</label>
409+
<label style={{ fontSize: '12px' }}>
410+
Arrays:
411+
<input
412+
type="number"
413+
value={arrayGrouped}
414+
onChange={(e) => setArrayGrouped(parseInt(e.target.value) || 10)}
415+
style={{ width: '50px', marginLeft: '4px', padding: '2px' }}
416+
min="1"
417+
max="100"
418+
/>
419+
</label>
420+
</div>
421+
</div>
422+
</div>
423+
209424
<div style={{ minWidth: '300px' }}>
210425
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>
211426
<input
@@ -264,7 +479,10 @@ export const Test = () => {
264479
Status: {parseError ? 'Invalid' : 'Valid'} |
265480
</>
266481
)}
267-
Expand Level: {expandLevel === true ? 'Full' : expandLevel === false ? 'None' : expandLevel}
482+
Expand Level: {expandLevel === true ? 'Full' : expandLevel === false ? 'None' : expandLevel} |
483+
Custom Renderers: {enableCustomRenderers ? 'ON' : 'OFF'} |
484+
Change Highlighting: {enableHighlighting ? 'ON' : 'OFF'} |
485+
Grouping: Objects({objectGrouped}) Arrays({arrayGrouped})
268486
</p>
269487
</div>
270488

@@ -288,6 +506,10 @@ export const Test = () => {
288506
value={getCurrentData()}
289507
name="testData"
290508
expandLevel={expandLevel}
509+
customRender={customRenderers}
510+
highlightUpdate={enableHighlighting}
511+
objectGrouped={objectGrouped}
512+
arrayGrouped={arrayGrouped}
291513
/>
292514
</div>
293515
</div>

src/style.css

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,6 @@
55
--jv-change-color: rgb(255, 50, 0);
66
}
77

8-
.react-state-dev-btn {
9-
position: fixed;
10-
bottom: 30px;
11-
right: 30px;
12-
transition: opacity 0.3s;
13-
14-
&[data-active="true"] {
15-
opacity: 0;
16-
pointer-events: none;
17-
}
18-
}
19-
208
.jv-root {
219

2210
font-family: monospace;

0 commit comments

Comments
 (0)