@expresscsv/react 0.1.5 → 0.1.6
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/LICENSE +21 -0
- package/README.md +205 -10
- package/dist/index.d.mts +1 -10
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ExpressCSV
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @expresscsv/react
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@expresscsv/react)
|
|
4
|
-
|
|
4
|
+

|
|
5
5
|
|
|
6
6
|
React hook for embedding the [ExpressCSV](https://expresscsv.com) CSV import widget. Wraps [`@expresscsv/sdk`](https://www.npmjs.com/package/@expresscsv/sdk) with automatic lifecycle management and reactive state.
|
|
7
7
|
|
|
@@ -93,7 +93,7 @@ const handleImport = () => {
|
|
|
93
93
|
};
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
To disable preloading:
|
|
96
|
+
To disable preloading (there will be a brief loading screen instead):
|
|
97
97
|
|
|
98
98
|
```tsx
|
|
99
99
|
const { open } = useExpressCSV({
|
|
@@ -104,6 +104,139 @@ const { open } = useExpressCSV({
|
|
|
104
104
|
});
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
## Theming and Styling
|
|
108
|
+
|
|
109
|
+
Customize the widget's appearance with the `theme`, `colorMode`, `customCSS`, and `fonts` options.
|
|
110
|
+
|
|
111
|
+
### Theme
|
|
112
|
+
|
|
113
|
+
Use the `theme` option to override CSS variables (colors, radius, typography). Pass either a single theme (applies to both light and dark) or a dual-mode theme with separate light/dark values:
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import { useExpressCSV, x, type ECSVTheme } from "@expresscsv/react";
|
|
117
|
+
|
|
118
|
+
// Single theme (both modes)
|
|
119
|
+
const theme: ECSVTheme = {
|
|
120
|
+
primary: "#4F46E5",
|
|
121
|
+
"primary-foreground": "#ffffff",
|
|
122
|
+
background: "#ffffff",
|
|
123
|
+
foreground: "#0f172a",
|
|
124
|
+
border: "#e5e7eb",
|
|
125
|
+
ring: "#A5B4FC",
|
|
126
|
+
radius: "0.5rem",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Dual-mode (light and dark)
|
|
130
|
+
const dualTheme: ECSVTheme = {
|
|
131
|
+
modes: {
|
|
132
|
+
light: {
|
|
133
|
+
primary: "#4F46E5",
|
|
134
|
+
background: "#ffffff",
|
|
135
|
+
foreground: "#0f172a",
|
|
136
|
+
},
|
|
137
|
+
dark: {
|
|
138
|
+
primary: "#a5b4fc",
|
|
139
|
+
background: "#09090b",
|
|
140
|
+
foreground: "#fafafa",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
function App() {
|
|
146
|
+
const { open } = useExpressCSV({
|
|
147
|
+
schema,
|
|
148
|
+
publishableKey: "your-publishable-key",
|
|
149
|
+
importIdentifier: "user-import",
|
|
150
|
+
theme,
|
|
151
|
+
});
|
|
152
|
+
// ...
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Theme variables (light mode defaults):
|
|
157
|
+
|
|
158
|
+
| Variable | Default |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `radius` | `0.625rem` |
|
|
161
|
+
| `background` | `oklch(1 0 0)` |
|
|
162
|
+
| `foreground` | `oklch(0.145 0 0)` |
|
|
163
|
+
| `card` | `oklch(1 0 0)` |
|
|
164
|
+
| `card-foreground` | `oklch(0.145 0 0)` |
|
|
165
|
+
| `popover` | `oklch(1 0 0)` |
|
|
166
|
+
| `popover-foreground` | `oklch(0.145 0 0)` |
|
|
167
|
+
| `primary` | `oklch(0.205 0 0)` |
|
|
168
|
+
| `primary-foreground` | `oklch(0.985 0 0)` |
|
|
169
|
+
| `secondary` | `oklch(0.97 0 0)` |
|
|
170
|
+
| `secondary-foreground` | `oklch(0.205 0 0)` |
|
|
171
|
+
| `muted` | `oklch(0.97 0 0)` |
|
|
172
|
+
| `muted-foreground` | `oklch(0.556 0 0)` |
|
|
173
|
+
| `accent` | `oklch(0.7 0.2 145)` |
|
|
174
|
+
| `accent-foreground` | `oklch(0.985 0 0)` |
|
|
175
|
+
| `destructive` | `oklch(0.577 0.245 27.325)` |
|
|
176
|
+
| `destructive-foreground` | `oklch(0.985 0 0)` |
|
|
177
|
+
| `success` | `oklch(0.7 0.2 145)` |
|
|
178
|
+
| `success-foreground` | `oklch(0.985 0 0)` |
|
|
179
|
+
| `warning` | `oklch(0.769 0.188 70)` |
|
|
180
|
+
| `warning-foreground` | `oklch(0.985 0 0)` |
|
|
181
|
+
| `border` | `oklch(0.922 0 0)` |
|
|
182
|
+
| `input` | `oklch(0.922 0 0)` |
|
|
183
|
+
| `ring` | `oklch(0.708 0 0)` |
|
|
184
|
+
| `font-title` | `inherit` |
|
|
185
|
+
| `font-body` | `inherit` |
|
|
186
|
+
|
|
187
|
+
### Color Mode
|
|
188
|
+
|
|
189
|
+
Control light/dark mode with `colorMode`:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
const { open } = useExpressCSV({
|
|
193
|
+
schema,
|
|
194
|
+
publishableKey: "your-publishable-key",
|
|
195
|
+
importIdentifier: "user-import",
|
|
196
|
+
colorMode: "system", // 'light' | 'dark' | 'system'
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Custom CSS
|
|
201
|
+
|
|
202
|
+
Inject custom CSS for fine-grained styling overrides.
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
const { open } = useExpressCSV({
|
|
206
|
+
schema,
|
|
207
|
+
publishableKey: "your-publishable-key",
|
|
208
|
+
importIdentifier: "user-import",
|
|
209
|
+
customCSS: `
|
|
210
|
+
.ecsv [data-step="upload"] {
|
|
211
|
+
border-radius: 1rem;
|
|
212
|
+
}
|
|
213
|
+
.ecsv button {
|
|
214
|
+
font-weight: 600;
|
|
215
|
+
}
|
|
216
|
+
`,
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Custom Fonts
|
|
221
|
+
|
|
222
|
+
Load custom fonts via the `fonts` option:
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
const { open } = useExpressCSV({
|
|
226
|
+
schema,
|
|
227
|
+
publishableKey: "your-publishable-key",
|
|
228
|
+
importIdentifier: "user-import",
|
|
229
|
+
fonts: {
|
|
230
|
+
title: { source: "google", name: "Space Grotesk", weights: [400, 600, 700] },
|
|
231
|
+
body: { source: "custom", url: "https://example.com/font.woff2", format: "woff2" },
|
|
232
|
+
},
|
|
233
|
+
theme: {
|
|
234
|
+
"font-title": "'Space Grotesk', sans-serif",
|
|
235
|
+
"font-body": "'Custom Font', sans-serif",
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
107
240
|
## Webhook Delivery
|
|
108
241
|
|
|
109
242
|
Deliver data to a server endpoint instead of (or in addition to) processing locally:
|
|
@@ -261,7 +394,7 @@ function useExpressCSV<TSchema>(
|
|
|
261
394
|
| `debug` | `boolean` | No | `false` | Enable debug logging |
|
|
262
395
|
| `developerMode` | `boolean` | No | `false` | Enable developer mode features |
|
|
263
396
|
| `theme` | `ECSVTheme` | No | - | Custom theme configuration |
|
|
264
|
-
| `colorMode` | `
|
|
397
|
+
| `colorMode` | `ColorModePref` | No | - | Light/dark mode (`'light'`, `'dark'`, or `'system'`) |
|
|
265
398
|
| `customCSS` | `string` | No | - | Custom CSS to inject into the widget |
|
|
266
399
|
| `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
|
|
267
400
|
| `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
|
|
@@ -301,7 +434,7 @@ Options passed to `open()`. At least one of `onData` or `webhook` must be provid
|
|
|
301
434
|
|
|
302
435
|
```typescript
|
|
303
436
|
interface RecordsChunk<T> {
|
|
304
|
-
records: T[];
|
|
437
|
+
records: T[]; // Automatically typed to your schema
|
|
305
438
|
totalChunks: number;
|
|
306
439
|
currentChunkIndex: number;
|
|
307
440
|
totalRecords: number;
|
|
@@ -323,24 +456,86 @@ interface WebhookConfig {
|
|
|
323
456
|
|
|
324
457
|
### Schema Builder
|
|
325
458
|
|
|
326
|
-
The `x` schema builder
|
|
459
|
+
The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
|
|
460
|
+
|
|
461
|
+
#### Field Types
|
|
327
462
|
|
|
328
463
|
```tsx
|
|
329
464
|
import { x } from "@expresscsv/react";
|
|
330
465
|
|
|
331
466
|
const schema = x.row({
|
|
332
|
-
|
|
467
|
+
// Strings with validation
|
|
468
|
+
name: x.string().label("Full Name").min(2).max(100),
|
|
333
469
|
email: x.string().email().label("Email"),
|
|
334
|
-
|
|
470
|
+
website: x.string().url().label("Website").optional(),
|
|
471
|
+
|
|
472
|
+
// Numbers with constraints
|
|
473
|
+
age: x.number().label("Age").min(0).max(150).integer(),
|
|
474
|
+
salary: x.number().currency("USD").label("Salary").min(0),
|
|
475
|
+
|
|
476
|
+
// Boolean
|
|
477
|
+
isActive: x.boolean().label("Active"),
|
|
478
|
+
|
|
479
|
+
// Dates and times
|
|
480
|
+
startDate: x.date().label("Start Date"),
|
|
481
|
+
createdAt: x.datetime().label("Created At"),
|
|
482
|
+
|
|
483
|
+
// Single selection (requires { label, value } objects)
|
|
335
484
|
role: x.select([
|
|
336
485
|
{ label: "Admin", value: "admin" },
|
|
337
|
-
{ label: "
|
|
486
|
+
{ label: "Editor", value: "editor" },
|
|
487
|
+
{ label: "Viewer", value: "viewer" },
|
|
338
488
|
]).label("Role"),
|
|
339
|
-
|
|
340
|
-
|
|
489
|
+
|
|
490
|
+
// Multi-selection
|
|
491
|
+
tags: x.multiselect([
|
|
492
|
+
{ label: "Engineering", value: "eng" },
|
|
493
|
+
{ label: "Design", value: "design" },
|
|
494
|
+
{ label: "Marketing", value: "mkt" },
|
|
495
|
+
]).label("Tags"),
|
|
341
496
|
});
|
|
342
497
|
```
|
|
343
498
|
|
|
499
|
+
#### Common Modifiers
|
|
500
|
+
|
|
501
|
+
All field types support:
|
|
502
|
+
|
|
503
|
+
| Modifier | Description |
|
|
504
|
+
|---|---|
|
|
505
|
+
| `.label(text)` | User-facing label shown in the widget |
|
|
506
|
+
| `.description(text)` | Help text for the field |
|
|
507
|
+
| `.example(text)` | Example value shown as placeholder |
|
|
508
|
+
| `.optional()` | Makes the field optional (default is required) |
|
|
509
|
+
| `.refine(fn)` | Custom validation function |
|
|
510
|
+
|
|
511
|
+
#### String Modifiers
|
|
512
|
+
|
|
513
|
+
| Modifier | Description |
|
|
514
|
+
|---|---|
|
|
515
|
+
| `.email()` | Validates email format |
|
|
516
|
+
| `.url()` | Validates URL format |
|
|
517
|
+
| `.uuid()` | Validates UUID format |
|
|
518
|
+
| `.ip()` | Validates IP address |
|
|
519
|
+
| `.phone()` | Validates phone number |
|
|
520
|
+
| `.regex(pattern)` | Matches a regular expression |
|
|
521
|
+
| `.min(n)` | Minimum string length |
|
|
522
|
+
| `.max(n)` | Maximum string length |
|
|
523
|
+
| `.length(n)` | Exact string length |
|
|
524
|
+
| `.includes(str)` | Must contain substring |
|
|
525
|
+
| `.startsWith(str)` | Must start with prefix |
|
|
526
|
+
| `.endsWith(str)` | Must end with suffix |
|
|
527
|
+
|
|
528
|
+
#### Number Modifiers
|
|
529
|
+
|
|
530
|
+
| Modifier | Description |
|
|
531
|
+
|---|---|
|
|
532
|
+
| `.min(n)` | Minimum value |
|
|
533
|
+
| `.max(n)` | Maximum value |
|
|
534
|
+
| `.integer()` | Must be a whole number |
|
|
535
|
+
| `.multipleOf(n)` | Must be a multiple of n |
|
|
536
|
+
| `.currency(code)` | Formats as currency (e.g. `"USD"`) |
|
|
537
|
+
| `.percentage()` | Formats as percentage |
|
|
538
|
+
|
|
344
539
|
## TypeScript
|
|
345
540
|
|
|
346
541
|
Full type inference from your schema is built in:
|
package/dist/index.d.mts
CHANGED
|
@@ -4,15 +4,6 @@ declare interface BICOptions {
|
|
|
4
4
|
|
|
5
5
|
declare type BooleanControlType = 'toggle' | 'checkbox' | 'dropdown';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Color mode configuration
|
|
9
|
-
*/
|
|
10
|
-
export declare interface ColorModeConfig {
|
|
11
|
-
default?: ColorModePref;
|
|
12
|
-
persist?: boolean;
|
|
13
|
-
onChange?: (mode: ColorModePref) => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
7
|
/**
|
|
17
8
|
* Color mode preference
|
|
18
9
|
*/
|
|
@@ -3744,7 +3735,7 @@ export declare interface UseExpressCSVOptions<TSchema extends ExType<unknown, Ex
|
|
|
3744
3735
|
developerMode?: boolean;
|
|
3745
3736
|
preload?: boolean;
|
|
3746
3737
|
theme?: ECSVTheme;
|
|
3747
|
-
colorMode?:
|
|
3738
|
+
colorMode?: ColorModePref;
|
|
3748
3739
|
customCSS?: string;
|
|
3749
3740
|
fonts?: Record<string, ECSVFontSource>;
|
|
3750
3741
|
stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expresscsv/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "React component wrapper for ExpressCSV SDK",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"react": "
|
|
28
|
+
"react": ">=16.8.0"
|
|
29
29
|
}
|
|
30
30
|
}
|