@fvc/input 3.0.1 → 3.0.2-next-ec65dfb844e6183b3d7f417eee613cfe5ecfd997

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.
Files changed (2) hide show
  1. package/README.md +432 -0
  2. package/package.json +14 -4
package/README.md ADDED
@@ -0,0 +1,432 @@
1
+ # @fvc/input
2
+
3
+ `@fvc/input` provides FE-VIS styled input primitives on top of Ant Design. It keeps the Ant Design input API familiar while adding the design-system behavior used across FE-VIS applications: labels, required markers, error messaging, custom clear icons, prefix/suffix handling, value transforms, and masked input support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @fvc/input
9
+ ```
10
+
11
+ ## Peer Dependencies
12
+
13
+ The package expects these dependencies to be available in the consuming application:
14
+
15
+ ```bash
16
+ bun add react antd antd-mask-input @fvc/icons @fvc/utils
17
+ ```
18
+
19
+ ## Import
20
+
21
+ ```tsx
22
+ import { Input } from '@fvc/input';
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```tsx
28
+ import { useState } from 'react';
29
+ import { Input } from '@fvc/input';
30
+
31
+ export function AccountForm() {
32
+ const [username, setUsername] = useState('');
33
+
34
+ return (
35
+ <Input
36
+ name="username"
37
+ label="Username"
38
+ placeholder="Enter username"
39
+ value={username}
40
+ onChange={(event) => setUsername(event.target.value)}
41
+ />
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## Components
47
+
48
+ | Component | Use case |
49
+ | --- | --- |
50
+ | `Input` | Standard text, number, email, telephone, or URL input. |
51
+ | `Input.Textarea` | Multi-line text entry. |
52
+ | `Input.Search` | Search input with optional Ant Design search button behavior. |
53
+ | `Input.Password` | Password input with Ant Design visibility toggle behavior. |
54
+ | `Input.Masked` | Masked input powered by `antd-mask-input`. |
55
+
56
+ All variants share the FE-VIS input styling and support the common props where applicable.
57
+
58
+ ## Common Usage
59
+
60
+ ### Label and Required Marker
61
+
62
+ Use `label` to render the FE-VIS label above the field. Add `withAsterisk` when the field is required.
63
+
64
+ ```tsx
65
+ <Input
66
+ name="email"
67
+ label="Email"
68
+ withAsterisk
69
+ placeholder="name@example.com"
70
+ />
71
+ ```
72
+
73
+ ### Error State
74
+
75
+ `error` can be a string or a boolean.
76
+
77
+ | Value | Behavior |
78
+ | --- | --- |
79
+ | `string` | Applies error styling and renders the message below the field. |
80
+ | `true` | Applies error styling without rendering a message. |
81
+ | `false` or `undefined` | Uses the default state. |
82
+
83
+ ```tsx
84
+ <Input
85
+ name="email"
86
+ label="Email"
87
+ error="Invalid email address"
88
+ placeholder="name@example.com"
89
+ />
90
+ ```
91
+
92
+ ### Controlled and Uncontrolled Inputs
93
+
94
+ Use `value` and `onChange` for controlled fields:
95
+
96
+ ```tsx
97
+ <Input
98
+ name="tin"
99
+ label="TIN"
100
+ value={tin}
101
+ onChange={(event) => setTin(event.target.value)}
102
+ />
103
+ ```
104
+
105
+ Use `defaultValue` when the field does not need to be controlled by React state:
106
+
107
+ ```tsx
108
+ <Input
109
+ name="country"
110
+ label="Country"
111
+ defaultValue="Azerbaijan"
112
+ />
113
+ ```
114
+
115
+ ### Prefix and Suffix
116
+
117
+ Use `prefix` and `suffix` for compact adornments such as currency, units, or static hints.
118
+
119
+ ```tsx
120
+ <Input
121
+ name="price"
122
+ label="Price"
123
+ prefix="$"
124
+ suffix="USD"
125
+ placeholder="Enter amount"
126
+ />
127
+ ```
128
+
129
+ `suffixType` controls suffix positioning.
130
+
131
+ | `suffixType` | Behavior |
132
+ | --- | --- |
133
+ | `fixed` | Renders the suffix as a standard input suffix. |
134
+ | `sticky` | Keeps the suffix visually aligned with the typed value. |
135
+
136
+ ```tsx
137
+ <Input
138
+ name="weight"
139
+ label="Weight"
140
+ suffix="kg"
141
+ suffixType="sticky"
142
+ value="100"
143
+ />
144
+ ```
145
+
146
+ ### Text Transforms
147
+
148
+ `textTransform` transforms the entered value before the component stores it internally and before `onChange` receives the event.
149
+
150
+ | Transform | Result |
151
+ | --- | --- |
152
+ | `uppercase` | Converts text to uppercase. |
153
+ | `lowercase` | Converts text to lowercase. |
154
+ | `capitalize` | Capitalizes each word. |
155
+ | `integer` | Keeps digits only. |
156
+
157
+ ```tsx
158
+ <Input
159
+ name="code"
160
+ label="Code"
161
+ textTransform="uppercase"
162
+ placeholder="Enter code"
163
+ />
164
+ ```
165
+
166
+ ### Number Input Without Native Controls
167
+
168
+ Set `controls={false}` to hide native number spinner controls.
169
+
170
+ ```tsx
171
+ <Input
172
+ name="amount"
173
+ label="Amount"
174
+ type="number"
175
+ controls={false}
176
+ placeholder="Enter amount"
177
+ />
178
+ ```
179
+
180
+ ### Clear Button
181
+
182
+ `allowClear` enables the FE-VIS clear icon.
183
+
184
+ ```tsx
185
+ <Input
186
+ name="search"
187
+ label="Search"
188
+ allowClear
189
+ placeholder="Search..."
190
+ />
191
+ ```
192
+
193
+ ## Subcomponents
194
+
195
+ ### Textarea
196
+
197
+ ```tsx
198
+ <Input.Textarea
199
+ name="description"
200
+ label="Description"
201
+ placeholder="Enter description"
202
+ />
203
+ ```
204
+
205
+ `Input.Textarea` does not accept `suffix`, `suffixType`, or `controls`.
206
+
207
+ ### Search
208
+
209
+ ```tsx
210
+ <Input.Search
211
+ placeholder="Search records"
212
+ enterButton="Search"
213
+ />
214
+ ```
215
+
216
+ ### Password
217
+
218
+ ```tsx
219
+ <Input.Password placeholder="Enter password" />
220
+ ```
221
+
222
+ ### Masked
223
+
224
+ ```tsx
225
+ <Input.Masked
226
+ name="phone"
227
+ label="Phone number"
228
+ mask="(999) 999-9999"
229
+ placeholder="Enter phone number"
230
+ />
231
+ ```
232
+
233
+ ## Props
234
+
235
+ The base `Input` accepts Ant Design input props plus the FE-VIS additions below.
236
+
237
+ | Prop | Type | Description |
238
+ | --- | --- | --- |
239
+ | `label` | `ReactNode` | Renders a label above the field. |
240
+ | `withAsterisk` | `boolean` | Shows a required marker next to the label. |
241
+ | `error` | `string \| boolean` | Applies error styling and optionally renders an error message. |
242
+ | `suffixType` | `'fixed' \| 'sticky'` | Controls suffix positioning. Defaults to `fixed`. |
243
+ | `textTransform` | `'uppercase' \| 'lowercase' \| 'capitalize' \| 'integer'` | Transforms the value before change handling. |
244
+ | `controls` | `boolean` | Controls native number spinners. Defaults to `true`. |
245
+ | `testId` | `string` | Maps to `data-testid`. |
246
+ | `variant` | `'outlined'` | Visual variant. Currently only `outlined` is supported. |
247
+
248
+ ## Consumer Example
249
+
250
+ ```tsx
251
+ import { Input } from '@fvc/input';
252
+
253
+ export function SettingsForm() {
254
+ return (
255
+ <form>
256
+ <Input
257
+ name="title"
258
+ label="Title"
259
+ withAsterisk
260
+ placeholder="Enter title"
261
+ />
262
+
263
+ <Input.Textarea
264
+ name="description"
265
+ label="Description"
266
+ placeholder="Write a short description"
267
+ />
268
+
269
+ <Input.Search placeholder="Search records" />
270
+ </form>
271
+ );
272
+ }
273
+ ```
274
+
275
+ ## Testing
276
+
277
+ Use `testId` when a stable test selector is needed.
278
+
279
+ ```tsx
280
+ <Input
281
+ name="customerName"
282
+ label="Customer name"
283
+ testId="customer-name-input"
284
+ />
285
+ ```
286
+
287
+ ```tsx
288
+ screen.getByTestId('customer-name-input');
289
+ ```
290
+
291
+ ## CSS Classes
292
+
293
+ The component applies BEM-style classes to its DOM elements. These can be used for targeted styling overrides in consuming applications.
294
+
295
+ ### Root and layout
296
+
297
+ | Class | Applied when |
298
+ | --- | --- |
299
+ | `.fvc-input-root` | Always — the outermost wrapper `<div>`. |
300
+ | `.fvc-input-label` | Always — the `<label>` element above the field. |
301
+ | `.fvc-input-label-asterisk` | When `withAsterisk={true}` — the `*` span inside the label. |
302
+ | `.fvc-input-error-text` | When `error` is a string — the error message container below the field. |
303
+
304
+ ### Input element modifiers
305
+
306
+ | Class | Applied when |
307
+ | --- | --- |
308
+ | `.fvc-input-outlined` | Always — the only supported `variant` value. |
309
+ | `.fvc-input-error` | When `error` is truthy (`string` or `true`). |
310
+ | `.fvc-input-empty` | When the current value is empty or undefined. |
311
+ | `.fvc-input-with-prefix` | When `prefix` is provided. |
312
+ | `.fvc-input-no-controls` | When `controls={false}`. |
313
+ | `.fvc-input-suffix-sticky` | When `suffixType="sticky"` and `suffix` is provided. |
314
+
315
+ ### Variant root classes
316
+
317
+ Each compound component variant adds its own `rootClassName` to the antd wrapper element:
318
+
319
+ | Class | Variant |
320
+ | --- | --- |
321
+ | `.fvc-input-textarea` | `Input.Textarea` |
322
+ | `.fvc-input-search` | `Input.Search` |
323
+ | `.fvc-input-password` | `Input.Password` |
324
+ | `.fvc-input-masked` | `Input.Masked` |
325
+
326
+ ### Example override
327
+
328
+ ```scss
329
+ // Target the error message text color for a specific form
330
+ .checkout-form .fvc-input-error-text {
331
+ color: var(--danger-700);
332
+ }
333
+
334
+ // Hide the spinner controls only inside a specific container
335
+ .summary-panel .fvc-input-no-controls input[type='number'] {
336
+ appearance: textfield;
337
+ }
338
+ ```
339
+
340
+ ---
341
+
342
+ ## CSS Custom Properties
343
+
344
+ Override these variables in your global stylesheet. All variables are declared on `:root` in `src/styles/variables.scss`.
345
+
346
+ ### Base
347
+
348
+ | Variable | Default |
349
+ | --- | --- |
350
+ | `--input-font-family` | `'Roboto', sans-serif` |
351
+ | `--input-border-width` | `1px` |
352
+ | `--input-addon-text-color` | `var(--blue-gray-600)` |
353
+ | `--input-addon-min-width` | `56px` |
354
+ | `--input-description-spacing` | `4px` |
355
+ | `--input-description-error-color` | `var(--red-800)` |
356
+ | `--input-asterisk-color` | `var(--red-800)` |
357
+
358
+ ### Size (md)
359
+
360
+ | Variable | Default |
361
+ | --- | --- |
362
+ | `--input-md-size-height` | `32px` |
363
+ | `--input-md-size-border-radius` | `4px` |
364
+ | `--input-md-size-spacing` | `7px 12px` |
365
+ | `--input-md-size-fz` | `14px` |
366
+ | `--input-md-size-fw` | `400` |
367
+ | `--input-md-size-lh` | `16px` |
368
+ | `--input-md-size-label-fw` | `700` |
369
+ | `--input-md-size-label-spacing` | `6px` |
370
+
371
+ ### Outlined variant — default state
372
+
373
+ | Variable | Default |
374
+ | --- | --- |
375
+ | `--input-outlined-text-color` | `var(--black-1000)` |
376
+ | `--input-outlined-placeholder-color` | `var(--blue-300)` |
377
+ | `--input-outlined-bg-color` | `var(--neutral-0)` |
378
+ | `--input-outlined-border-color` | `var(--gray-400)` |
379
+ | `--input-outlined-hover-bg-color` | `var(--neutral-0)` |
380
+ | `--input-outlined-hover-border-color` | `var(--gray-600)` |
381
+ | `--input-outlined-focus-border-color` | `var(--blue-400)` |
382
+ | `--input-outlined-valid-bg-color` | `var(--neutral-0)` |
383
+ | `--input-outlined-valid-border-color` | `var(--gray-400)` |
384
+ | `--input-outlined-disabled-bg-color` | `var(--gray-50)` |
385
+ | `--input-outlined-disabled-border-color` | `var(--gray-400)` |
386
+ | `--input-outlined-disabled-text-color` | `var(--blue-gray-600)` |
387
+ | `--input-outlined-label-color` | `var(--black-1000)` |
388
+ | `--input-outlined-addon-bg-color` | `var(--blue-20)` |
389
+
390
+ ### Error state
391
+
392
+ | Variable | Default |
393
+ | --- | --- |
394
+ | `--input-error-text-color` | `var(--black-1000)` |
395
+ | `--input-error-placeholder-color` | `var(--blue-300)` |
396
+ | `--input-error-bg-color` | `var(--red-100)` |
397
+ | `--input-error-border-color` | `var(--red-800)` |
398
+ | `--input-error-hover-bg-color` | `var(--red-100)` |
399
+ | `--input-error-hover-border-color` | `var(--red-600)` |
400
+ | `--input-error-focus-border-color` | `var(--red-800)` |
401
+ | `--input-error-valid-bg-color` | `var(--red-100)` |
402
+ | `--input-error-valid-border-color` | `var(--red-800)` |
403
+ | `--input-error-disabled-bg-color` | `var(--red-100)` |
404
+ | `--input-error-disabled-border-color` | `var(--red-800)` |
405
+ | `--input-error-disabled-text-color` | `var(--blue-gray-600)` |
406
+ | `--input-error-label-color` | `var(--black-1000)` |
407
+ | `--input-error-addon-bg-color` | `#f9cbd166` |
408
+
409
+ ### Global override example
410
+
411
+ ```scss
412
+ // globals.scss
413
+ :root {
414
+ --input-font-family: 'Inter', sans-serif;
415
+ --input-md-size-height: 36px;
416
+ --input-outlined-border-color: var(--gray-300);
417
+ --input-outlined-focus-border-color: var(--brand-500);
418
+ --input-error-border-color: var(--danger-600);
419
+ --input-error-bg-color: var(--danger-50);
420
+ }
421
+ ```
422
+
423
+ ---
424
+
425
+ ## Development
426
+
427
+ ```bash
428
+ bun run lint
429
+ bun run type-check
430
+ bun run test
431
+ bun run build
432
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fvc/input",
3
- "version": "3.0.1",
3
+ "version": "3.0.2-next-ec65dfb844e6183b3d7f417eee613cfe5ecfd997",
4
4
  "main": "./dist/lib/index.js",
5
5
  "types": "./dist/lib/input/src/index.d.ts",
6
6
  "files": [
@@ -27,10 +27,20 @@
27
27
  "test": "bun test --preload ../../tests/happydom.ts --preload ../../tests/testing-library.tsx"
28
28
  },
29
29
  "peerDependencies": {
30
- "@fvc/icons": "^1.0.0",
31
- "@fvc/utils": "^3.0.1",
30
+ "@fvc/icons": "1.1.4-next-ec65dfb844e6183b3d7f417eee613cfe5ecfd997",
31
+ "@fvc/utils": "3.0.2-next-ec65dfb844e6183b3d7f417eee613cfe5ecfd997",
32
32
  "react": "^18.0.0",
33
33
  "antd": "^5.0.0",
34
34
  "antd-mask-input": "^2.0.7"
35
- }
35
+ },
36
+ "keywords": [
37
+ "react",
38
+ "react-component",
39
+ "fvc",
40
+ "fe-vis-core",
41
+ "ui",
42
+ "input",
43
+ "design-system",
44
+ "antd"
45
+ ]
36
46
  }