react-lookup-select 1.0.0

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/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "react-lookup-select",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "sideEffects": [
7
+ "dist/styles.css"
8
+ ],
9
+ "main": "dist/index.cjs",
10
+ "module": "dist/index.mjs",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.mjs",
16
+ "require": "./dist/index.cjs"
17
+ },
18
+ "./styles.css": "./dist/styles.css"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "peerDependencies": {
24
+ "react": ">=18",
25
+ "react-dom": ">=18"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup src/index.ts --dts --format cjs,esm --sourcemap",
29
+ "dev": "tsup src/index.ts --dts --format cjs,esm --sourcemap --watch",
30
+ "lint": "eslint .",
31
+ "test": "vitest",
32
+ "prepare": "husky install",
33
+ "storybook": "storybook dev -p 6006",
34
+ "build-storybook": "storybook build"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/onurlulardanlulardan/react-lookup-select.git"
42
+ },
43
+ "keywords": [
44
+ "react",
45
+ "select",
46
+ "lookup",
47
+ "modal",
48
+ "grid",
49
+ "combobox",
50
+ "picker",
51
+ "headless",
52
+ "a11y"
53
+ ],
54
+ "description": "A headless, customizable React lookup select component with modal and grid support",
55
+ "devDependencies": {
56
+ "@storybook/addon-docs": "^9.1.7",
57
+ "@storybook/react-vite": "^9.1.7",
58
+ "@testing-library/jest-dom": "^6.8.0",
59
+ "@testing-library/react": "^16.3.0",
60
+ "@testing-library/user-event": "^14.6.1",
61
+ "@types/react": "^19.1.13",
62
+ "@types/react-dom": "^19.1.9",
63
+ "@typescript-eslint/eslint-plugin": "^8.44.0",
64
+ "@typescript-eslint/parser": "^8.44.0",
65
+ "eslint": "^9.35.0",
66
+ "eslint-plugin-storybook": "^9.1.7",
67
+ "husky": "^9.1.7",
68
+ "jsdom": "^27.0.0",
69
+ "prettier": "^3.6.2",
70
+ "storybook": "^9.1.7",
71
+ "tsup": "^8.5.0",
72
+ "typescript": "^5.9.2",
73
+ "vitest": "^3.2.4"
74
+ }
75
+ }
package/readme.md ADDED
@@ -0,0 +1,274 @@
1
+ # react-lookup-select
2
+
3
+ A headless, customizable React lookup select component with modal and grid support for single/multiple selection.
4
+
5
+ ## Features
6
+
7
+ - **Trigger (ComboBox appearance)**: Click to open modal
8
+ - **Grid inside Modal**: Single/multiple row selection (with checkboxes or row clicks)
9
+ - **Selection Modes**: single | multiple
10
+ - **Return Values**: id and text fields are user-mappable
11
+ - **Full Customization**: themes, icons, grid columns, cell renderers
12
+ - **Data Sources**: data (array) or dataSource (async: pagination/sort/search)
13
+ - **Accessibility**: keyboard navigation, ARIA roles, focus trap
14
+ - **Performance**: virtualization option for large datasets
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm i react-lookup-select
20
+ ```
21
+
22
+ ```tsx
23
+ import { LookupSelect } from 'react-lookup-select';
24
+ import 'react-lookup-select/styles.css';
25
+ ```
26
+
27
+ ## Example Usage
28
+
29
+ ### Single Selection – text = name + ' ' + surname
30
+
31
+ ```tsx
32
+ <LookupSelect
33
+ mode="single"
34
+ data={users}
35
+ columns={[
36
+ { key: 'name', title: 'Name' },
37
+ { key: 'surname', title: 'Surname' },
38
+ { key: 'email', title: 'Email' },
39
+ ]}
40
+ mapper={{
41
+ getId: (u) => u.userId,
42
+ getText: (u) => `${u.name} ${u.surname}`,
43
+ }}
44
+ returnShape="id-text"
45
+ onChange={(val) => console.log(val)}
46
+ />
47
+ ```
48
+
49
+ ### Multiple Selection – Custom return
50
+
51
+ ```tsx
52
+ <LookupSelect
53
+ mode="multiple"
54
+ data={products}
55
+ columns={[
56
+ { key: 'sku', title: 'SKU' },
57
+ { key: 'title', title: 'Product' },
58
+ { key: 'price', title: 'Price' },
59
+ ]}
60
+ mapper={{ getId: (p) => p.id, getText: (p) => p.title }}
61
+ returnShape="custom"
62
+ returnMap={{ map: (p) => ({ key: p.id, label: p.title, p }) }}
63
+ onChange={(vals) => save(vals)}
64
+ />
65
+ ```
66
+
67
+ ### Server-side data + search/pagination
68
+
69
+ ```tsx
70
+ const dataSource = async (q: QueryState) => {
71
+ const res = await fetch(
72
+ `/api/users?page=${q.page}&size=${q.pageSize}&search=${q.search ?? ''}`
73
+ );
74
+ const json = await res.json();
75
+ return { rows: json.items, total: json.total };
76
+ };
77
+
78
+ <LookupSelect
79
+ mode="multiple"
80
+ dataSource={dataSource}
81
+ pageSize={50}
82
+ columns={[
83
+ { key: 'name', title: 'Name', sortable: true },
84
+ { key: 'surname', title: 'Surname', sortable: true },
85
+ { key: 'department', title: 'Department' },
86
+ ]}
87
+ mapper={{ getId: (u) => u.id, getText: (u) => `${u.name} ${u.surname}` }}
88
+ onQueryChange={(q) => console.log('query changed', q)}
89
+ />;
90
+ ```
91
+
92
+ ## Theming and Customization
93
+
94
+ ### Pre-built Themes
95
+
96
+ ```tsx
97
+ {
98
+ /* Default theme */
99
+ }
100
+ <LookupSelect variant="default" {...props} />;
101
+
102
+ {
103
+ /* Dark theme */
104
+ }
105
+ <LookupSelect variant="dark" {...props} />;
106
+
107
+ {
108
+ /* Minimal theme */
109
+ }
110
+ <LookupSelect variant="minimal" {...props} />;
111
+
112
+ {
113
+ /* Compact theme */
114
+ }
115
+ <LookupSelect variant="compact" {...props} />;
116
+ ```
117
+
118
+ ### Size Options
119
+
120
+ ```tsx
121
+ {
122
+ /* Small size */
123
+ }
124
+ <LookupSelect size="small" {...props} />;
125
+
126
+ {
127
+ /* Medium size (default) */
128
+ }
129
+ <LookupSelect size="medium" {...props} />;
130
+
131
+ {
132
+ /* Large size */
133
+ }
134
+ <LookupSelect size="large" {...props} />;
135
+ ```
136
+
137
+ ### Customization with CSS Variables
138
+
139
+ ```tsx
140
+ <LookupSelect
141
+ theme={{
142
+ colorPrimary: '#8b5cf6',
143
+ colorBg: '#faf5ff',
144
+ colorText: '#4c1d95',
145
+ borderRadius: 12,
146
+ spacing: 10,
147
+ }}
148
+ {...props}
149
+ />
150
+ ```
151
+
152
+ ### Customization with CSS Classes
153
+
154
+ ```tsx
155
+ <LookupSelect
156
+ classNames={{
157
+ root: 'my-custom-lookup',
158
+ trigger: 'my-custom-trigger',
159
+ modal: 'my-custom-modal',
160
+ grid: 'my-custom-grid',
161
+ }}
162
+ {...props}
163
+ />
164
+ ```
165
+
166
+ ```css
167
+ .my-custom-lookup {
168
+ --lookup-select-color-primary: #10b981;
169
+ --lookup-select-border-radius: 8px;
170
+ --lookup-select-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
171
+ }
172
+
173
+ .my-custom-trigger {
174
+ border: 2px solid #10b981;
175
+ background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
176
+ }
177
+ ```
178
+
179
+ ### Inline Styles
180
+
181
+ ```tsx
182
+ <LookupSelect
183
+ styles={{
184
+ root: { border: '2px solid #f59e0b', borderRadius: '8px' },
185
+ trigger: { background: '#fef3c7', color: '#92400e' },
186
+ modal: { boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)' },
187
+ }}
188
+ {...props}
189
+ />
190
+ ```
191
+
192
+ ## Virtualization - Large Data Performance
193
+
194
+ ### Auto Virtualization
195
+
196
+ ```tsx
197
+ <LookupSelect
198
+ data={largeDataArray} // 1000+ records
199
+ virtualization={true} // Auto-enable when data > 100 items
200
+ {...props}
201
+ />
202
+ ```
203
+
204
+ ### Manual Virtualization Configuration
205
+
206
+ ```tsx
207
+ <LookupSelect
208
+ data={tenThousandItems}
209
+ virtualization={true}
210
+ virtualRowHeight={48} // Fixed row height
211
+ virtualContainerHeight={500} // Scroll container height
212
+ virtualOverscan={10} // Buffer for smooth scrolling
213
+ virtualThreshold={100} // Enable when data exceeds this
214
+ {...props}
215
+ />
216
+ ```
217
+
218
+ ### Hybrid Mode - Server + Client Virtualization
219
+
220
+ ```tsx
221
+ <LookupSelect
222
+ dataSource={serverDataSource}
223
+ virtualization={true}
224
+ pageSize={100} // Fetch 500 records from server (5x buffer)
225
+ virtualContainerHeight={400}
226
+ virtualRowHeight={40}
227
+ {...props}
228
+ />
229
+ ```
230
+
231
+ ### Performance Comparison
232
+
233
+ | Data Size | Virtualization | DOM Elements | Render Time | Memory |
234
+ | ----------- | -------------- | ------------ | ----------- | ------ |
235
+ | 10,000 item | ❌ Disabled | 10,000 rows | ~2000ms | ~200MB |
236
+ | 10,000 item | ✅ Enabled | ~20 rows | ~50ms | ~15MB |
237
+
238
+ ### Usage Recommendations
239
+
240
+ - **100+ records:** Auto virtualization
241
+ - **1,000+ records:** Client-side virtualization
242
+ - **10,000+ records:** Hybrid mode (server + client)
243
+ - **100,000+ records:** Pure server pagination
244
+
245
+ ### All CSS Customization Variables
246
+
247
+ ```css
248
+ :root {
249
+ /* Colors */
250
+ --lookup-select-color-primary: #0066cc;
251
+ --lookup-select-color-primary-hover: #0052a3;
252
+ --lookup-select-color-bg: #ffffff;
253
+ --lookup-select-color-text: #333333;
254
+ --lookup-select-color-border: #d1d5db;
255
+
256
+ /* Layout */
257
+ --lookup-select-border-radius: 6px;
258
+ --lookup-select-spacing: 8px;
259
+ --lookup-select-font-size: 14px;
260
+
261
+ /* Component specific sizes */
262
+ --lookup-select-trigger-height: 36px;
263
+ --lookup-select-modal-width: 600px;
264
+ --lookup-select-grid-row-height: 40px;
265
+
266
+ /* Shadows */
267
+ --lookup-select-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
268
+ --lookup-select-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
269
+ }
270
+ ```
271
+
272
+ ## License
273
+
274
+ MIT