frame.select 1.1.1 → 1.1.3
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/dist/App.d.ts.map +1 -1
- package/dist/App.js +91 -11
- package/dist/components/BrandList.d.ts +2 -1
- package/dist/components/BrandList.d.ts.map +1 -1
- package/dist/components/BrandList.js +26 -20
- package/dist/components/FrameList.d.ts +13 -0
- package/dist/components/FrameList.d.ts.map +1 -0
- package/dist/components/FrameList.js +122 -0
- package/dist/components/types.d.ts +6 -0
- package/dist/components/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/dist/components/BrandFilter.d.ts +0 -6
- package/dist/components/BrandFilter.d.ts.map +0 -1
- package/dist/components/BrandFilter.js +0 -32
- package/dist/components/DebounceInput.d.ts +0 -8
- package/dist/components/DebounceInput.d.ts.map +0 -1
- package/dist/components/DebounceInput.js +0 -41
- package/dist/components/ItemFilter.test.d.ts +0 -2
- package/dist/components/ItemFilter.test.d.ts.map +0 -1
- package/dist/components/ItemFilter.test.js +0 -41
- package/dist/components/ItemList.test.d.ts +0 -2
- package/dist/components/ItemList.test.d.ts.map +0 -1
- package/dist/components/ItemList.test.js +0 -74
package/dist/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AACA,OAAO,WAAW,CAAC;AAInB,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AACA,OAAO,WAAW,CAAC;AAInB,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,iBAAS,GAAG,sBA6LX;AAED,eAAe,GAAG,CAAC"}
|
package/dist/App.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createColumnHelper } from '@tanstack/react-table';
|
|
2
2
|
import './App.css';
|
|
3
|
-
import ItemList from './components/ItemList';
|
|
4
3
|
import { useState } from 'react';
|
|
5
4
|
import React from 'react';
|
|
6
5
|
import { BrandList } from './components/BrandList';
|
|
6
|
+
import { FrameList } from './components/FrameList';
|
|
7
7
|
function App() {
|
|
8
|
+
const [brand, setBrand] = useState('');
|
|
8
9
|
const brands = [
|
|
9
10
|
{
|
|
10
11
|
name: 'Adidas',
|
|
@@ -43,24 +44,102 @@ function App() {
|
|
|
43
44
|
// item: ['New Balance'],
|
|
44
45
|
},
|
|
45
46
|
];
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const framesAdidas = [
|
|
48
|
+
'ADI0000000000000000014362150000',
|
|
49
|
+
'ADI0000000000000000018362150000',
|
|
50
|
+
'ADI0000000000000000019362150000',
|
|
51
|
+
// 3456789 123456789 12345678901
|
|
52
|
+
'AFF000000000000000TMA4750190000',
|
|
53
|
+
];
|
|
54
|
+
const frameNike = [
|
|
55
|
+
'NIK0000000000000000030362150000',
|
|
56
|
+
'NIK0000000000000000031362150000',
|
|
57
|
+
];
|
|
58
|
+
const framePuma = [
|
|
59
|
+
'PUM000000000000000PUMA162150000',
|
|
60
|
+
'PUM000000000000000PUMA262150000',
|
|
61
|
+
];
|
|
62
|
+
const frameReebok = [
|
|
63
|
+
'REB000000000000000REEBO62150000',
|
|
64
|
+
'REB000000000000000EEBOK62150000',
|
|
65
|
+
];
|
|
66
|
+
const frameUnderArmour = [
|
|
67
|
+
'UND000000000000000UARMR62150000',
|
|
68
|
+
'UND000000000000000UNDER62150000',
|
|
69
|
+
];
|
|
70
|
+
const frameNewBalance = [
|
|
71
|
+
'NEW000000000000000NEWBL62150000',
|
|
72
|
+
'NEW000000000000000NWBLC62150000',
|
|
73
|
+
];
|
|
74
|
+
const frames = [
|
|
75
|
+
{ brand: 'Adidas', frames: framesAdidas },
|
|
76
|
+
{ brand: 'Nike', frames: frameNike },
|
|
77
|
+
{ brand: 'Puma', frames: framePuma },
|
|
78
|
+
{ brand: 'Reebok', frames: frameReebok },
|
|
79
|
+
{ brand: 'Under Armour', frames: frameUnderArmour },
|
|
80
|
+
{ brand: 'New Balance', frames: frameNewBalance },
|
|
81
|
+
];
|
|
82
|
+
function convertFrames(brand) {
|
|
83
|
+
const foundFrames = frames.find((b) => b.brand === brand);
|
|
84
|
+
if (!foundFrames) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
return foundFrames.frames.map((frame) => ({
|
|
88
|
+
id: frame,
|
|
89
|
+
name: frame.substring(18, 23),
|
|
90
|
+
length: parseInt(frame.substring(23, 25)),
|
|
91
|
+
width: parseInt(frame.substring(25, 27)),
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
const brandColumnHelper = createColumnHelper();
|
|
95
|
+
const extraBrandColumns = [
|
|
96
|
+
brandColumnHelper.accessor((row) => row.description, {
|
|
49
97
|
header: 'description',
|
|
50
98
|
cell: (info) => React.createElement("div", null, info.getValue()),
|
|
51
99
|
}),
|
|
52
100
|
];
|
|
53
|
-
const
|
|
101
|
+
const brandColWidth = [
|
|
54
102
|
{
|
|
55
|
-
column:
|
|
103
|
+
column: extraBrandColumns[0],
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
const frameColumnHelper = createColumnHelper();
|
|
107
|
+
const extraFrameColumns = [
|
|
108
|
+
frameColumnHelper.accessor((row) => row.length.toString(), {
|
|
109
|
+
header: 'length',
|
|
110
|
+
cell: (info) => React.createElement("div", null, info.getValue()),
|
|
111
|
+
}),
|
|
112
|
+
frameColumnHelper.accessor((row) => row.width.toString(), {
|
|
113
|
+
// Convert to string
|
|
114
|
+
header: 'width',
|
|
115
|
+
cell: (info) => React.createElement("div", null, info.getValue()),
|
|
116
|
+
}),
|
|
117
|
+
];
|
|
118
|
+
const frameColWidth = [
|
|
119
|
+
{
|
|
120
|
+
column: extraFrameColumns[0],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
column: extraFrameColumns[1],
|
|
56
124
|
},
|
|
57
125
|
];
|
|
58
126
|
const onClickItem = (item) => {
|
|
59
127
|
window.alert(`Item clicked: ${item.getValue()}\n${JSON.stringify(item.row.original)}`);
|
|
60
128
|
};
|
|
61
|
-
const onClickBrand = (index) => {
|
|
62
|
-
|
|
129
|
+
const onClickBrand = (cell, index) => {
|
|
130
|
+
console.log(`cell: ${JSON.stringify(cell.row.original, null, 2)}`);
|
|
131
|
+
const brand = brands.find((b) => b.name === cell.row.original.name);
|
|
132
|
+
// window.alert(`Item clicked: ${index}\n${JSON.stringify(brand, null, 2)}`);
|
|
133
|
+
if (brand) {
|
|
134
|
+
setBrand(brand.name);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const onClickFrame = (cell, index) => {
|
|
138
|
+
window.alert(`Frame clicked: ${JSON.stringify(cell.row.original)} at index ${index}`);
|
|
63
139
|
};
|
|
140
|
+
// const onClickFrame = (frame: string, index: number) => {
|
|
141
|
+
// window.alert(`Frame clicked: ${frame} at index ${index}`);
|
|
142
|
+
// };
|
|
64
143
|
const [filter, setFilter] = useState('');
|
|
65
144
|
function filterMatches(item, fltr) {
|
|
66
145
|
const match = item.name
|
|
@@ -75,12 +154,13 @@ function App() {
|
|
|
75
154
|
filterMatches,
|
|
76
155
|
placeholder: 'Filter Brands',
|
|
77
156
|
};
|
|
78
|
-
const renderItem = (item) =>
|
|
157
|
+
// const renderItem = (item: string) => <h4>{item}</h4>;
|
|
79
158
|
return (React.createElement(React.Fragment, null,
|
|
80
159
|
React.createElement("h1", null, "Brand List"),
|
|
81
|
-
React.createElement(ItemList, { itemList: brands, renderItem: renderItem, clickFunc: onClickItem, itemFilter: tItemFilter, extraColumns: colWidth }),
|
|
82
160
|
React.createElement(BrandList, { brandList: brands, onClick: onClickBrand,
|
|
83
161
|
// renderItem={renderItem}
|
|
84
|
-
extraColumns:
|
|
162
|
+
extraColumns: brandColWidth }),
|
|
163
|
+
React.createElement("h2", null, "Frame List"),
|
|
164
|
+
React.createElement(FrameList, { frameList: convertFrames(brand), onClick: onClickFrame, extraColumns: frameColWidth, style: { border: '1px solid black', padding: '10px' } })));
|
|
85
165
|
}
|
|
86
166
|
export default App;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { Cell } from '@tanstack/react-table';
|
|
1
2
|
import { TColumn } from './itemTypes';
|
|
2
3
|
import { JSX } from 'react';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { TBrandObj } from './types';
|
|
5
6
|
export declare function BrandList(props: {
|
|
6
7
|
brandList: TBrandObj[];
|
|
7
|
-
onClick?: (index: number) => void;
|
|
8
|
+
onClick?: (cell: Cell<TBrandObj, unknown>, index: number) => void;
|
|
8
9
|
renderItem?: (item: string) => React.ReactNode;
|
|
9
10
|
extraColumns?: TColumn<TBrandObj>[];
|
|
10
11
|
style?: React.CSSProperties;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrandList.d.ts","sourceRoot":"","sources":["../../src/components/BrandList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BrandList.d.ts","sourceRoot":"","sources":["../../src/components/BrandList.tsx"],"names":[],"mappings":"AASA,OAAO,EAIL,IAAI,EAKL,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAe,OAAO,EAAS,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,GAAG,EAA6C,MAAM,OAAO,CAAC;AACvE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,GAAG,GAAG,CAAC,OAAO,CA8Ld"}
|
|
@@ -29,6 +29,7 @@ export function BrandList(props) {
|
|
|
29
29
|
}
|
|
30
30
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
31
|
}, [serializedExtraColumns]); // Use the serialized version as a dependency
|
|
32
|
+
/***************************** filtered items *******************************/
|
|
32
33
|
const filteredItems = useMemo(() => {
|
|
33
34
|
if (!tBrandFilter) {
|
|
34
35
|
return props.brandList;
|
|
@@ -45,6 +46,7 @@ export function BrandList(props) {
|
|
|
45
46
|
// tBrandFilter.filterEvent?.(filteredList)
|
|
46
47
|
return filteredList;
|
|
47
48
|
}, [tBrandFilter, props.brandList, extraCols]);
|
|
49
|
+
/****************************************************************************/
|
|
48
50
|
const defaultHeader = 'Name';
|
|
49
51
|
const columnHelper = createColumnHelper();
|
|
50
52
|
const defaultColumns = [
|
|
@@ -60,9 +62,9 @@ export function BrandList(props) {
|
|
|
60
62
|
columns.push(col.column);
|
|
61
63
|
}
|
|
62
64
|
});
|
|
63
|
-
const onClick = (index) => () => {
|
|
65
|
+
const onClick = (cell, index) => () => {
|
|
64
66
|
if (props.onClick) {
|
|
65
|
-
props.onClick?.(index);
|
|
67
|
+
props.onClick?.(cell, index);
|
|
66
68
|
}
|
|
67
69
|
else {
|
|
68
70
|
console.log(`Clicked item index: ${index}`);
|
|
@@ -86,31 +88,35 @@ export function BrandList(props) {
|
|
|
86
88
|
}
|
|
87
89
|
return filter;
|
|
88
90
|
}
|
|
89
|
-
function displayBody(cell) {
|
|
90
|
-
let cellContent = React.createElement("div", null);
|
|
91
|
-
const cll = cell.getValue();
|
|
92
|
-
if (cell.column.columnDef.header === defaultHeader) {
|
|
93
|
-
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id },
|
|
94
|
-
React.createElement(Button, { onClick: onClick(cell.row.index) }, props.renderItem
|
|
95
|
-
? props.renderItem(cll)
|
|
96
|
-
: flexRender(cell.column.columnDef.cell, cell.getContext()))));
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id }, props.renderItem ? props.renderItem(cll) : React.createElement("div", null, cll)));
|
|
100
|
-
}
|
|
101
|
-
return cellContent;
|
|
102
|
-
}
|
|
103
91
|
const table = useReactTable({
|
|
104
92
|
data: filteredItems,
|
|
105
93
|
columns,
|
|
106
94
|
getCoreRowModel: getCoreRowModel(),
|
|
107
95
|
getFilteredRowModel: getFilteredRowModel(),
|
|
108
96
|
});
|
|
97
|
+
const paginatedRows = table.getRowModel().rows;
|
|
98
|
+
const renderRows = React.useCallback((rows) => {
|
|
99
|
+
function displayBody(cell) {
|
|
100
|
+
let cellContent = React.createElement("div", null);
|
|
101
|
+
const cll = cell.getValue();
|
|
102
|
+
if (cell.column.columnDef.header === defaultHeader) {
|
|
103
|
+
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id },
|
|
104
|
+
React.createElement(Button, { onClick: onClick(cell, cell.row.index) }, props.renderItem
|
|
105
|
+
? props.renderItem(cll)
|
|
106
|
+
: flexRender(cell.column.columnDef.cell, cell.getContext()))));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id }, props.renderItem ? props.renderItem(cll) : React.createElement("div", null, cll)));
|
|
110
|
+
}
|
|
111
|
+
return cellContent;
|
|
112
|
+
}
|
|
113
|
+
return rows.map((row) => (React.createElement(TableRow, { key: row.id }, row.getVisibleCells().map((cell) => {
|
|
114
|
+
// console.log(`cell: ${JSON.stringify(cell, null)}`)
|
|
115
|
+
return displayBody(cell);
|
|
116
|
+
}))));
|
|
117
|
+
}, [onClick, props]);
|
|
109
118
|
return (React.createElement(TableContainer, { "data-testid": "frame.select-TableContainer", style: props.style },
|
|
110
119
|
React.createElement(Table, { stickyHeader: true, "aria-label": "sticky table" },
|
|
111
120
|
React.createElement(TableHead, null, table.getHeaderGroups().map((headerGroup) => (React.createElement(TableRow, { key: headerGroup.id, "data-testid": headerGroup.id }, headerGroup.headers.map((header) => (React.createElement(TableCell, { key: header.id }, displayHeader(header)))))))),
|
|
112
|
-
React.createElement(TableBody,
|
|
113
|
-
// console.log(`cell: ${JSON.stringify(cell, null)}`)
|
|
114
|
-
return displayBody(cell);
|
|
115
|
-
}))))))));
|
|
121
|
+
React.createElement(TableBody, { "data-testid": "table.list-of-brands" }, renderRows(paginatedRows)))));
|
|
116
122
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Cell } from '@tanstack/react-table';
|
|
2
|
+
import { TColumn } from './itemTypes';
|
|
3
|
+
import { JSX } from 'react';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { TFrameObj } from './types';
|
|
6
|
+
export declare function FrameList(props: {
|
|
7
|
+
frameList: TFrameObj[];
|
|
8
|
+
onClick?: (cell: Cell<TFrameObj, unknown>, index: number) => void;
|
|
9
|
+
renderItem?: (item: string) => React.ReactNode;
|
|
10
|
+
extraColumns?: TColumn<TFrameObj>[];
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
}): JSX.Element;
|
|
13
|
+
//# sourceMappingURL=FrameList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FrameList.d.ts","sourceRoot":"","sources":["../../src/components/FrameList.tsx"],"names":[],"mappings":"AASA,OAAO,EAIL,IAAI,EAKL,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAe,OAAO,EAAS,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,GAAG,EAA6C,MAAM,OAAO,CAAC;AACvE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,GAAG,GAAG,CAAC,OAAO,CA8Ld"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Button, } from '@mui/material';
|
|
2
|
+
import { useReactTable, getCoreRowModel, getFilteredRowModel, createColumnHelper, flexRender, } from '@tanstack/react-table';
|
|
3
|
+
import ItemFilter from './ItemFilter';
|
|
4
|
+
import { useMemo, useState, useCallback } from 'react';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export function FrameList(props) {
|
|
7
|
+
'use no memo'; // For React Compiler compatibility with TanStack Table
|
|
8
|
+
const [filter, setFilter] = useState('');
|
|
9
|
+
const filterMatches = useCallback((item, fltr) => {
|
|
10
|
+
const match = item.name
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.includes(fltr ? fltr.toLowerCase() : '');
|
|
13
|
+
return match;
|
|
14
|
+
}, []);
|
|
15
|
+
const tFrameFilter = useMemo(() => ({
|
|
16
|
+
property: 'name',
|
|
17
|
+
filter,
|
|
18
|
+
setFilter,
|
|
19
|
+
filterMatches,
|
|
20
|
+
placeholder: 'Frames',
|
|
21
|
+
}), [filter, filterMatches]);
|
|
22
|
+
const serializedExtraColumns = useMemo(() => JSON.stringify(props.extraColumns), [props.extraColumns]);
|
|
23
|
+
const extraCols = useMemo(() => {
|
|
24
|
+
if (props.extraColumns) {
|
|
25
|
+
return props.extraColumns.filter((col) => col !== undefined);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
|
+
}, [serializedExtraColumns]); // Use the serialized version as a dependency
|
|
32
|
+
/***************************** filtered items *******************************/
|
|
33
|
+
const filteredItems = useMemo(() => {
|
|
34
|
+
if (!tFrameFilter) {
|
|
35
|
+
return props.frameList;
|
|
36
|
+
}
|
|
37
|
+
let filteredList = props.frameList;
|
|
38
|
+
if (tFrameFilter.filterMatches) {
|
|
39
|
+
filteredList = props.frameList.filter((item) => tFrameFilter.filterMatches(item, tFrameFilter.filter));
|
|
40
|
+
}
|
|
41
|
+
extraCols.forEach((col) => {
|
|
42
|
+
if (col?.filter) {
|
|
43
|
+
filteredList = filteredList.filter((item) => col.filter?.filterMatches(item, col.filter.filter));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
// tBrandFilter.filterEvent?.(filteredList)
|
|
47
|
+
return filteredList;
|
|
48
|
+
}, [tFrameFilter, props.frameList, extraCols]);
|
|
49
|
+
/****************************************************************************/
|
|
50
|
+
const defaultHeader = 'Name';
|
|
51
|
+
const columnHelper = createColumnHelper();
|
|
52
|
+
const defaultColumns = [
|
|
53
|
+
columnHelper.accessor((row) => row.name, {
|
|
54
|
+
header: defaultHeader,
|
|
55
|
+
cell: (info) => (React.createElement("div", { style: { fontWeight: 'bold' } }, info.getValue())),
|
|
56
|
+
footer: (info) => info.column.id,
|
|
57
|
+
}),
|
|
58
|
+
];
|
|
59
|
+
const columns = [...defaultColumns];
|
|
60
|
+
extraCols.forEach((col) => {
|
|
61
|
+
if (col) {
|
|
62
|
+
columns.push(col.column);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const onClick = (cell, index) => () => {
|
|
66
|
+
if (props.onClick) {
|
|
67
|
+
props.onClick?.(cell, index);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log(`Clicked item index: ${index}`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
function displayHeader(header) {
|
|
74
|
+
let filter = React.createElement("div", null);
|
|
75
|
+
if (header.id === defaultHeader) {
|
|
76
|
+
if (tFrameFilter) {
|
|
77
|
+
filter = (React.createElement("div", { style: { width: '100%' } },
|
|
78
|
+
React.createElement(ItemFilter, { itemFilter: tFrameFilter })));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
extraCols.forEach((col) => {
|
|
83
|
+
if (col && header.id === col.column.header) {
|
|
84
|
+
filter = col.filter ? (React.createElement("div", { style: { width: '100%' } },
|
|
85
|
+
React.createElement(ItemFilter, { itemFilter: col.filter }))) : (React.createElement("div", null));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return filter;
|
|
90
|
+
}
|
|
91
|
+
const table = useReactTable({
|
|
92
|
+
data: filteredItems,
|
|
93
|
+
columns,
|
|
94
|
+
getCoreRowModel: getCoreRowModel(),
|
|
95
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
96
|
+
});
|
|
97
|
+
const paginatedRows = table.getRowModel().rows;
|
|
98
|
+
const renderRows = React.useCallback((rows) => {
|
|
99
|
+
function displayBody(cell) {
|
|
100
|
+
let cellContent = React.createElement("div", null);
|
|
101
|
+
const cll = cell.getValue();
|
|
102
|
+
if (cell.column.columnDef.header === defaultHeader) {
|
|
103
|
+
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id },
|
|
104
|
+
React.createElement(Button, { onClick: onClick(cell, cell.row.index) }, props.renderItem
|
|
105
|
+
? props.renderItem(cll)
|
|
106
|
+
: flexRender(cell.column.columnDef.cell, cell.getContext()))));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
cellContent = (React.createElement(TableCell, { style: { backgroundColor: 'white', padding: 2 }, key: cell.id }, props.renderItem ? props.renderItem(cll) : React.createElement("div", null, cll)));
|
|
110
|
+
}
|
|
111
|
+
return cellContent;
|
|
112
|
+
}
|
|
113
|
+
return rows.map((row) => (React.createElement(TableRow, { key: row.id }, row.getVisibleCells().map((cell) => {
|
|
114
|
+
// console.log(`cell: ${JSON.stringify(cell, null)}`)
|
|
115
|
+
return displayBody(cell);
|
|
116
|
+
}))));
|
|
117
|
+
}, [onClick, props]);
|
|
118
|
+
return (React.createElement(TableContainer, { "data-testid": "frame.select-TableContainer", style: props.style },
|
|
119
|
+
React.createElement(Table, { stickyHeader: true, "aria-label": "sticky table" },
|
|
120
|
+
React.createElement(TableHead, null, table.getHeaderGroups().map((headerGroup) => (React.createElement(TableRow, { key: headerGroup.id, "data-testid": headerGroup.id }, headerGroup.headers.map((header) => (React.createElement(TableCell, { key: header.id }, displayHeader(header)))))))),
|
|
121
|
+
React.createElement(TableBody, { "data-testid": "table.list-of-frames" }, renderRows(paginatedRows)))));
|
|
122
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AACF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/app.tsx","../src/index.ts","../src/main.tsx","../src/vite-env.d.ts","../src/components/
|
|
1
|
+
{"root":["../src/app.tsx","../src/index.ts","../src/main.tsx","../src/vite-env.d.ts","../src/components/brandlist.tsx","../src/components/framelist.tsx","../src/components/itemfilter.tsx","../src/components/itemlist.tsx","../src/components/itemtypes.ts","../src/components/types.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frame.select",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "A React component for selecting items from a list with a search bar.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
"@eslint/js": "^9.39.2",
|
|
36
36
|
"@testing-library/dom": "^10.4.1",
|
|
37
37
|
"@testing-library/jest-dom": "^6.9.1",
|
|
38
|
-
"@testing-library/react": "^16.
|
|
38
|
+
"@testing-library/react": "^16.3.1",
|
|
39
39
|
"@types/react": "^19.2.7",
|
|
40
40
|
"@types/react-dom": "^19.2.3",
|
|
41
41
|
"@vitejs/plugin-react": "^5.1.2",
|
|
42
42
|
"eslint": "^9.39.2",
|
|
43
43
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
44
|
-
"eslint-plugin-react-refresh": "^0.4.
|
|
44
|
+
"eslint-plugin-react-refresh": "^0.4.26",
|
|
45
45
|
"globals": "^16.5.0",
|
|
46
46
|
"jsdom": "^27.3.0",
|
|
47
47
|
"typescript": "~5.9.3",
|
|
48
|
-
"typescript-eslint": "^8.
|
|
49
|
-
"vite": "^7.
|
|
50
|
-
"vitest": "^4.0.
|
|
48
|
+
"typescript-eslint": "^8.50.0",
|
|
49
|
+
"vite": "^7.3.0",
|
|
50
|
+
"vitest": "^4.0.16"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BrandFilter.d.ts","sourceRoot":"","sources":["../../src/components/BrandFilter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAI/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;CAAE,qBAgDvE"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { DebouncedInput } from './DebounceInput';
|
|
3
|
-
// import { Message } from '../../../../common/commands';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
export function BrandFilter({ column }) {
|
|
6
|
-
const columnFilterValue = column.getFilterValue();
|
|
7
|
-
const [value, setFilterValue] = React.useState('');
|
|
8
|
-
// const { filterVariant } = column.columnDef.meta ?? {};
|
|
9
|
-
React.useEffect(() => {
|
|
10
|
-
console.log(`has changed`);
|
|
11
|
-
setFilterValue(columnFilterValue);
|
|
12
|
-
}, [columnFilterValue]);
|
|
13
|
-
React.useEffect(() => {
|
|
14
|
-
console.log(`BrandFilter.CommandDBBrandFilter`);
|
|
15
|
-
// window.electron.ipcRenderer.on(
|
|
16
|
-
// Message.CommandDBBrandFilter,
|
|
17
|
-
// (_event: unknown, data: string) => {
|
|
18
|
-
// setVal(data);
|
|
19
|
-
// setFilterValue(data);
|
|
20
|
-
// }
|
|
21
|
-
// );
|
|
22
|
-
}, []);
|
|
23
|
-
// setFilterValue((columnFilterValue ?? '') as string);
|
|
24
|
-
const setVal = React.useCallback((str) => {
|
|
25
|
-
column.setFilterValue(str);
|
|
26
|
-
}, [column]);
|
|
27
|
-
return useMemo(() => (React.createElement(DebouncedInput, { className: "w-36 border shadow rounded", title: "brand", onChange: (value) => {
|
|
28
|
-
document.body.style.cursor = 'wait';
|
|
29
|
-
setVal(value);
|
|
30
|
-
document.body.style.cursor = 'default';
|
|
31
|
-
}, placeholder: `Search...`, type: "text", value: value })), [setVal, value]);
|
|
32
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export declare function DebouncedInput({ value: initialValue, title, onChange, debounce, }: {
|
|
3
|
-
value: string | number;
|
|
4
|
-
title: string;
|
|
5
|
-
onChange: (value: string | number) => void;
|
|
6
|
-
debounce?: number;
|
|
7
|
-
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>): React.JSX.Element;
|
|
8
|
-
//# sourceMappingURL=DebounceInput.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DebounceInput.d.ts","sourceRoot":"","sources":["../../src/components/DebounceInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EAAE,YAAY,EACnB,KAAK,EACL,QAAQ,EACR,QAAY,GACb,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC,qBAkEhE"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Box, Button, TextField } from '@mui/material';
|
|
2
|
-
import CancelPresentationRounded from '@mui/icons-material/CancelPresentationRounded';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
// import { Message } from '../../../../common/commands';
|
|
5
|
-
export function DebouncedInput({ value: initialValue, title, onChange, debounce = 0, }) {
|
|
6
|
-
const [value, setValue] = React.useState(initialValue);
|
|
7
|
-
React.useEffect(() => {
|
|
8
|
-
console.log(`DebounceInput.clearTextField`);
|
|
9
|
-
// window.electron.ipcRenderer.on(
|
|
10
|
-
// Message.CommandDBBrandClearFilter,
|
|
11
|
-
// (_event: unknown, _data: string) => {
|
|
12
|
-
// clearTextField();
|
|
13
|
-
// }
|
|
14
|
-
// );
|
|
15
|
-
}, []);
|
|
16
|
-
React.useEffect(() => {
|
|
17
|
-
setValue(initialValue);
|
|
18
|
-
}, [initialValue]);
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
const timeout = setTimeout(() => {
|
|
21
|
-
onChange(value);
|
|
22
|
-
}, debounce);
|
|
23
|
-
return () => clearTimeout(timeout);
|
|
24
|
-
}, [value]);
|
|
25
|
-
function clearTextField() {
|
|
26
|
-
setValue('');
|
|
27
|
-
}
|
|
28
|
-
return (React.createElement("div", null,
|
|
29
|
-
React.createElement(Box, { sx: { display: 'flex', alignItems: 'flex-end' } },
|
|
30
|
-
React.createElement(Button, { "data-testid": `button.clear-${title}`, style: {
|
|
31
|
-
height: '100%',
|
|
32
|
-
display: 'flex',
|
|
33
|
-
alignItems: 'center',
|
|
34
|
-
marginLeft: '8px',
|
|
35
|
-
}, onClick: clearTextField },
|
|
36
|
-
React.createElement(CancelPresentationRounded, null)),
|
|
37
|
-
React.createElement(TextField, { id: "input-with-sx", label: title, variant: "standard", value: value, onChange: (e) => {
|
|
38
|
-
console.log(e.target.value);
|
|
39
|
-
setValue(e.target.value);
|
|
40
|
-
}, sx: { width: '100px' } }))));
|
|
41
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ItemFilter.test.d.ts","sourceRoot":"","sources":["../../src/components/ItemFilter.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { render, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
-
import ItemFilter from './ItemFilter';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
describe('ItemFilter', () => {
|
|
6
|
-
it('should clear the filter when clearFilter is called', () => {
|
|
7
|
-
const setFilterMock = vi.fn();
|
|
8
|
-
const itemFilter = {
|
|
9
|
-
filter: 'test',
|
|
10
|
-
setFilter: setFilterMock,
|
|
11
|
-
placeholder: 'Filter Items',
|
|
12
|
-
property: 'name',
|
|
13
|
-
filterMatches: vi.fn(),
|
|
14
|
-
};
|
|
15
|
-
const { getByPlaceholderText, getByRole } = render(React.createElement(ItemFilter, { itemFilter: itemFilter }));
|
|
16
|
-
const input = getByPlaceholderText('Filter Items');
|
|
17
|
-
const button = getByRole('button');
|
|
18
|
-
// Ensure the input has the initial filter value
|
|
19
|
-
expect(input.value).toBe('test');
|
|
20
|
-
// Click the clear button
|
|
21
|
-
fireEvent.click(button);
|
|
22
|
-
// Ensure the setFilter function was called with an empty string
|
|
23
|
-
expect(setFilterMock).toHaveBeenCalledWith('');
|
|
24
|
-
});
|
|
25
|
-
it('should update the filter when handleInputChange is called', () => {
|
|
26
|
-
const setFilterMock = vi.fn();
|
|
27
|
-
const itemFilter = {
|
|
28
|
-
filter: '',
|
|
29
|
-
setFilter: setFilterMock,
|
|
30
|
-
placeholder: 'Filter Items',
|
|
31
|
-
property: 'name',
|
|
32
|
-
filterMatches: vi.fn(),
|
|
33
|
-
};
|
|
34
|
-
const { getByPlaceholderText } = render(React.createElement(ItemFilter, { itemFilter: itemFilter }));
|
|
35
|
-
const input = getByPlaceholderText('Filter Items');
|
|
36
|
-
// Simulate typing in the input field
|
|
37
|
-
fireEvent.change(input, { target: { value: 'new filter' } });
|
|
38
|
-
// Ensure the setFilter function was called with the new value
|
|
39
|
-
expect(setFilterMock).toHaveBeenCalledWith('new filter');
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ItemList.test.d.ts","sourceRoot":"","sources":["../../src/components/ItemList.test.tsx"],"names":[],"mappings":"AACA,OAAO,2BAA2B,CAAC"}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import '@testing-library/jest-dom';
|
|
3
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import { createColumnHelper } from '@tanstack/react-table';
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import ItemList from './ItemList';
|
|
7
|
-
describe('ItemList', () => {
|
|
8
|
-
const itemList = [
|
|
9
|
-
{ name: 'Item 1' },
|
|
10
|
-
{ name: 'Item 2' },
|
|
11
|
-
{ name: 'Item 3' },
|
|
12
|
-
];
|
|
13
|
-
const filterMatches = (item, filter) => item.name.includes(filter);
|
|
14
|
-
// const filterEvent = vi.fn()
|
|
15
|
-
const renderItem = (item) => React.createElement("span", null, item);
|
|
16
|
-
const clickFunc = vi.fn();
|
|
17
|
-
const itemFilter = {
|
|
18
|
-
filter: 'Item',
|
|
19
|
-
setFilter: vi.fn(),
|
|
20
|
-
property: 'name',
|
|
21
|
-
filterMatches,
|
|
22
|
-
placeholder: 'Filter Items',
|
|
23
|
-
};
|
|
24
|
-
it('renders the item list', () => {
|
|
25
|
-
render(React.createElement(ItemList, { itemList: itemList }));
|
|
26
|
-
itemList.forEach((item) => {
|
|
27
|
-
expect(screen.getByText(item.name)).toBeInTheDocument();
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
it('filters the item list based on filterMatches', () => {
|
|
31
|
-
render(React.createElement(ItemList, { itemList: itemList, itemFilter: itemFilter }));
|
|
32
|
-
expect(screen.getByText('Item 1')).toBeInTheDocument();
|
|
33
|
-
expect(screen.getByText('Item 2')).toBeInTheDocument();
|
|
34
|
-
expect(screen.getByText('Item 3')).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
// it('calls filterEvent when filter is applied', () => {
|
|
37
|
-
// render(<ItemList itemList={itemList} filterEvent={filterEvent} itemFilter={itemFilter} />)
|
|
38
|
-
// expect(filterEvent).toHaveBeenCalledWith(itemList)
|
|
39
|
-
// })
|
|
40
|
-
it('renders custom item using renderItem', () => {
|
|
41
|
-
render(React.createElement(ItemList, { itemList: itemList, renderItem: renderItem }));
|
|
42
|
-
itemList.forEach((item) => {
|
|
43
|
-
expect(screen.getByText(item.name)).toBeInTheDocument();
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
it('calls clickFunc with the correct cell when an item is clicked', () => {
|
|
47
|
-
render(React.createElement(ItemList, { itemList: itemList, clickFunc: clickFunc }));
|
|
48
|
-
const itemButton = screen.getByText('Item 1').closest('button');
|
|
49
|
-
fireEvent.click(itemButton);
|
|
50
|
-
expect(clickFunc).toHaveBeenCalled();
|
|
51
|
-
expect(clickFunc.mock.calls[0][0].getValue()).toBe('Item 1');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
describe('ItemList - createColumnHelper', () => {
|
|
55
|
-
it('creates columns correctly', () => {
|
|
56
|
-
const columnHelper = createColumnHelper();
|
|
57
|
-
const columns = [
|
|
58
|
-
columnHelper.accessor('name', {
|
|
59
|
-
header: 'Name',
|
|
60
|
-
cell: (info) => React.createElement("span", null, info.getValue()),
|
|
61
|
-
}),
|
|
62
|
-
columnHelper.accessor('age', {
|
|
63
|
-
header: 'Age',
|
|
64
|
-
cell: (info) => React.createElement("span", null, info.getValue()),
|
|
65
|
-
}),
|
|
66
|
-
];
|
|
67
|
-
expect(columns).toHaveLength(2);
|
|
68
|
-
expect(columns[0].accessorKey).toBe('name');
|
|
69
|
-
expect(columns[0].header).toBe('Name');
|
|
70
|
-
expect(typeof columns[0].cell).toBe('function');
|
|
71
|
-
expect(columns[1].header).toBe('Age');
|
|
72
|
-
expect(typeof columns[1].cell).toBe('function');
|
|
73
|
-
});
|
|
74
|
-
});
|