@waysnx/ui-core 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,475 @@
1
+ # @waysnx/ui-core
2
+
3
+ Core UI components for WaysNX - A comprehensive React component library with form controls, inputs, buttons, date pickers, and more.
4
+
5
+ ## Features
6
+
7
+ - 🎨 Modern, accessible UI components
8
+ - 📝 Complete form controls (Input, Select, Checkbox, Radio, etc.)
9
+ - 📅 Date and date range pickers
10
+ - 🔒 Built-in XSS protection with DOMPurify
11
+ - 🎯 TypeScript support
12
+ - 🌙 Dark mode ready
13
+ - 📦 Tree-shakeable
14
+ - 🎨 CSS variables for easy theming
15
+ - 📋 JSON Schema to Form converter
16
+ - ⚡ Optimized and minified for production
17
+
18
+ ## Installation
19
+
20
+ ### Prerequisites
21
+
22
+ This package requires React 18+ and react-datepicker as peer dependencies.
23
+
24
+ ### Install via npm
25
+
26
+ ```bash
27
+ npm install @waysnx/ui-core react-datepicker
28
+ ```
29
+
30
+ ### Authentication Setup
31
+
32
+ Since this package is hosted on GitHub Packages, you need to authenticate:
33
+
34
+ 1. Create a `.npmrc` file in your project root:
35
+
36
+ ```
37
+ @waysnx:registry=https://npm.pkg.github.com/
38
+ //npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
39
+ ```
40
+
41
+ 2. Generate a GitHub Personal Access Token:
42
+ - Go to: https://github.com/settings/tokens
43
+ - Click "Generate new token (classic)"
44
+ - Select scope: `read:packages`
45
+ - Copy the token and replace `YOUR_GITHUB_TOKEN` in `.npmrc`
46
+
47
+ 3. Add `.npmrc` to `.gitignore`:
48
+
49
+ ```bash
50
+ echo ".npmrc" >> .gitignore
51
+ ```
52
+
53
+ ### Import CSS
54
+
55
+ Import the required CSS files in your main entry file (e.g., `main.tsx` or `App.tsx`):
56
+
57
+ ```javascript
58
+ import '@waysnx/ui-core/dist/index.css';
59
+ import 'react-datepicker/dist/react-datepicker.css';
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ### Basic Components
65
+
66
+ ```jsx
67
+ import { Button, Input, Select, Checkbox } from '@waysnx/ui-core';
68
+ import { useState } from 'react';
69
+
70
+ function MyForm() {
71
+ const [name, setName] = useState('');
72
+ const [country, setCountry] = useState('');
73
+ const [agreed, setAgreed] = useState(false);
74
+
75
+ return (
76
+ <div>
77
+ <Input
78
+ label="Name"
79
+ value={name}
80
+ onChange={(e) => setName(e.target.value)}
81
+ placeholder="Enter your name"
82
+ required
83
+ />
84
+
85
+ <Select
86
+ label="Country"
87
+ value={country}
88
+ onChange={(e) => setCountry(e.target.value)}
89
+ options={[
90
+ { value: 'us', label: 'United States' },
91
+ { value: 'uk', label: 'United Kingdom' },
92
+ { value: 'ca', label: 'Canada' }
93
+ ]}
94
+ />
95
+
96
+ <Checkbox
97
+ label="I agree to terms and conditions"
98
+ checked={agreed}
99
+ onChange={(e) => setAgreed(e.target.checked)}
100
+ />
101
+
102
+ <Button variant="primary" type="submit">
103
+ Submit
104
+ </Button>
105
+ </div>
106
+ );
107
+ }
108
+ ```
109
+
110
+ ### Switch Component
111
+
112
+ ```jsx
113
+ import { Switch } from '@waysnx/ui-core';
114
+ import { useState } from 'react';
115
+
116
+ function MyComponent() {
117
+ const [enabled, setEnabled] = useState(false);
118
+
119
+ return (
120
+ <Switch
121
+ label="Enable notifications"
122
+ checked={enabled}
123
+ onChange={(e) => setEnabled(e.target.checked)}
124
+ />
125
+ );
126
+ }
127
+ ```
128
+
129
+ ### Date Picker
130
+
131
+ ```jsx
132
+ import { DatePicker } from '@waysnx/ui-core';
133
+ import { useState } from 'react';
134
+
135
+ function MyComponent() {
136
+ const [date, setDate] = useState(null);
137
+
138
+ return (
139
+ <DatePicker
140
+ label="Select Date"
141
+ selected={date}
142
+ onChange={setDate}
143
+ placeholder="Choose a date"
144
+ />
145
+ );
146
+ }
147
+ ```
148
+
149
+ ### Multi-Select with Select All
150
+
151
+ ```jsx
152
+ import { Select } from '@waysnx/ui-core';
153
+ import { useState } from 'react';
154
+
155
+ function MyComponent() {
156
+ const [selected, setSelected] = useState([]);
157
+
158
+ return (
159
+ <Select
160
+ label="Select Skills"
161
+ value={selected}
162
+ onChange={(e) => {
163
+ const options = Array.from(e.target.selectedOptions, option => option.value);
164
+ setSelected(options);
165
+ }}
166
+ options={[
167
+ { value: 'js', label: 'JavaScript' },
168
+ { value: 'ts', label: 'TypeScript' },
169
+ { value: 'react', label: 'React' }
170
+ ]}
171
+ multiple
172
+ showSelectAll
173
+ />
174
+ );
175
+ }
176
+ ```
177
+
178
+ ### JSON Schema to Form
179
+
180
+ Convert JSON Schema to form fields automatically:
181
+
182
+ ```jsx
183
+ import { schemaToFormFields, type JSONSchema } from '@waysnx/ui-core';
184
+ import { useState } from 'react';
185
+
186
+ const formSchema: JSONSchema = {
187
+ type: 'object',
188
+ properties: {
189
+ firstName: {
190
+ type: 'string',
191
+ title: 'First Name',
192
+ 'x-placeholder': 'John'
193
+ },
194
+ email: {
195
+ type: 'string',
196
+ format: 'email',
197
+ title: 'Email Address'
198
+ },
199
+ country: {
200
+ type: 'string',
201
+ title: 'Country',
202
+ enum: ['United States', 'United Kingdom', 'Canada']
203
+ },
204
+ birthdate: {
205
+ type: 'string',
206
+ format: 'date',
207
+ title: 'Date of Birth'
208
+ },
209
+ interests: {
210
+ type: 'array',
211
+ title: 'Interests',
212
+ items: {
213
+ type: 'string',
214
+ enum: ['Technology', 'Sports', 'Music', 'Travel']
215
+ },
216
+ 'x-component': 'checkbox-group'
217
+ },
218
+ newsletter: {
219
+ type: 'boolean',
220
+ title: 'Subscribe to newsletter',
221
+ 'x-component': 'checkbox'
222
+ },
223
+ status: {
224
+ type: 'boolean',
225
+ title: 'Active Status'
226
+ // Will render as Switch by default
227
+ }
228
+ },
229
+ required: ['firstName', 'email']
230
+ };
231
+
232
+ function DynamicForm() {
233
+ const [formData, setFormData] = useState({});
234
+
235
+ const handleChange = (name: string, value: any) => {
236
+ setFormData(prev => ({ ...prev, [name]: value }));
237
+ };
238
+
239
+ const fields = schemaToFormFields(formSchema, formData, handleChange);
240
+
241
+ const handleSubmit = (e: React.FormEvent) => {
242
+ e.preventDefault();
243
+ console.log('Form data:', formData);
244
+ };
245
+
246
+ return (
247
+ <form onSubmit={handleSubmit}>
248
+ {fields.map(field => (
249
+ <div key={field.name}>
250
+ {field.component}
251
+ </div>
252
+ ))}
253
+ </form>
254
+ );
255
+ }
256
+ ```
257
+
258
+ ## Available Components
259
+
260
+ ### Form Controls
261
+ - `Input` - Text, email, password, number inputs with optional password toggle
262
+ - `Select` - Single and multi-select dropdowns with optional select-all
263
+ - `Checkbox` - Single checkbox or checkbox group
264
+ - `Radio` - Radio button group
265
+ - `Textarea` - Multi-line text input
266
+ - `Switch` - Toggle switch
267
+ - `Slider` - Range slider
268
+ - `Autocomplete` - Searchable dropdown with filtering
269
+ - `FileUpload` - File upload with drag & drop
270
+
271
+ ### Date & Time Components
272
+ - `DatePicker` - Single date picker
273
+ - `DateRangePicker` - Date range picker
274
+ - `DateTimePicker` - Date and time picker
275
+ - `TimePicker` - Time picker
276
+
277
+ ### Buttons & Navigation
278
+ - `Button` - Button with variants (primary, secondary, destructive, outline, ghost)
279
+ - `Link` - Styled link component
280
+
281
+ ### Content & Display
282
+ - `HtmlEditor` - Rich text editor (sanitized with DOMPurify)
283
+ - `HtmlContent` - Display HTML content (sanitized with DOMPurify)
284
+ - `Alert` - Alert/notification component
285
+ - `Spinner` - Loading spinner
286
+ - `Divider` - Horizontal divider line
287
+
288
+ ### Layout & Structure
289
+ - `Stack` - Vertical or horizontal stack layout
290
+ - `Hidden` - Conditionally hide content
291
+ - `Tree` - Tree view component
292
+
293
+ ### Utilities
294
+ - `schemaToFormFields` - Convert JSON Schema to form components
295
+ - `useDebounce` - Debounce hook for performance
296
+
297
+ ## Button Variants
298
+
299
+ ```jsx
300
+ <Button variant="primary">Primary</Button>
301
+ <Button variant="secondary">Secondary</Button>
302
+ <Button variant="destructive">Delete</Button>
303
+ <Button variant="outline">Outline</Button>
304
+ <Button variant="ghost">Ghost</Button>
305
+ ```
306
+
307
+ ## Theming
308
+
309
+ The library uses CSS variables for easy theming. Override these in your CSS to match your app's design system.
310
+
311
+ ### Available CSS Variables
312
+
313
+ #### Color Variables
314
+
315
+ ```css
316
+ :root {
317
+ /* Primary Colors */
318
+ --wx-color-primary: #f19924;
319
+ --wx-color-primary-hover: #d88420;
320
+ --wx-color-primary-light: #fef3e6;
321
+
322
+ /* Secondary Colors */
323
+ --wx-color-secondary: #6b7280;
324
+ --wx-color-secondary-hover: #4b5563;
325
+
326
+ /* Status Colors */
327
+ --wx-color-success: #10b981;
328
+ --wx-color-danger: #ef4444;
329
+ --wx-color-warning: #f59e0b;
330
+ --wx-color-info: #3b82f6;
331
+
332
+ /* Text Colors */
333
+ --wx-text-primary: #111827;
334
+ --wx-text-secondary: #6b7280;
335
+ --wx-text-disabled: #9ca3af;
336
+
337
+ /* Background Colors */
338
+ --wx-bg-primary: #ffffff;
339
+ --wx-bg-secondary: #f9fafb;
340
+ --wx-bg-hover: #f3f4f6;
341
+
342
+ /* Border Colors */
343
+ --wx-border-color: #d1d5db;
344
+ --wx-border-focus: #f19924;
345
+
346
+ /* Accent Colors */
347
+ --wx-accent-orange: #f97316;
348
+ --wx-accent-orange-dark: #ea580c;
349
+ }
350
+ ```
351
+
352
+ #### Dark Mode Support
353
+
354
+ ```css
355
+ .dark {
356
+ --wx-color-primary: #fbbf24;
357
+ --wx-color-primary-hover: #f59e0b;
358
+
359
+ --wx-text-primary: #f3f4f6;
360
+ --wx-text-secondary: #9ca3af;
361
+ --wx-text-disabled: #6b7280;
362
+
363
+ --wx-bg-primary: #111827;
364
+ --wx-bg-secondary: #1f2937;
365
+ --wx-bg-hover: #374151;
366
+
367
+ --wx-border-color: #374151;
368
+ --wx-border-focus: #fbbf24;
369
+ }
370
+ ```
371
+
372
+ ### Dynamic Theme Integration
373
+
374
+ To integrate with your existing design system, create a theme override file:
375
+
376
+ ```css
377
+ /* theme-override.css */
378
+ :root {
379
+ /* Map your app's variables to library variables */
380
+ --wx-color-primary: var(--your-brand-color, #f19924);
381
+ --wx-color-secondary: var(--your-gray-600, #6b7280);
382
+ --wx-text-primary: var(--your-text-color, #111827);
383
+ --wx-bg-primary: var(--your-bg-color, #ffffff);
384
+ /* ... map other variables */
385
+ }
386
+ ```
387
+
388
+ Import this file after the library CSS:
389
+
390
+ ```javascript
391
+ import '@waysnx/ui-core/dist/index.css';
392
+ import './theme-override.css'; // Your overrides
393
+ ```
394
+
395
+ This ensures library components automatically match your app's theme, including dark mode support.
396
+
397
+ ## JSON Schema Extensions
398
+
399
+ The library supports custom JSON Schema extensions using the `x-` prefix:
400
+
401
+ - `x-placeholder` - Placeholder text for inputs
402
+ - `x-component` - Force specific component:
403
+ - `'checkbox'` - Single checkbox for boolean
404
+ - `'checkbox-group'` - Multiple checkboxes for array
405
+ - `'toggle'` or `'switch'` - Toggle switch for boolean
406
+ - `'button'` - Render as button
407
+ - `x-button-type` - Button type ('submit', 'button', 'reset')
408
+ - `x-button-variant` - Button variant ('primary', 'secondary', 'destructive', 'outline', 'ghost')
409
+
410
+ ### JSON Schema Type Mappings
411
+
412
+ The library automatically maps JSON Schema types to components:
413
+
414
+ | Schema Type | Format | Component |
415
+ |------------|--------|-----------|
416
+ | `string` | - | Input (text) |
417
+ | `string` | `email` | Input (email) |
418
+ | `string` | `password` | Input (password) with toggle |
419
+ | `string` | `date` | DatePicker |
420
+ | `string` | `date-time` | DateTimePicker |
421
+ | `string` | `time` | TimePicker |
422
+ | `string` | `binary` | FileUpload |
423
+ | `string` | `uri` | Input (url) |
424
+ | `string` | `textarea` | Textarea |
425
+ | `string` | `html` | HtmlEditor |
426
+ | `string` | `enum` | Select (single) |
427
+ | `integer` / `number` | - | Input (number) |
428
+ | `integer` / `number` | with min/max | Slider |
429
+ | `boolean` | - | Switch (default) |
430
+ | `boolean` | `x-component: 'checkbox'` | Checkbox |
431
+ | `array` | `enum` items | Select (multi) or Checkbox group |
432
+
433
+ ## TypeScript Support
434
+
435
+ Full TypeScript support with type definitions included:
436
+
437
+ ```typescript
438
+ import type { JSONSchema, FormField } from '@waysnx/ui-core';
439
+ ```
440
+
441
+ ## Security
442
+
443
+ This package includes built-in XSS protection:
444
+ - HTML content is sanitized using DOMPurify
445
+ - Safe to render user-generated content
446
+ - Code is minified and optimized for production
447
+
448
+ ## Browser Support
449
+
450
+ - Chrome (latest)
451
+ - Firefox (latest)
452
+ - Safari (latest)
453
+ - Edge (latest)
454
+
455
+ ## Peer Dependencies
456
+
457
+ - `react` >= 18
458
+ - `react-dom` >= 18
459
+ - `react-datepicker` ^8.0.0
460
+
461
+ ## License
462
+
463
+ MIT
464
+
465
+ ## Repository
466
+
467
+ https://github.com/waysnx/waysnx-ui-kit
468
+
469
+ ## Issues
470
+
471
+ https://github.com/waysnx/waysnx-ui-kit/issues
472
+
473
+ ## Author
474
+
475
+ WaysNX Technologies
@@ -0,0 +1 @@
1
+ .wx-alert{padding:12px 16px;border-radius:6px;font-size:14px}.wx-alert-info{background:#eff6ff;color:#1d4ed8}.wx-alert-success{background:#ecfdf5;color:#047857}.wx-alert-warning{background:#fffbeb;color:#b45309}.wx-alert-error{background:#fef2f2;color:#b91c1c}
@@ -0,0 +1,76 @@
1
+ .wx-autocomplete-wrapper {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 4px;
5
+ position: relative;
6
+ }
7
+
8
+ .wx-autocomplete-label {
9
+ font-size: 14px;
10
+ font-weight: 500;
11
+ }
12
+
13
+ .wx-autocomplete-input {
14
+ width: 100%;
15
+ padding: 10px;
16
+ border: 1px solid #ccc;
17
+ border-radius: 6px;
18
+ outline: none;
19
+ height: 40px;
20
+ box-sizing: border-box;
21
+ font-size: 14px;
22
+ }
23
+
24
+ .wx-autocomplete-input:focus {
25
+ border-color: var(--wx-color-primary, #f19924);
26
+ }
27
+
28
+ .wx-autocomplete-input-error {
29
+ border-color: var(--wx-color-error, #dc2626);
30
+ }
31
+
32
+ .wx-autocomplete-dropdown {
33
+ position: absolute;
34
+ top: 100%;
35
+ left: 0;
36
+ right: 0;
37
+ margin: 4px 0 0 0;
38
+ padding: 0;
39
+ max-width: 350px;
40
+ max-height: 240px;
41
+ overflow-y: auto;
42
+ background: #fff;
43
+ border: 1px solid #ccc;
44
+ border-radius: 6px;
45
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
46
+ z-index: 1000;
47
+ }
48
+
49
+ .wx-autocomplete-option {
50
+ padding: 10px 12px;
51
+ cursor: pointer;
52
+ display: block;
53
+ }
54
+
55
+ .wx-autocomplete-option:hover,
56
+ .wx-autocomplete-option-highlighted {
57
+ background: #f2f2f2;
58
+ }
59
+
60
+ .wx-autocomplete-no-options {
61
+ padding: 10px 12px;
62
+ color: #6b6b6d;
63
+ font-size: 14px;
64
+ text-align: center;
65
+ }
66
+
67
+ .wx-autocomplete-hint {
68
+ font-size: 12px;
69
+ color: #6b7280;
70
+ }
71
+
72
+ .wx-autocomplete-error-text {
73
+ font-size: 12px;
74
+ color: #dc2626;
75
+ }
76
+
@@ -0,0 +1,12 @@
1
+ .wx-button{font-weight:500;border-radius:6px;padding:10px 16px;cursor:pointer;transition:background 0.15s ease,color 0.15s ease;outline:none}
2
+ .wx-button--primary{background:var(--wx-color-primary,#f19924);color:#fff;border:none}
3
+ .wx-button--primary:hover{background:var(--wx-color-primary-hover,#e08916)}
4
+ .wx-button--secondary{background:transparent;color:var(--wx-color-primary,#f19924);border:1px solid var(--wx-color-primary,#f19924)}
5
+ .wx-button--secondary:hover{background:var(--wx-color-primary,#f19924);color:#fff}
6
+ .wx-button--destructive{background:var(--wx-color-destructive,#dc2626);color:#fff;border:none}
7
+ .wx-button--destructive:hover{background:var(--wx-color-destructive-hover,#b91c1c)}
8
+ .wx-button--outline{background:transparent;color:var(--wx-color-text,#333);border:1px solid var(--wx-color-border,#ddd)}
9
+ .wx-button--outline:hover{background:var(--wx-color-bg-subtle,#f5f5f5)}
10
+ .wx-button--ghost{background:transparent;color:var(--wx-color-text,#333);border:none}
11
+ .wx-button--ghost:hover{background:var(--wx-color-bg-subtle,#f5f5f5)}
12
+ .wx-button:disabled{opacity:0.6;cursor:not-allowed}
@@ -0,0 +1 @@
1
+ .wx-checkbox-wrapper{display:flex;gap:8px;align-items:center}.wx-checkbox{width:16px;height:16px}
@@ -0,0 +1,66 @@
1
+ .wx-datepicker-wrapper {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 4px;
5
+ }
6
+
7
+ .wx-datepicker-label {
8
+ font-size: 14px;
9
+ font-weight: 500;
10
+ }
11
+
12
+ .wx-datepicker-input-wrapper {
13
+ position: relative;
14
+ display: block;
15
+ }
16
+
17
+ .wx-datepicker-react-wrapper {
18
+ display: block;
19
+ width: 100%;
20
+ }
21
+
22
+ .wx-datepicker-input {
23
+ width: 100%;
24
+ padding: 10px 36px 10px 10px !important;
25
+ border: 1px solid #ccc;
26
+ border-radius: 6px;
27
+ outline: none;
28
+ height: 40px;
29
+ box-sizing: border-box;
30
+ font-size: 14px;
31
+ }
32
+
33
+ .wx-datepicker-icon {
34
+ position: absolute;
35
+ right: 10px;
36
+ top: 10px;
37
+ width: 18px;
38
+ height: 18px;
39
+ color: #6b7280;
40
+ pointer-events: none;
41
+ z-index: 10;
42
+ }
43
+
44
+ .wx-datepicker-input:focus {
45
+ border-color: var(--wx-color-primary, #f19924);
46
+ }
47
+
48
+ .wx-datepicker-input:disabled {
49
+ opacity: 0.6;
50
+ cursor: not-allowed;
51
+ }
52
+
53
+ .wx-datepicker-input-error {
54
+ border-color: var(--wx-color-error, #dc2626);
55
+ }
56
+
57
+ .wx-datepicker-hint {
58
+ font-size: 12px;
59
+ color: #6b7280;
60
+ }
61
+
62
+ .wx-datepicker-error-text {
63
+ font-size: 12px;
64
+ color: #dc2626;
65
+ }
66
+
@@ -0,0 +1,68 @@
1
+ .wx-daterangepicker-wrapper {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 4px;
5
+ }
6
+
7
+ .wx-daterangepicker-label {
8
+ font-size: 14px;
9
+ font-weight: 500;
10
+ }
11
+
12
+ .wx-daterangepicker-input-wrapper {
13
+ position: relative;
14
+ display: inline-block;
15
+ width: 100%;
16
+ }
17
+
18
+ .wx-daterangepicker-react-wrapper {
19
+ display: block;
20
+ width: 100%;
21
+ }
22
+
23
+ .wx-daterangepicker-input {
24
+ width: 100%;
25
+ padding: 10px 36px 10px 10px;
26
+ border: 1px solid #ccc;
27
+ border-radius: 6px;
28
+ outline: none;
29
+ height: 40px;
30
+ box-sizing: border-box;
31
+ font-size: 14px;
32
+ }
33
+
34
+ .wx-daterangepicker-icon {
35
+ position: absolute;
36
+ right: 10px;
37
+ top: 50%;
38
+ transform: translateY(-50%);
39
+ width: 18px;
40
+ height: 18px;
41
+ color: #6b7280;
42
+ pointer-events: none;
43
+ z-index: 1;
44
+ }
45
+
46
+ .wx-daterangepicker-input:focus {
47
+ border-color: var(--wx-color-primary, #f19924);
48
+ }
49
+
50
+ .wx-daterangepicker-input:disabled {
51
+ opacity: 0.6;
52
+ cursor: not-allowed;
53
+ }
54
+
55
+ .wx-daterangepicker-input-error {
56
+ border-color: var(--wx-color-error, #dc2626);
57
+ }
58
+
59
+ .wx-daterangepicker-hint {
60
+ font-size: 12px;
61
+ color: #6b7280;
62
+ }
63
+
64
+ .wx-daterangepicker-error-text {
65
+ font-size: 12px;
66
+ color: #dc2626;
67
+ }
68
+