Skip to content

Commit 2572cb3

Browse files
committed
Implement basic dsv import
1 parent 07975fc commit 2572cb3

File tree

7 files changed

+97
-16
lines changed

7 files changed

+97
-16
lines changed

.prettierrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
semi: true,
3-
trailingComma: "all",
3+
trailingComma: "none",
44
singleQuote: true,
55
printWidth: 120,
66
tabWidth: 2

.storybook/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
stories: ['../src/**/*.stories.[tj]sx'],
3-
addons: ['@storybook/preset-typescript'],
3+
addons: ['@storybook/preset-typescript', '@storybook/addon-actions/register'],
44
webpackFinal: async config => {
55
config.module.rules.push({
66
test: /\.(ts|tsx)$/,

src/DSVImport.stories.tsx

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/DSVImport.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/components/DSVImport.stories.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { DSVImport, ColumnsType } from './DSVImport';
3+
import { actions } from '@storybook/addon-actions';
4+
5+
export default { title: 'DSVImport' };
6+
7+
const defaultActions = actions('onChange');
8+
9+
type MinimalType = { forename: string; surname: string; email: string };
10+
const minimalColumns: ColumnsType<MinimalType> = [
11+
{ key: 'forename', label: 'Forename' },
12+
{ key: 'surname', label: 'Surname' },
13+
{ key: 'email', label: 'Email' }
14+
];
15+
export const Minimal = () => {
16+
return <DSVImport<MinimalType> columns={minimalColumns} {...defaultActions} />;
17+
};

src/components/DSVImport.tsx

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React, { PropsWithChildren } from 'react';
2+
3+
enum Separator {
4+
COMMA = ',',
5+
TAB = '\t'
6+
}
7+
8+
export type ColumnsType<T> = { key: keyof T; label: string }[];
9+
10+
interface Props<T> {
11+
onChange: (value: T[]) => void;
12+
columns: ColumnsType<T>;
13+
}
14+
15+
export const DSVImport = <T extends { [key: string]: string }>(props: PropsWithChildren<Props<T>>) => {
16+
const [separator, setSeparator] = React.useState<Separator>(Separator.COMMA);
17+
const [data, setData] = React.useState<T[]>([]);
18+
19+
const detectSeparatorFromValue = (value: string) => {
20+
let currentSeparator = separator;
21+
let maximumScore = 0;
22+
Object.values(Separator).forEach((s) => {
23+
const currentScore = (value.match(new RegExp(s, 'g')) || []).length;
24+
if (maximumScore < currentScore) {
25+
currentSeparator = s;
26+
maximumScore = currentScore;
27+
}
28+
});
29+
return currentSeparator;
30+
};
31+
32+
const parseData = (value: string, separator: Separator) => {
33+
const lines = value.split('\n');
34+
const parsedData = lines.map((line) => {
35+
const lineValues = line.split(separator);
36+
const parsedLine: T = {} as T;
37+
props.columns.forEach((column, columnIndex) => {
38+
parsedLine[column.key] = lineValues[columnIndex] as T[keyof T];
39+
});
40+
return parsedLine;
41+
});
42+
setData(parsedData);
43+
props.onChange(parsedData);
44+
};
45+
46+
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
47+
const currentSeparator = detectSeparatorFromValue(event.target.value);
48+
setSeparator(currentSeparator);
49+
parseData(event.target.value, currentSeparator);
50+
};
51+
52+
return (
53+
<>
54+
<textarea onChange={handleChange}></textarea>
55+
<table>
56+
<thead>
57+
<tr>
58+
{props.columns.map((c, i) => {
59+
return <th key={i}>{c.label}</th>;
60+
})}
61+
</tr>
62+
</thead>
63+
<tbody>
64+
{data.map((line, lineIndex) => {
65+
return (
66+
<tr key={lineIndex}>
67+
{props.columns.map((c, i) => {
68+
return <td key={i}>{line[c.key]}</td>;
69+
})}
70+
</tr>
71+
);
72+
})}
73+
</tbody>
74+
</table>
75+
</>
76+
);
77+
};

src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { DSVImport } from './DSVImport';
1+
import { DSVImport } from './components/DSVImport';
22

33
export { DSVImport };

0 commit comments

Comments
 (0)