@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.
Files changed (54) hide show
  1. package/package.json +28 -19
  2. package/src/App.tsx +626 -0
  3. package/src/components/Button/Button.css.ts +28 -0
  4. package/src/components/Button/Button.tsx +85 -0
  5. package/src/components/Card/Card.css.ts +11 -0
  6. package/src/components/Card/Card.tsx +106 -0
  7. package/src/components/Checkbox/Checkbox.css.ts +49 -0
  8. package/src/components/Checkbox/Checkbox.tsx +134 -0
  9. package/src/components/Icon/Icon.css.ts +39 -0
  10. package/src/components/Icon/Icon.tsx +163 -0
  11. package/src/components/Icon/IconPaths.tsx +80 -0
  12. package/src/components/Radio/Radio.css.ts +57 -0
  13. package/src/components/Radio/Radio.tsx +130 -0
  14. package/src/components/Ridge/Ridge.css.ts +11 -0
  15. package/src/components/Ridge/Ridge.tsx +66 -0
  16. package/src/components/Slider/Slider.css.ts +36 -0
  17. package/src/components/Slider/Slider.tsx +175 -0
  18. package/src/components/TextInput/TextInput.tsx +71 -0
  19. package/src/components/Toggle/Toggle.css.ts +55 -0
  20. package/src/components/Toggle/Toggle.tsx +167 -0
  21. package/src/index.ts +44 -0
  22. package/{react-neu/src → src}/main.tsx +0 -1
  23. package/src/styles/neumorphicEngine.ts +159 -0
  24. package/src/styles/theme.css.ts +38 -0
  25. package/src/styles/types.ts +45 -0
  26. package/tsconfig.json +26 -0
  27. package/LICENSE +0 -21
  28. package/react-neu/package-lock.json +0 -3753
  29. package/react-neu/package.json +0 -33
  30. package/react-neu/src/App.tsx +0 -30
  31. package/react-neu/src/components/Button/Button.css.ts +0 -12
  32. package/react-neu/src/components/Button/Button.tsx +0 -92
  33. package/react-neu/src/components/TextInput/TextInput.tsx +0 -72
  34. package/react-neu/src/index.ts +0 -3
  35. package/react-neu/src/styles/defaults.css.ts +0 -16
  36. package/react-neu/src/styles/filterDomProps.ts +0 -28
  37. package/react-neu/src/styles/global.css.ts +0 -12
  38. package/react-neu/src/styles/neumorphicEngine.ts +0 -110
  39. package/react-neu/src/styles/shadowUtils.ts +0 -68
  40. package/react-neu/src/styles/theme.css.ts +0 -26
  41. package/react-neu/tsconfig.json +0 -7
  42. /package/{react-neu/README.md → README.md} +0 -0
  43. /package/{react-neu/eslint.config.js → eslint.config.js} +0 -0
  44. /package/{react-neu/index.html → index.html} +0 -0
  45. /package/{react-neu/public → public}/vite.svg +0 -0
  46. /package/{react-neu/src → src}/assets/react.svg +0 -0
  47. /package/{react-neu/src → src}/components/TextInput/TextInput.css.ts +0 -0
  48. /package/{react-neu/src → src}/components/index.ts +0 -0
  49. /package/{react-neu/src → src}/styles/colorUtils.ts +0 -0
  50. /package/{react-neu/src → src}/utils/colorUtils.ts +0 -0
  51. /package/{react-neu/src → src}/utils/neuEngine.ts +0 -0
  52. /package/{react-neu/tsconfig.app.json → tsconfig.app.json} +0 -0
  53. /package/{react-neu/tsconfig.node.json → tsconfig.node.json} +0 -0
  54. /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
- "version": "1.0.27",
4
- "description": "Neumorphic components for react frontend",
5
- "keywords": [
6
- "React",
7
- "Neumorphism",
8
- "Frontend"
9
- ],
10
- "homepage": "https://github.com/PrasadJ28/react-neu#readme",
11
- "bugs": {
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
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/PrasadJ28/react-neu.git"
13
+ "dependencies": {
14
+ "react": "^19.1.1",
15
+ "react-dom": "^19.1.1"
17
16
  },
18
- "license": "MIT",
19
- "author": "prasadj28",
20
- "type": "typescript",
21
- "main": "index.js",
22
- "scripts": {
23
- "test": "echo \"Error: no test specified\" && exit 1"
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;