@expresscsv/react 0.1.17 → 0.1.19
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 +119 -1
- package/dist/index.d.cts +18 -3
- package/dist/index.d.mts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
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
|
|
|
8
|
+
If you want to define schemas in shared or backend code without any frontend dependencies, use [`@expresscsv/schemas`](https://www.npmjs.com/package/@expresscsv/schemas) for the schema definition itself, then pass that schema into `@expresscsv/react`.
|
|
9
|
+
|
|
8
10
|
## Installation
|
|
9
11
|
|
|
10
12
|
```bash
|
|
@@ -104,6 +106,40 @@ const { open } = useExpressCSV({
|
|
|
104
106
|
});
|
|
105
107
|
```
|
|
106
108
|
|
|
109
|
+
## Template Downloads
|
|
110
|
+
|
|
111
|
+
Generated templates can include example rows that match your schema.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useExpressCSV, x, type Infer } from "@expresscsv/react";
|
|
115
|
+
|
|
116
|
+
const candidateSchema = x.row({
|
|
117
|
+
firstName: x.string().label("First Name"),
|
|
118
|
+
email: x.string().email().label("Email"),
|
|
119
|
+
role: x.select([
|
|
120
|
+
{ label: "Admin", value: "admin" },
|
|
121
|
+
{ label: "Editor", value: "editor" },
|
|
122
|
+
]).label("Role"),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const { open } = useExpressCSV({
|
|
126
|
+
schema: candidateSchema,
|
|
127
|
+
publishableKey: "your-publishable-key",
|
|
128
|
+
importIdentifier: "candidate-import",
|
|
129
|
+
templateDownload: {
|
|
130
|
+
source: "generate",
|
|
131
|
+
formats: ["csv", "xlsx"],
|
|
132
|
+
exampleRows: () => [
|
|
133
|
+
{
|
|
134
|
+
firstName: "Alice",
|
|
135
|
+
email: "alice@example.com",
|
|
136
|
+
role: "admin",
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
107
143
|
## Theming and Styling
|
|
108
144
|
|
|
109
145
|
Customize the widget's appearance with the `theme`, `colorMode`, `customCSS`, and `fonts` options.
|
|
@@ -312,6 +348,8 @@ interface WebhookPayload {
|
|
|
312
348
|
}
|
|
313
349
|
```
|
|
314
350
|
|
|
351
|
+
When you already have a schema, prefer `InferWebhookPayload<typeof schema>` from `@expresscsv/schemas` instead of rewriting this object shape by hand.
|
|
352
|
+
|
|
315
353
|
Example payload:
|
|
316
354
|
|
|
317
355
|
```json
|
|
@@ -350,6 +388,25 @@ Your endpoint should return a **2xx** status code to acknowledge each chunk. Non
|
|
|
350
388
|
|
|
351
389
|
Chunks are delivered **serially** — the next chunk is only sent after the previous one succeeds.
|
|
352
390
|
|
|
391
|
+
If your schema lives in shared or backend code via `@expresscsv/schemas`, you can reuse the built-in webhook payload helper in your webhook handler:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
import express from "express";
|
|
395
|
+
import type { InferWebhookPayload } from "@expresscsv/schemas";
|
|
396
|
+
import { candidateSchema } from "../shared/candidate-schema";
|
|
397
|
+
|
|
398
|
+
const app = express();
|
|
399
|
+
app.use(express.json());
|
|
400
|
+
|
|
401
|
+
app.post("/webhooks/csv-import", async (req, res) => {
|
|
402
|
+
const payload = req.body as InferWebhookPayload<typeof candidateSchema>;
|
|
403
|
+
|
|
404
|
+
await importCandidates(payload.records);
|
|
405
|
+
|
|
406
|
+
res.status(200).json({ ok: true });
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
353
410
|
Below is a minimal Express.js example:
|
|
354
411
|
|
|
355
412
|
```typescript
|
|
@@ -507,7 +564,7 @@ function useExpressCSV<TSchema>(
|
|
|
507
564
|
| `fonts` | `Record<string, ECSVFontSource>` | No | - | Custom font sources |
|
|
508
565
|
| `stepDisplay` | `'progressBar' \| 'segmented' \| 'numbered'` | No | `'progressBar'` | Step indicator style |
|
|
509
566
|
| `previewSchemaBeforeUpload` | `boolean` | No | `true` | Show schema preview before upload |
|
|
510
|
-
| `templateDownload` | `
|
|
567
|
+
| `templateDownload` | `TemplateDownloadOptions<TSchema>` | No | - | Template download configuration with optional schema-typed example rows |
|
|
511
568
|
| `saveSession` | `boolean` | No | - | Persist session state |
|
|
512
569
|
| `locale` | `DeepPartial<ExpressCSVLocaleInput>` | No | - | Localization overrides |
|
|
513
570
|
|
|
@@ -566,6 +623,8 @@ interface WebhookConfig {
|
|
|
566
623
|
|
|
567
624
|
The `x` schema builder provides a type-safe, fluent API for defining your CSV structure.
|
|
568
625
|
|
|
626
|
+
For apps that share schemas with backend code or webhook receivers, prefer defining the schema in `@expresscsv/schemas` and importing it into your React app. That keeps schema authoring free of React and widget dependencies, while also giving your backend access to `InferWebhookPayload<typeof schema>`.
|
|
627
|
+
|
|
569
628
|
#### Field Types
|
|
570
629
|
|
|
571
630
|
```tsx
|
|
@@ -604,6 +663,65 @@ const schema = x.row({
|
|
|
604
663
|
});
|
|
605
664
|
```
|
|
606
665
|
|
|
666
|
+
#### Runtime-Built Schemas
|
|
667
|
+
|
|
668
|
+
For a fixed schema, keep it directly in `x.row(...)`:
|
|
669
|
+
|
|
670
|
+
```tsx
|
|
671
|
+
const schema = x.row({
|
|
672
|
+
email: x.string().email().label("Email"),
|
|
673
|
+
lifecycleStage: x
|
|
674
|
+
.select([
|
|
675
|
+
{ label: "Lead", value: "lead" },
|
|
676
|
+
{ label: "Customer", value: "customer" },
|
|
677
|
+
{ label: "Churned", value: "churned" },
|
|
678
|
+
])
|
|
679
|
+
.label("Lifecycle Stage"),
|
|
680
|
+
accountOwner: x.string().label("Account Owner").optional(),
|
|
681
|
+
contractValue: x.number().currency("USD").label("Contract Value").optional(),
|
|
682
|
+
});
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
`x.row(...)` also works for runtime-built schemas, which is useful when the shape depends on account data, user preferences, or enabled custom fields.
|
|
686
|
+
|
|
687
|
+
```tsx
|
|
688
|
+
import { x } from "@expresscsv/react";
|
|
689
|
+
|
|
690
|
+
function buildCustomerSchema(options: {
|
|
691
|
+
collectCrmId: boolean;
|
|
692
|
+
collectHealthScore: boolean;
|
|
693
|
+
collectSegment: boolean;
|
|
694
|
+
}) {
|
|
695
|
+
return x.row({
|
|
696
|
+
email: x.string().email().label("Email"),
|
|
697
|
+
companyName: x.string().label("Company Name"),
|
|
698
|
+
...(options.collectCrmId ? { crmId: x.string().label("CRM ID") } : {}),
|
|
699
|
+
...(options.collectHealthScore
|
|
700
|
+
? { healthScore: x.number().label("Health Score") }
|
|
701
|
+
: {}),
|
|
702
|
+
...(options.collectSegment
|
|
703
|
+
? {
|
|
704
|
+
segment: x
|
|
705
|
+
.select([
|
|
706
|
+
{ label: "SMB", value: "smb" },
|
|
707
|
+
{ label: "Mid-Market", value: "mid-market" },
|
|
708
|
+
{ label: "Enterprise", value: "enterprise" },
|
|
709
|
+
])
|
|
710
|
+
.label("Segment"),
|
|
711
|
+
}
|
|
712
|
+
: {}),
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const schema = buildCustomerSchema({
|
|
717
|
+
collectCrmId: true,
|
|
718
|
+
collectHealthScore: true,
|
|
719
|
+
collectSegment: false,
|
|
720
|
+
});
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
Dynamic schema assembly preserves the same runtime parsing behavior, but it can widen `Infer<typeof schema>` because the exact keys are no longer fully known to TypeScript. Use it intentionally.
|
|
724
|
+
|
|
607
725
|
#### Common Modifiers
|
|
608
726
|
|
|
609
727
|
All field types support:
|
package/dist/index.d.cts
CHANGED
|
@@ -3015,6 +3015,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
|
|
|
3015
3015
|
* Factory method to create an ExRow validator for a row of data
|
|
3016
3016
|
*
|
|
3017
3017
|
* @param shape - Object defining the structure of fields in the row
|
|
3018
|
+
*
|
|
3019
|
+
* Object literals preserve exact key inference. If callers build the shape
|
|
3020
|
+
* through a widened variable or conditional assembly, TypeScript may widen
|
|
3021
|
+
* the resulting row type as well.
|
|
3022
|
+
*
|
|
3018
3023
|
* @returns A new ExRow instance
|
|
3019
3024
|
*/
|
|
3020
3025
|
static create<T extends ExRowShape>(shape: T): ExRow<T>;
|
|
@@ -3695,19 +3700,29 @@ export declare interface TailwindThemeVars {
|
|
|
3695
3700
|
|
|
3696
3701
|
/**
|
|
3697
3702
|
* Configuration for template download in the upload step.
|
|
3698
|
-
* When `source` is `"generate"`, a
|
|
3699
|
-
*
|
|
3703
|
+
* When `source` is `"generate"`, a template file is created client-side
|
|
3704
|
+
* from the schema column names and optional example rows.
|
|
3700
3705
|
*/
|
|
3701
3706
|
export declare interface TemplateDownloadConfig {
|
|
3702
3707
|
source: 'generate';
|
|
3703
3708
|
formats?: TemplateDownloadFormat[];
|
|
3709
|
+
exampleRows?: TemplateDownloadExampleRow[];
|
|
3704
3710
|
}
|
|
3705
3711
|
|
|
3712
|
+
/**
|
|
3713
|
+
* A serializable example row used to populate generated templates.
|
|
3714
|
+
*/
|
|
3715
|
+
export declare type TemplateDownloadExampleRow = Record<string, unknown>;
|
|
3716
|
+
|
|
3706
3717
|
/**
|
|
3707
3718
|
* Template download format
|
|
3708
3719
|
*/
|
|
3709
3720
|
export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
|
|
3710
3721
|
|
|
3722
|
+
export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
|
|
3723
|
+
exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
|
|
3724
|
+
};
|
|
3725
|
+
|
|
3711
3726
|
/**
|
|
3712
3727
|
* A branded string type for locale entries that require interpolation via `{variable}` syntax.
|
|
3713
3728
|
* Widget code cannot render a `TemplateString` directly in JSX — it must go through the `t()` function.
|
|
@@ -3754,7 +3769,7 @@ export declare interface UseExpressCSVOptions<TSchema extends ExType<unknown, Ex
|
|
|
3754
3769
|
fonts?: Record<string, ECSVFontSource>;
|
|
3755
3770
|
stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
|
|
3756
3771
|
previewSchemaBeforeUpload?: boolean;
|
|
3757
|
-
templateDownload?:
|
|
3772
|
+
templateDownload?: TemplateDownloadOptions<TSchema>;
|
|
3758
3773
|
saveSession?: boolean;
|
|
3759
3774
|
locale?: DeepPartial<ExpressCSVLocaleInput>;
|
|
3760
3775
|
disableStatusStep?: boolean;
|
package/dist/index.d.mts
CHANGED
|
@@ -3015,6 +3015,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
|
|
|
3015
3015
|
* Factory method to create an ExRow validator for a row of data
|
|
3016
3016
|
*
|
|
3017
3017
|
* @param shape - Object defining the structure of fields in the row
|
|
3018
|
+
*
|
|
3019
|
+
* Object literals preserve exact key inference. If callers build the shape
|
|
3020
|
+
* through a widened variable or conditional assembly, TypeScript may widen
|
|
3021
|
+
* the resulting row type as well.
|
|
3022
|
+
*
|
|
3018
3023
|
* @returns A new ExRow instance
|
|
3019
3024
|
*/
|
|
3020
3025
|
static create<T extends ExRowShape>(shape: T): ExRow<T>;
|
|
@@ -3695,19 +3700,29 @@ export declare interface TailwindThemeVars {
|
|
|
3695
3700
|
|
|
3696
3701
|
/**
|
|
3697
3702
|
* Configuration for template download in the upload step.
|
|
3698
|
-
* When `source` is `"generate"`, a
|
|
3699
|
-
*
|
|
3703
|
+
* When `source` is `"generate"`, a template file is created client-side
|
|
3704
|
+
* from the schema column names and optional example rows.
|
|
3700
3705
|
*/
|
|
3701
3706
|
export declare interface TemplateDownloadConfig {
|
|
3702
3707
|
source: 'generate';
|
|
3703
3708
|
formats?: TemplateDownloadFormat[];
|
|
3709
|
+
exampleRows?: TemplateDownloadExampleRow[];
|
|
3704
3710
|
}
|
|
3705
3711
|
|
|
3712
|
+
/**
|
|
3713
|
+
* A serializable example row used to populate generated templates.
|
|
3714
|
+
*/
|
|
3715
|
+
export declare type TemplateDownloadExampleRow = Record<string, unknown>;
|
|
3716
|
+
|
|
3706
3717
|
/**
|
|
3707
3718
|
* Template download format
|
|
3708
3719
|
*/
|
|
3709
3720
|
export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
|
|
3710
3721
|
|
|
3722
|
+
export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
|
|
3723
|
+
exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
|
|
3724
|
+
};
|
|
3725
|
+
|
|
3711
3726
|
/**
|
|
3712
3727
|
* A branded string type for locale entries that require interpolation via `{variable}` syntax.
|
|
3713
3728
|
* Widget code cannot render a `TemplateString` directly in JSX — it must go through the `t()` function.
|
|
@@ -3754,7 +3769,7 @@ export declare interface UseExpressCSVOptions<TSchema extends ExType<unknown, Ex
|
|
|
3754
3769
|
fonts?: Record<string, ECSVFontSource>;
|
|
3755
3770
|
stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
|
|
3756
3771
|
previewSchemaBeforeUpload?: boolean;
|
|
3757
|
-
templateDownload?:
|
|
3772
|
+
templateDownload?: TemplateDownloadOptions<TSchema>;
|
|
3758
3773
|
saveSession?: boolean;
|
|
3759
3774
|
locale?: DeepPartial<ExpressCSVLocaleInput>;
|
|
3760
3775
|
disableStatusStep?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -3015,6 +3015,11 @@ declare class ExRow<T extends ExRowShape> extends ExType<{
|
|
|
3015
3015
|
* Factory method to create an ExRow validator for a row of data
|
|
3016
3016
|
*
|
|
3017
3017
|
* @param shape - Object defining the structure of fields in the row
|
|
3018
|
+
*
|
|
3019
|
+
* Object literals preserve exact key inference. If callers build the shape
|
|
3020
|
+
* through a widened variable or conditional assembly, TypeScript may widen
|
|
3021
|
+
* the resulting row type as well.
|
|
3022
|
+
*
|
|
3018
3023
|
* @returns A new ExRow instance
|
|
3019
3024
|
*/
|
|
3020
3025
|
static create<T extends ExRowShape>(shape: T): ExRow<T>;
|
|
@@ -3695,19 +3700,29 @@ export declare interface TailwindThemeVars {
|
|
|
3695
3700
|
|
|
3696
3701
|
/**
|
|
3697
3702
|
* Configuration for template download in the upload step.
|
|
3698
|
-
* When `source` is `"generate"`, a
|
|
3699
|
-
*
|
|
3703
|
+
* When `source` is `"generate"`, a template file is created client-side
|
|
3704
|
+
* from the schema column names and optional example rows.
|
|
3700
3705
|
*/
|
|
3701
3706
|
export declare interface TemplateDownloadConfig {
|
|
3702
3707
|
source: 'generate';
|
|
3703
3708
|
formats?: TemplateDownloadFormat[];
|
|
3709
|
+
exampleRows?: TemplateDownloadExampleRow[];
|
|
3704
3710
|
}
|
|
3705
3711
|
|
|
3712
|
+
/**
|
|
3713
|
+
* A serializable example row used to populate generated templates.
|
|
3714
|
+
*/
|
|
3715
|
+
export declare type TemplateDownloadExampleRow = Record<string, unknown>;
|
|
3716
|
+
|
|
3706
3717
|
/**
|
|
3707
3718
|
* Template download format
|
|
3708
3719
|
*/
|
|
3709
3720
|
export declare type TemplateDownloadFormat = 'csv' | 'xlsx';
|
|
3710
3721
|
|
|
3722
|
+
export declare type TemplateDownloadOptions<TSchema extends ExType<unknown, ExBaseDef, unknown>> = Omit<TemplateDownloadConfig, 'exampleRows'> & {
|
|
3723
|
+
exampleRows?: Infer<TSchema>[] | (() => Infer<TSchema>[]);
|
|
3724
|
+
};
|
|
3725
|
+
|
|
3711
3726
|
/**
|
|
3712
3727
|
* A branded string type for locale entries that require interpolation via `{variable}` syntax.
|
|
3713
3728
|
* Widget code cannot render a `TemplateString` directly in JSX — it must go through the `t()` function.
|
|
@@ -3754,7 +3769,7 @@ export declare interface UseExpressCSVOptions<TSchema extends ExType<unknown, Ex
|
|
|
3754
3769
|
fonts?: Record<string, ECSVFontSource>;
|
|
3755
3770
|
stepDisplay?: 'progressBar' | 'segmented' | 'numbered';
|
|
3756
3771
|
previewSchemaBeforeUpload?: boolean;
|
|
3757
|
-
templateDownload?:
|
|
3772
|
+
templateDownload?: TemplateDownloadOptions<TSchema>;
|
|
3758
3773
|
saveSession?: boolean;
|
|
3759
3774
|
locale?: DeepPartial<ExpressCSVLocaleInput>;
|
|
3760
3775
|
disableStatusStep?: boolean;
|