@capyx/components-library 0.0.2 → 0.0.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/README.md +250 -225
- package/dist/addons/AutocompleteInput.d.ts +40 -0
- package/dist/addons/AutocompleteInput.d.ts.map +1 -0
- package/dist/addons/AutocompleteInput.js +101 -0
- package/dist/addons/index.d.ts +2 -0
- package/dist/addons/index.d.ts.map +1 -1
- package/dist/addons/index.js +1 -0
- package/dist/components/TextInput.d.ts +33 -54
- package/dist/components/TextInput.d.ts.map +1 -1
- package/dist/components/TextInput.js +36 -136
- package/package.json +87 -87
package/README.md
CHANGED
|
@@ -1,225 +1,250 @@
|
|
|
1
|
-
# Components Library
|
|
2
|
-
|
|
3
|
-
A comprehensive React component library built with TypeScript, React 19, react-hook-form, react-bootstrap, and Material-UI (MUI).
|
|
4
|
-
|
|
5
|
-
## Architecture
|
|
6
|
-
|
|
7
|
-
This library follows a clear separation between **Components** and **Addons**:
|
|
8
|
-
|
|
9
|
-
### Components (Base Input Types)
|
|
10
|
-
|
|
11
|
-
Components are specific input elements based on HTML input types and specialized use cases:
|
|
12
|
-
|
|
13
|
-
- **CheckInput** - Checkbox input for boolean values
|
|
14
|
-
- **DateInput** - Date picker with formatted string output (using MUI DatePicker)
|
|
15
|
-
- **FileInput** - File upload with validation and preview
|
|
16
|
-
- **SelectInput** - Dropdown selection for single/multiple options
|
|
17
|
-
- **SwitchInput** - Toggle switch for on/off values
|
|
18
|
-
- **TagsInput** - Tag management with MUI Autocomplete
|
|
19
|
-
- **TextAreaInput** - Multiline text input with auto-growing height
|
|
20
|
-
- **TextInput** - Single-line text input
|
|
21
|
-
|
|
22
|
-
### Addons (Enhancement Wrappers)
|
|
23
|
-
|
|
24
|
-
Addons wrap existing components to add functionality:
|
|
25
|
-
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- ✅ **
|
|
34
|
-
- ✅ **
|
|
35
|
-
- ✅ **
|
|
36
|
-
- ✅ **react-
|
|
37
|
-
- ✅ **
|
|
38
|
-
- ✅
|
|
39
|
-
- ✅
|
|
40
|
-
- ✅
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
import {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
##
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
1
|
+
# Components Library
|
|
2
|
+
|
|
3
|
+
A comprehensive React component library built with TypeScript, React 19, react-hook-form, react-bootstrap, and Material-UI (MUI).
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
This library follows a clear separation between **Components** and **Addons**:
|
|
8
|
+
|
|
9
|
+
### Components (Base Input Types)
|
|
10
|
+
|
|
11
|
+
Components are specific input elements based on HTML input types and specialized use cases:
|
|
12
|
+
|
|
13
|
+
- **CheckInput** - Checkbox input for boolean values
|
|
14
|
+
- **DateInput** - Date picker with formatted string output (using MUI DatePicker)
|
|
15
|
+
- **FileInput** - File upload with validation and preview
|
|
16
|
+
- **SelectInput** - Dropdown selection for single/multiple options
|
|
17
|
+
- **SwitchInput** - Toggle switch for on/off values
|
|
18
|
+
- **TagsInput** - Tag management with MUI Autocomplete
|
|
19
|
+
- **TextAreaInput** - Multiline text input with auto-growing height
|
|
20
|
+
- **TextInput** - Single-line text input for various types (text, email, password, number, etc.)
|
|
21
|
+
|
|
22
|
+
### Addons (Enhancement Wrappers)
|
|
23
|
+
|
|
24
|
+
Addons wrap existing components to add functionality:
|
|
25
|
+
|
|
26
|
+
- **AutocompleteInput** - Adds autocomplete/suggestions dropdown to text inputs
|
|
27
|
+
- **CharacterCountInput** - Adds character counting to text, textarea, or editor inputs
|
|
28
|
+
- **EditorAddon** - Wraps TextAreaInput to add rich text editing (ReactQuill)
|
|
29
|
+
- **Editor** (Legacy) - Standalone rich text editor (deprecated, use EditorAddon instead)
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- ✅ **React 19** compatible
|
|
34
|
+
- ✅ **TypeScript** with full type safety and auto-generated type declarations
|
|
35
|
+
- ✅ **ESM and CommonJS** dual module support
|
|
36
|
+
- ✅ **react-hook-form** integration for form state management and validation
|
|
37
|
+
- ✅ **react-bootstrap** for consistent styling
|
|
38
|
+
- ✅ **Material-UI (MUI)** for advanced components (DatePicker, Autocomplete)
|
|
39
|
+
- ✅ Standalone or form-integrated modes
|
|
40
|
+
- ✅ Consistent error handling
|
|
41
|
+
- ✅ Customizable styling
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @capyx/components-library
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Peer Dependencies
|
|
50
|
+
|
|
51
|
+
This library requires the following peer dependencies to be installed in your project:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install react react-dom react-hook-form react-bootstrap @mui/material @mui/x-date-pickers dayjs react-quill-new react-autosuggest
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## TypeScript Support
|
|
58
|
+
|
|
59
|
+
This library is written in TypeScript and includes full type definitions. Type declarations are automatically provided when you install the package, giving you:
|
|
60
|
+
|
|
61
|
+
- Full IntelliSense and autocomplete in your IDE
|
|
62
|
+
- Type checking for component props
|
|
63
|
+
- Improved development experience with inline documentation
|
|
64
|
+
|
|
65
|
+
No additional `@types` packages are needed!
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
### Basic Component Usage
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { TextInput, CheckInput, DateInput } from '@your-package/components-library';
|
|
73
|
+
import { FormProvider, useForm } from 'react-hook-form';
|
|
74
|
+
|
|
75
|
+
function MyForm() {
|
|
76
|
+
const methods = useForm();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<FormProvider {...methods}>
|
|
80
|
+
<form>
|
|
81
|
+
<TextInput
|
|
82
|
+
name='username'
|
|
83
|
+
label='Username'
|
|
84
|
+
required
|
|
85
|
+
maxLength={50}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
<CheckInput
|
|
89
|
+
name='terms'
|
|
90
|
+
label='I agree to terms'
|
|
91
|
+
required
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<DateInput
|
|
95
|
+
name='birthdate'
|
|
96
|
+
label='Date of Birth'
|
|
97
|
+
required
|
|
98
|
+
/>
|
|
99
|
+
</form>
|
|
100
|
+
</FormProvider>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Using Addons
|
|
106
|
+
|
|
107
|
+
#### Autocomplete Addon
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { TextInput, AutocompleteInput } from '@your-package/components-library';
|
|
111
|
+
|
|
112
|
+
function MyForm() {
|
|
113
|
+
const countries = ['USA', 'Canada', 'UK', 'Australia'];
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<AutocompleteInput suggestions={countries}>
|
|
117
|
+
<TextInput
|
|
118
|
+
name='country'
|
|
119
|
+
label='Country'
|
|
120
|
+
placeholder='Type to search...'
|
|
121
|
+
/>
|
|
122
|
+
</AutocompleteInput>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Character Count Addon
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { TextInput, CharacterCountInput } from '@your-package/components-library';
|
|
131
|
+
|
|
132
|
+
function MyForm() {
|
|
133
|
+
return (
|
|
134
|
+
<CharacterCountInput>
|
|
135
|
+
<TextInput
|
|
136
|
+
name='bio'
|
|
137
|
+
label='Biography'
|
|
138
|
+
maxLength={200}
|
|
139
|
+
/>
|
|
140
|
+
</CharacterCountInput>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Editor Addon (Rich Text)
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import { EditorAddon } from '@your-package/components-library';
|
|
149
|
+
import { Controller, useFormContext } from 'react-hook-form';
|
|
150
|
+
|
|
151
|
+
function MyForm() {
|
|
152
|
+
const { control } = useFormContext();
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<Controller
|
|
156
|
+
name='content'
|
|
157
|
+
control={control}
|
|
158
|
+
render={({ field }) => (
|
|
159
|
+
<EditorAddon
|
|
160
|
+
value={field.value}
|
|
161
|
+
onChange={field.onChange}
|
|
162
|
+
maxLength={5000}
|
|
163
|
+
/>
|
|
164
|
+
)}
|
|
165
|
+
/>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Combining Addons
|
|
171
|
+
|
|
172
|
+
Addons can be nested to combine their functionality:
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { TextInput, AutocompleteInput, CharacterCountInput } from '@your-package/components-library';
|
|
176
|
+
|
|
177
|
+
function MyForm() {
|
|
178
|
+
const cities = ['New York', 'Los Angeles', 'Chicago', 'Houston'];
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<CharacterCountInput>
|
|
182
|
+
<AutocompleteInput suggestions={cities}>
|
|
183
|
+
<TextInput
|
|
184
|
+
name='city'
|
|
185
|
+
label='City'
|
|
186
|
+
maxLength={50}
|
|
187
|
+
/>
|
|
188
|
+
</AutocompleteInput>
|
|
189
|
+
</CharacterCountInput>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Component API
|
|
195
|
+
|
|
196
|
+
### Common Props
|
|
197
|
+
|
|
198
|
+
All components support these common props when used with react-hook-form:
|
|
199
|
+
|
|
200
|
+
- `name: string` (required) - Field name for form registration
|
|
201
|
+
- `label?: string` - Label text
|
|
202
|
+
- `required?: boolean` - Whether the field is required
|
|
203
|
+
- `disabled?: boolean` - Whether the field is disabled
|
|
204
|
+
|
|
205
|
+
### Standalone Mode
|
|
206
|
+
|
|
207
|
+
All components can be used without react-hook-form by providing `value` and `onChange` props:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
<TextInput
|
|
211
|
+
name='standalone'
|
|
212
|
+
value={value}
|
|
213
|
+
onChange={(newValue) => setValue(newValue)}
|
|
214
|
+
/>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Styling
|
|
218
|
+
|
|
219
|
+
Components use react-bootstrap and MUI components, making them easy to customize:
|
|
220
|
+
|
|
221
|
+
- Override Bootstrap variables for global theming
|
|
222
|
+
- Use MUI theme provider for MUI components
|
|
223
|
+
- Add custom className props (where supported)
|
|
224
|
+
|
|
225
|
+
## TypeScript Support
|
|
226
|
+
|
|
227
|
+
All components are fully typed with TypeScript. Import types as needed:
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import type { TextAreaInputProps, CheckInputProps } from '@your-package/components-library';
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## React 19 Compatibility
|
|
234
|
+
|
|
235
|
+
This library is built and tested with React 19. All components use modern React patterns:
|
|
236
|
+
|
|
237
|
+
- Functional components with hooks
|
|
238
|
+
- No deprecated lifecycle methods
|
|
239
|
+
- No unsafe React APIs
|
|
240
|
+
- Full concurrent mode support
|
|
241
|
+
|
|
242
|
+
## Contributing
|
|
243
|
+
|
|
244
|
+
When adding new components:
|
|
245
|
+
|
|
246
|
+
1. **Components** go in `lib/components/` - base input types
|
|
247
|
+
2. **Addons** go in `lib/addons/` - wrappers that enhance components
|
|
248
|
+
3. All components must support both react-hook-form and standalone modes
|
|
249
|
+
4. Export types alongside components
|
|
250
|
+
5. Update index files for proper exports
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { FC, PropsWithChildren } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the AutocompleteInput component
|
|
4
|
+
*/
|
|
5
|
+
export type AutocompleteInputProps = PropsWithChildren<{
|
|
6
|
+
/** Array of suggestion values for autocomplete */
|
|
7
|
+
suggestions: string[];
|
|
8
|
+
/** Whether to highlight the first suggestion (default: true) */
|
|
9
|
+
highlightFirstSuggestion?: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* AutocompleteInput - A wrapper addon that adds autocomplete/suggestions to text inputs
|
|
13
|
+
*
|
|
14
|
+
* Wraps any text input component (like TextInput) and enhances it with dropdown
|
|
15
|
+
* suggestions that filter based on user input. Works seamlessly with both standalone
|
|
16
|
+
* and react-hook-form integrated inputs.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // With react-hook-form
|
|
21
|
+
* <AutocompleteInput suggestions={["USA", "Canada", "UK"]}>
|
|
22
|
+
* <TextInput
|
|
23
|
+
* name="country"
|
|
24
|
+
* label="Country"
|
|
25
|
+
* placeholder="Type to search..."
|
|
26
|
+
* />
|
|
27
|
+
* </AutocompleteInput>
|
|
28
|
+
*
|
|
29
|
+
* // Standalone mode
|
|
30
|
+
* <AutocompleteInput suggestions={skills}>
|
|
31
|
+
* <TextInput
|
|
32
|
+
* name="skill"
|
|
33
|
+
* value={value}
|
|
34
|
+
* onChange={setValue}
|
|
35
|
+
* />
|
|
36
|
+
* </AutocompleteInput>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const AutocompleteInput: FC<AutocompleteInputProps>;
|
|
40
|
+
//# sourceMappingURL=AutocompleteInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompleteInput.d.ts","sourceRoot":"","sources":["../../lib/addons/AutocompleteInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAgC,MAAM,OAAO,CAAC;AAKjF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;IACtD,kDAAkD;IAClD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gEAAgE;IAChE,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAgHxD,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cloneElement, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import Autosuggest from 'react-autosuggest';
|
|
4
|
+
import { useFormContext } from 'react-hook-form';
|
|
5
|
+
/**
|
|
6
|
+
* AutocompleteInput - A wrapper addon that adds autocomplete/suggestions to text inputs
|
|
7
|
+
*
|
|
8
|
+
* Wraps any text input component (like TextInput) and enhances it with dropdown
|
|
9
|
+
* suggestions that filter based on user input. Works seamlessly with both standalone
|
|
10
|
+
* and react-hook-form integrated inputs.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // With react-hook-form
|
|
15
|
+
* <AutocompleteInput suggestions={["USA", "Canada", "UK"]}>
|
|
16
|
+
* <TextInput
|
|
17
|
+
* name="country"
|
|
18
|
+
* label="Country"
|
|
19
|
+
* placeholder="Type to search..."
|
|
20
|
+
* />
|
|
21
|
+
* </AutocompleteInput>
|
|
22
|
+
*
|
|
23
|
+
* // Standalone mode
|
|
24
|
+
* <AutocompleteInput suggestions={skills}>
|
|
25
|
+
* <TextInput
|
|
26
|
+
* name="skill"
|
|
27
|
+
* value={value}
|
|
28
|
+
* onChange={setValue}
|
|
29
|
+
* />
|
|
30
|
+
* </AutocompleteInput>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const AutocompleteInput = ({ suggestions: allSuggestions, children, highlightFirstSuggestion = true, }) => {
|
|
34
|
+
const formContext = useFormContext();
|
|
35
|
+
const [filteredSuggestions, setFilteredSuggestions] = useState([]);
|
|
36
|
+
const [inputValue, setInputValue] = useState('');
|
|
37
|
+
const nameRef = useRef('');
|
|
38
|
+
// Extract child props
|
|
39
|
+
const childElement = children;
|
|
40
|
+
const childProps = childElement?.props;
|
|
41
|
+
const name = childProps?.name || '';
|
|
42
|
+
nameRef.current = name;
|
|
43
|
+
// Sync input value with form context or child value
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (formContext && name) {
|
|
46
|
+
const formValue = formContext.getValues(name);
|
|
47
|
+
setInputValue(formValue || '');
|
|
48
|
+
}
|
|
49
|
+
else if (childProps?.value !== undefined) {
|
|
50
|
+
setInputValue(String(childProps.value));
|
|
51
|
+
}
|
|
52
|
+
}, [formContext, name, childProps?.value]);
|
|
53
|
+
// Filter suggestions based on input value
|
|
54
|
+
const getSuggestions = (value) => {
|
|
55
|
+
const trimmedValue = value.trim().toLowerCase();
|
|
56
|
+
if (trimmedValue.length === 0)
|
|
57
|
+
return [];
|
|
58
|
+
return allSuggestions.filter((suggestion) => suggestion.toLowerCase().includes(trimmedValue));
|
|
59
|
+
};
|
|
60
|
+
const onSuggestionsFetchRequested = ({ value }) => {
|
|
61
|
+
setFilteredSuggestions(getSuggestions(value));
|
|
62
|
+
};
|
|
63
|
+
const onSuggestionsClearRequested = () => {
|
|
64
|
+
setFilteredSuggestions([]);
|
|
65
|
+
};
|
|
66
|
+
const getSuggestionValue = (suggestion) => suggestion;
|
|
67
|
+
const renderSuggestion = (suggestion) => _jsx("span", { children: suggestion });
|
|
68
|
+
const handleChange = (_event, { newValue }) => {
|
|
69
|
+
setInputValue(newValue);
|
|
70
|
+
// Update form context if available
|
|
71
|
+
if (formContext && name) {
|
|
72
|
+
formContext.setValue(name, newValue);
|
|
73
|
+
}
|
|
74
|
+
// Call child's onChange if provided
|
|
75
|
+
childProps?.onChange?.(newValue);
|
|
76
|
+
};
|
|
77
|
+
return (_jsx(Autosuggest, { suggestions: filteredSuggestions, onSuggestionsFetchRequested: onSuggestionsFetchRequested, onSuggestionsClearRequested: onSuggestionsClearRequested, getSuggestionValue: getSuggestionValue, renderSuggestion: renderSuggestion, highlightFirstSuggestion: highlightFirstSuggestion, inputProps: {
|
|
78
|
+
value: inputValue,
|
|
79
|
+
onChange: handleChange,
|
|
80
|
+
}, renderInputComponent: (inputProps) => {
|
|
81
|
+
// Clone the child element and merge with autosuggest props
|
|
82
|
+
const { value, onChange: autosuggestOnChange, ...autosuggestProps } = inputProps;
|
|
83
|
+
return cloneElement(childElement, {
|
|
84
|
+
...autosuggestProps,
|
|
85
|
+
value,
|
|
86
|
+
onChange: (newValue) => {
|
|
87
|
+
// Handle both event objects and direct values
|
|
88
|
+
const actualValue = typeof newValue === 'string'
|
|
89
|
+
? newValue
|
|
90
|
+
: newValue?.target
|
|
91
|
+
?.value || '';
|
|
92
|
+
// Create synthetic event for Autosuggest
|
|
93
|
+
const syntheticEvent = {};
|
|
94
|
+
autosuggestOnChange?.(syntheticEvent, {
|
|
95
|
+
newValue: actualValue,
|
|
96
|
+
method: 'type',
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
} }));
|
|
101
|
+
};
|
package/dist/addons/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export type { AutocompleteInputProps } from './AutocompleteInput';
|
|
2
|
+
export { AutocompleteInput } from './AutocompleteInput';
|
|
1
3
|
export type { CharacterCountInputProps } from './CharacterCountInput';
|
|
2
4
|
export { CharacterCountInput } from './CharacterCountInput';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/addons/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/addons/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/addons/index.js
CHANGED
|
@@ -1,64 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { FC } from 'react';
|
|
2
2
|
/**
|
|
3
3
|
* Props for the TextInput component
|
|
4
4
|
*/
|
|
5
5
|
export type TextInputProps = {
|
|
6
6
|
/** The name of the text input field */
|
|
7
|
-
name
|
|
7
|
+
name: string;
|
|
8
8
|
/** Label text displayed for the input */
|
|
9
9
|
label?: string;
|
|
10
10
|
/** HTML input type (default: "text") */
|
|
11
11
|
type?: string;
|
|
12
|
-
/** Minimum value for number/date inputs */
|
|
13
|
-
min?: string | number;
|
|
14
|
-
/** Maximum value for number/date inputs */
|
|
15
|
-
max?: string | number;
|
|
16
|
-
/** Whether the field is required */
|
|
17
|
-
required?: boolean;
|
|
18
|
-
/** Maximum number of characters allowed */
|
|
19
|
-
maxLength?: number;
|
|
20
|
-
/** Size variant of the input control */
|
|
21
|
-
controlSize?: 'sm' | 'lg' | undefined;
|
|
22
12
|
/** Placeholder text shown when input is empty */
|
|
23
13
|
placeholder?: string;
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
/** Callback
|
|
29
|
-
|
|
14
|
+
/** Size of the input control */
|
|
15
|
+
size?: 'sm' | 'lg';
|
|
16
|
+
/** Current input value (standalone mode) */
|
|
17
|
+
value?: string | number;
|
|
18
|
+
/** Callback function called when the input value changes */
|
|
19
|
+
onChange?: (value: string) => void;
|
|
20
|
+
/** Callback function called when the input loses focus */
|
|
21
|
+
onBlur?: () => void;
|
|
22
|
+
/** Whether the field is required */
|
|
23
|
+
required?: boolean;
|
|
30
24
|
/** Whether the input is disabled */
|
|
31
25
|
disabled?: boolean;
|
|
32
26
|
/** Whether the input is read-only */
|
|
33
|
-
|
|
27
|
+
readOnly?: boolean;
|
|
34
28
|
/** Whether to render as plain text */
|
|
35
|
-
|
|
29
|
+
plainText?: boolean;
|
|
30
|
+
/** Minimum value for number inputs */
|
|
31
|
+
min?: string | number;
|
|
32
|
+
/** Maximum value for number inputs */
|
|
33
|
+
max?: string | number;
|
|
34
|
+
/** Maximum number of characters allowed */
|
|
35
|
+
maxLength?: number;
|
|
36
36
|
/** Regex pattern for validation */
|
|
37
37
|
pattern?: string;
|
|
38
|
-
/** Icon element to display in the input group */
|
|
39
|
-
icon?: ReactElement | null;
|
|
40
|
-
/** Enable autocomplete/suggestions functionality */
|
|
41
|
-
shouldAutoComplete?: boolean;
|
|
42
|
-
/** Array of suggestion values for autocomplete */
|
|
43
|
-
values?: string[];
|
|
44
|
-
/** Debounce delay in milliseconds for value changes */
|
|
45
|
-
debounceMs?: number;
|
|
46
38
|
};
|
|
47
39
|
/**
|
|
48
|
-
* A
|
|
49
|
-
* autocomplete suggestions, debouncing, and various input types.
|
|
40
|
+
* TextInput - A text input component with react-hook-form integration
|
|
50
41
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* - Debounced value updates to reduce callback frequency
|
|
55
|
-
* - Support for various input types (text, number, email, tel, etc.)
|
|
56
|
-
* - Built-in validation rules (required, min, max, maxLength, pattern)
|
|
57
|
-
* - Icon support for enhanced UI
|
|
58
|
-
* - Automatic phone number formatting for tel type
|
|
42
|
+
* Provides a text input that works both standalone and with react-hook-form.
|
|
43
|
+
* Supports various input types (text, number, email, tel, password, etc.) and
|
|
44
|
+
* automatic validation.
|
|
59
45
|
*
|
|
60
46
|
* @example
|
|
61
|
-
*
|
|
47
|
+
* ```tsx
|
|
48
|
+
* // With react-hook-form
|
|
62
49
|
* <TextInput
|
|
63
50
|
* name="email"
|
|
64
51
|
* label="Email Address"
|
|
@@ -67,23 +54,15 @@ export type TextInputProps = {
|
|
|
67
54
|
* placeholder="Enter your email"
|
|
68
55
|
* />
|
|
69
56
|
*
|
|
70
|
-
*
|
|
71
|
-
* // With autocomplete suggestions
|
|
72
|
-
* <TextInput
|
|
73
|
-
* name="country"
|
|
74
|
-
* label="Country"
|
|
75
|
-
* shouldAutoComplete
|
|
76
|
-
* values={["USA", "Canada", "Mexico"]}
|
|
77
|
-
* />
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* // With debouncing and custom callbacks
|
|
57
|
+
* // Standalone mode
|
|
81
58
|
* <TextInput
|
|
82
|
-
* name="
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
59
|
+
* name="username"
|
|
60
|
+
* label="Username"
|
|
61
|
+
* value={username}
|
|
62
|
+
* onChange={setUsername}
|
|
63
|
+
* maxLength={50}
|
|
86
64
|
* />
|
|
65
|
+
* ```
|
|
87
66
|
*/
|
|
88
67
|
export declare const TextInput: FC<TextInputProps>;
|
|
89
68
|
//# sourceMappingURL=TextInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../lib/components/TextInput.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../lib/components/TextInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,EAAE,EAAE,MAAM,OAAO,CAAC;AAI7C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA6GxC,CAAC"}
|
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import
|
|
3
|
-
import { useEffect, useRef, useState, } from 'react';
|
|
4
|
-
import Autosuggest from 'react-autosuggest';
|
|
5
|
-
import { Form, InputGroup } from 'react-bootstrap';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Form } from 'react-bootstrap';
|
|
6
3
|
import { Controller, useFormContext } from 'react-hook-form';
|
|
7
|
-
const formatSpaces = (value) => value.replace(/(?<=[A-Z])(?![0-9]+)(?=[A-Z][a-z])|(?<=[^A-Z])(?![0-9]+)(?=[A-Z])|(?<=[A-Za-z])(?![0-9]+)(?=[^A-Za-z])/g, ' ');
|
|
8
4
|
/**
|
|
9
|
-
* A
|
|
10
|
-
* autocomplete suggestions, debouncing, and various input types.
|
|
5
|
+
* TextInput - A text input component with react-hook-form integration
|
|
11
6
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* - Debounced value updates to reduce callback frequency
|
|
16
|
-
* - Support for various input types (text, number, email, tel, etc.)
|
|
17
|
-
* - Built-in validation rules (required, min, max, maxLength, pattern)
|
|
18
|
-
* - Icon support for enhanced UI
|
|
19
|
-
* - Automatic phone number formatting for tel type
|
|
7
|
+
* Provides a text input that works both standalone and with react-hook-form.
|
|
8
|
+
* Supports various input types (text, number, email, tel, password, etc.) and
|
|
9
|
+
* automatic validation.
|
|
20
10
|
*
|
|
21
11
|
* @example
|
|
22
|
-
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* // With react-hook-form
|
|
23
14
|
* <TextInput
|
|
24
15
|
* name="email"
|
|
25
16
|
* label="Email Address"
|
|
@@ -28,107 +19,34 @@ const formatSpaces = (value) => value.replace(/(?<=[A-Z])(?![0-9]+)(?=[A-Z][a-z]
|
|
|
28
19
|
* placeholder="Enter your email"
|
|
29
20
|
* />
|
|
30
21
|
*
|
|
31
|
-
*
|
|
32
|
-
* // With autocomplete suggestions
|
|
33
|
-
* <TextInput
|
|
34
|
-
* name="country"
|
|
35
|
-
* label="Country"
|
|
36
|
-
* shouldAutoComplete
|
|
37
|
-
* values={["USA", "Canada", "Mexico"]}
|
|
38
|
-
* />
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* // With debouncing and custom callbacks
|
|
22
|
+
* // Standalone mode
|
|
42
23
|
* <TextInput
|
|
43
|
-
* name="
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
24
|
+
* name="username"
|
|
25
|
+
* label="Username"
|
|
26
|
+
* value={username}
|
|
27
|
+
* onChange={setUsername}
|
|
28
|
+
* maxLength={50}
|
|
47
29
|
* />
|
|
30
|
+
* ```
|
|
48
31
|
*/
|
|
49
|
-
export const TextInput = ({ name, label, type = 'text',
|
|
32
|
+
export const TextInput = ({ name, label, type = 'text', placeholder, size, value, onChange, onBlur, required = false, disabled = false, readOnly = false, plainText = false, min, max, maxLength, pattern, }) => {
|
|
50
33
|
const formContext = useFormContext();
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (debounceMs && setFieldValue) {
|
|
57
|
-
debouncedSetFieldValueRef.current = debounce(setFieldValue, debounceMs);
|
|
58
|
-
}
|
|
59
|
-
if (debounceMs && saveFieldvalue) {
|
|
60
|
-
debouncedSaveFieldValueRef.current = debounce(saveFieldvalue, debounceMs);
|
|
34
|
+
// Helper to safely get nested error
|
|
35
|
+
const getFieldError = (fieldName) => {
|
|
36
|
+
try {
|
|
37
|
+
const error = formContext?.formState?.errors?.[fieldName];
|
|
38
|
+
return error?.message;
|
|
61
39
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
debouncedSetFieldValueRef.current?.cancel();
|
|
65
|
-
debouncedSaveFieldValueRef.current?.cancel();
|
|
66
|
-
};
|
|
67
|
-
}, [debounceMs, setFieldValue, saveFieldvalue]);
|
|
68
|
-
const fieldError = formContext && name ? formContext.formState.errors[name] : null;
|
|
69
|
-
const isInvalid = !!fieldError;
|
|
70
|
-
const [suggestions, setSuggestions] = useState([]);
|
|
71
|
-
const getSuggestions = (value) => {
|
|
72
|
-
const inputValue = value.trim().toLowerCase();
|
|
73
|
-
const inputLength = inputValue.length;
|
|
74
|
-
return inputLength === 0
|
|
75
|
-
? []
|
|
76
|
-
: values.filter((v) => v.trim().toLowerCase().indexOf(inputValue) > -1);
|
|
77
|
-
};
|
|
78
|
-
const onChange = (_event, { newValue }) => {
|
|
79
|
-
if (debounceMs) {
|
|
80
|
-
if (debouncedSetFieldValueRef.current)
|
|
81
|
-
debouncedSetFieldValueRef.current(newValue);
|
|
82
|
-
if (debouncedSaveFieldValueRef.current)
|
|
83
|
-
debouncedSaveFieldValueRef.current(newValue);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
if (setFieldValue)
|
|
87
|
-
setFieldValue(newValue);
|
|
88
|
-
if (saveFieldvalue)
|
|
89
|
-
saveFieldvalue(newValue);
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
90
42
|
}
|
|
91
43
|
};
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const isPasted = nativeEvent.inputType?.startsWith('insertFromPaste');
|
|
96
|
-
if (isPasted) {
|
|
97
|
-
const pasted = event.currentTarget.value;
|
|
98
|
-
const formatted = pasted.replace(/[./]/g, ' ');
|
|
99
|
-
event.currentTarget.value = formatted;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (setFieldValue)
|
|
103
|
-
setFieldValue(event.currentTarget.value);
|
|
104
|
-
if (saveFieldvalue)
|
|
105
|
-
saveFieldvalue(event.currentTarget.value);
|
|
44
|
+
const errorMessage = getFieldError(name);
|
|
45
|
+
const handleTextChange = (event) => {
|
|
46
|
+
onChange?.(event.currentTarget.value);
|
|
106
47
|
};
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
processedFieldValue = formatSpaces(fieldValue);
|
|
110
|
-
}
|
|
111
|
-
if (formContext && name) {
|
|
112
|
-
// With react-hook-form Controller
|
|
113
|
-
if (shouldAutoComplete && values?.length > 0) {
|
|
114
|
-
return (_jsx(Autosuggest, { suggestions: suggestions, onSuggestionsFetchRequested: ({ value }) => {
|
|
115
|
-
const newSuggestions = getSuggestions(value);
|
|
116
|
-
setSuggestions(newSuggestions);
|
|
117
|
-
}, onSuggestionsClearRequested: () => setSuggestions([]), getSuggestionValue: (item) => item, renderSuggestion: (suggestion) => (_jsx("span", { children: suggestion }, suggestion)), highlightFirstSuggestion: true, inputProps: {
|
|
118
|
-
value: String(processedFieldValue || ''),
|
|
119
|
-
onChange: (_event, { newValue }) => {
|
|
120
|
-
if (formContext && name) {
|
|
121
|
-
formContext.setValue(name, newValue);
|
|
122
|
-
}
|
|
123
|
-
if (setFieldValue)
|
|
124
|
-
setFieldValue(newValue);
|
|
125
|
-
if (saveFieldvalue)
|
|
126
|
-
saveFieldvalue(newValue);
|
|
127
|
-
},
|
|
128
|
-
}, renderInputComponent: ({ value, onChange, ...props }) => (_jsxs(InputGroup, { children: [icon && _jsx(InputGroup.Text, { children: icon }), _jsx(Form.Control, { type: type,
|
|
129
|
-
// biome-ignore lint/suspicious/noExplicitAny: Type mismatch between Props and Form.Control - controlSize needs type assertion
|
|
130
|
-
size: controlSize, min: min ?? undefined, max: max ?? undefined, required: required ?? false, maxLength: maxLength ?? undefined, placeholder: placeholder ?? undefined, value: value, onChange: onChange, disabled: disabled, readOnly: isReadOnly, plaintext: isPlainText, pattern: pattern, isInvalid: isInvalid, ...props })] })) }));
|
|
131
|
-
}
|
|
48
|
+
// Integrated with react-hook-form
|
|
49
|
+
if (formContext) {
|
|
132
50
|
return (_jsx(Controller, { name: name, control: formContext.control, rules: {
|
|
133
51
|
required: required ? `${label || 'This field'} is required` : false,
|
|
134
52
|
maxLength: maxLength
|
|
@@ -146,32 +64,14 @@ export const TextInput = ({ name, label, type = 'text', min, max, required, maxL
|
|
|
146
64
|
pattern: pattern
|
|
147
65
|
? { value: new RegExp(pattern), message: 'Invalid format' }
|
|
148
66
|
: undefined,
|
|
149
|
-
}, render: ({ field
|
|
150
|
-
// biome-ignore lint/suspicious/noExplicitAny: Type mismatch between Props and Form.Control - controlSize needs type assertion
|
|
151
|
-
size: controlSize, min: min ?? undefined, max: max ?? undefined, required: required ?? false, maxLength: maxLength ?? undefined, placeholder: placeholder ?? undefined, onChange: (e) => {
|
|
67
|
+
}, render: ({ field }) => (_jsx(Form.Control, { ...field, value: field.value ?? '', type: type, size: size, min: min, max: max, required: required, maxLength: maxLength, placeholder: placeholder, onChange: (e) => {
|
|
152
68
|
field.onChange(e);
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}, disabled: disabled, readOnly:
|
|
158
|
-
}
|
|
159
|
-
// Without react-hook-form (fallback)
|
|
160
|
-
if (shouldAutoComplete && values?.length > 0) {
|
|
161
|
-
return (_jsx(Autosuggest, { suggestions: suggestions, onSuggestionsFetchRequested: ({ value }) => {
|
|
162
|
-
const newSuggestions = getSuggestions(value);
|
|
163
|
-
setSuggestions(newSuggestions);
|
|
164
|
-
}, onSuggestionsClearRequested: () => setSuggestions([]), getSuggestionValue: (item) => item, renderSuggestion: (suggestion) => (_jsx("span", { children: suggestion }, suggestion)), highlightFirstSuggestion: true, inputProps: {
|
|
165
|
-
value: String(processedFieldValue || ''),
|
|
166
|
-
onChange,
|
|
167
|
-
}, renderInputComponent: (inputProps) => {
|
|
168
|
-
const { value, onChange, ...props } = inputProps;
|
|
169
|
-
return (_jsxs(InputGroup, { children: [icon && _jsx(InputGroup.Text, { children: icon }), _jsx(Form.Control, { type: type,
|
|
170
|
-
// biome-ignore lint/suspicious/noExplicitAny: Type mismatch between Props and Form.Control - controlSize needs type assertion
|
|
171
|
-
size: controlSize, min: min ?? undefined, max: max ?? undefined, required: required ?? false, maxLength: maxLength ?? undefined, placeholder: placeholder ?? undefined, value: String(value || ''), onChange: onChange, disabled: disabled, readOnly: isReadOnly, plaintext: isPlainText, pattern: pattern, ...props })] }));
|
|
172
|
-
} }));
|
|
69
|
+
onChange?.(e.target.value);
|
|
70
|
+
}, onBlur: () => {
|
|
71
|
+
field.onBlur();
|
|
72
|
+
onBlur?.();
|
|
73
|
+
}, disabled: disabled, readOnly: readOnly, plaintext: plainText, pattern: pattern, isInvalid: !!errorMessage })) }));
|
|
173
74
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
size: controlSize, min: min ?? undefined, max: max ?? undefined, required: required ?? false, maxLength: maxLength ?? undefined, placeholder: placeholder ?? undefined, onChange: defaultOnChange, value: processedFieldValue, disabled: disabled, readOnly: isReadOnly, plaintext: isPlainText, pattern: pattern }));
|
|
75
|
+
// Standalone mode (no form context)
|
|
76
|
+
return (_jsx(Form.Control, { type: type, size: size, min: min, max: max, required: required, maxLength: maxLength, placeholder: placeholder, value: value ?? '', onChange: handleTextChange, onBlur: onBlur, disabled: disabled, readOnly: readOnly, plaintext: plainText, pattern: pattern }));
|
|
177
77
|
};
|
package/package.json
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@capyx/components-library",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Capyx Components Library for forms across applications",
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
8
|
-
"keywords": [
|
|
9
|
-
"components",
|
|
10
|
-
"library",
|
|
11
|
-
"typescript"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://gitlab.com/capyx/rmt/components-library#readme",
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://gitlab.com/capyx/rmt/components-library/issues"
|
|
16
|
-
},
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+ssh://git@gitlab.com/capyx/rmt/components-library.git"
|
|
20
|
-
},
|
|
21
|
-
"author": "tinael.devresse@capyx.be",
|
|
22
|
-
"type": "module",
|
|
23
|
-
"main": "./dist/index.js",
|
|
24
|
-
"types": "./dist/index.d.ts",
|
|
25
|
-
"exports": {
|
|
26
|
-
".": {
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
28
|
-
"import": "./dist/index.js",
|
|
29
|
-
"require": "./dist/index.cjs"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"files": [
|
|
33
|
-
"dist",
|
|
34
|
-
"README.md"
|
|
35
|
-
],
|
|
36
|
-
"directories": {
|
|
37
|
-
"lib": "lib"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"build": "tsc && npm run build:cjs",
|
|
41
|
-
"build:cjs": "tsc --module commonjs --outDir dist-cjs && node scripts/rename-cjs.js",
|
|
42
|
-
"prepublishOnly": "npm run build",
|
|
43
|
-
"lint": "biome lint .",
|
|
44
|
-
"lint:fix": "biome lint --write .",
|
|
45
|
-
"format": "biome format .",
|
|
46
|
-
"format:fix": "biome format --write .",
|
|
47
|
-
"check": "biome check .",
|
|
48
|
-
"check:fix": "biome check --write .",
|
|
49
|
-
"storybook": "storybook dev -p 6006",
|
|
50
|
-
"build-storybook": "storybook build"
|
|
51
|
-
},
|
|
52
|
-
"devDependencies": {
|
|
53
|
-
"@biomejs/biome": "^2.3.11",
|
|
54
|
-
"@chromatic-com/storybook": "^5.0.0",
|
|
55
|
-
"@storybook/addon-a11y": "^10.1.11",
|
|
56
|
-
"@storybook/addon-docs": "^10.1.11",
|
|
57
|
-
"@storybook/addon-onboarding": "^10.1.11",
|
|
58
|
-
"@storybook/addon-vitest": "^10.1.11",
|
|
59
|
-
"@storybook/react-vite": "^10.1.11",
|
|
60
|
-
"@types/dateformat": "^5.0.3",
|
|
61
|
-
"@types/lodash.debounce": "^4.0.9",
|
|
62
|
-
"@types/node": "^25.0.9",
|
|
63
|
-
"@types/react": "^19.2.8",
|
|
64
|
-
"@types/react-autosuggest": "^10.1.11",
|
|
65
|
-
"@types/react-datepicker": "^7.0.0",
|
|
66
|
-
"@vitest/browser-playwright": "^4.0.17",
|
|
67
|
-
"@vitest/coverage-v8": "^4.0.17",
|
|
68
|
-
"playwright": "^1.57.0",
|
|
69
|
-
"storybook": "^10.1.11",
|
|
70
|
-
"typescript": "^5.9.3",
|
|
71
|
-
"vitest": "^4.0.17"
|
|
72
|
-
},
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"@emotion/styled": "^11.14.1",
|
|
75
|
-
"@mui/material": "^7.3.7",
|
|
76
|
-
"@mui/x-date-pickers": "^8.25.0",
|
|
77
|
-
"bootstrap": "^5.3.8",
|
|
78
|
-
"dateformat": "^5.0.3",
|
|
79
|
-
"dayjs": "^1.11.19",
|
|
80
|
-
"lodash.debounce": "^4.0.8",
|
|
81
|
-
"react": "^19.2.3",
|
|
82
|
-
"react-autosuggest": "^10.1.0",
|
|
83
|
-
"react-bootstrap": "^2.10.10",
|
|
84
|
-
"react-hook-form": "^7.71.1",
|
|
85
|
-
"react-quill-new": "^3.7.0"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@capyx/components-library",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Capyx Components Library for forms across applications",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"components",
|
|
10
|
+
"library",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://gitlab.com/capyx/rmt/components-library#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://gitlab.com/capyx/rmt/components-library/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+ssh://git@gitlab.com/capyx/rmt/components-library.git"
|
|
20
|
+
},
|
|
21
|
+
"author": "tinael.devresse@capyx.be",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"directories": {
|
|
37
|
+
"lib": "lib"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc && npm run build:cjs",
|
|
41
|
+
"build:cjs": "tsc --module commonjs --outDir dist-cjs && node scripts/rename-cjs.js",
|
|
42
|
+
"prepublishOnly": "npm run build",
|
|
43
|
+
"lint": "biome lint .",
|
|
44
|
+
"lint:fix": "biome lint --write .",
|
|
45
|
+
"format": "biome format .",
|
|
46
|
+
"format:fix": "biome format --write .",
|
|
47
|
+
"check": "biome check .",
|
|
48
|
+
"check:fix": "biome check --write .",
|
|
49
|
+
"storybook": "storybook dev -p 6006",
|
|
50
|
+
"build-storybook": "storybook build"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@biomejs/biome": "^2.3.11",
|
|
54
|
+
"@chromatic-com/storybook": "^5.0.0",
|
|
55
|
+
"@storybook/addon-a11y": "^10.1.11",
|
|
56
|
+
"@storybook/addon-docs": "^10.1.11",
|
|
57
|
+
"@storybook/addon-onboarding": "^10.1.11",
|
|
58
|
+
"@storybook/addon-vitest": "^10.1.11",
|
|
59
|
+
"@storybook/react-vite": "^10.1.11",
|
|
60
|
+
"@types/dateformat": "^5.0.3",
|
|
61
|
+
"@types/lodash.debounce": "^4.0.9",
|
|
62
|
+
"@types/node": "^25.0.9",
|
|
63
|
+
"@types/react": "^19.2.8",
|
|
64
|
+
"@types/react-autosuggest": "^10.1.11",
|
|
65
|
+
"@types/react-datepicker": "^7.0.0",
|
|
66
|
+
"@vitest/browser-playwright": "^4.0.17",
|
|
67
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
68
|
+
"playwright": "^1.57.0",
|
|
69
|
+
"storybook": "^10.1.11",
|
|
70
|
+
"typescript": "^5.9.3",
|
|
71
|
+
"vitest": "^4.0.17"
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@emotion/styled": "^11.14.1",
|
|
75
|
+
"@mui/material": "^7.3.7",
|
|
76
|
+
"@mui/x-date-pickers": "^8.25.0",
|
|
77
|
+
"bootstrap": "^5.3.8",
|
|
78
|
+
"dateformat": "^5.0.3",
|
|
79
|
+
"dayjs": "^1.11.19",
|
|
80
|
+
"lodash.debounce": "^4.0.8",
|
|
81
|
+
"react": "^19.2.3",
|
|
82
|
+
"react-autosuggest": "^10.1.0",
|
|
83
|
+
"react-bootstrap": "^2.10.10",
|
|
84
|
+
"react-hook-form": "^7.71.1",
|
|
85
|
+
"react-quill-new": "^3.7.0"
|
|
86
|
+
}
|
|
87
|
+
}
|