@umituz/react-native-design-system 2.6.88 → 2.6.89

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.
@@ -1,23 +1,23 @@
1
1
  # FormField
2
2
 
3
- FormField, form alanları için tam özellikli bir molekül bileşenidir. `AtomicInput` ile birlikte etiket, hata mesajı ve yardımcı metin sunar.
3
+ FormField is a molecule component that combines a label, input field, and validation messages into a complete form input unit. It wraps `AtomicInput` with `AtomicText` for labels and error/helper messages.
4
4
 
5
- ## Özellikler
5
+ ## Features
6
6
 
7
- - 🏷️ **Label Entegrasyonu**: Otomatik etiket oluşturma
8
- - **Error Handling**: Hata mesajı gösterimi
9
- - ℹ️ **Helper Text**: Yardımcı metin desteği
10
- - **Required Indicator**: Zorunlu alan işareti
11
- - 🎨 **Tam Özelleştirilebilir**: Stil ve tema desteği
12
- - **Erişilebilir**: Tam erişilebilirlik desteği
7
+ - 📝 **Complete Form Input**: Label, input, and messages in one component
8
+ - **Validation**: Error and helper text support
9
+ - 🔴 **Required Indicator**: Visual required field marker
10
+ - 🎨 **Theme-Aware**: Design token integration
11
+ - **Accessible**: Full accessibility support
12
+ - 🎯 **Simple API**: Easy to use with minimal props
13
13
 
14
- ## Kurulum
14
+ ## Installation
15
15
 
16
16
  ```tsx
17
17
  import { FormField } from 'react-native-design-system';
18
18
  ```
19
19
 
20
- ## Temel Kullanım
20
+ ## Basic Usage
21
21
 
22
22
  ```tsx
23
23
  import React, { useState } from 'react';
@@ -30,316 +30,516 @@ export const BasicExample = () => {
30
30
  return (
31
31
  <View style={{ padding: 16 }}>
32
32
  <FormField
33
- label="E-posta"
33
+ label="Email"
34
34
  value={email}
35
35
  onChangeText={setEmail}
36
- placeholder="ornek@email.com"
37
- keyboardType="email-address"
36
+ placeholder="Enter your email"
38
37
  />
39
38
  </View>
40
39
  );
41
40
  };
42
41
  ```
43
42
 
44
- ## Zorunlu Alan
43
+ ## Basic Input
45
44
 
46
45
  ```tsx
47
46
  <FormField
48
- label="Ad Soyad"
49
- required
50
- value={name}
51
- onChangeText={setName}
52
- placeholder="Adınız ve soyadınız"
47
+ label="Username"
48
+ value={username}
49
+ onChangeText={setUsername}
50
+ placeholder="Enter username"
53
51
  />
54
52
  ```
55
53
 
56
- ## Hata Durumu
54
+ ## With Error
57
55
 
58
56
  ```tsx
59
57
  <FormField
60
- label="E-posta"
58
+ label="Email"
61
59
  value={email}
62
60
  onChangeText={setEmail}
63
- placeholder="ornek@email.com"
64
- error="Geçerli bir e-posta adresi girin"
65
- state="error"
61
+ placeholder="Enter your email"
62
+ error="Please enter a valid email address"
66
63
  />
67
64
  ```
68
65
 
69
- ## Helper Text
66
+ ## Required Field
70
67
 
71
68
  ```tsx
72
69
  <FormField
73
- label="Şifre"
70
+ label="Password"
74
71
  value={password}
75
72
  onChangeText={setPassword}
76
- placeholder="Şifreniz"
73
+ placeholder="Enter password"
77
74
  secureTextEntry
78
- helperText="En az 8 karakter olmalıdır"
75
+ required
79
76
  />
80
77
  ```
81
78
 
82
- ## İkonlu Form Field
79
+ ## Helper Text
83
80
 
84
81
  ```tsx
85
82
  <FormField
86
- label="Kullanıcı Adı"
83
+ label="Username"
87
84
  value={username}
88
85
  onChangeText={setUsername}
89
- placeholder="Kullanıcı adınız"
90
- leadingIcon="person-outline"
86
+ placeholder="Choose a username"
87
+ helperText="Must be at least 3 characters long"
91
88
  />
92
89
  ```
93
90
 
94
- ## Password Field
91
+ ## Custom Required Indicator
95
92
 
96
93
  ```tsx
97
94
  <FormField
98
- label="Şifre"
99
- value={password}
100
- onChangeText={setPassword}
101
- placeholder="Şifreniz"
102
- secureTextEntry
103
- showPasswordToggle
104
- helperText="En az 8 karakter, 1 büyük harf ve 1 rakam"
95
+ label="Email"
96
+ value={email}
97
+ onChangeText={setEmail}
98
+ placeholder="your@email.com"
105
99
  required
100
+ requiredIndicator=" (required)"
106
101
  />
107
102
  ```
108
103
 
109
- ## Custom Required Indicator
104
+ ## With Icons
110
105
 
111
106
  ```tsx
112
107
  <FormField
113
- label="Telefon"
114
- value={phone}
115
- onChangeText={setPhone}
116
- placeholder="+90 555 123 4567"
117
- required
118
- requiredIndicator=" *"
119
- keyboardType="phone-pad"
108
+ label="Email"
109
+ value={email}
110
+ onChangeText={setEmail}
111
+ placeholder="your@email.com"
112
+ leftIcon="mail-outline"
113
+ rightIcon="checkmark-circle-outline"
120
114
  />
121
115
  ```
122
116
 
123
- ## Örnek Kullanımlar
117
+ ## Example Usages
124
118
 
125
- ### Kayıt Formu
119
+ ### Login Form
126
120
 
127
121
  ```tsx
128
- import React, { useState } from 'react';
129
- import { View, ScrollView, Button } from 'react-native';
130
- import { FormField } from 'react-native-design-system';
122
+ export const LoginForm = () => {
123
+ const [email, setEmail] = useState('');
124
+ const [password, setPassword] = useState('');
125
+ const [errors, setErrors] = useState({});
126
+
127
+ const validate = () => {
128
+ const newErrors = {};
129
+
130
+ if (!email) {
131
+ newErrors.email = 'Email is required';
132
+ } else if (!isValidEmail(email)) {
133
+ newErrors.email = 'Please enter a valid email';
134
+ }
135
+
136
+ if (!password) {
137
+ newErrors.password = 'Password is required';
138
+ } else if (password.length < 6) {
139
+ newErrors.password = 'Password must be at least 6 characters';
140
+ }
141
+
142
+ setErrors(newErrors);
143
+ return Object.keys(newErrors).length === 0;
144
+ };
145
+
146
+ const handleSubmit = () => {
147
+ if (validate()) {
148
+ login({ email, password });
149
+ }
150
+ };
151
+
152
+ return (
153
+ <View style={{ padding: 16 }}>
154
+ <FormField
155
+ label="Email"
156
+ value={email}
157
+ onChangeText={setEmail}
158
+ placeholder="your@email.com"
159
+ keyboardType="email-address"
160
+ autoCapitalize="none"
161
+ error={errors.email}
162
+ required
163
+ />
164
+
165
+ <FormField
166
+ label="Password"
167
+ value={password}
168
+ onChangeText={setPassword}
169
+ placeholder="Enter password"
170
+ secureTextEntry
171
+ error={errors.password}
172
+ required
173
+ />
174
+
175
+ <Button title="Login" onPress={handleSubmit} />
176
+ </View>
177
+ );
178
+ };
179
+ ```
131
180
 
132
- export const RegisterForm = () => {
181
+ ### Registration Form
182
+
183
+ ```tsx
184
+ export const RegistrationForm = () => {
133
185
  const [formData, setFormData] = useState({
134
- name: '',
186
+ firstName: '',
187
+ lastName: '',
135
188
  email: '',
136
189
  password: '',
137
190
  confirmPassword: '',
138
191
  });
192
+
139
193
  const [errors, setErrors] = useState({});
140
194
 
141
- const handleInputChange = (field) => (value) => {
142
- setFormData(prev => ({ ...prev, [field]: value }));
143
- // Clear error when user types
195
+ const handleChange = (field, value) => {
196
+ setFormData({ ...formData, [field]: value });
197
+ // Clear error when user starts typing
144
198
  if (errors[field]) {
145
- setErrors(prev => ({ ...prev, [field]: null }));
199
+ setErrors({ ...errors, [field]: null });
146
200
  }
147
201
  };
148
202
 
149
203
  const validate = () => {
150
204
  const newErrors = {};
151
205
 
152
- if (!formData.name) {
153
- newErrors.name = 'Ad soyad zorunludur';
154
- }
155
-
156
- if (!formData.email) {
157
- newErrors.email = 'E-posta zorunludur';
158
- } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
159
- newErrors.email = 'Geçerli bir e-posta adresi girin';
160
- }
161
-
162
- if (!formData.password) {
163
- newErrors.password = 'Şifre zorunludur';
164
- } else if (formData.password.length < 8) {
165
- newErrors.password = 'Şifre en az 8 karakter olmalıdır';
166
- }
167
-
206
+ if (!formData.firstName) newErrors.firstName = 'First name is required';
207
+ if (!formData.lastName) newErrors.lastName = 'Last name is required';
208
+ if (!formData.email) newErrors.email = 'Email is required';
209
+ if (!formData.password) newErrors.password = 'Password is required';
168
210
  if (formData.password !== formData.confirmPassword) {
169
- newErrors.confirmPassword = 'Şifreler eşleşmiyor';
211
+ newErrors.confirmPassword = 'Passwords do not match';
170
212
  }
171
213
 
172
214
  setErrors(newErrors);
173
215
  return Object.keys(newErrors).length === 0;
174
216
  };
175
217
 
176
- const handleSubmit = () => {
177
- if (validate()) {
178
- console.log('Form submitted:', formData);
179
- }
180
- };
181
-
182
218
  return (
183
219
  <ScrollView style={{ padding: 16 }}>
184
220
  <FormField
185
- label="Ad Soyad"
186
- value={formData.name}
187
- onChangeText={handleInputChange('name')}
188
- placeholder="Adınız ve soyadınız"
189
- error={errors.name}
221
+ label="First Name"
222
+ value={formData.firstName}
223
+ onChangeText={(value) => handleChange('firstName', value)}
224
+ placeholder="John"
225
+ error={errors.firstName}
226
+ required
227
+ />
228
+
229
+ <FormField
230
+ label="Last Name"
231
+ value={formData.lastName}
232
+ onChangeText={(value) => handleChange('lastName', value)}
233
+ placeholder="Doe"
234
+ error={errors.lastName}
190
235
  required
191
236
  />
192
237
 
193
238
  <FormField
194
- label="E-posta"
239
+ label="Email"
195
240
  value={formData.email}
196
- onChangeText={handleInputChange('email')}
197
- placeholder="ornek@email.com"
241
+ onChangeText={(value) => handleChange('email', value)}
242
+ placeholder="john.doe@example.com"
198
243
  keyboardType="email-address"
199
244
  autoCapitalize="none"
200
245
  error={errors.email}
201
- helperText="Size ulaşmak için kullanacağız"
202
246
  required
203
247
  />
204
248
 
205
249
  <FormField
206
- label="Şifre"
250
+ label="Password"
207
251
  value={formData.password}
208
- onChangeText={handleInputChange('password')}
209
- placeholder="En az 8 karakter"
252
+ onChangeText={(value) => handleChange('password', value)}
253
+ placeholder="Create a password"
210
254
  secureTextEntry
211
- showPasswordToggle
212
255
  error={errors.password}
213
- helperText="En az 8 karakter, 1 büyük harf ve 1 rakam"
256
+ helperText="Must be at least 8 characters"
214
257
  required
215
258
  />
216
259
 
217
260
  <FormField
218
- label="Şifre Tekrar"
261
+ label="Confirm Password"
219
262
  value={formData.confirmPassword}
220
- onChangeText={handleInputChange('confirmPassword')}
221
- placeholder="Şifrenizi tekrar girin"
263
+ onChangeText={(value) => handleChange('confirmPassword', value)}
264
+ placeholder="Confirm your password"
222
265
  secureTextEntry
223
- showPasswordToggle
224
266
  error={errors.confirmPassword}
225
267
  required
226
268
  />
227
269
 
228
- <Button title="Kayıt Ol" onPress={handleSubmit} />
270
+ <Button title="Create Account" onPress={validate} />
229
271
  </ScrollView>
230
272
  );
231
273
  };
232
274
  ```
233
275
 
234
- ### Giriş Formu
276
+ ### Profile Settings
235
277
 
236
278
  ```tsx
237
- export const LoginForm = () => {
238
- const [email, setEmail] = useState('');
239
- const [password, setPassword] = useState('');
240
- const [error, setError] = useState('');
241
-
242
- const handleLogin = () => {
243
- if (!email || !password) {
244
- setError('Lütfen tüm alanları doldurun');
245
- return;
246
- }
247
- // Login logic
248
- };
279
+ export const ProfileSettings = () => {
280
+ const [profile, setProfile] = useState({
281
+ displayName: '',
282
+ username: '',
283
+ bio: '',
284
+ location: '',
285
+ website: '',
286
+ });
249
287
 
250
288
  return (
251
- <View style={{ padding: 16 }}>
289
+ <ScrollView style={{ padding: 16 }}>
252
290
  <FormField
253
- label="E-posta"
254
- value={email}
255
- onChangeText={setEmail}
256
- placeholder="ornek@email.com"
257
- keyboardType="email-address"
258
- autoCapitalize="none"
291
+ label="Display Name"
292
+ value={profile.displayName}
293
+ onChangeText={(value) => setProfile({ ...profile, displayName: value })}
294
+ placeholder="John Doe"
295
+ helperText="This is how you'll appear on your profile"
259
296
  />
260
297
 
261
298
  <FormField
262
- label="Şifre"
263
- value={password}
264
- onChangeText={setPassword}
265
- placeholder="Şifreniz"
266
- secureTextEntry
267
- showPasswordToggle
299
+ label="Username"
300
+ value={profile.username}
301
+ onChangeText={(value) => setProfile({ ...profile, username: value })}
302
+ placeholder="johndoe"
303
+ helperText="https://example.com/username"
304
+ leftIcon="at-outline"
305
+ />
306
+
307
+ <FormField
308
+ label="Bio"
309
+ value={profile.bio}
310
+ onChangeText={(value) => setProfile({ ...profile, bio: value })}
311
+ placeholder="Tell us about yourself"
312
+ multiline
313
+ numberOfLines={4}
314
+ helperText="Maximum 150 characters"
268
315
  />
269
316
 
270
- {error ? (
271
- <AtomicText color="error" style={{ marginBottom: 16 }}>
272
- {error}
273
- </AtomicText>
274
- ) : null}
317
+ <FormField
318
+ label="Location"
319
+ value={profile.location}
320
+ onChangeText={(value) => setProfile({ ...profile, location: value })}
321
+ placeholder="New York, NY"
322
+ leftIcon="location-outline"
323
+ />
275
324
 
276
- <Button title="Giriş Yap" onPress={handleLogin} />
277
- </View>
325
+ <FormField
326
+ label="Website"
327
+ value={profile.website}
328
+ onChangeText={(value) => setProfile({ ...profile, website: value })}
329
+ placeholder="https://yourwebsite.com"
330
+ keyboardType="url"
331
+ autoCapitalize="none"
332
+ leftIcon="link-outline"
333
+ />
334
+
335
+ <Button title="Save Changes" onPress={handleSave} />
336
+ </ScrollView>
278
337
  );
279
338
  };
280
339
  ```
281
340
 
282
- ### Profil Formu
341
+ ### Address Form
283
342
 
284
343
  ```tsx
285
- export const ProfileForm = () => {
286
- const [profile, setProfile] = useState({
287
- firstName: 'Ahmet',
288
- lastName: 'Yılmaz',
289
- email: 'ahmet@example.com',
290
- phone: '+90 555 123 4567',
291
- bio: '',
344
+ export const AddressForm = () => {
345
+ const [address, setAddress] = useState({
346
+ street: '',
347
+ apartment: '',
348
+ city: '',
349
+ state: '',
350
+ zipCode: '',
351
+ country: '',
292
352
  });
293
353
 
294
354
  return (
295
- <ScrollView style={{ padding: 16 }}>
355
+ <View style={{ padding: 16 }}>
296
356
  <FormField
297
- label="Ad"
298
- value={profile.firstName}
299
- onChangeText={(text) => setProfile({ ...profile, firstName: text })}
300
- placeholder="Adınız"
357
+ label="Street Address"
358
+ value={address.street}
359
+ onChangeText={(value) => setAddress({ ...address, street: value })}
360
+ placeholder="123 Main St"
301
361
  required
302
362
  />
303
363
 
304
364
  <FormField
305
- label="Soyad"
306
- value={profile.lastName}
307
- onChangeText={(text) => setProfile({ ...profile, lastName: text })}
308
- placeholder="Soyadınız"
365
+ label="Apartment/Suite (optional)"
366
+ value={address.apartment}
367
+ onChangeText={(value) => setAddress({ ...address, apartment: value })}
368
+ placeholder="Apt 4B"
369
+ />
370
+
371
+ <FormField
372
+ label="City"
373
+ value={address.city}
374
+ onChangeText={(value) => setAddress({ ...address, city: value })}
375
+ placeholder="New York"
309
376
  required
310
377
  />
311
378
 
379
+ <View style={{ flexDirection: 'row', gap: 8 }}>
380
+ <View style={{ flex: 1 }}>
381
+ <FormField
382
+ label="State"
383
+ value={address.state}
384
+ onChangeText={(value) => setAddress({ ...address, state: value })}
385
+ placeholder="NY"
386
+ required
387
+ />
388
+ </View>
389
+
390
+ <View style={{ flex: 1 }}>
391
+ <FormField
392
+ label="ZIP Code"
393
+ value={address.zipCode}
394
+ onChangeText={(value) => setAddress({ ...address, zipCode: value })}
395
+ placeholder="10001"
396
+ keyboardType="number-pad"
397
+ required
398
+ />
399
+ </View>
400
+ </View>
401
+
312
402
  <FormField
313
- label="E-posta"
314
- value={profile.email}
315
- onChangeText={(text) => setProfile({ ...profile, email: text })}
316
- placeholder="ornek@email.com"
317
- keyboardType="email-address"
318
- autoCapitalize="none"
319
- leadingIcon="mail-outline"
403
+ label="Country"
404
+ value={address.country}
405
+ onChangeText={(value) => setAddress({ ...address, country: value })}
406
+ placeholder="United States"
320
407
  required
321
408
  />
409
+ </View>
410
+ );
411
+ };
412
+ ```
413
+
414
+ ### Credit Card Form
415
+
416
+ ```tsx
417
+ export const CreditCardForm = () => {
418
+ const [card, setCard] = useState({
419
+ cardNumber: '',
420
+ cardHolder: '',
421
+ expiryDate: '',
422
+ cvv: '',
423
+ });
424
+
425
+ const formatCardNumber = (text) => {
426
+ return text.replace(/\s/g, '').replace(/(.{4})/g, '$1 ').trim();
427
+ };
428
+
429
+ const formatExpiry = (text) => {
430
+ if (text.length === 2 && !text.includes('/')) {
431
+ return text + '/';
432
+ }
433
+ return text;
434
+ };
322
435
 
436
+ return (
437
+ <View style={{ padding: 16 }}>
323
438
  <FormField
324
- label="Telefon"
325
- value={profile.phone}
326
- onChangeText={(text) => setProfile({ ...profile, phone: text })}
327
- placeholder="+90 555 123 4567"
328
- keyboardType="phone-pad"
329
- leadingIcon="call-outline"
439
+ label="Card Number"
440
+ value={card.cardNumber}
441
+ onChangeText={(value) => setCard({ ...card, cardNumber: formatCardNumber(value) })}
442
+ placeholder="1234 5678 9012 3456"
443
+ keyboardType="number-pad"
444
+ maxLength={19}
445
+ leftIcon="card-outline"
446
+ required
330
447
  />
331
448
 
332
449
  <FormField
333
- label="Hakkımda"
334
- value={profile.bio}
335
- onChangeText={(text) => setProfile({ ...profile, bio: text })}
336
- placeholder="Kendinizden bahsedin"
337
- multiline
338
- numberOfLines={4}
339
- maxLength={200}
340
- showCharacterCount
450
+ label="Cardholder Name"
451
+ value={card.cardHolder}
452
+ onChangeText={(value) => setCard({ ...card, cardHolder: value })}
453
+ placeholder="JOHN DOE"
454
+ autoCapitalize="characters"
455
+ required
341
456
  />
342
- </ScrollView>
457
+
458
+ <View style={{ flexDirection: 'row', gap: 8 }}>
459
+ <View style={{ flex: 1 }}>
460
+ <FormField
461
+ label="Expiry Date"
462
+ value={card.expiryDate}
463
+ onChangeText={(value) => setCard({ ...card, expiryDate: formatExpiry(value) })}
464
+ placeholder="MM/YY"
465
+ keyboardType="number-pad"
466
+ maxLength={5}
467
+ required
468
+ />
469
+ </View>
470
+
471
+ <View style={{ flex: 1 }}>
472
+ <FormField
473
+ label="CVV"
474
+ value={card.cvv}
475
+ onChangeText={(value) => setCard({ ...card, cvv: value })}
476
+ placeholder="123"
477
+ keyboardType="number-pad"
478
+ maxLength={4}
479
+ secureTextEntry
480
+ helperText="3 or 4 digits on back of card"
481
+ required
482
+ />
483
+ </View>
484
+ </View>
485
+ </View>
486
+ );
487
+ };
488
+ ```
489
+
490
+ ### Search Form
491
+
492
+ ```tsx
493
+ export const SearchForm = () => {
494
+ const [searchTerm, setSearchTerm] = useState('');
495
+ const [filters, setFilters] = useState({
496
+ category: '',
497
+ minPrice: '',
498
+ maxPrice: '',
499
+ });
500
+
501
+ return (
502
+ <View style={{ padding: 16 }}>
503
+ <FormField
504
+ label="Search"
505
+ value={searchTerm}
506
+ onChangeText={setSearchTerm}
507
+ placeholder="What are you looking for?"
508
+ leftIcon="search-outline"
509
+ />
510
+
511
+ <FormField
512
+ label="Category"
513
+ value={filters.category}
514
+ onChangeText={(value) => setFilters({ ...filters, category: value })}
515
+ placeholder="Select a category"
516
+ rightIcon="chevron-down-outline"
517
+ />
518
+
519
+ <View style={{ flexDirection: 'row', gap: 8 }}>
520
+ <View style={{ flex: 1 }}>
521
+ <FormField
522
+ label="Min Price"
523
+ value={filters.minPrice}
524
+ onChangeText={(value) => setFilters({ ...filters, minPrice: value })}
525
+ placeholder="$0"
526
+ keyboardType="number-pad"
527
+ />
528
+ </View>
529
+
530
+ <View style={{ flex: 1 }}>
531
+ <FormField
532
+ label="Max Price"
533
+ value={filters.maxPrice}
534
+ onChangeText={(value) => setFilters({ ...filters, maxPrice: value })}
535
+ placeholder="$1000"
536
+ keyboardType="number-pad"
537
+ />
538
+ </View>
539
+ </View>
540
+
541
+ <Button title="Search" onPress={handleSearch} />
542
+ </View>
343
543
  );
344
544
  };
345
545
  ```
@@ -348,139 +548,90 @@ export const ProfileForm = () => {
348
548
 
349
549
  ### FormFieldProps
350
550
 
351
- `FormField`, `AtomicInputProps`'ın tüm props'larını alır ve aşağıdakileri ekler:
352
-
353
- | Prop | Tip | Varsayılan | Açıklama |
354
- |------|-----|------------|----------|
355
- | `label` | `string` | - | Alan etiketi |
356
- | `error` | `string` | - | Hata mesajı |
357
- | `helperText` | `string` | - | Yardımcı metin |
358
- | `required` | `boolean` | `false` | Zorunlu alan |
359
- | `requiredIndicator` | `string` | `' *'` | Zorunlu alan işareti |
360
- | `containerStyle` | `ViewStyle` | - | Container stili |
361
- | `style` | `ViewStyle` | - | Container stili (alias) |
551
+ Extends `Omit<AtomicInputProps, 'state' | 'label'>`
362
552
 
363
- ## Stil Özelleştirme
553
+ | Prop | Type | Default | Description |
554
+ |------|------|---------|-------------|
555
+ | `label` | `string` | - | Field label |
556
+ | `error` | `string` | - | Error message |
557
+ | `helperText` | `string` | - | Helper text |
558
+ | `required` | `boolean` | `false` | Show required indicator |
559
+ | `containerStyle` | `ViewStyle` | - | Container style |
560
+ | `style` | `ViewStyle` | - | Alias for containerStyle |
561
+ | `requiredIndicator` | `string` | `' *'` | Required indicator text |
364
562
 
365
- ```tsx
366
- <FormField
367
- label="Özel Alan"
368
- value={value}
369
- onChangeText={setValue}
370
- containerStyle={{
371
- marginBottom: 24,
372
- backgroundColor: '#f9fafb',
373
- padding: 16,
374
- borderRadius: 8,
375
- }}
376
- />
377
- ```
563
+ Plus all AtomicInput props:
564
+ - `value`, `onChangeText`, `placeholder`, `secureTextEntry`, `keyboardType`, etc.
378
565
 
379
566
  ## Best Practices
380
567
 
381
568
  ### 1. Error Handling
382
569
 
383
570
  ```tsx
384
- // Hataları state'de tutun
385
- const [errors, setErrors] = useState({});
386
-
387
- // Form submit'da validate edin
388
- const validate = () => {
389
- const newErrors = {};
390
- if (!email) newErrors.email = 'Bu alan zorunludur';
391
- setErrors(newErrors);
392
- return Object.keys(newErrors).length === 0;
393
- };
571
+ // Good: Clear specific errors
572
+ <FormField
573
+ error="Email must be in format: user@example.com"
574
+ />
394
575
 
395
- // Form field'da gösterin
576
+ // Bad: Vague errors
396
577
  <FormField
397
- error={errors.email}
398
- // ...
578
+ error="Invalid"
399
579
  />
400
580
  ```
401
581
 
402
- ### 2. Helper Text Kullanımı
582
+ ### 2. Helper Text
403
583
 
404
584
  ```tsx
405
- // Kullanıcıya rehberlik edin
585
+ // Good: Helpful guidance
586
+ <FormField
587
+ helperText="Must be at least 8 characters with 1 number"
588
+ />
589
+
590
+ // ❌ Bad: Obvious info
406
591
  <FormField
407
- label="Şifre"
408
- helperText="En az 8 karakter, 1 büyük harf ve 1 rakam içermelidir"
409
- // ...
592
+ helperText="Enter text here"
410
593
  />
411
594
  ```
412
595
 
413
596
  ### 3. Required Fields
414
597
 
415
598
  ```tsx
416
- // Zorunlu alanları işaretleyin
599
+ // Good: Use sparingly
417
600
  <FormField
418
- label="E-posta"
601
+ label="Email"
419
602
  required
420
- // ...
421
603
  />
422
- ```
423
-
424
- ## Erişilebilirlik
425
-
426
- FormField, tam erişilebilirlik desteği sunar:
427
-
428
- - ✅ Label ilişkilendirmesi
429
- - ✅ Error state anonsu
430
- - ✅ Required field göstergesi
431
- - ✅ Screen reader desteği
432
-
433
- ## Form Validasyon Örneği
434
-
435
- ```tsx
436
- const useFormValidation = (schema) => {
437
- const [errors, setErrors] = useState({});
438
604
 
439
- const validate = (data) => {
440
- const newErrors = {};
605
+ // Bad: Overuse
606
+ <FormField
607
+ label="Optional Field"
608
+ required
609
+ />
610
+ ```
441
611
 
442
- Object.keys(schema).forEach((key) => {
443
- const rules = schema[key];
444
- const value = data[key];
612
+ ## Accessibility
445
613
 
446
- if (rules.required && !value) {
447
- newErrors[key] = `${rules.label} zorunludur`;
448
- } else if (rules.pattern && !rules.pattern.test(value)) {
449
- newErrors[key] = rules.message || 'Geçersiz değer';
450
- } else if (rules.minLength && value.length < rules.minLength) {
451
- newErrors[key] = `${rules.label} en az ${rules.minLength} karakter olmalıdır`;
452
- }
453
- });
614
+ FormField provides full accessibility support:
454
615
 
455
- setErrors(newErrors);
456
- return Object.keys(newErrors).length === 0;
457
- };
616
+ - ✅ Screen reader labels
617
+ - Error announcements
618
+ - ✅ Required field indicators
619
+ - ✅ Helper text
620
+ - ✅ Auto-focus handling
458
621
 
459
- return { errors, validate };
460
- };
622
+ ## Performance Tips
461
623
 
462
- // Kullanım
463
- const { errors, validate } = useFormValidation({
464
- email: {
465
- required: true,
466
- label: 'E-posta',
467
- pattern: /\S+@\S+\.\S+/,
468
- message: 'Geçerli bir e-posta adresi girin',
469
- },
470
- password: {
471
- required: true,
472
- label: 'Şifre',
473
- minLength: 8,
474
- },
475
- });
476
- ```
624
+ 1. **Controlled Inputs**: Always use controlled inputs with state
625
+ 2. **Validation Debounce**: Debounce validation for better UX
626
+ 3. **Memoization**: Memo validation functions
477
627
 
478
- ## İlgili Bileşenler
628
+ ## Related Components
479
629
 
480
- - [`AtomicInput`](../atoms/input/README.md) - Input bileşeni
481
- - [`AtomicButton`](../atoms/button/README.md) - Form butonu
482
- - [`BaseModal`](./BaseModal/README.md) - Modal form
630
+ - [`AtomicInput`](../atoms/input/README.md) - Base input component
631
+ - [`AtomicText`](../atoms/AtomicText/README.md) - Text component
632
+ - [`Button`](../atoms/button/README.md) - Button component
633
+ - [`AlertInline`](../alerts/README.md) - Inline alert component
483
634
 
484
- ## Lisans
635
+ ## License
485
636
 
486
637
  MIT