@prasadj28/react-neu 1.0.27 → 1.0.28
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/package.json +28 -19
- package/src/App.tsx +626 -0
- package/src/components/Button/Button.css.ts +28 -0
- package/src/components/Button/Button.tsx +85 -0
- package/src/components/Card/Card.css.ts +11 -0
- package/src/components/Card/Card.tsx +106 -0
- package/src/components/Checkbox/Checkbox.css.ts +49 -0
- package/src/components/Checkbox/Checkbox.tsx +134 -0
- package/src/components/Icon/Icon.css.ts +39 -0
- package/src/components/Icon/Icon.tsx +163 -0
- package/src/components/Icon/IconPaths.tsx +80 -0
- package/src/components/Radio/Radio.css.ts +57 -0
- package/src/components/Radio/Radio.tsx +130 -0
- package/src/components/Ridge/Ridge.css.ts +11 -0
- package/src/components/Ridge/Ridge.tsx +66 -0
- package/src/components/Slider/Slider.css.ts +36 -0
- package/src/components/Slider/Slider.tsx +175 -0
- package/src/components/TextInput/TextInput.tsx +71 -0
- package/src/components/Toggle/Toggle.css.ts +55 -0
- package/src/components/Toggle/Toggle.tsx +167 -0
- package/src/index.ts +44 -0
- package/{react-neu/src → src}/main.tsx +0 -1
- package/src/styles/neumorphicEngine.ts +159 -0
- package/src/styles/theme.css.ts +38 -0
- package/src/styles/types.ts +45 -0
- package/tsconfig.json +26 -0
- package/LICENSE +0 -21
- package/react-neu/package-lock.json +0 -3753
- package/react-neu/package.json +0 -33
- package/react-neu/src/App.tsx +0 -30
- package/react-neu/src/components/Button/Button.css.ts +0 -12
- package/react-neu/src/components/Button/Button.tsx +0 -92
- package/react-neu/src/components/TextInput/TextInput.tsx +0 -72
- package/react-neu/src/index.ts +0 -3
- package/react-neu/src/styles/defaults.css.ts +0 -16
- package/react-neu/src/styles/filterDomProps.ts +0 -28
- package/react-neu/src/styles/global.css.ts +0 -12
- package/react-neu/src/styles/neumorphicEngine.ts +0 -110
- package/react-neu/src/styles/shadowUtils.ts +0 -68
- package/react-neu/src/styles/theme.css.ts +0 -26
- package/react-neu/tsconfig.json +0 -7
- /package/{react-neu/README.md → README.md} +0 -0
- /package/{react-neu/eslint.config.js → eslint.config.js} +0 -0
- /package/{react-neu/index.html → index.html} +0 -0
- /package/{react-neu/public → public}/vite.svg +0 -0
- /package/{react-neu/src → src}/assets/react.svg +0 -0
- /package/{react-neu/src → src}/components/TextInput/TextInput.css.ts +0 -0
- /package/{react-neu/src → src}/components/index.ts +0 -0
- /package/{react-neu/src → src}/styles/colorUtils.ts +0 -0
- /package/{react-neu/src → src}/utils/colorUtils.ts +0 -0
- /package/{react-neu/src → src}/utils/neuEngine.ts +0 -0
- /package/{react-neu/tsconfig.app.json → tsconfig.app.json} +0 -0
- /package/{react-neu/tsconfig.node.json → tsconfig.node.json} +0 -0
- /package/{react-neu/vite.config.ts → vite.config.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prasadj28/react-neu",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"url": "https://github.com/PrasadJ28/react-neu/issues"
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.0.28",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite --open",
|
|
8
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
9
|
+
"build:vite": "LIB=true vite build",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"preview": "vite preview"
|
|
13
12
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"react": "^19.1.1",
|
|
15
|
+
"react-dom": "^19.1.1"
|
|
17
16
|
},
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@eslint/js": "^9.36.0",
|
|
19
|
+
"@types/node": "^24.6.0",
|
|
20
|
+
"@types/react": "^19.1.16",
|
|
21
|
+
"@types/react-dom": "^19.1.9",
|
|
22
|
+
"@vanilla-extract/css": "^1.17.4",
|
|
23
|
+
"@vanilla-extract/vite-plugin": "^5.1.1",
|
|
24
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
25
|
+
"eslint": "^9.36.0",
|
|
26
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
27
|
+
"eslint-plugin-react-refresh": "^0.4.22",
|
|
28
|
+
"globals": "^16.4.0",
|
|
29
|
+
"tsup": "^8.5.1",
|
|
30
|
+
"typescript": "~5.9.3",
|
|
31
|
+
"typescript-eslint": "^8.45.0",
|
|
32
|
+
"vite": "^7.1.7"
|
|
24
33
|
}
|
|
25
34
|
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { NeuButton } from "./components/Button/Button";
|
|
3
|
+
import { NeuTextInput } from "./components/TextInput/TextInput";
|
|
4
|
+
import { NeuCard } from "./components/Card/Card";
|
|
5
|
+
import { NeuRidge } from "./components/Ridge/Ridge";
|
|
6
|
+
import { NeuCheckbox } from "./components/Checkbox/Checkbox";
|
|
7
|
+
import { NeuRadio } from "./components/Radio/Radio";
|
|
8
|
+
import { NeuSlider } from "./components/Slider/Slider";
|
|
9
|
+
import type { NeuVariant, NeuSurface } from "./styles/types";
|
|
10
|
+
import { NeuSwitch } from "./components/Toggle/Toggle";
|
|
11
|
+
import { NeuIcon } from "./components/Icon/Icon";
|
|
12
|
+
import { iconRegistry, type IconName } from "./components/Icon/IconPaths";
|
|
13
|
+
|
|
14
|
+
function App() {
|
|
15
|
+
const [active, setActive] = React.useState(false);
|
|
16
|
+
const [isOn, setIsOn] = React.useState(false);
|
|
17
|
+
const [sliderVal, setSliderVal] = React.useState(30);
|
|
18
|
+
const [val, setVal] = React.useState("dot");
|
|
19
|
+
const [shapeVal, setShapeVal] = React.useState("circle");
|
|
20
|
+
const variants: NeuVariant[] = ["flat", "pop", "inset"];
|
|
21
|
+
const surfaces: NeuSurface[] = ["flat", "convex", "concave"];
|
|
22
|
+
const [isLiked, setIsLiked] = React.useState(false);
|
|
23
|
+
const sectionStyle: React.CSSProperties = {
|
|
24
|
+
display: "flex",
|
|
25
|
+
flexDirection: "column",
|
|
26
|
+
gap: "20px",
|
|
27
|
+
marginBottom: "40px",
|
|
28
|
+
width: "100%",
|
|
29
|
+
maxWidth: "400px",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const rowStyle: React.CSSProperties = {
|
|
33
|
+
display: "flex",
|
|
34
|
+
gap: "15px",
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
justifyContent: "center",
|
|
37
|
+
flexWrap: "wrap",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const labelStyle: React.CSSProperties = {
|
|
41
|
+
fontSize: "0.85rem",
|
|
42
|
+
textTransform: "uppercase",
|
|
43
|
+
letterSpacing: "1px",
|
|
44
|
+
color: "#888",
|
|
45
|
+
marginBottom: "10px",
|
|
46
|
+
textAlign: "center",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const titleStyle: React.CSSProperties = {
|
|
50
|
+
fontSize: "0.9rem",
|
|
51
|
+
textTransform: "uppercase",
|
|
52
|
+
letterSpacing: "1px",
|
|
53
|
+
color: "#888",
|
|
54
|
+
marginBottom: "5px",
|
|
55
|
+
borderBottom: "1px solid #ccc",
|
|
56
|
+
paddingBottom: "5px"
|
|
57
|
+
};
|
|
58
|
+
const headingStyle: React.CSSProperties = {
|
|
59
|
+
fontSize: "0.9rem",
|
|
60
|
+
textTransform: "uppercase",
|
|
61
|
+
letterSpacing: "1px",
|
|
62
|
+
color: "#777",
|
|
63
|
+
borderBottom: "1px solid #ccc",
|
|
64
|
+
paddingBottom: "5px",
|
|
65
|
+
marginBottom: "10px"
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const allIcons = Object.keys(iconRegistry) as IconName[];
|
|
69
|
+
|
|
70
|
+
// State to track which icons are "active" (filled)
|
|
71
|
+
const [activeSet, setActiveSet] = React.useState<Set<string>>(new Set());
|
|
72
|
+
|
|
73
|
+
const toggleIcon = (name: string) => {
|
|
74
|
+
const next = new Set(activeSet);
|
|
75
|
+
if (next.has(name)) next.delete(name);
|
|
76
|
+
else next.add(name);
|
|
77
|
+
setActiveSet(next);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div style={{ padding: "40px", display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
83
|
+
|
|
84
|
+
{/* SECTION 1: BUTTON VARIANTS */}
|
|
85
|
+
<div style={sectionStyle}>
|
|
86
|
+
<div style={labelStyle}>1. Button Variants</div>
|
|
87
|
+
|
|
88
|
+
{/* Flat: Flush -> Sinks */}
|
|
89
|
+
<div style={rowStyle}>
|
|
90
|
+
<NeuButton variant="flat">Flat</NeuButton>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
{/* Pop: Raised -> Sinks (Mechanical Feel) */}
|
|
94
|
+
<div style={rowStyle}>
|
|
95
|
+
<NeuButton variant="pop" color="#e0e0e0">Pop</NeuButton>
|
|
96
|
+
<NeuButton variant="pop" color="#3b82f6" style={{ color: "white" }}>
|
|
97
|
+
Blue Pop
|
|
98
|
+
</NeuButton>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{/* Inset: Recessed -> Deeper Press */}
|
|
102
|
+
<div style={rowStyle}>
|
|
103
|
+
<NeuButton variant="inset">Inset</NeuButton>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
{/* SECTION 2: SHAPES & SIZES */}
|
|
109
|
+
<div style={sectionStyle}>
|
|
110
|
+
<div style={labelStyle}>2. Shapes & Sizes</div>
|
|
111
|
+
<div style={rowStyle}>
|
|
112
|
+
<NeuButton variant="pop" shape="square" style={{ width: "50px", height: "50px", padding: 0 }}>
|
|
113
|
+
Sq
|
|
114
|
+
</NeuButton>
|
|
115
|
+
<NeuButton variant="pop" shape="rounded">Rounded</NeuButton>
|
|
116
|
+
<NeuButton variant="pop" shape="pill">Pill Shape</NeuButton>
|
|
117
|
+
<NeuButton variant="pop" shape="circle" style={{ width: "50px", height: "50px", padding: 0 }}>
|
|
118
|
+
●
|
|
119
|
+
</NeuButton>
|
|
120
|
+
<div onClick={() => setActive(!active)} style={{ cursor: 'pointer' }}>
|
|
121
|
+
{/* STATE OFF: Convex Surface (Bulges out) + Pop Button
|
|
122
|
+
STATE ON: Concave Surface (Dips in) + Inset Button
|
|
123
|
+
*/}
|
|
124
|
+
<NeuButton
|
|
125
|
+
variant={active ? "inset" : "pop"}
|
|
126
|
+
surface={active ? "concave" : "convex"}
|
|
127
|
+
shape="circle"
|
|
128
|
+
style={{ width: '80px', height: '80px' }}
|
|
129
|
+
>
|
|
130
|
+
{active ? "ON" : "OFF"}
|
|
131
|
+
</NeuButton>
|
|
132
|
+
|
|
133
|
+
<NeuButton variant="pop" surface="concave" >Convex</NeuButton>
|
|
134
|
+
|
|
135
|
+
<NeuButton
|
|
136
|
+
variant="pop" // Stays elevated (Drop Shadow)
|
|
137
|
+
surface={isOn ? "concave" : "convex"} // The Morphing Magic
|
|
138
|
+
shape="circle"
|
|
139
|
+
onClick={() => setIsOn(!isOn)}
|
|
140
|
+
|
|
141
|
+
// 1. Customize the Transition Speed
|
|
142
|
+
// Slower transition (0.5s) makes the "morph" more visible and luxurious
|
|
143
|
+
style={{
|
|
144
|
+
width: "80px",
|
|
145
|
+
height: "80px",
|
|
146
|
+
transition: "all 0.5s ease-in-out",
|
|
147
|
+
color: isOn ? "#3b82f6" : "#888",
|
|
148
|
+
fontSize: "0.8rem"
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
{isOn ? "ON" : "OFF"}
|
|
152
|
+
</NeuButton>
|
|
153
|
+
|
|
154
|
+
{/* Helper Text */}
|
|
155
|
+
<span style={{ color: '#888', fontSize: '14px' }}>
|
|
156
|
+
Current Surface: <b>{isOn ? "Concave" : "Convex"}</b>
|
|
157
|
+
</span>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
{/* SECTION 3: INPUT BEHAVIORS */}
|
|
164
|
+
<div style={sectionStyle}>
|
|
165
|
+
<div style={labelStyle}>3. Input Behaviors</div>
|
|
166
|
+
|
|
167
|
+
{/* Standard Inset: Deep -> Sharp Focus */}
|
|
168
|
+
<NeuTextInput
|
|
169
|
+
variant="inset"
|
|
170
|
+
placeholder="Inset (Standard)"
|
|
171
|
+
/>
|
|
172
|
+
|
|
173
|
+
{/* Pop Input: Raised -> Sinks on Focus */}
|
|
174
|
+
<NeuTextInput
|
|
175
|
+
variant="pop"
|
|
176
|
+
placeholder="Pop (Sinks on Focus)"
|
|
177
|
+
/>
|
|
178
|
+
|
|
179
|
+
{/* Flat Input: Flush -> Sinks on Focus */}
|
|
180
|
+
<NeuTextInput
|
|
181
|
+
variant="flat"
|
|
182
|
+
placeholder="Flat (Flush)"
|
|
183
|
+
/>
|
|
184
|
+
<NeuTextInput variant="pop" ridge={true} placeholder="Type here..." />
|
|
185
|
+
|
|
186
|
+
</div>
|
|
187
|
+
<div style={sectionStyle}>
|
|
188
|
+
<div style={titleStyle}>2. Ridge Container</div>
|
|
189
|
+
<div style={rowStyle}>
|
|
190
|
+
{/* A Ridge creates a tight seam around content */}
|
|
191
|
+
<NeuRidge ridgeWidth="10px">
|
|
192
|
+
<NeuButton>Content</NeuButton>
|
|
193
|
+
</NeuRidge>
|
|
194
|
+
|
|
195
|
+
{/* 2. Using a number (Defaults to pixels) */}
|
|
196
|
+
<NeuRidge ridgeWidth={30}>
|
|
197
|
+
<NeuButton>Content</NeuButton>
|
|
198
|
+
</NeuRidge>
|
|
199
|
+
|
|
200
|
+
{/* 3. Combined with other props */}
|
|
201
|
+
<NeuRidge
|
|
202
|
+
ridgeWidth="1rem"
|
|
203
|
+
variant="inset"
|
|
204
|
+
shape="rounded"
|
|
205
|
+
>
|
|
206
|
+
<NeuButton>Content</NeuButton>
|
|
207
|
+
</NeuRidge>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
{/* 3. CARDS */}
|
|
212
|
+
<div style={{
|
|
213
|
+
padding: "40px",
|
|
214
|
+
backgroundColor: "#e0e0e0",
|
|
215
|
+
minHeight: "100vh",
|
|
216
|
+
fontFamily: "sans-serif"
|
|
217
|
+
}}>
|
|
218
|
+
|
|
219
|
+
<h1 style={{ color: "#555", textAlign: "center", marginBottom: "40px" }}>
|
|
220
|
+
Neumorphic Engine Matrix (3x3)
|
|
221
|
+
</h1>
|
|
222
|
+
|
|
223
|
+
{/* THE MATRIX GRID */}
|
|
224
|
+
<div style={{
|
|
225
|
+
display: "grid",
|
|
226
|
+
gridTemplateColumns: "150px repeat(3, 1fr)",
|
|
227
|
+
gap: "40px",
|
|
228
|
+
alignItems: "center",
|
|
229
|
+
maxWidth: "1000px",
|
|
230
|
+
margin: "0 auto"
|
|
231
|
+
}}>
|
|
232
|
+
|
|
233
|
+
{/* Header Row */}
|
|
234
|
+
<div></div>
|
|
235
|
+
{surfaces.map(s => (
|
|
236
|
+
<div key={s} style={{
|
|
237
|
+
textAlign: "center",
|
|
238
|
+
textTransform: "uppercase",
|
|
239
|
+
fontWeight: "bold",
|
|
240
|
+
color: "#888"
|
|
241
|
+
}}>
|
|
242
|
+
Surface: {s}
|
|
243
|
+
</div>
|
|
244
|
+
))}
|
|
245
|
+
|
|
246
|
+
{/* Rows */}
|
|
247
|
+
{variants.map((variant) => (
|
|
248
|
+
<React.Fragment key={variant}>
|
|
249
|
+
{/* Row Label */}
|
|
250
|
+
<div style={{
|
|
251
|
+
textAlign: "right",
|
|
252
|
+
textTransform: "uppercase",
|
|
253
|
+
fontWeight: "bold",
|
|
254
|
+
color: "#888"
|
|
255
|
+
}}>
|
|
256
|
+
Variant: {variant}
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
{/* Columns */}
|
|
260
|
+
{surfaces.map((surface) => (
|
|
261
|
+
<div key={`${variant}-${surface}`} style={{ display: 'flex', justifyContent: 'center' }}>
|
|
262
|
+
<NeuCard
|
|
263
|
+
variant={variant}
|
|
264
|
+
surface={surface}
|
|
265
|
+
elevation={4} // Higher elevation makes the curve more visible
|
|
266
|
+
style={{
|
|
267
|
+
width: "160px",
|
|
268
|
+
height: "160px",
|
|
269
|
+
alignItems: "center",
|
|
270
|
+
justifyContent: "center",
|
|
271
|
+
textAlign: "center",
|
|
272
|
+
color: "#666",
|
|
273
|
+
fontWeight: 500
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
{variant}
|
|
277
|
+
<br />
|
|
278
|
+
+
|
|
279
|
+
<br />
|
|
280
|
+
{surface}
|
|
281
|
+
</NeuCard>
|
|
282
|
+
</div>
|
|
283
|
+
))}
|
|
284
|
+
</React.Fragment>
|
|
285
|
+
))}
|
|
286
|
+
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
<div style={sectionStyle}>
|
|
290
|
+
<div style={titleStyle}>5. Checkbox & Radio</div>
|
|
291
|
+
|
|
292
|
+
{/* Checkboxes */}
|
|
293
|
+
<div style={{ padding: "40px", maxWidth: "800px", margin: "0 auto", fontFamily: "sans-serif" }}>
|
|
294
|
+
<h1 style={{ color: "#444", textAlign: "center" }}>Checkbox Gallery</h1>
|
|
295
|
+
|
|
296
|
+
{/* 1. SELECTION STYLES */}
|
|
297
|
+
<div style={sectionStyle}>
|
|
298
|
+
<div style={headingStyle}>1. Selection Styles (Pop Variant)</div>
|
|
299
|
+
<div style={rowStyle}>
|
|
300
|
+
|
|
301
|
+
<NeuCheckbox selectionStyle="check" defaultChecked>
|
|
302
|
+
Check (Default)
|
|
303
|
+
</NeuCheckbox>
|
|
304
|
+
|
|
305
|
+
<NeuCheckbox selectionStyle="cross" defaultChecked>
|
|
306
|
+
Cross
|
|
307
|
+
</NeuCheckbox>
|
|
308
|
+
|
|
309
|
+
<NeuCheckbox selectionStyle="fill" defaultChecked>
|
|
310
|
+
Fill (Sink Only)
|
|
311
|
+
</NeuCheckbox>
|
|
312
|
+
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
{/* 2. SHAPES */}
|
|
317
|
+
<div style={sectionStyle}>
|
|
318
|
+
<div style={headingStyle}>2. Shapes</div>
|
|
319
|
+
<div style={rowStyle}>
|
|
320
|
+
|
|
321
|
+
<NeuCheckbox shape="square" defaultChecked>
|
|
322
|
+
Square
|
|
323
|
+
</NeuCheckbox>
|
|
324
|
+
|
|
325
|
+
<NeuCheckbox shape="rounded" defaultChecked>
|
|
326
|
+
Rounded
|
|
327
|
+
</NeuCheckbox>
|
|
328
|
+
|
|
329
|
+
<NeuCheckbox shape="circle" selectionStyle="check" defaultChecked>
|
|
330
|
+
Circle
|
|
331
|
+
</NeuCheckbox>
|
|
332
|
+
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
{/* 3. VARIANTS (Base Physics) */}
|
|
337
|
+
<div style={sectionStyle}>
|
|
338
|
+
<div style={headingStyle}>3. Variants (Unchecked State)</div>
|
|
339
|
+
<div style={rowStyle}>
|
|
340
|
+
|
|
341
|
+
{/* Pop: Raised -> Sinks */}
|
|
342
|
+
<NeuCheckbox variant="pop">
|
|
343
|
+
Pop
|
|
344
|
+
</NeuCheckbox>
|
|
345
|
+
|
|
346
|
+
{/* Inset: Recessed -> Deeper Recess */}
|
|
347
|
+
<NeuCheckbox variant="inset">
|
|
348
|
+
Inset
|
|
349
|
+
</NeuCheckbox>
|
|
350
|
+
|
|
351
|
+
{/* Flat: Flush -> Sinks */}
|
|
352
|
+
<NeuCheckbox variant="flat">
|
|
353
|
+
Flat
|
|
354
|
+
</NeuCheckbox>
|
|
355
|
+
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
{/* 4. RIDGE & COLOR */}
|
|
360
|
+
<div style={sectionStyle}>
|
|
361
|
+
<div style={headingStyle}>4. Special Features</div>
|
|
362
|
+
<div style={rowStyle}>
|
|
363
|
+
|
|
364
|
+
{/* Ridge: Adds a border seam */}
|
|
365
|
+
<NeuCheckbox ridge={true} variant="pop" defaultChecked>
|
|
366
|
+
Ridge Mode
|
|
367
|
+
</NeuCheckbox>
|
|
368
|
+
|
|
369
|
+
{/* Custom Color */}
|
|
370
|
+
<NeuCheckbox
|
|
371
|
+
selectionStyle="check"
|
|
372
|
+
selectedColor="#ef4444" // Red Icon
|
|
373
|
+
defaultChecked
|
|
374
|
+
>
|
|
375
|
+
Red Check
|
|
376
|
+
</NeuCheckbox>
|
|
377
|
+
|
|
378
|
+
<NeuCheckbox
|
|
379
|
+
selectionStyle="cross"
|
|
380
|
+
selectedColor="#3b82f6" // Blue Icon
|
|
381
|
+
defaultChecked
|
|
382
|
+
>
|
|
383
|
+
Blue Cross
|
|
384
|
+
</NeuCheckbox>
|
|
385
|
+
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
{/* 5. SIZES */}
|
|
390
|
+
<div style={sectionStyle}>
|
|
391
|
+
<div style={headingStyle}>5. Custom Sizes</div>
|
|
392
|
+
<div style={rowStyle}>
|
|
393
|
+
<NeuCheckbox size="20px" defaultChecked />
|
|
394
|
+
<NeuCheckbox size="30px" defaultChecked />
|
|
395
|
+
<NeuCheckbox size="40px" selectionStyle="cross" defaultChecked />
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
{/* Radios */}
|
|
402
|
+
<div style={{ padding: "40px", maxWidth: "800px", margin: "0 auto", fontFamily: "sans-serif" }}>
|
|
403
|
+
<h1 style={{ color: "#444", textAlign: "center" }}>Radio Gallery</h1>
|
|
404
|
+
|
|
405
|
+
{/* 1. STYLES */}
|
|
406
|
+
<div style={sectionStyle}>
|
|
407
|
+
<div style={headingStyle}>1. Styles (Group A)</div>
|
|
408
|
+
<div style={rowStyle}>
|
|
409
|
+
<NeuRadio
|
|
410
|
+
name="g1"
|
|
411
|
+
checked={val === "dot"}
|
|
412
|
+
onChange={() => setVal("dot")}
|
|
413
|
+
selectionStyle="dot"
|
|
414
|
+
>
|
|
415
|
+
Dot (Standard)
|
|
416
|
+
</NeuRadio>
|
|
417
|
+
|
|
418
|
+
<NeuRadio
|
|
419
|
+
name="g1"
|
|
420
|
+
checked={val === "check"}
|
|
421
|
+
onChange={() => setVal("check")}
|
|
422
|
+
selectionStyle="check"
|
|
423
|
+
selectedColor="#3b82f6"
|
|
424
|
+
>
|
|
425
|
+
Check
|
|
426
|
+
</NeuRadio>
|
|
427
|
+
|
|
428
|
+
<NeuRadio
|
|
429
|
+
name="g1"
|
|
430
|
+
checked={val === "fill"}
|
|
431
|
+
onChange={() => setVal("fill")}
|
|
432
|
+
selectionStyle="fill"
|
|
433
|
+
>
|
|
434
|
+
Fill (Sink)
|
|
435
|
+
</NeuRadio>
|
|
436
|
+
</div>
|
|
437
|
+
</div>
|
|
438
|
+
|
|
439
|
+
{/* 2. SHAPES */}
|
|
440
|
+
<div style={sectionStyle}>
|
|
441
|
+
<div style={headingStyle}>2. Shapes (Group B)</div>
|
|
442
|
+
<div style={rowStyle}>
|
|
443
|
+
<NeuRadio name="g2" shape="circle" checked={shapeVal === "circle"} onChange={() => setShapeVal("circle")}>
|
|
444
|
+
Circle
|
|
445
|
+
</NeuRadio>
|
|
446
|
+
<NeuRadio name="g2" shape="rounded" checked={shapeVal === "rounded"} onChange={() => setShapeVal("rounded")}>
|
|
447
|
+
Rounded
|
|
448
|
+
</NeuRadio>
|
|
449
|
+
<NeuRadio name="g2" shape="square" checked={shapeVal === "square"} onChange={() => setShapeVal("square")}>
|
|
450
|
+
Square
|
|
451
|
+
</NeuRadio>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
{/* 3. VARIANTS & RIDGE */}
|
|
456
|
+
<div style={sectionStyle}>
|
|
457
|
+
<div style={headingStyle}>3. Variants</div>
|
|
458
|
+
<div style={rowStyle}>
|
|
459
|
+
<NeuRadio checked={true} variant="pop">Pop</NeuRadio>
|
|
460
|
+
<NeuRadio checked={true} variant="inset">Inset</NeuRadio>
|
|
461
|
+
<NeuRadio checked={true} variant="pop" ridge={true}>Ridge</NeuRadio>
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
</div>
|
|
466
|
+
|
|
467
|
+
{/* 3. VARIANTS & RIDGE */}
|
|
468
|
+
<div style={sectionStyle}>
|
|
469
|
+
<div style={headingStyle}>3. Variants</div>
|
|
470
|
+
<div style={rowStyle}>
|
|
471
|
+
<NeuRadio checked={true} variant="pop">Pop</NeuRadio>
|
|
472
|
+
<NeuRadio checked={true} variant="inset">Inset</NeuRadio>
|
|
473
|
+
<NeuRadio checked={true} variant="pop" ridge={true}>Ridge</NeuRadio>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
</div>
|
|
478
|
+
|
|
479
|
+
{/* 6. SLIDER */}
|
|
480
|
+
<div style={sectionStyle}>
|
|
481
|
+
<div style={headingStyle}>3. Sliders (Value: {sliderVal})</div>
|
|
482
|
+
|
|
483
|
+
{/* Standard Inset Track */}
|
|
484
|
+
<NeuSlider
|
|
485
|
+
value={sliderVal}
|
|
486
|
+
onChange={setSliderVal}
|
|
487
|
+
min={0}
|
|
488
|
+
max={100}
|
|
489
|
+
/>
|
|
490
|
+
|
|
491
|
+
{/* Ridged Track with Larger Thumb */}
|
|
492
|
+
<div style={{ marginTop: "10px" }}>
|
|
493
|
+
<NeuSlider
|
|
494
|
+
value={sliderVal}
|
|
495
|
+
onChange={setSliderVal}
|
|
496
|
+
thumbSize="32px"
|
|
497
|
+
ridge={true} // Adds the border seam to the track
|
|
498
|
+
/>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
{/* 4. SWITCHES */}
|
|
503
|
+
<div style={sectionStyle}>
|
|
504
|
+
<div style={headingStyle}>4. Switches (Toggle)</div>
|
|
505
|
+
<div style={rowStyle}>
|
|
506
|
+
|
|
507
|
+
{/* A. Standard Pill (Default) */}
|
|
508
|
+
<div style={{ textAlign: 'center' }}>
|
|
509
|
+
<div style={{ marginBottom: '8px', fontSize: '0.8rem' }}>Standard</div>
|
|
510
|
+
<NeuSwitch
|
|
511
|
+
width="60px"
|
|
512
|
+
defaultChecked={false}
|
|
513
|
+
/>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
{/* B. Square Shape + Check Icon + Blue */}
|
|
517
|
+
<div style={{ textAlign: 'center' }}>
|
|
518
|
+
<div style={{ marginBottom: '8px', fontSize: '0.8rem' }}>Square Check</div>
|
|
519
|
+
<NeuSwitch
|
|
520
|
+
width="60px"
|
|
521
|
+
shape="square"
|
|
522
|
+
selectionStyle="check"
|
|
523
|
+
selectedColor="#3b82f6" // Blue
|
|
524
|
+
defaultChecked={true}
|
|
525
|
+
/>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
{/* C. Ridge Track + Cross Icon + Red */}
|
|
529
|
+
<div style={{ textAlign: 'center' }}>
|
|
530
|
+
<div style={{ marginBottom: '8px', fontSize: '0.8rem' }}>Ridge Cross</div>
|
|
531
|
+
<NeuSwitch
|
|
532
|
+
width="70px"
|
|
533
|
+
ridge={true} // Adds the border frame
|
|
534
|
+
selectionStyle="cross"
|
|
535
|
+
selectedColor="#ef4444" // Red
|
|
536
|
+
defaultChecked={true}
|
|
537
|
+
/>
|
|
538
|
+
</div>
|
|
539
|
+
|
|
540
|
+
{/* D. Flat Variant (Subtle) */}
|
|
541
|
+
<div style={{ textAlign: 'center' }}>
|
|
542
|
+
<div style={{ marginBottom: '8px', fontSize: '0.8rem' }}>Flat Variant</div>
|
|
543
|
+
<NeuSwitch
|
|
544
|
+
width="50px"
|
|
545
|
+
variant="flat"
|
|
546
|
+
defaultChecked={false}
|
|
547
|
+
/>
|
|
548
|
+
</div>
|
|
549
|
+
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
<NeuIcon
|
|
553
|
+
icon="heart"
|
|
554
|
+
transparent={true}
|
|
555
|
+
filled={isLiked}
|
|
556
|
+
onClick={() => setIsLiked(!isLiked)}
|
|
557
|
+
/>
|
|
558
|
+
|
|
559
|
+
// 2. STANDARD BUTTON (With Circle Container)
|
|
560
|
+
<NeuIcon
|
|
561
|
+
icon="heart"
|
|
562
|
+
filled={isLiked}
|
|
563
|
+
// transparent={false} is default
|
|
564
|
+
/>
|
|
565
|
+
<div style={{
|
|
566
|
+
padding: "40px",
|
|
567
|
+
backgroundColor: "#e0e0e0",
|
|
568
|
+
minHeight: "100vh",
|
|
569
|
+
fontFamily: "sans-serif",
|
|
570
|
+
color: "#555"
|
|
571
|
+
}}>
|
|
572
|
+
|
|
573
|
+
<h1 style={{ textAlign: "center", marginBottom: "10px" }}>Icon Library</h1>
|
|
574
|
+
<p style={{ textAlign: "center", marginBottom: "50px", opacity: 0.7 }}>
|
|
575
|
+
Click any icon to toggle its active state
|
|
576
|
+
</p>
|
|
577
|
+
|
|
578
|
+
{/* THE GRID */}
|
|
579
|
+
<div style={{
|
|
580
|
+
display: "grid",
|
|
581
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(120px, 1fr))",
|
|
582
|
+
gap: "40px",
|
|
583
|
+
maxWidth: "1000px",
|
|
584
|
+
margin: "0 auto"
|
|
585
|
+
}}>
|
|
586
|
+
|
|
587
|
+
{allIcons.map((iconName) => (
|
|
588
|
+
<div
|
|
589
|
+
key={iconName}
|
|
590
|
+
style={{
|
|
591
|
+
display: "flex",
|
|
592
|
+
flexDirection: "column",
|
|
593
|
+
alignItems: "center",
|
|
594
|
+
gap: "15px"
|
|
595
|
+
}}
|
|
596
|
+
>
|
|
597
|
+
{/* The Icon Component */}
|
|
598
|
+
<NeuIcon
|
|
599
|
+
icon={iconName}
|
|
600
|
+
size="60px"
|
|
601
|
+
filled={activeSet.has(iconName)}
|
|
602
|
+
onClick={() => toggleIcon(iconName)}
|
|
603
|
+
// Optional: Customize based on icon type
|
|
604
|
+
shape={["circle", "search", "user"].includes(iconName) ? "circle" : "rounded"}
|
|
605
|
+
fillColor="#ef4444" // Uniform color for the demo
|
|
606
|
+
/>
|
|
607
|
+
|
|
608
|
+
{/* The Label */}
|
|
609
|
+
<span style={{
|
|
610
|
+
fontSize: "0.85rem",
|
|
611
|
+
opacity: 0.6,
|
|
612
|
+
fontFamily: "monospace"
|
|
613
|
+
}}>
|
|
614
|
+
{iconName}
|
|
615
|
+
</span>
|
|
616
|
+
</div>
|
|
617
|
+
))}
|
|
618
|
+
|
|
619
|
+
</div>
|
|
620
|
+
</div>
|
|
621
|
+
|
|
622
|
+
</div>
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export default App;
|