• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Duit-Foundation / duit_kernel / 20170886726

12 Dec 2025 03:05PM UTC coverage: 76.396% (+0.02%) from 76.374%
20170886726

Pull #49

github

web-flow
Merge b75f75083 into 5d8920b5e
Pull Request #49: feat: Focus node management API

28 of 36 new or added lines in 3 files covered. (77.78%)

1 existing line in 1 file now uncovered.

1751 of 2292 relevant lines covered (76.4%)

4.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.81
/lib/src/view_attributes/data_source.dart
1
import "dart:convert";
2
import "dart:typed_data";
3
import "dart:ui";
4

5
import "package:duit_kernel/duit_kernel.dart";
6
import "package:flutter/gestures.dart";
7
import "package:flutter/material.dart";
8
import "package:flutter/rendering.dart";
9

10
part "lookup.dart";
11
part "fields.dart";
12

13
/// Shortand for the extension type instance methods
14
typedef _DispatchFn = dynamic Function(
15
  DuitDataSource self,
16
  String key,
17
  Object? target,
18
  bool warmUp,
19
);
20

21
/// A wrapper for JSON data that provides type-safe access to Dart/Flutter properties.
22
///
23
/// This extension type wraps a [Map<String, dynamic>] and provides methods to safely
24
/// parse and convert JSON values into Dart/Flutter types. It implements [Map<String, dynamic>]
25
/// to maintain compatibility with JSON operations.
26
///
27
/// The extension type provides methods for:
28
/// - Parsing basic types (int, double, string, bool)
29
/// - Converting colors from hex strings or RGB arrays
30
/// - Parsing Dart/Flutter-specific types (Size, EdgeInsets, Alignment, etc.)
31
/// - Handling enums through string or integer lookups
32
/// - Managing widget states and properties
33
///
34
/// Example usage:
35
/// ```dart
36
/// final data = DuitDataSource({
37
///   'color': '#FF0000',
38
///   'size': {'width': 100, 'height': 100},
39
///   'padding': [10, 20, 10, 20],
40
/// });
41
///
42
/// final color = data.parseColor(); // Returns Color(0xFFFF0000)
43
/// final size = data.size('size'); // Returns Size(100, 100)
44
/// final padding = data.edgeInsets(); // Returns EdgeInsets(10, 20, 10, 20)
45
/// ```
46
extension type DuitDataSource(Map<String, dynamic> _json)
47
    implements Map<String, dynamic> {
48
  /// Retrieves a [ServerAction] from the JSON map associated with the given [key].
49
  ///
50
  /// If the value associated with the [key] is already a [ServerAction], it returns that action.
51
  /// If the value is a [Map<String, dynamic>], it attempts to parse it into a [ServerAction].
52
  /// Otherwise, it returns `null`.
53
  ///
54
  /// The parsed or existing [ServerAction] is also stored back into the JSON map at the given [key].
55
  ///
56
  /// Returns:
57
  /// - A [ServerAction] if the value is valid or can be parsed.
58
  /// - `null` if the value is not a valid [ServerAction] or cannot be parsed.
59
  @preferInline
4✔
60
  ServerAction? getAction(String key) {
61
    final action = _json[key];
4✔
62

63
    if (action is ServerAction) return action;
4✔
64

65
    if (action == null) {
66
      return null;
67
    }
68

69
    if (action is Map<String, dynamic>) {
4✔
70
      return _json[key] = ServerAction.parse(action);
8✔
71
    }
72

73
    return null;
74
  }
75

76
  /// Retrieves a list of action dependencies from the JSON map.
77
  ///
78
  /// This method checks if the JSON map contains a "dependsOn" key, which is
79
  /// expected to be a non-empty list. If present, it converts each element
80
  /// of the list into an `ActionDependency` using `ActionDependency.fromJson`.
81
  /// If the key is absent or the list is empty, it returns an empty iterable.
82
  ///
83
  /// Returns:
84
  /// - A non-empty `Iterable<ActionDependency>` if "dependsOn" exists and is valid.
85
  /// - An empty iterable if "dependsOn" does not exist or is empty.
86
  @preferInline
4✔
87
  Iterable<ActionDependency> getActionDependencies() {
88
    final dependsOn = _json["dependsOn"];
4✔
89

90
    if (dependsOn is List) {
4✔
91
      return dependsOn
92
          .map((e) => _actionDependency(Map<String, dynamic>.from(e)));
16✔
93
    } else {
94
      return const <ActionDependency>[];
95
    }
96
  }
97

98
  //
99
  @preferInline
4✔
100
  ActionDependency _actionDependency(Map<String, dynamic> dep) {
101
    final data = DuitDataSource(dep);
4✔
102
    return ActionDependency(
4✔
103
      target: data.getString(key: "target"),
4✔
104
      id: data.getString(key: "id"),
4✔
105
    );
106
  }
107

108
  @preferInline
4✔
109
  HttpActionMetainfo? get meta {
110
    final metaData = _json["meta"];
4✔
111

112
    if (metaData == null) {
113
      return null;
114
    }
115
    return HttpActionMetainfo.fromJson(metaData);
4✔
116
  }
117

118
  @preferInline
4✔
119
  int get executionType {
120
    final executionType = _json["executionType"];
4✔
121
    return executionType is int ? executionType : 0;
4✔
122
  }
123

124
  @preferInline
4✔
125
  ScriptDefinition get script {
126
    final Map<String, dynamic> scriptData = _json["script"];
4✔
127
    final data = DuitDataSource(scriptData);
4✔
128
    return ScriptDefinition(
4✔
129
      sourceCode: data.getString(key: "sourceCode"),
4✔
130
      functionName: data.getString(key: "functionName"),
4✔
131
      meta: data["meta"],
4✔
132
    );
133
  }
134

135
  @preferInline
4✔
136
  String? get parentBuilderId {
137
    final id = _json["parentBuilderId"];
4✔
138
    return id is String ? id : null;
4✔
139
  }
140

141
  @preferInline
4✔
142
  Iterable<String>? get affectedProperties {
143
    final value = _json["affectedProperties"];
4✔
144
    return value is Iterable ? Set<String>.from(value) : null;
8✔
145
  }
146

147
  //Reads a value from the JSON map associated with the given [key].
148
  //
149
  // If attribute warm up is enabled, it returns the target value if [warmUp] is true.
150
  // Otherwise, it returns the value from the JSON map.
151
  //
152
  // The value is stored back into the JSON map at the given [key].
153
  //
154
  // Returns:
155
  // - The value from the JSON map if attribute warm up is disabled.
156
  // - The target value if attribute warm up is enabled and [warmUp] is true.
157
  // - `null` if the value is not found in the JSON map.
158
  @preferInline
8✔
159
  dynamic _readProp(String key, Object? target, bool warmUp) {
160
    if (envAttributeWarmUpEnabled) {
161
      if (warmUp) {
162
        return target;
163
      } else {
164
        return _json[key];
4✔
165
      }
166
    }
167
    return _json[key];
4✔
168
  }
169

170
  /// Converts a given hex color string to a [Color].
171
  ///
172
  /// The provided [color] must be a valid hex color string, optionally prefixed with a '#'.
173
  /// If the [color] is `null`, or if it's not a valid hex color string, this function returns `null`.
174
  /// The hex color string can be 6 or 7 characters long. If the length is 6, the opacity is assumed to be 0xFF.
175
  /// If the length is 7, the first character is assumed to be the opacity, and the remaining 6 characters are the color.
176
  @preferInline
8✔
177
  Color? _colorFromHexString(String color) {
178
    final isHexColor = color.startsWith("#");
8✔
179
    if (isHexColor) {
180
      final buffer = StringBuffer();
8✔
181
      if (color.length == 6 || color.length == 7) buffer.write("ff");
40✔
182
      buffer.write(color.replaceFirst("#", ""));
16✔
183
      return Color(int.parse(buffer.toString(), radix: 16));
24✔
184
    }
185
    return null;
186
  }
187

188
  /// Converts a list of 3 or 4 elements to a [Color].
189
  ///
190
  /// The list must contain 3 or 4 elements, each of which must be a valid
191
  /// [int] value between 0 and 255. If the list has 3 elements, the opacity
192
  /// is assumed to be 1.0. If the list has 4 elements, the first element is
193
  /// assumed to be the opacity, and the remaining 3 elements are the color.
194
  ///
195
  /// If the list is `null`, or if it does not contain exactly 3 or 4 elements,
196
  /// or if any of the elements are not valid integers between 0 and 255, this
197
  /// function returns `null`.
198
  @preferInline
4✔
199
  Color? _colorFromList(List color) {
200
    final colorData = color.map((e) => e as num).toList();
12✔
201
    return switch (colorData.length) {
4✔
202
      4 => Color.fromRGBO(
8✔
203
          colorData[0].toInt(),
8✔
204
          colorData[1].toInt(),
8✔
205
          colorData[2].toInt(),
8✔
206
          colorData[3].toDouble(),
8✔
207
        ),
208
      3 => Color.fromRGBO(
8✔
209
          colorData[0].toInt(),
8✔
210
          colorData[1].toInt(),
8✔
211
          colorData[2].toInt(),
8✔
212
          1.0,
213
        ),
214
      _ => null,
215
    };
216
  }
217

218
  /// Converts a JSON value to a [Color].
219
  ///
220
  /// The JSON value must be either a string (which is interpreted as a
221
  /// hexadecimal color string) or a list of 3 or 4 elements (which is
222
  /// interpreted as a color with optional opacity).
223
  ///
224
  /// If the JSON value is not a valid color (i.e. it is not a string or a list
225
  /// of 3 or 4 elements), this function returns `null`.
226
  @preferInline
4✔
227
  Color? _parseColor(color) => switch (color) {
228
        String() => _colorFromHexString(color),
8✔
229
        List() => _colorFromList(color),
×
230
        _ => null,
231
      };
232

233
  /// Retrieves a color value from the JSON map associated with the given [key].
234
  ///
235
  /// If the value associated with the [key] is already a [Color], it returns that color.
236
  /// If the value is a [String], it attempts to parse it into a [Color].
237
  /// If the value is a [List], it attempts to parse it into a [Color].
238
  /// Otherwise, it returns [defaultValue].
239
  ///
240
  /// The parsed or existing [Color] is also stored back into the JSON map at the given [key].
241
  ///
242
  /// Returns:
243
  /// - A [Color] if the value is valid or can be parsed.
244
  /// - [defaultValue] if the value is not a valid [Color] or cannot be parsed.
245
  @preferInline
8✔
246
  Color parseColor({
247
    String key = FlutterPropertyKeys.color,
248
    Color defaultValue = Colors.transparent,
249
  }) {
250
    final value = _json[key];
8✔
251

252
    if (value is Color) return value;
8✔
253

254
    if (value == null) return defaultValue;
255

256
    return _json[key] = switch (value) {
4✔
257
      String() => _colorFromHexString(value) ?? defaultValue,
8✔
258
      List() => _colorFromList(value) ?? defaultValue,
8✔
259
      _ => defaultValue,
260
    };
261
  }
262

263
  /// Retrieves a color value from the JSON map associated with the given [key].
264
  ///
265
  /// If the value associated with the [key] is already a [Color], it returns that color.
266
  /// If the value is a [String], it attempts to parse it into a [Color].
267
  /// If the value is a [List], it attempts to parse it into a [Color].
268
  /// Otherwise, it returns [defaultValue].
269
  ///
270
  /// Unlike [parseColor], this method does not store the parsed or existing [Color] back into the JSON map.
271
  ///
272
  /// Returns:
273
  /// - A [Color] if the value is valid or can be parsed.
274
  /// - [defaultValue] if the value is not a valid [Color] or cannot be parsed.
275
  @preferInline
8✔
276
  Color? tryParseColor({
277
    String key = FlutterPropertyKeys.color,
278
    Color? defaultValue,
279
    Object? target,
280
    bool warmUp = false,
281
  }) {
282
    final value = _readProp(key, target, warmUp);
8✔
283

284
    if (value is Color) return value;
8✔
285

286
    if (value == null) return defaultValue;
287

288
    switch (value) {
289
      case String():
8✔
290
        if (envAttributeWarmUpEnabled) {
291
          if (warmUp) {
292
            return _colorFromHexString(value);
4✔
293
          } else {
294
            return _json[key] = _colorFromHexString(value);
×
295
          }
296
        } else {
297
          return _json[key] = _colorFromHexString(value);
8✔
298
        }
299
      case List():
4✔
300
        if (envAttributeWarmUpEnabled) {
301
          if (warmUp) {
302
            return _colorFromList(value);
×
303
          } else {
304
            return _json[key] = _colorFromList(value);
×
305
          }
306
        } else {
307
          return _json[key] = _colorFromList(value);
8✔
308
        }
309
      default:
310
        return defaultValue;
311
    }
312
  }
313

314
  /// Retrieves a duration value from the JSON map associated with the given [key].
315
  ///
316
  /// If the value associated with the [key] is already a [Duration], it returns that duration.
317
  /// If the value is a [num], it attempts to parse it into a [Duration].
318
  /// Otherwise, it returns [defaultValue].
319
  ///
320
  /// The parsed or existing [Duration] is also stored back into the JSON map at the given [key].
321
  ///
322
  /// Returns:
323
  /// - A [Duration] if the value is valid or can be parsed.
324
  /// - [defaultValue] if the value is not a valid [Duration] or cannot be parsed.
325
  @preferInline
8✔
326
  Duration duration({
327
    String key = FlutterPropertyKeys.duration,
328
    Duration? defaultValue,
329
    Object? target,
330
    bool warmUp = false,
331
  }) {
332
    final value = _readProp(key, target, warmUp);
8✔
333

334
    if (value is Duration) return value;
8✔
335

336
    if (value == null) {
337
      return defaultValue ?? Duration.zero;
338
    }
339

340
    switch (value) {
341
      case int():
8✔
342
        if (envAttributeWarmUpEnabled) {
343
          if (warmUp) {
344
            return Duration(milliseconds: value);
4✔
345
          } else {
346
            return _json[key] = Duration(milliseconds: value);
×
347
          }
348
        } else {
349
          return _json[key] = Duration(milliseconds: value);
8✔
350
        }
351
      default:
352
        return defaultValue ?? Duration.zero;
353
    }
354
  }
355

356
  /// Retrieves an [int] value from the JSON map associated with the given [key].
357
  ///
358
  /// If the value associated with the [key] is already an [int], it returns that value.
359
  /// If the value is a [num], it attempts to parse it into an [int].
360
  /// Otherwise, it returns [defaultValue].
361
  ///
362
  /// The parsed or existing [int] is also stored back into the JSON map at the given [key].
363
  ///
364
  /// Returns:
365
  /// - An [int] if the value is valid or can be parsed.
366
  /// - [defaultValue] if the value is not a valid [int] or cannot be parsed.
367
  /// - 0 if both the value and [defaultValue] are null.
368
  @preferInline
4✔
369
  int getInt({
370
    required String key,
371
    int? defaultValue,
372
  }) {
373
    final value = _json[key];
4✔
374
    if (value is num) {
4✔
375
      return value.toInt();
4✔
376
    }
377
    return defaultValue ?? 0;
378
  }
379

380
  /// Retrieves an [int] value from the JSON map associated with the given [key].
381
  ///
382
  /// If the value associated with the [key] is already an [int], it returns that value.
383
  /// If the value is a [num], it attempts to parse it into an [int].
384
  /// Otherwise, it returns [defaultValue].
385
  ///
386
  /// Unlike [getInt], this method does not store the parsed or existing [int] back into the JSON map.
387
  ///
388
  /// Returns:
389
  /// - An [int] if the value is valid or can be parsed.
390
  /// - [defaultValue] if the value is not a valid [int] or cannot be parsed.
391
  /// - `null` if both the value and [defaultValue] are null.
392
  @preferInline
8✔
393
  int? tryGetInt({
394
    required String key,
395
    int? defaultValue,
396
  }) {
397
    final value = _json[key];
8✔
398
    if (value is num) {
8✔
399
      return value.toInt();
4✔
400
    }
401
    return defaultValue;
402
  }
403

404
  /// Retrieves a [double] value from the JSON map associated with the given [key].
405
  ///
406
  /// If the value associated with the [key] is already a [double], it returns that value.
407
  /// If the value is a [num], it attempts to parse it into a [double].
408
  /// Otherwise, it returns [defaultValue].
409
  ///
410
  /// The parsed or existing [double] is also stored back into the JSON map at the given [key].
411
  ///
412
  /// Returns:
413
  /// - A [double] if the value is valid or can be parsed.
414
  /// - [defaultValue] if the value is not a valid [double] or cannot be parsed.
415
  /// - 0.0 if both the value and [defaultValue] are null.
416
  @preferInline
8✔
417
  double getDouble({
418
    required String key,
419
    double? defaultValue,
420
  }) {
421
    final value = _json[key];
8✔
422
    if (value is num) {
8✔
423
      return value.toDouble();
8✔
424
    }
425
    return defaultValue ?? 0.0;
426
  }
427

428
  /// Retrieves a [double] value from the JSON map associated with the given [key].
429
  ///
430
  /// If the value associated with the [key] is already a [double], it returns that value.
431
  /// If the value is a [num], it attempts to parse it into a [double].
432
  /// Otherwise, it returns [defaultValue].
433
  ///
434
  /// Unlike [getDouble], this method does not store the parsed or existing [double] back into the JSON map.
435
  ///
436
  /// Returns:
437
  /// - A [double] if the value is valid or can be parsed.
438
  /// - [defaultValue] if the value is not a valid [double] or cannot be parsed.
439
  /// - `null` if both the value and [defaultValue] are null.
440
  @preferInline
8✔
441
  double? tryGetDouble({
442
    required String key,
443
    double? defaultValue,
444
  }) {
445
    final value = _json[key];
8✔
446
    if (value is num) {
8✔
447
      return value.toDouble();
8✔
448
    }
449
    return defaultValue;
450
  }
451

452
  /// Retrieves a [String] value from the JSON map associated with the given [key].
453
  ///
454
  /// If the value associated with the [key] is already a [String], it returns that value.
455
  /// Otherwise, it returns [defaultValue].
456
  ///
457
  /// The parsed or existing [String] is also stored back into the JSON map at the given [key].
458
  ///
459
  /// Returns:
460
  /// - A [String] if the value is valid.
461
  /// - [defaultValue] if the value is not a valid [String].
462
  /// - Empty string ("") if both the value and [defaultValue] are null.
463
  @preferInline
8✔
464
  String getString({
465
    required String key,
466
    String? defaultValue,
467
  }) {
468
    final value = _json[key];
8✔
469
    if (value is String) {
8✔
470
      return value;
471
    }
472
    return defaultValue ?? "";
473
  }
474

475
  /// Retrieves a [String] value from the JSON map associated with the given [key].
476
  ///
477
  /// If the value associated with the [key] is already a [String], it returns that value.
478
  /// Otherwise, it returns [defaultValue].
479
  ///
480
  /// Unlike [getString], this method does not store the parsed or existing [String] back into the JSON map.
481
  ///
482
  /// Returns:
483
  /// - A [String] if the value is valid.
484
  /// - [defaultValue] if the value is not a valid [String].
485
  /// - `null` if both the value and [defaultValue] are null.
486
  @preferInline
8✔
487
  String? tryGetString(
488
    String key, {
489
    String? defaultValue,
490
  }) {
491
    final value = _json[key];
8✔
492
    if (value is String) {
8✔
493
      return value;
494
    }
495
    return defaultValue;
496
  }
497

498
  /// Retrieves a [bool] value from the JSON map associated with the given [key].
499
  ///
500
  /// If the value associated with the [key] is already a [bool], it returns that value.
501
  /// Otherwise, it returns [defaultValue].
502
  ///
503
  /// The parsed or existing [bool] is also stored back into the JSON map at the given [key].
504
  ///
505
  /// Returns:
506
  /// - A [bool] if the value is valid.
507
  /// - [defaultValue] if the value is not a valid [bool].
508
  /// - false if both the value and [defaultValue] are null.
509
  @preferInline
8✔
510
  bool getBool(
511
    String key, {
512
    bool? defaultValue,
513
  }) {
514
    final value = _json[key];
8✔
515
    if (value is bool) {
8✔
516
      return value;
517
    }
518
    return defaultValue ?? false;
519
  }
520

521
  /// Retrieves a [bool] value from the JSON map associated with the given [key].
522
  ///
523
  /// If the value associated with the [key] is already a [bool], it returns that value.
524
  /// Otherwise, it returns [defaultValue].
525
  ///
526
  /// Unlike [getBool], this method does not store the parsed or existing [bool] back into the JSON map.
527
  @preferInline
8✔
528
  bool? tryGetBool(
529
    String key, {
530
    bool? defaultValue,
531
  }) {
532
    final value = _json[key];
8✔
533
    if (value is bool) {
8✔
534
      return value;
535
    }
536
    return defaultValue;
537
  }
538

539
  /// Retrieves a [TextAlign] value from the JSON map associated with the given [key].
540
  ///
541
  /// If the value associated with the [key] is already a [TextAlign], it returns that value.
542
  /// If the value is a [String] or [int], it is converted using the lookup tables.
543
  /// Otherwise, it returns [defaultValue].
544
  ///
545
  /// The parsed or existing [TextAlign] is also stored back into the JSON map at the given [key].
546
  ///
547
  /// Returns:
548
  /// - A [TextAlign] if the value is valid or can be parsed.
549
  /// - [defaultValue] if the value is not a valid [TextAlign] or cannot be parsed.
550
  /// - `null` if the value is `null` and [defaultValue] is provided.
551
  @preferInline
8✔
552
  TextAlign? textAlign({
553
    String key = FlutterPropertyKeys.textAlign,
554
    TextAlign defaultValue = TextAlign.start,
555
    Object? target,
556
    bool warmUp = false,
557
  }) {
558
    final value = _readProp(key, target, warmUp);
8✔
559

560
    if (value is TextAlign) return value;
8✔
561

562
    if (value == null) return defaultValue;
563

564
    switch (value) {
565
      case String():
8✔
566
        if (envAttributeWarmUpEnabled) {
567
          if (warmUp) {
568
            return _textAlignStringLookupTable[value];
4✔
569
          } else {
570
            return _json[key] = _textAlignStringLookupTable[value];
×
571
          }
572
        } else {
573
          return _json[key] = _textAlignStringLookupTable[value];
8✔
574
        }
575
      case int():
4✔
576
        if (envAttributeWarmUpEnabled) {
577
          if (warmUp) {
578
            return _textAlignIntLookupTable[value];
×
579
          } else {
580
            return _json[key] = _textAlignIntLookupTable[value];
×
581
          }
582
        } else {
583
          return _json[key] = _textAlignIntLookupTable[value];
8✔
584
        }
585
      default:
586
        return defaultValue;
587
    }
588
  }
589

590
  /// Retrieves a [TextDirection] value from the JSON map for the given [key].
591
  ///
592
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextDirection],
593
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
594
  /// If the value is `null` and [defaultValue] is provided, [defaultValue] is returned.
595
  /// Otherwise, returns `defaultValue` if the value cannot be resolved.
596
  ///
597
  /// - [key]: The key to look up in the JSON map. Defaults to 'textDirection'.
598
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved.
599
  ///
600
  /// Example:
601
  ///   textDirection(key: 'myDirection', defaultValue: TextDirection.ltr)
602
  @preferInline
8✔
603
  TextDirection? textDirection({
604
    String key = FlutterPropertyKeys.textDirection,
605
    TextDirection? defaultValue,
606
    Object? target,
607
    bool warmUp = false,
608
  }) {
609
    final value = _readProp(key, target, warmUp);
8✔
610

611
    if (value is TextDirection) return value;
8✔
612

613
    if (value == null && defaultValue != null) {
614
      return defaultValue;
615
    }
616

617
    switch (value) {
618
      case String():
8✔
619
        if (envAttributeWarmUpEnabled) {
620
          if (warmUp) {
621
            return _textDirectionStringLookupTable[value];
4✔
622
          } else {
623
            return _json[key] = _textDirectionStringLookupTable[value];
×
624
          }
625
        } else {
626
          return _json[key] = _textDirectionStringLookupTable[value];
8✔
627
        }
628
      case int():
4✔
629
        if (envAttributeWarmUpEnabled) {
630
          if (warmUp) {
631
            return _textDirectionIntLookupTable[value];
×
632
          } else {
633
            return _json[key] = _textDirectionIntLookupTable[value];
×
634
          }
635
        } else {
636
          return _json[key] = _textDirectionIntLookupTable[value];
8✔
637
        }
638
      default:
639
        return defaultValue;
640
    }
641
  }
642

643
  /// Retrieves a [TextOverflow] value from the JSON map for the given [key].
644
  ///
645
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextOverflow],
646
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
647
  /// If the value is `null` and [defaultValue] is provided, [defaultValue] is returned.
648
  /// Otherwise, returns `null` if the value cannot be resolved.
649
  ///
650
  /// - [key]: The key to look up in the JSON map. Defaults to 'overflow'.
651
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved.
652
  ///
653
  /// Example:
654
  ///   textOverflow(key: 'myOverflow', defaultValue: TextOverflow.ellipsis)
655
  @preferInline
8✔
656
  TextOverflow? textOverflow({
657
    String key = FlutterPropertyKeys.textOverflow,
658
    TextOverflow defaultValue = TextOverflow.clip,
659
    Object? target,
660
    bool warmUp = false,
661
  }) {
662
    final value = _readProp(key, target, warmUp);
8✔
663

664
    if (value is TextOverflow) return value;
8✔
665

666
    if (value == null) return defaultValue;
667

668
    switch (value) {
669
      case String():
8✔
670
        if (envAttributeWarmUpEnabled) {
671
          if (warmUp) {
672
            return _textOverflowStringLookupTable[value];
4✔
673
          } else {
674
            return _json[key] = _textOverflowStringLookupTable[value];
×
675
          }
676
        } else {
677
          return _json[key] = _textOverflowStringLookupTable[value];
8✔
678
        }
679
      case int():
4✔
680
        if (envAttributeWarmUpEnabled) {
681
          if (warmUp) {
682
            return _textOverflowIntLookupTable[value];
×
683
          } else {
684
            return _json[key] = _textOverflowIntLookupTable[value];
×
685
          }
686
        } else {
687
          return _json[key] = _textOverflowIntLookupTable[value];
8✔
688
        }
689
      default:
690
        return defaultValue;
691
    }
692
  }
693

694
  /// Retrieves a [Clip] value from the JSON map for the given [key].
695
  ///
696
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Clip],
697
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
698
  /// If the value is `null`, returns [defaultValue].
699
  ///
700
  /// - [key]: The key to look up in the JSON map. Defaults to 'clipBehavior'.
701
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved.
702
  ///   Defaults to [Clip.hardEdge].
703
  ///
704
  /// Example:
705
  ///   clipBehavior(key: 'myClip', defaultValue: Clip.antiAlias)
706
  @preferInline
8✔
707
  Clip? clipBehavior({
708
    String key = FlutterPropertyKeys.clipBehavior,
709
    Clip defaultValue = Clip.hardEdge,
710
    Object? target,
711
    bool warmUp = false,
712
  }) {
713
    final value = _readProp(key, target, warmUp);
8✔
714

715
    if (value is Clip) return value;
8✔
716

717
    if (value == null) return defaultValue;
718

719
    switch (value) {
720
      case String():
8✔
721
        if (envAttributeWarmUpEnabled) {
722
          if (warmUp) {
723
            return _clipStringLookupTable[value];
4✔
724
          } else {
725
            return _json[key] = _clipStringLookupTable[value];
×
726
          }
727
        } else {
728
          return _json[key] = _clipStringLookupTable[value];
8✔
729
        }
730
      case int():
4✔
731
        if (envAttributeWarmUpEnabled) {
732
          if (warmUp) {
733
            return _clipIntLookupTable[value];
×
734
          } else {
735
            return _json[key] = _clipIntLookupTable[value];
×
736
          }
737
        } else {
738
          return _json[key] = _clipIntLookupTable[value];
8✔
739
        }
740
      default:
741
        return defaultValue;
742
    }
743
  }
744

745
  /// Creates a [Size] object from a map containing width and height values.
746
  ///
747
  /// The map should contain 'width' and 'height' keys with numeric values.
748
  /// If a value is not provided, it defaults to [double.infinity].
749
  ///
750
  /// - [map]: The map containing width and height values.
751
  /// Returns a [Size] object with the specified dimensions.
752
  @preferInline
4✔
753
  Size _sizeFromMap(Map<String, dynamic> map) {
754
    switch (map) {
755
      case {
756
          "width": num width,
8✔
757
          "height": num height,
8✔
758
        }:
759
        return Size(
4✔
760
          width.toDouble(),
4✔
761
          height.toDouble(),
4✔
762
        );
763
      case {
764
          "value": num value,
8✔
765
          "mainAxis": dynamic _,
4✔
766
        }:
767
        final axis = DuitDataSource(map).axis(key: "mainAxis");
8✔
768

769
        if (axis == Axis.horizontal) {
4✔
770
          return Size.fromWidth(value.toDouble());
8✔
771
        } else {
772
          return Size.fromHeight(value.toDouble());
8✔
773
        }
774
      default:
775
        return Size.zero;
776
    }
777
  }
778

779
  /// Creates a [Size] object from a list of numeric values.
780
  ///
781
  /// The list should contain exactly 2 elements representing width and height.
782
  ///
783
  /// - [list]: A list containing width and height values.
784
  /// Returns a [Size] object with the specified dimensions.
785
  @preferInline
4✔
786
  Size _sizeFromList(List<num> list) => Size(
4✔
787
        list[0].toDouble(),
8✔
788
        list[1].toDouble(),
8✔
789
      );
790

791
  /// Retrieves a [Size] value from the JSON map for the given [key].
792
  ///
793
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Size],
794
  /// it is returned as is. The value can be provided in several formats:
795
  /// - A map with 'width' and 'height' keys
796
  /// - A list of two numbers [width, height]
797
  /// - A single number (creates a square size)
798
  /// If the value is `null`, returns [defaultValue].
799
  ///
800
  /// - [key]: The key to look up in the JSON map.
801
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved.
802
  ///   Defaults to [Size.zero].
803
  ///
804
  /// Example:
805
  ///   size('dimensions', defaultValue: Size(100, 100))
806
  @preferInline
4✔
807
  Size size(
808
    String key, {
809
    Size defaultValue = Size.zero,
810
  }) {
811
    final value = _json[key];
4✔
812

813
    if (value is Size) return value;
4✔
814

815
    if (value == null) return defaultValue;
816

817
    switch (value) {
818
      case Map<String, dynamic>():
4✔
819
        return _json[key] = _sizeFromMap(value);
8✔
820
      case List<num>():
4✔
821
        return _json[key] = _sizeFromList(value);
8✔
822
      case double():
4✔
823
        return _json[key] = Size.square(value);
8✔
824
      default:
825
        return defaultValue;
826
    }
827
  }
828

829
  /// Creates an [EdgeInsets] object from a list of double values.
830
  ///
831
  /// The list should contain either 2 or 4 elements representing vertical and horizontal padding
832
  /// or left, top, right, and bottom padding.
833
  ///
834
  /// - [value]: A list containing padding values.
835
  /// Returns an [EdgeInsets] object with the specified padding.
836
  @preferInline
8✔
837
  EdgeInsets _edgeInsetsFromList(List<num> value) {
838
    return switch (value.length) {
8✔
839
      2 => EdgeInsets.symmetric(
12✔
840
          vertical: value[0].toDouble(),
8✔
841
          horizontal: value[1].toDouble(),
8✔
842
        ),
843
      4 => EdgeInsets.only(
16✔
844
          left: value[0].toDouble(),
16✔
845
          top: value[1].toDouble(),
16✔
846
          right: value[2].toDouble(),
16✔
847
          bottom: value[3].toDouble(),
16✔
848
        ),
849
      _ => EdgeInsets.zero
850
    };
851
  }
852

853
  /// Retrieves an [EdgeInsets] value from the JSON map for the given [key].
854
  ///
855
  /// Looks up the value associated with [key] in the JSON. If the value is already an [EdgeInsets],
856
  /// it is returned as is. The value can be provided in several formats:
857
  /// - A list of 2 or 4 numbers [vertical, horizontal] or [left, top, right, bottom]
858
  /// - A single number (creates a square padding)
859
  /// If the value is `null`, returns [defaultValue].
860
  @preferInline
8✔
861
  EdgeInsets? edgeInsets({
862
    String key = FlutterPropertyKeys.padding,
863
    EdgeInsets? defaultValue,
864
    Object? target,
865
    bool warmUp = false,
866
  }) {
867
    final value = _readProp(key, target, warmUp);
8✔
868

869
    if (value is EdgeInsets) return value;
8✔
870

871
    if (value == null) return defaultValue;
872

873
    switch (value) {
874
      case List():
8✔
875
        final lst = List<num>.from(value);
8✔
876
        if (envAttributeWarmUpEnabled) {
877
          if (warmUp) {
878
            return _edgeInsetsFromList(lst);
4✔
879
          } else {
880
            return _json[key] = _edgeInsetsFromList(lst);
×
881
          }
882
        } else {
883
          return _json[key] = _edgeInsetsFromList(lst);
8✔
884
        }
885
      case num():
8✔
886
        if (envAttributeWarmUpEnabled) {
887
          if (warmUp) {
888
            return EdgeInsets.all(value.toDouble());
8✔
889
          } else {
890
            return _json[key] = EdgeInsets.all(value.toDouble());
×
891
          }
892
        } else {
893
          return _json[key] = EdgeInsets.all(value.toDouble());
12✔
894
        }
895
      default:
896
        return defaultValue;
897
    }
898
  }
899

900
  /// Retrieves a [Curve] value from the JSON map for the given [key].
901
  ///
902
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Curve],
903
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
904
  /// If the value is `null`, returns [defaultValue].
905
  ///
906
  /// - [key]: The key to look up in the JSON map. Defaults to 'curve'.
907
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to Curves.linear.
908
  ///
909
  /// Example:
910
  ///   curve(key: 'myCurve', defaultValue: Curves.ease)
911
  ///
912
  @preferInline
8✔
913
  Curve? curve({
914
    String key = FlutterPropertyKeys.curve,
915
    Curve defaultValue = Curves.linear,
916
    Object? target,
917
    bool warmUp = false,
918
  }) {
919
    final value = _readProp(key, target, warmUp);
8✔
920

921
    if (value is Curve) return value;
8✔
922

923
    if (value == null) return defaultValue;
924

925
    switch (value) {
926
      case String():
8✔
927
        if (envAttributeWarmUpEnabled) {
928
          if (warmUp) {
929
            return _curveStringLookupTable[value];
4✔
930
          } else {
931
            return _json[key] = _curveStringLookupTable[value];
×
932
          }
933
        } else {
934
          return _json[key] = _curveStringLookupTable[value];
8✔
935
        }
936
      case int():
4✔
937
        if (envAttributeWarmUpEnabled) {
938
          if (warmUp) {
939
            return _curveIntLookupTable[value];
×
940
          } else {
941
            return _json[key] = _curveIntLookupTable[value];
×
942
          }
943
        } else {
944
          return _json[key] = _curveIntLookupTable[value];
8✔
945
        }
946
      case Map<String, dynamic>():
4✔
947
        if (envAttributeWarmUpEnabled) {
948
          if (warmUp) {
949
            return _customCurveFromMap(value);
×
950
          } else {
951
            return _json[key] = _customCurveFromMap(value);
×
952
          }
953
        } else {
954
          return _json[key] = _customCurveFromMap(value);
×
955
        }
956
      default:
957
        return defaultValue;
958
    }
959
  }
960

961
  @preferInline
×
962
  static Curve _customCurveFromMap(Map<String, dynamic> value) {
963
    final source = DuitDataSource(value);
×
964
    final type = source.tryGetString("type");
×
965

966
    if (type != null) {
967
      final parser = _customCurveStringLookupTable[type];
×
968
      if (parser != null) {
969
        return parser(source);
×
970
      } else {
971
        return Curves.linear;
972
      }
973
    } else {
974
      return Curves.linear;
975
    }
976
  }
977

978
  /// Retrieves a [TextBaseline] value from the JSON map for the given [key].
979
  ///
980
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextBaseline],
981
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
982
  /// If the value is `null`, returns [defaultValue].
983
  ///
984
  /// Unlike [textBaseline], this method does not store the parsed or existing [TextBaseline] back into the JSON map.
985
  ///
986
  /// - [key]: The key to look up in the JSON map. Defaults to 'textBaseline'.
987
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
988
  ///
989
  /// Returns:
990
  /// - A [TextBaseline] if the value is valid or can be converted.
991
  /// - [defaultValue] if the value is not a valid [TextBaseline] or cannot be converted.
992
  /// - `null` if both the value and [defaultValue] are null.
993
  ///
994
  /// Example:
995
  ///   tryTextBaseline(key: 'myBaseline', defaultValue: TextBaseline.alphabetic)
996

997
  @preferInline
8✔
998
  TextBaseline? textBaseline({
999
    String key = FlutterPropertyKeys.textBaseline,
1000
    TextBaseline? defaultValue,
1001
    Object? target,
1002
    bool warmUp = false,
1003
  }) {
1004
    final value = _readProp(key, target, warmUp);
8✔
1005

1006
    if (value is TextBaseline) return value;
8✔
1007

1008
    if (value == null) return defaultValue;
1009

1010
    switch (value) {
1011
      case String():
8✔
1012
        if (envAttributeWarmUpEnabled) {
1013
          if (warmUp) {
1014
            return _textBaselineStringLookupTable[value];
4✔
1015
          } else {
1016
            return _json[key] = _textBaselineStringLookupTable[value];
×
1017
          }
1018
        } else {
1019
          return _json[key] = _textBaselineStringLookupTable[value];
8✔
1020
        }
1021
      case int():
4✔
1022
        if (envAttributeWarmUpEnabled) {
1023
          if (warmUp) {
1024
            return _textBaselineIntLookupTable[value];
×
1025
          } else {
1026
            return _json[key] = _textBaselineIntLookupTable[value];
×
1027
          }
1028
        } else {
1029
          return _json[key] = _textBaselineIntLookupTable[value];
8✔
1030
        }
1031
      default:
1032
        return defaultValue;
1033
    }
1034
  }
1035

1036
  /// Retrieves a [TextWidthBasis] value from the JSON map for the given [key].
1037
  ///
1038
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextWidthBasis],
1039
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1040
  /// If the value is `null`, returns [defaultValue].
1041
  ///
1042
  /// - [key]: The key to look up in the JSON map. Defaults to 'textWidthBasis'.
1043
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to TextWidthBasis.parent.
1044
  ///
1045
  /// Example:
1046
  ///   textWidthBasis(key: 'myBasis', defaultValue: TextWidthBasis.longestLine)
1047
  @preferInline
8✔
1048
  TextWidthBasis? textWidthBasis({
1049
    String key = FlutterPropertyKeys.textWidthBasis,
1050
    TextWidthBasis defaultValue = TextWidthBasis.parent,
1051
    Object? target,
1052
    bool warmUp = false,
1053
  }) {
1054
    final value = _readProp(key, target, warmUp);
8✔
1055

1056
    if (value is TextWidthBasis) return value;
8✔
1057

1058
    if (value == null) return defaultValue;
1059

1060
    switch (value) {
1061
      case String():
8✔
1062
        if (envAttributeWarmUpEnabled) {
1063
          if (warmUp) {
1064
            return _textWidthBasisStringLookupTable[value];
4✔
1065
          } else {
1066
            return _json[key] = _textWidthBasisStringLookupTable[value];
×
1067
          }
1068
        } else {
1069
          return _json[key] = _textWidthBasisStringLookupTable[value];
8✔
1070
        }
1071

1072
      case int():
4✔
1073
        if (envAttributeWarmUpEnabled) {
1074
          if (warmUp) {
1075
            return _textWidthBasisIntLookupTable[value];
×
1076
          } else {
1077
            return _json[key] = _textWidthBasisIntLookupTable[value];
×
1078
          }
1079
        } else {
1080
          return _json[key] = _textWidthBasisIntLookupTable[value];
8✔
1081
        }
1082
      default:
1083
        return defaultValue;
1084
    }
1085
  }
1086

1087
  /// Retrieves a [TextStyle] value from the JSON map associated with the given [key].
1088
  ///
1089
  /// If the value associated with the [key] is already a [TextStyle], it returns that value.
1090
  /// If the value is a [Map<String, dynamic>], it attempts to parse it into a [TextStyle].
1091
  /// Otherwise, it returns [defaultValue].
1092
  ///
1093
  /// The parsed or existing [TextStyle] is also stored back into the JSON map at the given [key].
1094
  ///
1095
  /// Returns:
1096
  /// - A [TextStyle] if the value is valid or can be parsed.
1097
  /// - [defaultValue] if the value is not a valid [TextStyle] or cannot be parsed.
1098
  /// - `null` if both the value and [defaultValue] are null.
1099
  @preferInline
8✔
1100
  TextStyle? textStyle({
1101
    String key = FlutterPropertyKeys.style,
1102
    TextStyle? defaultValue,
1103
    Object? target,
1104
    bool warmUp = false,
1105
  }) {
1106
    final value = _readProp(key, target, warmUp);
8✔
1107

1108
    if (value is TextStyle) return value;
8✔
1109

1110
    if (value == null) return defaultValue;
1111

1112
    switch (value) {
1113
      case Map<String, dynamic>():
8✔
1114
        if (envAttributeWarmUpEnabled) {
1115
          if (warmUp) {
1116
            return _textStyleFromMap(value);
4✔
1117
          } else {
1118
            return _json[key] = _textStyleFromMap(value);
×
1119
          }
1120
        } else {
1121
          return _json[key] = _textStyleFromMap(value);
8✔
1122
        }
1123
      default:
1124
        return defaultValue;
1125
    }
1126
  }
1127

1128
  /// Parses a [TextStyle] from a JSON map.
1129
  ///
1130
  /// The map should contain the following keys:
1131
  /// - 'color': A color value.
1132
  /// - 'fontFamily': A font family string.
1133
  /// - 'fontWeight': A font weight value.
1134
  /// - 'fontSize': A font size value.
1135
  /// - 'fontStyle': A font style value.
1136
  /// - 'overflow': A text overflow value.
1137
  /// - 'textBaseline': A text baseline value.
1138
  /// - 'height': A text height value.
1139
  /// - 'letterSpacing': A letter spacing value.
1140
  /// - 'wordSpacing': A word spacing value.
1141
  /// - 'backgroundColor': A background color value.
1142
  /// - 'decoration': A text decoration value.
1143
  /// - 'decorationColor': A text decoration color value.
1144
  /// - 'decorationStyle': A text decoration style value.
1145
  /// - 'decorationThickness': A text decoration thickness value.
1146
  /// - 'debugLabel': A debug label value.
1147
  /// - 'package': A package value.
1148
  /// - 'leadingDistribution': A leading distribution value.
1149
  @preferInline
8✔
1150
  TextStyle _textStyleFromMap(Map<String, dynamic> data) {
1151
    final source = DuitDataSource(data);
8✔
1152
    return TextStyle(
8✔
1153
      color: source.tryParseColor(key: "color"),
8✔
1154
      fontFamily: source.tryGetString("fontFamily"),
8✔
1155
      fontWeight: source.fontWeight(),
8✔
1156
      fontSize: source.tryGetDouble(key: "fontSize"),
8✔
1157
      fontStyle: source.fontStyle(),
8✔
1158
      overflow: source.textOverflow(),
8✔
1159
      textBaseline: source.textBaseline(),
8✔
1160
      height: source.tryGetDouble(key: "height"),
8✔
1161
      letterSpacing: source.tryGetDouble(key: "letterSpacing"),
8✔
1162
      wordSpacing: source.tryGetDouble(key: "wordSpacing"),
8✔
1163
      backgroundColor: source.tryParseColor(key: "backgroundColor"),
8✔
1164
      decoration: source.textDecoration(),
8✔
1165
      decorationColor: source.tryParseColor(key: "decorationColor"),
8✔
1166
      decorationStyle: source.textDecorationStyle(),
8✔
1167
      decorationThickness: source.tryGetDouble(key: "decorationThickness"),
8✔
1168
      debugLabel: source.tryGetString("debugLabel"),
8✔
1169
      package: source.tryGetString("package"),
8✔
1170
      leadingDistribution: source.textLeadingDistribution(),
8✔
1171
    );
1172
  }
1173

1174
  /// Parses a [Gradient] from a JSON map.
1175
  ///
1176
  /// The map should contain the following keys:
1177
  /// - 'colors': A list of color values.
1178
  /// - 'stops': A list of stop values.
1179
  /// - 'begin': An alignment value.
1180
  /// - 'end': An alignment value.
1181
  @preferInline
8✔
1182
  Gradient? _gradientFromMap(Map<String, dynamic>? data) {
1183
    if (data == null) return null;
1184

1185
    final source = DuitDataSource(data);
4✔
1186

1187
    final List? colors = source["colors"];
4✔
1188
    if (colors == null) return null;
1189

1190
    final dColors = <Color>[];
4✔
1191

1192
    for (var color in colors) {
8✔
1193
      dColors.add(_parseColor(color) ?? Colors.transparent);
8✔
1194
    }
1195

1196
    final angle = source.tryGetDouble(key: "rotationAngle");
4✔
1197

1198
    return LinearGradient(
4✔
1199
      colors: dColors,
1200
      stops: source["stops"],
4✔
1201
      begin:
1202
          source.alignment(key: "begin", defaultValue: Alignment.centerLeft)!,
4✔
1203
      end: source.alignment(key: "end", defaultValue: Alignment.centerRight)!,
4✔
1204
      transform: angle != null ? GradientRotation(angle) : null,
4✔
1205
    );
1206
  }
1207

1208
  /// Parses a [BoxShadow] from a JSON map.
1209
  ///
1210
  /// The map should contain the following keys:
1211
  /// - 'color': A color value.
1212
  /// - 'offset': An offset value.
1213
  /// - 'blurRadius': A blur radius value.
1214
  /// - 'spreadRadius': A spread radius value.
1215
  @preferInline
14✔
1216
  BoxShadow _boxShadowFromMap(json) {
6✔
1217
    final source = DuitDataSource(json);
8✔
1218
    return BoxShadow(
8✔
1219
      color: source.parseColor(key: "color"),
8✔
1220
      offset: source.offset(defaultValue: Offset.zero)!,
8✔
1221
      blurRadius: source.getDouble(key: "blurRadius"),
8✔
1222
      spreadRadius: source.getDouble(key: "spreadRadius"),
8✔
1223
    );
1224
  }
1225

1226
  /// Parses an [Offset] from a JSON map.
1227
  ///
1228
  /// The map should contain the following keys:
1229
  /// - 'dx': An x-axis offset value.
1230
  /// - 'dy': A y-axis offset value.
1231
  @preferInline
8✔
1232
  Offset _offsetFromMap(Map<String, dynamic> map) {
1233
    final source = DuitDataSource(map);
8✔
1234
    return Offset(
8✔
1235
      source.getDouble(key: "dx"),
8✔
1236
      source.getDouble(key: "dy"),
8✔
1237
    );
1238
  }
1239

1240
  /// Retrieves an [Offset] value from the JSON map for the given [key].
1241
  ///
1242
  /// Looks up the value associated with [key] in the JSON. If the value is already an [Offset],
1243
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into an [Offset].
1244
  /// Otherwise, it returns [defaultValue].
1245
  ///
1246
  /// - [key]: The key to look up in the JSON map. Defaults to 'offset'.
1247
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1248
  ///
1249
  /// Returns:
1250
  /// - An [Offset] if the value is valid or can be parsed.
1251
  /// - [defaultValue] if the value is not a valid [Offset] or cannot be parsed.
1252
  /// - `null` if both the value and [defaultValue] are null.
1253
  @preferInline
8✔
1254
  Offset? offset({
1255
    String key = FlutterPropertyKeys.offset,
1256
    Offset? defaultValue,
1257
    Object? target,
1258
    bool warmUp = false,
1259
  }) {
1260
    final value = _readProp(key, target, warmUp);
8✔
1261

1262
    if (value is Offset) return value;
8✔
1263

1264
    if (value == null) return defaultValue;
1265

1266
    switch (value) {
1267
      case Map<String, dynamic>():
8✔
1268
        if (envAttributeWarmUpEnabled) {
1269
          if (warmUp) {
1270
            return _offsetFromMap(value);
4✔
1271
          } else {
1272
            return _json[key] = _offsetFromMap(value);
×
1273
          }
1274
        } else {
1275
          return _json[key] = _offsetFromMap(value);
8✔
1276
        }
1277
      default:
1278
        return defaultValue;
1279
    }
1280
  }
1281

1282
  /// Retrieves a list of [BoxShadow] values from the JSON map for the given [key].
1283
  ///
1284
  /// Looks up the value associated with [key] in the JSON. If the value is already a [List<BoxShadow>],
1285
  /// it is returned as is. If the value is a [List], it attempts to parse it into a list of [BoxShadow].
1286
  /// Otherwise, it returns [defaultValue].
1287
  ///
1288
  /// - [key]: The key to look up in the JSON map. Defaults to 'boxShadow'.
1289
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1290
  ///
1291
  /// Returns:
1292
  /// - A list of [BoxShadow] if the value is valid or can be parsed.
1293
  /// - [defaultValue] if the value is not a valid list of [BoxShadow] or cannot be parsed.
1294
  /// - `null` if both the value and [defaultValue] are null.
1295
  ///
1296
  @preferInline
8✔
1297
  List<BoxShadow>? boxShadow({
1298
    String key = FlutterPropertyKeys.boxShadow,
1299
    List<BoxShadow>? defaultValue,
1300
    Object? target,
1301
    bool warmUp = false,
1302
  }) {
1303
    final value = _readProp(key, target, warmUp);
8✔
1304

1305
    if (value is List<BoxShadow>) return value;
8✔
1306

1307
    if (value == null) return defaultValue;
1308

1309
    switch (value) {
1310
      case List():
8✔
1311
        if (envAttributeWarmUpEnabled) {
1312
          if (warmUp) {
1313
            return value.map<BoxShadow>(_boxShadowFromMap).toList();
12✔
1314
          } else {
1315
            return _json[key] =
×
1316
                value.map<BoxShadow>(_boxShadowFromMap).toList();
×
1317
          }
1318
        } else {
1319
          return _json[key] = value.map<BoxShadow>(_boxShadowFromMap).toList();
16✔
1320
        }
1321
      default:
1322
        return defaultValue;
1323
    }
1324
  }
1325

1326
  /// Parses a [Decoration] from a JSON map.
1327
  ///
1328
  /// The map should contain the following keys:
1329
  /// - 'color': A color value.
1330
  /// - 'borderRadius': A border radius value.
1331
  /// - 'border': A border value.
1332
  /// - 'gradient': A gradient value.
1333
  /// - 'boxShadow': A list of box shadow values.
1334
  @preferInline
8✔
1335
  Decoration _decorationFromMap(Map<String, dynamic> data) {
1336
    final source = DuitDataSource(data);
8✔
1337
    return BoxDecoration(
8✔
1338
      color: source.tryParseColor(key: "color"),
8✔
1339
      borderRadius: source.borderRadius(),
8✔
1340
      border: source.border(),
8✔
1341
      gradient: _gradientFromMap(source["gradient"]),
16✔
1342
      boxShadow: source.boxShadow(),
8✔
1343
    );
1344
  }
1345

1346
  /// Retrieves a [Decoration] value from the JSON map for the given [key].
1347
  ///
1348
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Decoration],
1349
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [Decoration].
1350
  /// Otherwise, it returns [defaultValue].
1351
  ///
1352
  /// - [key]: The key to look up in the JSON map. Defaults to 'decoration'.
1353
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1354
  ///
1355
  /// Returns:
1356
  /// - A [Decoration] if the value is valid or can be parsed.
1357
  /// - [defaultValue] if the value is not a valid [Decoration] or cannot be parsed.
1358
  /// - `null` if both the value and [defaultValue] are null.
1359
  @preferInline
8✔
1360
  Decoration? decoration({
1361
    String key = FlutterPropertyKeys.decoration,
1362
    Decoration? defaultValue,
1363
    Object? target,
1364
    bool warmUp = false,
1365
  }) {
1366
    final value = _readProp(key, target, warmUp);
8✔
1367

1368
    if (value is Decoration) return value;
8✔
1369

1370
    if (value == null) return defaultValue;
1371

1372
    switch (value) {
1373
      case Map<String, dynamic>():
8✔
1374
        if (envAttributeWarmUpEnabled) {
1375
          if (warmUp) {
1376
            return _decorationFromMap(value);
4✔
1377
          } else {
1378
            return _json[key] = _decorationFromMap(value);
×
1379
          }
1380
        } else {
1381
          return _json[key] = _decorationFromMap(value);
8✔
1382
        }
1383
      default:
1384
        return defaultValue;
1385
    }
1386
  }
1387

1388
  /// Retrieves a [TextDecoration] value from the JSON map for the given [key].
1389
  ///
1390
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextDecoration],
1391
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1392
  /// Otherwise, it returns [defaultValue].
1393
  ///
1394
  /// - [key]: The key to look up in the JSON map. Defaults to 'decoration'.
1395
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1396
  ///
1397
  /// Returns:
1398
  /// - A [TextDecoration] if the value is valid or can be parsed.
1399
  /// - [defaultValue] if the value is not a valid [TextDecoration] or cannot be parsed.
1400
  /// - `null` if both the value and [defaultValue] are null.
1401
  @preferInline
8✔
1402
  TextDecoration? textDecoration({
1403
    String key = FlutterPropertyKeys.decoration,
1404
    TextDecoration? defaultValue,
1405
    Object? target,
1406
    bool warmUp = false,
1407
  }) {
1408
    final value = _readProp(key, target, warmUp);
8✔
1409

1410
    if (value is TextDecoration) return value;
8✔
1411

1412
    if (value == null) return defaultValue;
1413

1414
    switch (value) {
1415
      case String():
8✔
1416
        if (envAttributeWarmUpEnabled) {
1417
          if (warmUp) {
1418
            return _textDecorationStringLookupTable[value];
4✔
1419
          } else {
1420
            return _json[key] = _textDecorationStringLookupTable[value];
×
1421
          }
1422
        } else {
1423
          return _json[key] = _textDecorationStringLookupTable[value];
8✔
1424
        }
1425
      case int():
4✔
1426
        if (envAttributeWarmUpEnabled) {
1427
          if (warmUp) {
1428
            return _textDecorationIntLookupTable[value];
×
1429
          } else {
1430
            return _json[key] = _textDecorationIntLookupTable[value];
×
1431
          }
1432
        } else {
1433
          return _json[key] = _textDecorationIntLookupTable[value];
8✔
1434
        }
1435
      default:
1436
        return defaultValue;
1437
    }
1438
  }
1439

1440
  /// Retrieves a [TextDecorationStyle] value from the JSON map for the given [key].
1441
  ///
1442
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextDecorationStyle],
1443
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1444
  /// Otherwise, it returns [defaultValue].
1445
  ///
1446
  /// - [key]: The key to look up in the JSON map. Defaults to 'decorationStyle'.
1447
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1448
  ///
1449
  /// Returns:
1450
  /// - A [TextDecorationStyle] if the value is valid or can be parsed.
1451
  /// - [defaultValue] if the value is not a valid [TextDecorationStyle] or cannot be parsed.
1452
  /// - `null` if both the value and [defaultValue] are null.
1453
  @preferInline
8✔
1454
  TextDecorationStyle? textDecorationStyle({
1455
    String key = FlutterPropertyKeys.decorationStyle,
1456
    TextDecorationStyle? defaultValue,
1457
    Object? target,
1458
    bool warmUp = false,
1459
  }) {
1460
    final value = _readProp(key, target, warmUp);
8✔
1461

1462
    if (value is TextDecorationStyle) return value;
8✔
1463

1464
    if (value == null) return defaultValue;
1465

1466
    switch (value) {
1467
      case int():
8✔
1468
        if (envAttributeWarmUpEnabled) {
1469
          if (warmUp) {
1470
            return _textDecorationStyleIntLookupTable[value];
×
1471
          } else {
1472
            return _json[key] = _textDecorationStyleIntLookupTable[value];
×
1473
          }
1474
        } else {
1475
          return _json[key] = _textDecorationStyleIntLookupTable[value];
8✔
1476
        }
1477
      case String():
8✔
1478
        if (envAttributeWarmUpEnabled) {
1479
          if (warmUp) {
1480
            return _textDecorationStyleStringLookupTable[value];
4✔
1481
          } else {
1482
            return _json[key] = _textDecorationStyleStringLookupTable[value];
×
1483
          }
1484
        } else {
1485
          return _json[key] = _textDecorationStyleStringLookupTable[value];
8✔
1486
        }
1487
      default:
1488
        return defaultValue;
1489
    }
1490
  }
1491

1492
  /// Retrieves a [FontWeight] value from the JSON map for the given [key].
1493
  ///
1494
  /// Looks up the value associated with [key] in the JSON. If the value is already a [FontWeight],
1495
  /// it is returned as is. If the value is an [int], it is converted using the lookup tables.
1496
  /// Otherwise, it returns [defaultValue].
1497
  ///
1498
  /// - [key]: The key to look up in the JSON map. Defaults to 'fontWeight'.
1499
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1500
  ///
1501
  /// Returns:
1502
  /// - A [FontWeight] if the value is valid or can be parsed.
1503
  /// - [defaultValue] if the value is not a valid [FontWeight] or cannot be parsed.
1504
  /// - `null` if both the value and [defaultValue] are null.
1505
  @preferInline
8✔
1506
  FontWeight? fontWeight({
1507
    String key = FlutterPropertyKeys.fontWeight,
1508
    FontWeight? defaultValue,
1509
    Object? target,
1510
    bool warmUp = false,
1511
  }) {
1512
    final value = _readProp(key, target, warmUp);
8✔
1513

1514
    if (value is FontWeight) return value;
8✔
1515

1516
    if (value == null) return defaultValue;
1517

1518
    switch (value) {
1519
      case int():
8✔
1520
        if (envAttributeWarmUpEnabled) {
1521
          if (warmUp) {
1522
            return _fontWeightLookupTable[value];
4✔
1523
          } else {
1524
            return _json[key] = _fontWeightLookupTable[value];
×
1525
          }
1526
        } else {
1527
          return _json[key] = _fontWeightLookupTable[value];
8✔
1528
        }
1529
      default:
1530
        return defaultValue;
1531
    }
1532
  }
1533

1534
  @preferInline
8✔
1535
  FontStyle? fontStyle({
1536
    String key = FlutterPropertyKeys.fontStyle,
1537
    FontStyle? defaultValue,
1538
    Object? target,
1539
    bool warmUp = false,
1540
  }) {
1541
    dynamic value;
1542
    if (envAttributeWarmUpEnabled) {
1543
      if (warmUp) {
1544
        value = target;
1545
      } else {
1546
        value = _json[key];
4✔
1547
      }
1548
    } else {
1549
      value = _json[key];
4✔
1550
    }
1551

1552
    if (value is FontStyle) return value;
8✔
1553

1554
    if (value == null) return defaultValue;
1555

1556
    switch (value) {
1557
      case String():
8✔
1558
        if (envAttributeWarmUpEnabled) {
1559
          if (warmUp) {
1560
            return _fontStyleStringLookupTable[value];
4✔
1561
          } else {
1562
            return _json[key] = _fontStyleStringLookupTable[value];
×
1563
          }
1564
        } else {
1565
          return _json[key] = _fontStyleStringLookupTable[value];
8✔
1566
        }
1567
      case int():
4✔
1568
        if (envAttributeWarmUpEnabled) {
1569
          if (warmUp) {
1570
            return _fontStyleIntLookupTable[value];
×
1571
          } else {
1572
            return _json[key] = _fontStyleIntLookupTable[value];
×
1573
          }
1574
        } else {
1575
          return _json[key] = _fontStyleIntLookupTable[value];
8✔
1576
        }
1577
      default:
1578
        return defaultValue;
1579
    }
1580
  }
1581

1582
  /// Parses a [TextSpan] from a JSON map.
1583
  ///
1584
  /// The map should contain the following keys:
1585
  /// - 'text': A text string.
1586
  /// - 'children': A list of text span values.
1587
  /// - 'style': A text style value.
1588
  /// - 'spellOut': A boolean value.
1589
  /// - 'semanticsLabel': A semantics label value.
1590
  @preferInline
8✔
1591
  TextSpan _textSpanFromMap(Map<String, dynamic> value) {
1592
    final source = DuitDataSource(value);
8✔
1593
    final List? children = value["children"];
8✔
1594
    final spanChildren = <InlineSpan>[];
8✔
1595

1596
    if (children != null) {
1597
      for (final child in children) {
8✔
1598
        spanChildren.add(_textSpanFromMap(child));
8✔
1599
      }
1600
    }
1601

1602
    return TextSpan(
8✔
1603
      text: source.tryGetString("text"),
8✔
1604
      children: spanChildren.isNotEmpty ? spanChildren : null,
8✔
1605
      style: source.textStyle(),
8✔
1606
      spellOut: source.tryGetBool("spellOut"),
8✔
1607
      semanticsLabel: source.tryGetString("semanticsLabel"),
8✔
1608
    );
1609
  }
1610

1611
  /// Retrieves a [TextSpan] value from the JSON map for the given [key].
1612
  ///
1613
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextSpan],
1614
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [TextSpan].
1615
  /// Otherwise, it returns [defaultValue].
1616
  ///
1617
  /// - [key]: The key to look up in the JSON map. Defaults to 'textSpan'.
1618
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to a default [TextSpan].
1619
  ///
1620
  /// Returns:
1621
  /// - A [TextSpan] if the value is valid or can be parsed.
1622
  /// - [defaultValue] if the value is not a valid [TextSpan] or cannot be parsed.
1623
  /// - `null` if both the value and [defaultValue] are null.
1624
  @preferInline
8✔
1625
  TextSpan textSpan({
1626
    String key = FlutterPropertyKeys.textSpan,
1627
    TextSpan defaultValue = const TextSpan(),
1628
    Object? target,
1629
    bool warmUp = false,
1630
  }) {
1631
    final value = _readProp(key, target, warmUp);
8✔
1632

1633
    if (value is TextSpan) {
8✔
1634
      return value;
1635
    }
1636

1637
    if (value == null) return defaultValue;
1638

1639
    switch (value) {
1640
      case Map<String, dynamic>():
8✔
1641
        if (envAttributeWarmUpEnabled) {
1642
          if (warmUp) {
1643
            return _textSpanFromMap(value);
4✔
1644
          } else {
1645
            return _json[key] = _textSpanFromMap(value);
×
1646
          }
1647
        } else {
1648
          return _json[key] = _textSpanFromMap(value);
8✔
1649
        }
1650
      default:
1651
        return defaultValue;
1652
    }
1653
  }
1654

1655
  /// Parses a [TextHeightBehavior] from a JSON map.
1656
  ///
1657
  /// The map should contain the following keys:
1658
  /// - 'applyHeightToFirstAscent': A boolean value.
1659
  /// - 'applyHeightToLastDescent': A boolean value.
1660
  /// - 'leadingDistribution': A leading distribution value.
1661
  @preferInline
8✔
1662
  TextHeightBehavior? _textHeightBehaviorFromMap(Map<String, dynamic> data) {
1663
    final source = DuitDataSource(data);
8✔
1664
    return TextHeightBehavior(
8✔
1665
      applyHeightToFirstAscent: source.getBool(
8✔
1666
        "applyHeightToFirstAscent",
1667
        defaultValue: true,
1668
      ),
1669
      applyHeightToLastDescent: source.getBool(
8✔
1670
        "applyHeightToLastDescent",
1671
        defaultValue: true,
1672
      ),
1673
      leadingDistribution: source.textLeadingDistribution(
8✔
1674
        defaultValue: TextLeadingDistribution.proportional,
1675
      )!,
1676
    );
1677
  }
1678

1679
  /// Retrieves a [TextHeightBehavior] value from the JSON map for the given [key].
1680
  ///
1681
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextHeightBehavior],
1682
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [TextHeightBehavior].
1683
  /// Otherwise, it returns [defaultValue].
1684
  ///
1685
  /// - [key]: The key to look up in the JSON map. Defaults to 'textHeightBehavior'.
1686
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1687
  ///
1688
  /// Returns:
1689
  /// - A [TextHeightBehavior] if the value is valid or can be parsed.
1690
  /// - [defaultValue] if the value is not a valid [TextHeightBehavior] or cannot be parsed.
1691
  /// - `null` if both the value and [defaultValue] are null.
1692
  @preferInline
8✔
1693
  TextHeightBehavior? textHeightBehavior({
1694
    String key = "textHeightBehavior",
1695
    TextHeightBehavior? defaultValue,
1696
    Object? target,
1697
    bool warmUp = false,
1698
  }) {
1699
    final value = _readProp(key, target, warmUp);
8✔
1700

1701
    if (value is TextHeightBehavior) return value;
8✔
1702

1703
    if (value == null) return defaultValue;
1704

1705
    switch (value) {
1706
      case Map<String, dynamic>():
8✔
1707
        if (envAttributeWarmUpEnabled) {
1708
          if (warmUp) {
1709
            return _textHeightBehaviorFromMap(value);
4✔
1710
          } else {
1711
            return _json[key] = _textHeightBehaviorFromMap(value);
×
1712
          }
1713
        } else {
1714
          return _json[key] = _textHeightBehaviorFromMap(value);
8✔
1715
        }
1716
      default:
1717
        return defaultValue;
1718
    }
1719
  }
1720

1721
  /// Parses a [TextScaler] from a JSON map.
1722
  ///
1723
  /// The map should contain the following keys:
1724
  /// - 'textScaleFactor': A double value.
1725
  @preferInline
4✔
1726
  TextScaler _textScalerFromMap(Map<String, dynamic> data) {
1727
    final source = DuitDataSource(data);
4✔
1728
    return TextScaler.linear(
4✔
1729
      source.getDouble(
4✔
1730
        key: "textScaleFactor",
1731
        defaultValue: 1.0,
1732
      ),
1733
    );
1734
  }
1735

1736
  /// Retrieves a [TextScaler] value from the JSON map for the given [key].
1737
  ///
1738
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextScaler],
1739
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [TextScaler].
1740
  /// Otherwise, it returns [defaultValue].
1741
  ///
1742
  /// - [key]: The key to look up in the JSON map. Defaults to 'textScaler'.
1743
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to TextScaler.noScaling.
1744
  ///
1745
  /// Returns:
1746
  /// - A [TextScaler] if the value is valid or can be parsed.
1747
  /// - [defaultValue] if the value is not a valid [TextScaler] or cannot be parsed.
1748
  /// - `null` if both the value and [defaultValue] are null.
1749
  @preferInline
8✔
1750
  TextScaler textScaler({
1751
    String key = FlutterPropertyKeys.textScaler,
1752
    TextScaler defaultValue = TextScaler.noScaling,
1753
    Object? target,
1754
    bool warmUp = false,
1755
  }) {
1756
    final value = _readProp(key, target, warmUp);
8✔
1757

1758
    if (value is TextScaler) return value;
8✔
1759

1760
    if (value == null) return defaultValue;
1761

1762
    switch (value) {
1763
      case Map<String, dynamic>():
8✔
1764
        if (envAttributeWarmUpEnabled) {
1765
          if (warmUp) {
1766
            return _textScalerFromMap(value);
×
1767
          } else {
1768
            return _json[key] = _textScalerFromMap(value);
×
1769
          }
1770
        } else {
1771
          return _json[key] = _textScalerFromMap(value);
8✔
1772
        }
1773
      case double():
8✔
1774
        if (envAttributeWarmUpEnabled) {
1775
          if (warmUp) {
1776
            return TextScaler.linear(value);
4✔
1777
          } else {
1778
            return _json[key] = TextScaler.linear(value);
×
1779
          }
1780
        } else {
1781
          return _json[key] = TextScaler.linear(value);
8✔
1782
        }
1783
      default:
1784
        return defaultValue;
1785
    }
1786
  }
1787

1788
  /// Parses a [StrutStyle] from a JSON map.
1789
  ///
1790
  /// The map should contain the following keys:
1791
  /// - 'fontSize': A double value.
1792
  /// - 'height': A double value.
1793
  /// - 'leading': A double value.
1794
  /// - 'fontWeight': A font weight value.
1795
  /// - 'fontFamily': A font family string.
1796
  /// - 'fontStyle': A font style value.
1797
  /// - 'forceStrutHeight': A boolean value.
1798
  /// - 'debugLabel': A debug label value.
1799
  /// - 'leadingDistribution': A leading distribution value.
1800
  @preferInline
8✔
1801
  StrutStyle _strutStyleFromMap(Map<String, dynamic> data) {
1802
    final jsosource = DuitDataSource(data);
8✔
1803
    return StrutStyle(
8✔
1804
      fontSize: jsosource.tryGetDouble(key: "fontSize"),
8✔
1805
      height: jsosource.tryGetDouble(key: "height"),
8✔
1806
      leading: jsosource.tryGetDouble(key: "leading"),
8✔
1807
      fontWeight: jsosource.fontWeight(),
8✔
1808
      fontFamily: jsosource.tryGetString("fontFamily"),
8✔
1809
      fontStyle: jsosource.fontStyle(),
8✔
1810
      forceStrutHeight: jsosource.tryGetBool("forceStrutHeight"),
8✔
1811
      debugLabel: jsosource.tryGetString("debugLabel"),
8✔
1812
      leadingDistribution: jsosource.textLeadingDistribution(),
8✔
1813
    );
1814
  }
1815

1816
  /// Retrieves a [StrutStyle] value from the JSON map for the given [key].
1817
  ///
1818
  /// Looks up the value associated with [key] in the JSON. If the value is already a [StrutStyle],
1819
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [StrutStyle].
1820
  /// Otherwise, it returns [defaultValue].
1821
  ///
1822
  /// - [key]: The key to look up in the JSON map. Defaults to 'strutStyle'.
1823
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1824
  ///
1825
  /// Returns:
1826
  /// - A [StrutStyle] if the value is valid or can be parsed.
1827
  /// - [defaultValue] if the value is not a valid [StrutStyle] or cannot be parsed.
1828
  /// - `null` if both the value and [defaultValue] are null.
1829
  @preferInline
8✔
1830
  StrutStyle? strutStyle({
1831
    String key = FlutterPropertyKeys.strutStyle,
1832
    StrutStyle? defaultValue,
1833
    Object? target,
1834
    bool warmUp = false,
1835
  }) {
1836
    final value = _readProp(key, target, warmUp);
8✔
1837

1838
    if (value is StrutStyle) return value;
8✔
1839

1840
    if (value == null) return defaultValue;
1841

1842
    switch (value) {
1843
      case Map<String, dynamic>():
8✔
1844
        if (envAttributeWarmUpEnabled) {
1845
          if (warmUp) {
1846
            return _strutStyleFromMap(value);
4✔
1847
          } else {
1848
            return _json[key] = _strutStyleFromMap(value);
×
1849
          }
1850
        } else {
1851
          return _json[key] = _strutStyleFromMap(value);
8✔
1852
        }
1853
      default:
1854
        return defaultValue;
1855
    }
1856
  }
1857

1858
  /// Retrieves a [TextLeadingDistribution] value from the JSON map for the given [key].
1859
  ///
1860
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TextLeadingDistribution],
1861
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1862
  /// Otherwise, it returns [defaultValue].
1863
  ///
1864
  /// - [key]: The key to look up in the JSON map. Defaults to 'leadingDistribution'.
1865
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1866
  ///
1867
  /// Returns:
1868
  /// - A [TextLeadingDistribution] if the value is valid or can be parsed.
1869
  /// - [defaultValue] if the value is not a valid [TextLeadingDistribution] or cannot be parsed.
1870
  /// - `null` if both the value and [defaultValue] are null.
1871
  @preferInline
8✔
1872
  TextLeadingDistribution? textLeadingDistribution({
1873
    String key = FlutterPropertyKeys.leadingDistribution,
1874
    TextLeadingDistribution? defaultValue,
1875
    Object? target,
1876
    bool warmUp = false,
1877
  }) {
1878
    final value = _readProp(key, target, warmUp);
8✔
1879

1880
    if (value is TextLeadingDistribution) return value;
8✔
1881

1882
    if (value == null) return defaultValue;
1883

1884
    switch (value) {
1885
      case String():
8✔
1886
        if (envAttributeWarmUpEnabled) {
1887
          if (warmUp) {
1888
            return _leadingDistributionStringLookupTable[value];
4✔
1889
          } else {
1890
            return _json[key] = _leadingDistributionStringLookupTable[value];
×
1891
          }
1892
        } else {
1893
          return _json[key] = _leadingDistributionStringLookupTable[value];
8✔
1894
        }
1895
      case int():
4✔
1896
        if (envAttributeWarmUpEnabled) {
1897
          if (warmUp) {
1898
            return _leadingDistributionIntLookupTable[value];
×
1899
          } else {
1900
            return _json[key] = _leadingDistributionIntLookupTable[value];
×
1901
          }
1902
        } else {
1903
          return _json[key] = _leadingDistributionIntLookupTable[value];
8✔
1904
        }
1905
      default:
1906
        return defaultValue;
1907
    }
1908
  }
1909

1910
  /// Retrieves an [Axis] value from the JSON map for the given [key].
1911
  ///
1912
  /// Looks up the value associated with [key] in the JSON. If the value is already an [Axis],
1913
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1914
  /// Otherwise, it returns [defaultValue].
1915
  ///
1916
  /// - [key]: The key to look up in the JSON map. Defaults to 'scrollDirection'.
1917
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to Axis.vertical.
1918
  ///
1919
  /// Returns:
1920
  /// - An [Axis] if the value is valid or can be parsed.
1921
  /// - [defaultValue] if the value is not a valid [Axis] or cannot be parsed.
1922
  @preferInline
8✔
1923
  Axis axis({
1924
    String key = FlutterPropertyKeys.scrollDirection,
1925
    Axis defaultValue = Axis.vertical,
1926
    Object? target,
1927
    bool warmUp = false,
1928
  }) {
1929
    final value = _readProp(key, target, warmUp);
8✔
1930

1931
    if (value is Axis) return value;
8✔
1932

1933
    if (value == null) return defaultValue;
1934

1935
    switch (value) {
1936
      case String():
8✔
1937
        if (envAttributeWarmUpEnabled) {
1938
          if (warmUp) {
1939
            return _axisStringLookupTable[value]!;
4✔
1940
          } else {
1941
            return _json[key] = _axisStringLookupTable[value]!;
×
1942
          }
1943
        } else {
1944
          return _json[key] = _axisStringLookupTable[value]!;
8✔
1945
        }
1946
      case int():
4✔
1947
        if (envAttributeWarmUpEnabled) {
1948
          if (warmUp) {
1949
            return _axisIntLookupTable[value]!;
×
1950
          } else {
1951
            return _json[key] = _axisIntLookupTable[value]!;
×
1952
          }
1953
        } else {
1954
          return _json[key] = _axisIntLookupTable[value]!;
8✔
1955
        }
1956
      default:
1957
        return defaultValue;
1958
    }
1959
  }
1960

1961
  /// Retrieves a [WrapCrossAlignment] value from the JSON map for the given [key].
1962
  ///
1963
  /// Looks up the value associated with [key] in the JSON. If the value is already a [WrapCrossAlignment],
1964
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
1965
  /// Otherwise, it returns [defaultValue].
1966
  ///
1967
  /// - [key]: The key to look up in the JSON map. Defaults to 'crossAxisAlignment'.
1968
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
1969
  ///
1970
  /// Returns:
1971
  /// - A [WrapCrossAlignment] if the value is valid or can be parsed.
1972
  /// - [defaultValue] if the value is not a valid [WrapCrossAlignment] or cannot be parsed.
1973
  /// - `null` if both the value and [defaultValue] are null.
1974
  @preferInline
8✔
1975
  WrapCrossAlignment? wrapCrossAlignment({
1976
    String key = FlutterPropertyKeys.wrapCrossAlignment,
1977
    WrapCrossAlignment? defaultValue,
1978
    Object? target,
1979
    bool warmUp = false,
1980
  }) {
1981
    final value = _readProp(key, target, warmUp);
8✔
1982

1983
    if (value is WrapCrossAlignment) return value;
8✔
1984

1985
    if (value == null) return defaultValue;
1986

1987
    switch (value) {
1988
      case String():
8✔
1989
        if (envAttributeWarmUpEnabled) {
1990
          if (warmUp) {
1991
            return _wrapCrossAlignmentStringLookupTable[value];
4✔
1992
          } else {
1993
            return _json[key] = _wrapCrossAlignmentStringLookupTable[value];
×
1994
          }
1995
        } else {
1996
          return _json[key] = _wrapCrossAlignmentStringLookupTable[value];
8✔
1997
        }
1998
      case int():
4✔
1999
        if (envAttributeWarmUpEnabled) {
2000
          if (warmUp) {
2001
            return _wrapCrossAlignmentIntLookupTable[value];
×
2002
          } else {
2003
            return _json[key] = _wrapCrossAlignmentIntLookupTable[value];
×
2004
          }
2005
        } else {
2006
          return _json[key] = _wrapCrossAlignmentIntLookupTable[value];
8✔
2007
        }
2008
      default:
2009
        return defaultValue;
2010
    }
2011
  }
2012

2013
  @preferInline
8✔
2014
  WrapAlignment? wrapAlignment({
2015
    String key = FlutterPropertyKeys.wrapAlignment,
2016
    WrapAlignment? defaultValue,
2017
    Object? target,
2018
    bool warmUp = false,
2019
  }) {
2020
    final value = _readProp(key, target, warmUp);
8✔
2021

2022
    if (value is WrapAlignment) return value;
8✔
2023

2024
    if (value == null) return defaultValue;
2025

2026
    switch (value) {
2027
      case String():
8✔
2028
        if (envAttributeWarmUpEnabled) {
2029
          if (warmUp) {
2030
            return _wrapAlignmentStringLookupTable[value];
4✔
2031
          } else {
2032
            return _json[key] = _wrapAlignmentStringLookupTable[value];
×
2033
          }
2034
        } else {
2035
          return _json[key] = _wrapAlignmentStringLookupTable[value];
8✔
2036
        }
2037
      case int():
4✔
2038
        return _json[key] = _wrapAlignmentIntLookupTable[value];
8✔
2039
      default:
2040
        return defaultValue;
2041
    }
2042
  }
2043

2044
  /// Parses a [BoxConstraints] from a JSON map.
2045
  ///
2046
  /// The map should contain the following keys:
2047
  /// - 'minWidth': A double value.
2048
  /// - 'maxWidth': A double value.
2049
  /// - 'minHeight': A double value.
2050
  /// - 'maxHeight': A double value.
2051
  @preferInline
8✔
2052
  BoxConstraints _boxConstraintsFromMap(Map<String, dynamic> data) {
2053
    final source = DuitDataSource(data);
8✔
2054
    return BoxConstraints(
8✔
2055
      minWidth: source.getDouble(
8✔
2056
        key: "minWidth",
2057
        defaultValue: 0.0,
2058
      ),
2059
      maxWidth: source.getDouble(
8✔
2060
        key: "maxWidth",
2061
        defaultValue: double.infinity,
2062
      ),
2063
      minHeight: source.getDouble(
8✔
2064
        key: "minHeight",
2065
        defaultValue: 0.0,
2066
      ),
2067
      maxHeight: source.getDouble(
8✔
2068
        key: "maxHeight",
2069
        defaultValue: double.infinity,
2070
      ),
2071
    );
2072
  }
2073

2074
  /// Retrieves a [BoxConstraints] value from the JSON map for the given [key].
2075
  ///
2076
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BoxConstraints],
2077
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [BoxConstraints].
2078
  /// Otherwise, it returns [defaultValue].
2079
  ///
2080
  /// - [key]: The key to look up in the JSON map. Defaults to 'constraints'.
2081
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2082
  ///
2083
  /// Returns:
2084
  /// - A [BoxConstraints] if the value is valid or can be parsed.
2085
  /// - [defaultValue] if the value is not a valid [BoxConstraints] or cannot be parsed.
2086
  @preferInline
8✔
2087
  BoxConstraints? boxConstraints({
2088
    String key = FlutterPropertyKeys.constraints,
2089
    BoxConstraints? defaultValue,
2090
    Object? target,
2091
    bool warmUp = false,
2092
  }) {
2093
    final value = _readProp(key, target, warmUp);
8✔
2094

2095
    if (value is BoxConstraints) return value;
8✔
2096

2097
    if (value == null) return defaultValue;
2098

2099
    switch (value) {
2100
      case Map<String, dynamic>():
8✔
2101
        if (envAttributeWarmUpEnabled) {
2102
          if (warmUp) {
2103
            return _boxConstraintsFromMap(value);
4✔
2104
          } else {
2105
            return _json[key] = _boxConstraintsFromMap(value);
×
2106
          }
2107
        } else {
2108
          return _json[key] = _boxConstraintsFromMap(value);
8✔
2109
        }
2110
      default:
2111
        return defaultValue;
2112
    }
2113
  }
2114

2115
  /// Retrieves a [StackFit] value from the JSON map for the given [key].
2116
  ///
2117
  /// Looks up the value associated with [key] in the JSON. If the value is already a [StackFit],
2118
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2119
  /// Otherwise, it returns [defaultValue].
2120
  ///
2121
  /// - [key]: The key to look up in the JSON map. Defaults to 'fit'.
2122
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to StackFit.loose.
2123
  ///
2124
  /// Returns:
2125
  /// - A [StackFit] if the value is valid or can be parsed.
2126
  /// - [defaultValue] if the value is not a valid [StackFit] or cannot be parsed.
2127
  @preferInline
8✔
2128
  StackFit? stackFit({
2129
    String key = FlutterPropertyKeys.stackFit,
2130
    StackFit? defaultValue,
2131
    Object? target,
2132
    bool warmUp = false,
2133
  }) {
2134
    final value = _readProp(key, target, warmUp);
8✔
2135

2136
    if (value is StackFit) return value;
8✔
2137

2138
    if (value == null) return defaultValue;
2139

2140
    switch (value) {
2141
      case String():
8✔
2142
        if (envAttributeWarmUpEnabled) {
2143
          if (warmUp) {
2144
            return _stackFitStringLookupTable[value];
4✔
2145
          } else {
2146
            return _json[key] = _stackFitStringLookupTable[value];
×
2147
          }
2148
        } else {
2149
          return _json[key] = _stackFitStringLookupTable[value];
8✔
2150
        }
2151
      case int():
4✔
2152
        if (envAttributeWarmUpEnabled) {
2153
          if (warmUp) {
2154
            return _stackFitIntLookupTable[value];
×
2155
          } else {
2156
            return _json[key] = _stackFitIntLookupTable[value];
×
2157
          }
2158
        } else {
2159
          return _json[key] = _stackFitIntLookupTable[value];
8✔
2160
        }
2161
      default:
2162
        return defaultValue;
2163
    }
2164
  }
2165

2166
  /// Retrieves an [OverflowBoxFit] value from the JSON map for the given [key].
2167
  ///
2168
  /// Looks up the value associated with [key] in the JSON. If the value is already an [OverflowBoxFit],
2169
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2170
  /// Otherwise, it returns [defaultValue].
2171
  ///
2172
  /// - [key]: The key to look up in the JSON map. Defaults to 'fit'.
2173
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to OverflowBoxFit.max.
2174
  ///
2175
  /// Returns:
2176
  /// - An [OverflowBoxFit] if the value is valid or can be parsed.
2177
  /// - [defaultValue] if the value is not a valid [OverflowBoxFit] or cannot be parsed.
2178
  @preferInline
8✔
2179
  OverflowBoxFit? overflowBoxFit({
2180
    String key = FlutterPropertyKeys.overflowBoxFit,
2181
    OverflowBoxFit defaultValue = OverflowBoxFit.max,
2182
    Object? target,
2183
    bool warmUp = false,
2184
  }) {
2185
    final value = _readProp(key, target, warmUp);
8✔
2186

2187
    if (value is OverflowBoxFit) return value;
8✔
2188

2189
    if (value == null) return defaultValue;
2190

2191
    switch (value) {
2192
      case String():
8✔
2193
        if (envAttributeWarmUpEnabled) {
2194
          if (warmUp) {
2195
            return _overflowBoxFitStringLookupTable[value];
4✔
2196
          } else {
2197
            return _json[key] = _overflowBoxFitStringLookupTable[value];
×
2198
          }
2199
        } else {
2200
          return _json[key] = _overflowBoxFitStringLookupTable[value];
8✔
2201
        }
2202
      case int():
4✔
2203
        if (envAttributeWarmUpEnabled) {
2204
          if (warmUp) {
2205
            return _overflowBoxFitIntLookupTable[value];
×
2206
          } else {
2207
            return _json[key] = _overflowBoxFitIntLookupTable[value];
×
2208
          }
2209
        } else {
2210
          return _json[key] = _overflowBoxFitIntLookupTable[value];
8✔
2211
        }
2212
      default:
2213
        return defaultValue;
2214
    }
2215
  }
2216

2217
  /// Retrieves an [Alignment] value from the JSON map for the given [key].
2218
  ///
2219
  /// Looks up the value associated with [key] in the JSON. If the value is already an [Alignment],
2220
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2221
  /// Otherwise, it returns [defaultValue].
2222
  ///
2223
  /// - [key]: The key to look up in the JSON map. Defaults to 'alignment'.
2224
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2225
  ///
2226
  /// Returns:
2227
  /// - An [Alignment] if the value is valid or can be parsed.
2228
  /// - [defaultValue] if the value is not a valid [Alignment] or cannot be parsed.
2229
  /// - `null` if both the value and [defaultValue] are null.
2230
  @preferInline
8✔
2231
  Alignment? alignment({
2232
    String key = FlutterPropertyKeys.alignment,
2233
    Alignment? defaultValue,
2234
    Object? target,
2235
    bool warmUp = false,
2236
  }) {
2237
    final value = _readProp(key, target, warmUp);
8✔
2238

2239
    if (value is Alignment) return value;
8✔
2240

2241
    if (value == null) return defaultValue;
2242

2243
    switch (value) {
2244
      case String():
8✔
2245
        if (envAttributeWarmUpEnabled) {
2246
          if (warmUp) {
2247
            return _alignmentStringLookupTable[value];
4✔
2248
          } else {
2249
            return _json[key] = _alignmentStringLookupTable[value];
×
2250
          }
2251
        } else {
2252
          return _json[key] = _alignmentStringLookupTable[value];
8✔
2253
        }
2254
      case int():
4✔
2255
        if (envAttributeWarmUpEnabled) {
2256
          if (warmUp) {
2257
            return _alignmentIntLookupTable[value];
×
2258
          } else {
2259
            return _json[key] = _alignmentIntLookupTable[value];
×
2260
          }
2261
        } else {
2262
          return _json[key] = _alignmentIntLookupTable[value];
8✔
2263
        }
2264
      case List<num>() when value.length == 2:
12✔
2265
        if (envAttributeWarmUpEnabled) {
2266
          if (warmUp) {
2267
            return Alignment(
×
2268
              value[0].toDouble(),
×
2269
              value[1].toDouble(),
×
2270
            );
2271
          } else {
2272
            return _json[key] = Alignment(
×
2273
              value[0].toDouble(),
×
2274
              value[1].toDouble(),
×
2275
            );
2276
          }
2277
        } else {
2278
          return _json[key] = Alignment(
8✔
2279
            value[0].toDouble(),
8✔
2280
            value[1].toDouble(),
8✔
2281
          );
2282
        }
2283
      default:
2284
        return defaultValue;
2285
    }
2286
  }
2287

2288
  /// Retrieves an [AlignmentDirectional] value from the JSON map for the given [key].
2289
  ///
2290
  /// Looks up the value associated with [key] in the JSON. If the value is already an [AlignmentDirectional],
2291
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2292
  /// Otherwise, it returns [defaultValue].
2293
  ///
2294
  /// - [key]: The key to look up in the JSON map. Defaults to 'alignment'.
2295
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2296
  ///
2297
  /// Returns:
2298
  /// - An [AlignmentDirectional] if the value is valid or can be parsed.
2299
  /// - [defaultValue] if the value is not a valid [AlignmentDirectional] or cannot be parsed.
2300
  /// - `null` if both the value and [defaultValue] are null.
2301
  @preferInline
8✔
2302
  AlignmentDirectional? alignmentDirectional({
2303
    String key = FlutterPropertyKeys.alignmentDirectional,
2304
    AlignmentDirectional? defaultValue,
2305
    Object? target,
2306
    bool warmUp = false,
2307
  }) {
2308
    final value = _readProp(key, target, warmUp);
8✔
2309

2310
    if (value is AlignmentDirectional) return value;
8✔
2311

2312
    if (value == null) return defaultValue;
2313

2314
    switch (value) {
2315
      case String():
8✔
2316
        if (envAttributeWarmUpEnabled) {
2317
          if (warmUp) {
2318
            return _alignmentDirectionalStringLookupTable[value];
4✔
2319
          } else {
2320
            return _json[key] = _alignmentDirectionalStringLookupTable[value];
×
2321
          }
2322
        } else {
2323
          return _json[key] = _alignmentDirectionalStringLookupTable[value];
8✔
2324
        }
2325
      case int():
4✔
2326
        if (envAttributeWarmUpEnabled) {
2327
          if (warmUp) {
2328
            return _alignmentDirectionalIntLookupTable[value];
×
2329
          } else {
2330
            return _json[key] = _alignmentDirectionalIntLookupTable[value];
×
2331
          }
2332
        } else {
2333
          return _json[key] = _alignmentDirectionalIntLookupTable[value];
8✔
2334
        }
2335
      case List<num>() when value.length == 2:
12✔
2336
        if (envAttributeWarmUpEnabled) {
2337
          if (warmUp) {
2338
            return AlignmentDirectional(
×
2339
              value[0].toDouble(),
×
2340
              value[1].toDouble(),
×
2341
            );
2342
          } else {
2343
            return _json[key] = AlignmentDirectional(
×
2344
              value[0].toDouble(),
×
2345
              value[1].toDouble(),
×
2346
            );
2347
          }
2348
        } else {
2349
          return _json[key] = AlignmentDirectional(
8✔
2350
            value[0].toDouble(),
8✔
2351
            value[1].toDouble(),
8✔
2352
          );
2353
        }
2354
      default:
2355
        return defaultValue;
2356
    }
2357
  }
2358

2359
  /// Retrieves a [MainAxisAlignment] value from the JSON map for the given [key].
2360
  ///
2361
  /// Looks up the value associated with [key] in the JSON. If the value is already a [MainAxisAlignment],
2362
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2363
  /// Otherwise, it returns [defaultValue].
2364
  ///
2365
  /// - [key]: The key to look up in the JSON map. Defaults to 'mainAxisAlignment'.
2366
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2367
  ///
2368
  /// Returns:
2369
  /// - A [MainAxisAlignment] if the value is valid or can be parsed.
2370
  /// - [defaultValue] if the value is not a valid [MainAxisAlignment] or cannot be parsed.
2371
  /// - `null` if both the value and [defaultValue] are null.
2372
  @preferInline
8✔
2373
  MainAxisAlignment? mainAxisAlignment({
2374
    String key = FlutterPropertyKeys.mainAxisAlignment,
2375
    MainAxisAlignment? defaultValue,
2376
    Object? target,
2377
    bool warmUp = false,
2378
  }) {
2379
    final value = _readProp(key, target, warmUp);
8✔
2380

2381
    if (value is MainAxisAlignment) return value;
8✔
2382

2383
    if (value == null) return defaultValue;
2384

2385
    switch (value) {
2386
      case String():
8✔
2387
        if (envAttributeWarmUpEnabled) {
2388
          if (warmUp) {
2389
            return _mainAxisAlignmentStringLookupTable[value];
4✔
2390
          } else {
2391
            return _json[key] = _mainAxisAlignmentStringLookupTable[value];
×
2392
          }
2393
        } else {
2394
          return _json[key] = _mainAxisAlignmentStringLookupTable[value];
8✔
2395
        }
2396
      case int():
4✔
2397
        if (envAttributeWarmUpEnabled) {
2398
          if (warmUp) {
2399
            return _mainAxisAlignmentIntLookupTable[value];
×
2400
          } else {
2401
            return _json[key] = _mainAxisAlignmentIntLookupTable[value];
×
2402
          }
2403
        } else {
2404
          return _json[key] = _mainAxisAlignmentIntLookupTable[value];
8✔
2405
        }
2406
      default:
2407
        return defaultValue;
2408
    }
2409
  }
2410

2411
  /// Retrieves a [CrossAxisAlignment] value from the JSON map for the given [key].
2412
  ///
2413
  /// Looks up the value associated with [key] in the JSON. If the value is already a [CrossAxisAlignment],
2414
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2415
  /// Otherwise, it returns [defaultValue].
2416
  ///
2417
  /// - [key]: The key to look up in the JSON map. Defaults to 'crossAxisAlignment'.
2418
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2419
  ///
2420
  /// Returns:
2421
  /// - A [CrossAxisAlignment] if the value is valid or can be parsed.
2422
  /// - [defaultValue] if the value is not a valid [CrossAxisAlignment] or cannot be parsed.
2423
  /// - `null` if both the value and [defaultValue] are null.
2424
  @preferInline
8✔
2425
  CrossAxisAlignment? crossAxisAlignment({
2426
    String key = FlutterPropertyKeys.crossAxisAlignment,
2427
    CrossAxisAlignment? defaultValue,
2428
    Object? target,
2429
    bool warmUp = false,
2430
  }) {
2431
    final value = _readProp(key, target, warmUp);
8✔
2432

2433
    if (value is CrossAxisAlignment) return value;
8✔
2434

2435
    if (value == null) return defaultValue;
2436

2437
    switch (value) {
2438
      case String():
8✔
2439
        if (envAttributeWarmUpEnabled) {
2440
          if (warmUp) {
2441
            return _crossAxisAlignmentStringLookupTable[value];
4✔
2442
          } else {
2443
            return _json[key] = _crossAxisAlignmentStringLookupTable[value];
×
2444
          }
2445
        } else {
2446
          return _json[key] = _crossAxisAlignmentStringLookupTable[value];
8✔
2447
        }
2448
      case int():
4✔
2449
        if (envAttributeWarmUpEnabled) {
2450
          if (warmUp) {
2451
            return _crossAxisAlignmentIntLookupTable[value];
×
2452
          } else {
2453
            return _json[key] = _crossAxisAlignmentIntLookupTable[value];
×
2454
          }
2455
        } else {
2456
          return _json[key] = _crossAxisAlignmentIntLookupTable[value];
8✔
2457
        }
2458
      default:
2459
        return defaultValue;
2460
    }
2461
  }
2462

2463
  /// Retrieves a [MainAxisSize] value from the JSON map for the given [key].
2464
  ///
2465
  /// Looks up the value associated with [key] in the JSON. If the value is already a [MainAxisSize],
2466
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2467
  /// Otherwise, it returns [defaultValue].
2468
  ///
2469
  /// - [key]: The key to look up in the JSON map. Defaults to 'mainAxisSize'.
2470
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2471
  ///
2472
  /// Returns:
2473
  /// - A [MainAxisSize] if the value is valid or can be parsed.
2474
  /// - [defaultValue] if the value is not a valid [MainAxisSize] or cannot be parsed.
2475
  /// - `null` if both the value and [defaultValue] are null.
2476
  @preferInline
8✔
2477
  MainAxisSize? mainAxisSize({
2478
    String key = FlutterPropertyKeys.mainAxisSize,
2479
    MainAxisSize? defaultValue,
2480
    Object? target,
2481
    bool warmUp = false,
2482
  }) {
2483
    final value = _readProp(key, target, warmUp);
8✔
2484

2485
    if (value is MainAxisSize) return value;
8✔
2486

2487
    if (value == null) return defaultValue;
2488

2489
    switch (value) {
2490
      case String():
8✔
2491
        if (envAttributeWarmUpEnabled) {
2492
          if (warmUp) {
2493
            return _mainAxisSizeStringLookupTable[value];
4✔
2494
          } else {
2495
            return _json[key] = _mainAxisSizeStringLookupTable[value];
×
2496
          }
2497
        } else {
2498
          return _json[key] = _mainAxisSizeStringLookupTable[value];
8✔
2499
        }
2500
      case int():
4✔
2501
        if (envAttributeWarmUpEnabled) {
2502
          if (warmUp) {
2503
            return _mainAxisSizeIntLookupTable[value];
×
2504
          } else {
2505
            return _json[key] = _mainAxisSizeIntLookupTable[value];
×
2506
          }
2507
        } else {
2508
          return _json[key] = _mainAxisSizeIntLookupTable[value];
8✔
2509
        }
2510
      default:
2511
        return defaultValue;
2512
    }
2513
  }
2514

2515
  /// Retrieves a [SliderInteraction] value from the JSON map for the given [key].
2516
  ///
2517
  /// Looks up the value associated with [key] in the JSON. If the value is already a [SliderInteraction],
2518
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2519
  /// Otherwise, it returns [defaultValue].
2520
  ///
2521
  /// - [key]: The key to look up in the JSON map. Defaults to 'interaction'.
2522
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2523
  ///
2524
  /// Returns:
2525
  /// - A [SliderInteraction] if the value is valid or can be parsed.
2526
  /// - [defaultValue] if the value is not a valid [SliderInteraction] or cannot be parsed.
2527
  /// - `null` if both the value and [defaultValue] are null.
2528
  @preferInline
8✔
2529
  SliderInteraction? sliderInteraction({
2530
    String key = FlutterPropertyKeys.allowedInteraction,
2531
    SliderInteraction? defaultValue,
2532
    Object? target,
2533
    bool warmUp = false,
2534
  }) {
2535
    final value = _readProp(key, target, warmUp);
8✔
2536

2537
    if (value is SliderInteraction) return value;
8✔
2538

2539
    if (value == null) return defaultValue;
2540

2541
    switch (value) {
2542
      case String():
8✔
2543
        if (envAttributeWarmUpEnabled) {
2544
          if (warmUp) {
2545
            return _sliderInteractionStringLookupTable[value];
4✔
2546
          } else {
2547
            return _json[key] = _sliderInteractionStringLookupTable[value];
×
2548
          }
2549
        } else {
2550
          return _json[key] = _sliderInteractionStringLookupTable[value];
8✔
2551
        }
2552
      case int():
4✔
2553
        return _json[key] = _sliderInteractionIntLookupTable[value];
8✔
2554
      default:
2555
        return defaultValue;
2556
    }
2557
  }
2558

2559
  /// Retrieves a [MaterialTapTargetSize] value from the JSON map for the given [key].
2560
  ///
2561
  /// Looks up the value associated with [key] in the JSON. If the value is already a [MaterialTapTargetSize],
2562
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2563
  /// Otherwise, it returns [defaultValue].
2564
  ///
2565
  /// - [key]: The key to look up in the JSON map. Defaults to 'materialTapTargetSize'.
2566
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2567
  ///
2568
  /// Returns:
2569
  /// - A [MaterialTapTargetSize] if the value is valid or can be parsed.
2570
  /// - [defaultValue] if the value is not a valid [MaterialTapTargetSize] or cannot be parsed.
2571
  /// - `null` if both the value and [defaultValue] are null.
2572
  @preferInline
8✔
2573
  MaterialTapTargetSize? materialTapTargetSize({
2574
    String key = FlutterPropertyKeys.materialTapTargetSize,
2575
    MaterialTapTargetSize? defaultValue,
2576
    Object? target,
2577
    bool warmUp = false,
2578
  }) {
2579
    final value = _readProp(key, target, warmUp);
8✔
2580

2581
    if (value is MaterialTapTargetSize) return value;
8✔
2582

2583
    if (value == null) return defaultValue;
2584

2585
    switch (value) {
2586
      case String():
8✔
2587
        if (envAttributeWarmUpEnabled) {
2588
          if (warmUp) {
2589
            return _materialTapTargetSizeStringLookupTable[value];
4✔
2590
          } else {
2591
            return _json[key] = _materialTapTargetSizeStringLookupTable[value];
×
2592
          }
2593
        } else {
2594
          return _json[key] = _materialTapTargetSizeStringLookupTable[value];
8✔
2595
        }
2596
      case int():
4✔
2597
        if (envAttributeWarmUpEnabled) {
2598
          if (warmUp) {
2599
            return _materialTapTargetSizeIntLookupTable[value];
×
2600
          } else {
2601
            return _json[key] = _materialTapTargetSizeIntLookupTable[value];
×
2602
          }
2603
        } else {
2604
          return _json[key] = _materialTapTargetSizeIntLookupTable[value];
8✔
2605
        }
2606
      default:
2607
        return defaultValue;
2608
    }
2609
  }
2610

2611
  /// Retrieves a [FilterQuality] value from the JSON map for the given [key].
2612
  ///
2613
  /// Looks up the value associated with [key] in the JSON. If the value is already a [FilterQuality],
2614
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2615
  /// Otherwise, it returns [defaultValue].
2616
  ///
2617
  /// - [key]: The key to look up in the JSON map. Defaults to 'filterQuality'.
2618
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to FilterQuality.medium.
2619
  ///
2620
  /// Returns:
2621
  /// - A [FilterQuality] if the value is valid or can be parsed.
2622
  /// - [defaultValue] if the value is not a valid [FilterQuality] or cannot be parsed.
2623
  /// - `null` if both the value and [defaultValue] are null.
2624
  @preferInline
8✔
2625
  FilterQuality filterQuality({
2626
    String key = FlutterPropertyKeys.filterQuality,
2627
    FilterQuality defaultValue = FilterQuality.medium,
2628
    Object? target,
2629
    bool warmUp = false,
2630
  }) {
2631
    final value = _readProp(key, target, warmUp);
8✔
2632

2633
    if (value is FilterQuality) return value;
8✔
2634

2635
    if (value == null) return defaultValue;
2636

2637
    switch (value) {
2638
      case String():
8✔
2639
        if (envAttributeWarmUpEnabled) {
2640
          if (warmUp) {
2641
            return _filterQualityStringLookupTable[value]!;
4✔
2642
          } else {
2643
            return _json[key] = _filterQualityStringLookupTable[value]!;
×
2644
          }
2645
        } else {
2646
          return _json[key] = _filterQualityStringLookupTable[value]!;
8✔
2647
        }
2648
      case int():
4✔
2649
        if (envAttributeWarmUpEnabled) {
2650
          if (warmUp) {
2651
            return _filterQualityIntLookupTable[value]!;
×
2652
          } else {
2653
            return _json[key] = _filterQualityIntLookupTable[value]!;
×
2654
          }
2655
        } else {
2656
          return _json[key] = _filterQualityIntLookupTable[value]!;
8✔
2657
        }
2658
      default:
2659
        return defaultValue;
2660
    }
2661
  }
2662

2663
  /// Retrieves an [ImageRepeat] value from the JSON map for the given [key].
2664
  ///
2665
  /// Looks up the value associated with [key] in the JSON. If the value is already an [ImageRepeat],
2666
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2667
  /// Otherwise, it returns [defaultValue].
2668
  ///
2669
  /// - [key]: The key to look up in the JSON map. Defaults to 'repeat'.
2670
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to ImageRepeat.noRepeat.
2671
  ///
2672
  /// Returns:
2673
  /// - An [ImageRepeat] if the value is valid or can be parsed.
2674
  /// - [defaultValue] if the value is not a valid [ImageRepeat] or cannot be parsed.
2675
  /// - `null` if both the value and [defaultValue] are null.
2676
  @preferInline
8✔
2677
  ImageRepeat imageRepeat({
2678
    String key = FlutterPropertyKeys.repeat,
2679
    ImageRepeat defaultValue = ImageRepeat.noRepeat,
2680
    Object? target,
2681
    bool warmUp = false,
2682
  }) {
2683
    final value = _readProp(key, target, warmUp);
8✔
2684

2685
    if (value is ImageRepeat) return value;
8✔
2686

2687
    if (value == null) return defaultValue;
2688

2689
    switch (value) {
2690
      case String():
8✔
2691
        if (envAttributeWarmUpEnabled) {
2692
          if (warmUp) {
2693
            return _imageRepeatStringLookupTable[value]!;
4✔
2694
          } else {
2695
            return _json[key] = _imageRepeatStringLookupTable[value]!;
×
2696
          }
2697
        } else {
2698
          return _json[key] = _imageRepeatStringLookupTable[value]!;
8✔
2699
        }
2700
      case int():
4✔
2701
        if (envAttributeWarmUpEnabled) {
2702
          if (warmUp) {
2703
            return _imageRepeatIntLookupTable[value]!;
×
2704
          } else {
2705
            return _json[key] = _imageRepeatIntLookupTable[value]!;
×
2706
          }
2707
        } else {
2708
          return _json[key] = _imageRepeatIntLookupTable[value]!;
8✔
2709
        }
2710
      default:
2711
        return defaultValue;
2712
    }
2713
  }
2714

2715
  /// Parses a [Uint8List] from a base64 encoded string.
2716
  ///
2717
  /// - [value]: The base64 encoded string.
2718
  /// Returns a [Uint8List] decoded from the string.
2719
  @preferInline
4✔
2720
  Uint8List _uint8ListFromString(String value) => base64Decode(value);
4✔
2721

2722
  /// Parses a [Uint8List] from a list of integers.
2723
  ///
2724
  /// - [value]: The list of integers.
2725
  /// Returns a [Uint8List] created from the list.
2726
  @preferInline
4✔
2727
  Uint8List _uint8ListFromList(List<int> value) => Uint8List.fromList(value);
4✔
2728

2729
  /// Retrieves a [Uint8List] value from the JSON map for the given [key].
2730
  ///
2731
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Uint8List],
2732
  /// it is returned as is. If the value is a [String] or [List<int>], it is converted using the lookup tables.
2733
  /// Otherwise, it returns [defaultValue].
2734
  ///
2735
  /// - [key]: The key to look up in the JSON map. Defaults to 'byteData'.
2736
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2737
  ///
2738
  /// Returns:
2739
  /// - A [Uint8List] if the value is valid or can be parsed.
2740
  /// - [defaultValue] if the value is not a valid [Uint8List] or cannot be parsed.
2741
  @preferInline
8✔
2742
  Uint8List uint8List({
2743
    String key = FlutterPropertyKeys.byteData,
2744
    Uint8List? defaultValue,
2745
    Object? target,
2746
    bool warmUp = false,
2747
  }) {
2748
    final value = _readProp(key, target, warmUp);
8✔
2749

2750
    if (value is Uint8List) return value;
8✔
2751

2752
    if (value == null) {
2753
      return defaultValue ?? Uint8List(0);
4✔
2754
    }
2755

2756
    switch (value) {
2757
      case List<int>():
8✔
2758
        if (envAttributeWarmUpEnabled) {
2759
          if (warmUp) {
2760
            return _uint8ListFromList(value);
×
2761
          } else {
2762
            return _json[key] = _uint8ListFromList(value);
×
2763
          }
2764
        } else {
2765
          return _json[key] = _uint8ListFromList(value);
8✔
2766
        }
2767
      case String():
8✔
2768
        if (envAttributeWarmUpEnabled) {
2769
          if (warmUp) {
2770
            return _uint8ListFromString(value);
×
2771
          } else {
2772
            return _json[key] = _uint8ListFromString(value);
×
2773
          }
2774
        } else {
2775
          return _json[key] = _uint8ListFromString(value);
8✔
2776
        }
2777
      default:
2778
        return defaultValue ?? Uint8List(0);
4✔
2779
    }
2780
  }
2781

2782
  /// Retrieves a [BoxFit] value from the JSON map for the given [key].
2783
  ///
2784
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BoxFit],
2785
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2786
  /// Otherwise, it returns [defaultValue].
2787
  ///
2788
  /// - [key]: The key to look up in the JSON map. Defaults to 'fit'.
2789
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
2790
  ///
2791
  /// Returns:
2792
  /// - A [BoxFit] if the value is valid or can be parsed.
2793
  /// - [defaultValue] if the value is not a valid [BoxFit] or cannot be parsed.
2794
  @preferInline
8✔
2795
  BoxFit? boxFit({
2796
    String key = FlutterPropertyKeys.fit,
2797
    BoxFit? defaultValue,
2798
    Object? target,
2799
    bool warmUp = false,
2800
  }) {
2801
    final value = _readProp(key, target, warmUp);
8✔
2802

2803
    if (value is BoxFit) return value;
8✔
2804

2805
    if (value == null) return defaultValue;
2806

2807
    switch (value) {
2808
      case String():
8✔
2809
        if (envAttributeWarmUpEnabled) {
2810
          if (warmUp) {
2811
            return _boxFitStringLookupTable[value];
4✔
2812
          } else {
2813
            return _json[key] = _boxFitStringLookupTable[value];
×
2814
          }
2815
        } else {
2816
          return _json[key] = _boxFitStringLookupTable[value];
8✔
2817
        }
2818
      case int():
4✔
2819
        if (envAttributeWarmUpEnabled) {
2820
          if (warmUp) {
2821
            return _boxFitIntLookupTable[value];
×
2822
          } else {
2823
            return _json[key] = _boxFitIntLookupTable[value];
×
2824
          }
2825
        } else {
2826
          return _json[key] = _boxFitIntLookupTable[value];
8✔
2827
        }
2828
      default:
2829
        return defaultValue;
2830
    }
2831
  }
2832

2833
  /// Retrieves a [BlendMode] value from the JSON map for the given [key].
2834
  ///
2835
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BlendMode],
2836
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2837
  /// Otherwise, it returns [defaultValue].
2838
  ///
2839
  /// - [key]: The key to look up in the JSON map. Defaults to 'blendMode'.
2840
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to BlendMode.srcOver.
2841
  ///
2842
  /// Returns:
2843
  /// - A [BlendMode] if the value is valid or can be parsed.
2844
  /// - [defaultValue] if the value is not a valid [BlendMode] or cannot be parsed.
2845
  @preferInline
8✔
2846
  BlendMode blendMode({
2847
    String key = FlutterPropertyKeys.blendMode,
2848
    BlendMode defaultValue = BlendMode.srcOver,
2849
    Object? target,
2850
    bool warmUp = false,
2851
  }) {
2852
    final value = _readProp(key, target, warmUp);
8✔
2853

2854
    if (value is BlendMode) return value;
8✔
2855

2856
    if (value == null) return defaultValue;
2857

2858
    switch (value) {
2859
      case String():
8✔
2860
        if (envAttributeWarmUpEnabled) {
2861
          if (warmUp) {
2862
            return _blendModeStringLookupTable[value]!;
4✔
2863
          } else {
2864
            return _json[key] = _blendModeStringLookupTable[value]!;
×
2865
          }
2866
        } else {
2867
          return _json[key] = _blendModeStringLookupTable[value]!;
8✔
2868
        }
2869
      case int():
4✔
2870
        if (envAttributeWarmUpEnabled) {
2871
          if (warmUp) {
2872
            return _blendModeIntLookupTable[value]!;
×
2873
          } else {
2874
            return _json[key] = _blendModeIntLookupTable[value]!;
×
2875
          }
2876
        } else {
2877
          return _json[key] = _blendModeIntLookupTable[value]!;
8✔
2878
        }
2879
      default:
2880
        return defaultValue;
2881
    }
2882
  }
2883

2884
  /// Retrieves a [TileMode] value from the JSON map for the given [key].
2885
  ///
2886
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TileMode],
2887
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
2888
  /// Otherwise, it returns [defaultValue].
2889
  ///
2890
  /// - [key]: The key to look up in the JSON map. Defaults to 'tileMode'.
2891
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to TileMode.clamp.
2892
  ///
2893
  /// Returns:
2894
  /// - A [TileMode] if the value is valid or can be parsed.
2895
  /// - [defaultValue] if the value is not a valid [TileMode] or cannot be parsed.
2896
  TileMode tileMode({
8✔
2897
    String key = FlutterPropertyKeys.tileMode,
2898
    TileMode defaultValue = TileMode.clamp,
2899
    Object? target,
2900
    bool warmUp = false,
2901
  }) {
2902
    final value = _readProp(key, target, warmUp);
8✔
2903

2904
    if (value is TileMode) return value;
8✔
2905

2906
    if (value == null) return defaultValue;
2907

2908
    switch (value) {
2909
      case String():
8✔
2910
        if (envAttributeWarmUpEnabled) {
2911
          if (warmUp) {
2912
            return _tileModeStringLookupTable[value]!;
4✔
2913
          } else {
2914
            return _json[key] = _tileModeStringLookupTable[value]!;
×
2915
          }
2916
        } else {
2917
          return _json[key] = _tileModeStringLookupTable[value]!;
8✔
2918
        }
2919
      case int():
4✔
2920
        if (envAttributeWarmUpEnabled) {
2921
          if (warmUp) {
2922
            return _tileModeIntLookupTable[value]!;
×
2923
          } else {
2924
            return _json[key] = _tileModeIntLookupTable[value]!;
×
2925
          }
2926
        } else {
2927
          return _json[key] = _tileModeIntLookupTable[value]!;
8✔
2928
        }
2929
      default:
2930
        return defaultValue;
2931
    }
2932
  }
2933

2934
  /// Creates a blur [ImageFilter] from a map containing blur parameters.
2935
  ///
2936
  /// The map should contain the following keys:
2937
  /// - `sigmaX`: The horizontal blur radius (double)
2938
  /// - `sigmaY`: The vertical blur radius (double)
2939
  /// - `tileMode`: The tile mode for the blur effect (optional)
2940
  ///
2941
  /// - [value]: The map containing blur parameters.
2942
  /// Returns an [ImageFilter] that applies a blur effect.
2943
  @preferInline
8✔
2944
  static ImageFilter _blurImageFilterFromMap(Map<String, dynamic> value) {
2945
    final source = DuitDataSource(value);
8✔
2946
    return ImageFilter.blur(
8✔
2947
      sigmaX: source.getDouble(key: "sigmaX"),
8✔
2948
      sigmaY: source.getDouble(key: "sigmaY"),
8✔
2949
      tileMode: source.tileMode(),
8✔
2950
    );
2951
  }
2952

2953
  /// Creates a dilate [ImageFilter] from a map containing dilate parameters.
2954
  ///
2955
  /// The map should contain the following keys:
2956
  /// - `radiusX`: The horizontal dilation radius (double)
2957
  /// - `radiusY`: The vertical dilation radius (double)
2958
  ///
2959
  /// - [value]: The map containing dilate parameters.
2960
  /// Returns an [ImageFilter] that applies a dilation effect.
2961
  @preferInline
4✔
2962
  static ImageFilter _dilateImageFilterFromMap(Map<String, dynamic> value) {
2963
    final source = DuitDataSource(value);
4✔
2964
    return ImageFilter.dilate(
4✔
2965
      radiusX: source.getDouble(key: "radiusX"),
4✔
2966
      radiusY: source.getDouble(key: "radiusY"),
4✔
2967
    );
2968
  }
2969

2970
  /// Creates an erode [ImageFilter] from a map containing erode parameters.
2971
  ///
2972
  /// The map should contain the following keys:
2973
  /// - `radiusX`: The horizontal erosion radius (double)
2974
  /// - `radiusY`: The vertical erosion radius (double)
2975
  ///
2976
  /// - [value]: The map containing erode parameters.
2977
  /// Returns an [ImageFilter] that applies an erosion effect.
2978
  @preferInline
4✔
2979
  static ImageFilter _erodeImageFilterFromMap(Map<String, dynamic> value) {
2980
    final source = DuitDataSource(value);
4✔
2981
    return ImageFilter.erode(
4✔
2982
      radiusX: source.getDouble(key: "radiusX"),
4✔
2983
      radiusY: source.getDouble(key: "radiusY"),
4✔
2984
    );
2985
  }
2986

2987
  /// Creates a matrix [ImageFilter] from a map containing matrix parameters.
2988
  ///
2989
  /// The map should contain the following keys:
2990
  /// - `matrix4`: A 4x4 transformation matrix as a list of 16 doubles
2991
  /// - `filterQuality`: The quality of the filter (optional, defaults to medium)
2992
  ///
2993
  /// - [value]: The map containing matrix parameters.
2994
  /// Returns an [ImageFilter] that applies a matrix transformation.
2995
  @preferInline
4✔
2996
  static ImageFilter _matrixImageFilterFromMap(Map<String, dynamic> value) {
2997
    final source = DuitDataSource(value);
4✔
2998
    return ImageFilter.matrix(
4✔
2999
      Float64List.fromList(value["matrix4"] as List<double>),
8✔
3000
      filterQuality: source.filterQuality(defaultValue: FilterQuality.medium),
4✔
3001
    );
3002
  }
3003

3004
  /// Creates a compose [ImageFilter] from a map containing compose parameters.
3005
  ///
3006
  /// The map should contain the following keys:
3007
  /// - `outer`: The outer filter to apply
3008
  /// - `inner`: The inner filter to apply
3009
  ///
3010
  /// Both outer and inner filters are parsed using the [imageFilter] method.
3011
  /// If either filter is not provided, a default blur filter is used.
3012
  ///
3013
  /// - [value]: The map containing compose parameters.
3014
  /// Returns an [ImageFilter] that combines two filters.
3015
  @preferInline
4✔
3016
  static ImageFilter _composeImageFilterFromMap(Map<String, dynamic> value) {
3017
    final source = DuitDataSource(value);
4✔
3018
    return ImageFilter.compose(
4✔
3019
      outer: source.imageFilter(defaultValue: ImageFilter.blur())!,
8✔
3020
      inner: source.imageFilter(defaultValue: ImageFilter.blur())!,
8✔
3021
    );
3022
  }
3023

3024
  /// Creates an [ImageFilter] from a map based on the filter type.
3025
  ///
3026
  /// The map should contain a `type` key that specifies the filter type.
3027
  /// The type can be either a string or integer identifier.
3028
  /// Based on the type, the appropriate filter creation function is called
3029
  /// with the provided map as parameters.
3030
  ///
3031
  /// - [value]: The map containing filter type and parameters.
3032
  /// Returns an [ImageFilter] if the type is valid, otherwise `null`.
3033
  @preferInline
8✔
3034
  ImageFilter? _imageFilterFromMap(Map<String, dynamic> value) {
3035
    final fType = value["type"];
8✔
3036

3037
    switch (fType) {
3038
      case String():
8✔
3039
        return _imageFilterTypeStringLookupTable[fType]?.call(value);
16✔
3040
      case int():
4✔
3041
        return _imageFilterTypeIntLookupTable[fType]?.call(value);
8✔
3042
      default:
3043
        return null;
3044
    }
3045
  }
3046

3047
  /// Retrieves an [ImageFilter] value from the JSON map for the given [key].
3048
  ///
3049
  /// Looks up the value associated with [key] in the JSON. If the value is already an [ImageFilter],
3050
  /// it is returned as is. If the value is a [Map<String, dynamic>], it is parsed using [_imageFilterFromMap].
3051
  /// If the value is `null`, returns [defaultValue].
3052
  ///
3053
  /// The parsed or existing [ImageFilter] is also stored back into the JSON map at the given [key].
3054
  ///
3055
  /// Supported filter types:
3056
  /// - `blur`: Applies a blur effect with sigmaX and sigmaY parameters
3057
  /// - `dilate`: Applies a dilation effect with radiusX and radiusY parameters
3058
  /// - `erode`: Applies an erosion effect with radiusX and radiusY parameters
3059
  /// - `matrix`: Applies a matrix transformation with a 4x4 matrix
3060
  /// - `compose`: Combines two filters (outer and inner)
3061
  ///
3062
  /// - [key]: The key to look up in the JSON map. Defaults to 'filter'.
3063
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved.
3064
  ///
3065
  /// Example:
3066
  /// ```dart
3067
  /// // Blur filter
3068
  /// final blurFilter = data.imageFilter(key: 'blurFilter');
3069
  /// // JSON: {"type": "blur", "sigmaX": 5.0, "sigmaY": 5.0}
3070
  ///
3071
  /// // Matrix filter
3072
  /// final matrixFilter = data.imageFilter(key: 'matrixFilter');
3073
  /// // JSON: {"type": "matrix", "matrix4": [1.0, 0.0, 0.0, 0.0, ...]}
3074
  /// ```
3075
  @preferInline
8✔
3076
  ImageFilter? imageFilter({
3077
    String key = FlutterPropertyKeys.filter,
3078
    ImageFilter? defaultValue,
3079
    Object? target,
3080
    bool warmUp = false,
3081
  }) {
3082
    final value = _readProp(key, target, warmUp);
8✔
3083

3084
    if (value is ImageFilter) return value;
8✔
3085

3086
    if (value == null) return defaultValue;
3087

3088
    switch (value) {
3089
      case Map<String, dynamic>():
8✔
3090
        if (envAttributeWarmUpEnabled) {
3091
          if (warmUp) {
3092
            return _imageFilterFromMap(value);
4✔
3093
          } else {
3094
            return _json[key] = _imageFilterFromMap(value);
×
3095
          }
3096
        } else {
3097
          return _json[key] = _imageFilterFromMap(value);
8✔
3098
        }
3099
      default:
3100
        return defaultValue;
3101
    }
3102
  }
3103

3104
  /// Retrieves a [VerticalDirection] value from the JSON map for the given [key].
3105
  ///
3106
  /// Looks up the value associated with [key] in the JSON. If the value is already a [VerticalDirection],
3107
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3108
  /// Otherwise, it returns [defaultValue].
3109
  ///
3110
  /// - [key]: The key to look up in the JSON map. Defaults to 'verticalDirection'.
3111
  @preferInline
8✔
3112
  VerticalDirection verticalDirection({
3113
    String key = FlutterPropertyKeys.verticalDirection,
3114
    Object? target,
3115
    bool warmUp = false,
3116
    VerticalDirection defaultValue = VerticalDirection.down,
3117
  }) {
3118
    final value = _json[key];
8✔
3119

3120
    if (value is VerticalDirection) return value;
8✔
3121

3122
    if (value == null) return defaultValue;
3123

3124
    switch (value) {
3125
      case String():
4✔
3126
        if (envAttributeWarmUpEnabled) {
3127
          if (warmUp) {
3128
            return _verticalDirectionStringLookupTable[value]!;
×
3129
          } else {
3130
            return _json[key] = _verticalDirectionStringLookupTable[value]!;
×
3131
          }
3132
        } else {
3133
          return _json[key] = _verticalDirectionStringLookupTable[value]!;
8✔
3134
        }
3135
      case int():
4✔
3136
        if (envAttributeWarmUpEnabled) {
3137
          if (warmUp) {
3138
            return _verticalDirectionIntLookupTable[value]!;
×
3139
          } else {
3140
            return _json[key] = _verticalDirectionIntLookupTable[value]!;
×
3141
          }
3142
        } else {
3143
          return _json[key] = _verticalDirectionIntLookupTable[value]!;
8✔
3144
        }
3145
      default:
3146
        return defaultValue;
3147
    }
3148
  }
3149

3150
  /// Retrieves a [BoxShape] value from the JSON map for the given [key].
3151
  ///
3152
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BoxShape],
3153
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3154
  /// Otherwise, it returns [defaultValue].
3155
  ///
3156
  /// - [key]: The key to look up in the JSON map. Defaults to 'shape'.
3157
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
3158
  ///
3159
  /// Returns:
3160
  /// - A [BoxShape] if the value is valid or can be parsed.
3161
  /// - [defaultValue] if the value is not a valid [BoxShape] or cannot be parsed.
3162
  /// - `null` if both the value and [defaultValue] are null.
3163
  @preferInline
8✔
3164
  BoxShape? boxShape({
3165
    String key = FlutterPropertyKeys.boxShape,
3166
    BoxShape? defaultValue,
3167
    Object? target,
3168
    bool warmUp = false,
3169
  }) {
3170
    final value = _readProp(key, target, warmUp);
8✔
3171

3172
    if (value is BoxShape) return value;
8✔
3173

3174
    if (value == null) return defaultValue;
3175

3176
    switch (value) {
3177
      case String():
8✔
3178
        if (envAttributeWarmUpEnabled) {
3179
          if (warmUp) {
3180
            return _boxShapeStringLookupTable[value]!;
4✔
3181
          } else {
3182
            return _json[key] = _boxShapeStringLookupTable[value]!;
×
3183
          }
3184
        } else {
3185
          return _json[key] = _boxShapeStringLookupTable[value]!;
8✔
3186
        }
3187
      case int():
4✔
3188
        return _json[key] = _boxShapeIntLookupTable[value]!;
8✔
3189
      default:
3190
        return defaultValue;
3191
    }
3192
  }
3193

3194
  /// Parses an [InputDecoration] from a JSON map.
3195
  ///
3196
  /// The map should contain the following keys:
3197
  /// - 'labelText': A string value.
3198
  /// - 'labelStyle': A [TextStyle] value.
3199
  /// - 'floatingLabelStyle': A [TextStyle] value.
3200
  /// - 'helperText': A string value.
3201
  /// - 'helperMaxLines': An integer value.
3202
  /// - 'helperStyle': A [TextStyle] value.
3203
  /// - 'hintText': A string value.
3204
  /// - 'hintStyle': A [TextStyle] value.
3205
  /// - 'hintMaxLines': An integer value.
3206
  /// - 'errorText': A string value.
3207
  /// - 'errorMaxLines': An integer value.
3208
  /// - 'errorStyle': A [TextStyle] value.
3209
  /// - 'enabledBorder': An [InputBorder] value.
3210
  /// - 'border': An [InputBorder] value.
3211
  /// - 'errorBorder': An [InputBorder] value.
3212
  /// - 'focusedBorder': An [InputBorder] value.
3213
  /// - 'focusedErrorBorder': An [InputBorder] value.
3214
  /// - 'enabled': A boolean value.
3215
  /// - 'isCollapsed': A boolean value.
3216
  /// - 'isDense': A boolean value.
3217
  /// - 'suffixText': A string value.
3218
  /// - 'suffixStyle': A [TextStyle] value.
3219
  /// - 'prefixText': A string value.
3220
  /// - 'prefixStyle': A [TextStyle] value.
3221
  /// - 'counterText': A string value.
3222
  /// - 'counterStyle': A [TextStyle] value.
3223
  /// - 'alignLabelWithHint': A boolean value.
3224
  /// - 'filled': A boolean value.
3225
  /// - 'fillColor': A color value.
3226
  /// - 'focusColor': A color value.
3227
  /// - 'hoverColor': A color value.
3228
  /// - 'contentPadding': An [EdgeInsets] value.
3229
  /// - 'prefixIconColor': A color value.
3230
  /// - 'suffixIconColor': A color value.
3231
  ///
3232
  /// - [value]: The JSON map to parse.
3233
  /// Returns an [InputDecoration] created from the map.
3234
  @preferInline
8✔
3235
  InputDecoration _inputDecorationFromMap(Map<String, dynamic> value) {
3236
    final source = DuitDataSource(value);
8✔
3237
    return InputDecoration(
8✔
3238
      labelText: source.tryGetString("labelText"),
8✔
3239
      labelStyle: source.textStyle(key: "labelStyle"),
8✔
3240
      floatingLabelStyle: source.textStyle(key: "floatingLabelStyle"),
8✔
3241
      helperText: source.tryGetString("helperText"),
8✔
3242
      helperMaxLines: source.tryGetInt(key: "helperMaxLines"),
8✔
3243
      helperStyle: source.textStyle(key: "helperStyle"),
8✔
3244
      hintText: source.tryGetString("hintText"),
8✔
3245
      hintStyle: source.textStyle(key: "hintStyle"),
8✔
3246
      hintMaxLines: source.tryGetInt(key: "hintMaxLines"),
8✔
3247
      errorText: source.tryGetString("errorText"),
8✔
3248
      errorMaxLines: source.tryGetInt(key: "errorMaxLines"),
8✔
3249
      errorStyle: source.textStyle(key: "errorStyle"),
8✔
3250
      enabledBorder: source.inputBorder(key: "enabledBorder"),
8✔
3251
      border: source.inputBorder(key: "inputBorder"),
8✔
3252
      errorBorder: source.inputBorder(key: "errorBorder"),
8✔
3253
      focusedBorder: source.inputBorder(key: "focusedBorder"),
8✔
3254
      focusedErrorBorder: source.inputBorder(key: "focusedErrorBorder"),
8✔
3255
      enabled: source.getBool("enabled", defaultValue: true),
8✔
3256
      isCollapsed: source.tryGetBool("isCollapsed"),
8✔
3257
      isDense: source.tryGetBool("isDense"),
8✔
3258
      suffixText: source.tryGetString("suffixText"),
8✔
3259
      suffixStyle: source.textStyle(key: "suffixStyle"),
8✔
3260
      prefixText: source.tryGetString("prefixText"),
8✔
3261
      prefixStyle: source.textStyle(key: "prefixStyle"),
8✔
3262
      counterText: source.tryGetString("counterText"),
8✔
3263
      counterStyle: source.textStyle(key: "counterStyle"),
8✔
3264
      alignLabelWithHint: source.tryGetBool("alignLabelWithHint"),
8✔
3265
      filled: source.tryGetBool("filled"),
8✔
3266
      fillColor: source.tryParseColor(key: "fillColor"),
8✔
3267
      focusColor: source.tryParseColor(key: "focusColor"),
8✔
3268
      hoverColor: source.tryParseColor(key: "hoverColor"),
8✔
3269
      contentPadding: source.edgeInsets(key: "contentPadding"),
8✔
3270
      prefixIconColor: source.tryParseColor(key: "prefixIconColor"),
8✔
3271
      suffixIconColor: source.tryParseColor(key: "suffixIconColor"),
8✔
3272
    );
3273
  }
3274

3275
  /// Parses a [BorderSide] from a JSON map.
3276
  ///
3277
  /// The map should contain the following keys:
3278
  /// - 'color': A color value.
3279
  /// - 'width': A double value.
3280
  /// - 'style': A [BorderStyle] value.
3281
  ///
3282
  /// - [value]: The JSON map to parse.
3283
  /// Returns a [BorderSide] created from the map.
3284
  @preferInline
8✔
3285
  BorderSide _borderSideFromMap(Map<String, dynamic> value) {
3286
    final source = DuitDataSource(value);
8✔
3287
    return BorderSide(
8✔
3288
      color: source.parseColor(key: "color"),
8✔
3289
      width: source.getDouble(
8✔
3290
        key: "width",
3291
        defaultValue: 1.0,
3292
      ),
3293
      style: source.borderStyle(
8✔
3294
        key: "style",
3295
        defaultValue: BorderStyle.solid,
3296
      )!,
3297
      strokeAlign: source.getDouble(
8✔
3298
        key: "strokeAlign",
3299
        defaultValue: BorderSide.strokeAlignOutside,
3300
      ),
3301
    );
3302
  }
3303

3304
  /// Retrieves a [BorderStyle] value from the JSON map for the given [key].
3305
  ///
3306
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BorderStyle],
3307
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3308
  /// Otherwise, it returns [defaultValue].
3309
  ///
3310
  /// - [key]: The key to look up in the JSON map. Defaults to 'style'.
3311
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to BorderStyle.solid.
3312
  ///
3313
  /// Returns:
3314
  /// - A [BorderStyle] if the value is valid or can be parsed.
3315
  /// - [defaultValue] if the value is not a valid [BorderStyle] or cannot be parsed.
3316
  /// - `null` if both the value and [defaultValue] are null.
3317
  @preferInline
8✔
3318
  BorderStyle? borderStyle({
3319
    String key = FlutterPropertyKeys.style,
3320
    BorderStyle? defaultValue,
3321
    Object? target,
3322
    bool warmUp = false,
3323
  }) {
3324
    final value = _readProp(key, target, warmUp);
8✔
3325

3326
    if (value is BorderStyle) return value;
8✔
3327

3328
    if (value == null) return defaultValue;
3329

3330
    switch (value) {
3331
      case String():
8✔
3332
        if (envAttributeWarmUpEnabled) {
3333
          if (warmUp) {
3334
            return _borderStyleStringLookupTable[value]!;
4✔
3335
          } else {
3336
            return _json[key] = _borderStyleStringLookupTable[value]!;
×
3337
          }
3338
        } else {
3339
          return _json[key] = _borderStyleStringLookupTable[value]!;
8✔
3340
        }
3341
      case int():
4✔
3342
        if (envAttributeWarmUpEnabled) {
3343
          if (warmUp) {
3344
            return _borderStyleIntLookupTable[value]!;
×
3345
          } else {
3346
            return _json[key] = _borderStyleIntLookupTable[value]!;
×
3347
          }
3348
        } else {
3349
          return _json[key] = _borderStyleIntLookupTable[value]!;
8✔
3350
        }
3351
      default:
3352
        return defaultValue;
3353
    }
3354
  }
3355

3356
  /// Retrieves a [BorderSide] value from the JSON map for the given [key].
3357
  ///
3358
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BorderSide],
3359
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [BorderSide].
3360
  /// Otherwise, it returns [defaultValue].
3361
  ///
3362
  /// - [key]: The key to look up in the JSON map. Defaults to 'side'.
3363
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to BorderSide.none.
3364
  ///
3365
  /// Returns:
3366
  /// - A [BorderSide] if the value is valid or can be parsed.
3367
  /// - [defaultValue] if the value is not a valid [BorderSide] or cannot be parsed.
3368
  /// - `null` if both the value and [defaultValue] are null.
3369
  @preferInline
8✔
3370
  BorderSide borderSide({
3371
    String key = FlutterPropertyKeys.side,
3372
    BorderSide defaultValue = BorderSide.none,
3373
    Object? target,
3374
    bool warmUp = false,
3375
  }) {
3376
    final value = _readProp(key, target, warmUp);
8✔
3377

3378
    if (value is BorderSide) return value;
8✔
3379

3380
    if (value == null) return defaultValue;
3381

3382
    switch (value) {
3383
      case Map<String, dynamic>():
8✔
3384
        if (envAttributeWarmUpEnabled) {
3385
          if (warmUp) {
3386
            return _borderSideFromMap(value);
4✔
3387
          } else {
3388
            return _json[key] = _borderSideFromMap(value);
×
3389
          }
3390
        } else {
3391
          return _json[key] = _borderSideFromMap(value);
8✔
3392
        }
3393
      default:
3394
        return defaultValue;
3395
    }
3396
  }
3397

3398
  /// Parses an [OutlineInputBorder] from a JSON map.
3399
  ///
3400
  /// The map should contain the following keys:
3401
  /// - 'borderSide': A [BorderSide] value.
3402
  /// - 'gapPadding': A double value.
3403
  /// - 'borderRadius': A double value.
3404
  ///
3405
  /// - [value]: The JSON map to parse.
3406
  /// Returns an [OutlineInputBorder] created from the map.
3407
  @preferInline
8✔
3408
  static InputBorder _outlineInputBorderFromMap(Map<String, dynamic> value) {
3409
    final source = DuitDataSource(value);
8✔
3410
    return OutlineInputBorder(
8✔
3411
      borderSide: source.borderSide(key: "borderSide"),
8✔
3412
      gapPadding: source.getDouble(key: "gapPadding", defaultValue: 4.0),
8✔
3413
      borderRadius: source.borderRadius(),
8✔
3414
    );
3415
  }
3416

3417
  /// Parses an [UnderlineInputBorder] from a JSON map.
3418
  ///
3419
  /// The map should contain the following keys:
3420
  /// - 'borderSide': A [BorderSide] value.
3421
  ///
3422
  /// - [value]: The JSON map to parse.
3423
  @preferInline
8✔
3424
  static InputBorder _underlineInputBorderFromMap(Map<String, dynamic> value) {
3425
    final source = DuitDataSource(value);
8✔
3426
    return UnderlineInputBorder(
8✔
3427
      borderSide: source.borderSide(key: "borderSide"),
8✔
3428
      borderRadius: source.borderRadius(),
8✔
3429
    );
3430
  }
3431

3432
  /// Parses an [InputBorder] from a JSON map.
3433
  ///
3434
  /// The map should contain the following keys:
3435
  /// - 'type': A string value representing the type of input border.
3436
  /// - 'borderSide': A [BorderSide] value.
3437
  /// - 'gapPadding': A double value.
3438
  /// - 'borderRadius': A double value.
3439
  @preferInline
8✔
3440
  InputBorder _inputBorderFromMap(Map<String, dynamic> value) {
3441
    final source = DuitDataSource(value);
8✔
3442
    final type = source.getString(key: "type");
8✔
3443
    return _inputBorderTypeStringLookupTable[type]?.call(value) ??
16✔
3444
        const OutlineInputBorder();
3445
  }
3446

3447
  /// Retrieves an [InputBorder] value from the JSON map for the given [key].
3448
  ///
3449
  /// Looks up the value associated with [key] in the JSON. If the value is already an [InputBorder],
3450
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into an [InputBorder].
3451
  /// Otherwise, it returns [defaultValue].
3452
  ///
3453
  /// - [key]: The key to look up in the JSON map. Defaults to 'border'.
3454
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
3455
  ///
3456
  /// Returns:
3457
  /// - An [InputBorder] if the value is valid or can be parsed.
3458
  /// - [defaultValue] if the value is not a valid [InputBorder] or cannot be parsed.
3459
  /// - `null` if both the value and [defaultValue] are null.
3460
  @preferInline
8✔
3461
  InputBorder? inputBorder({
3462
    String key = FlutterPropertyKeys.inputBorder,
3463
    InputBorder? defaultValue,
3464
    Object? target,
3465
    bool warmUp = false,
3466
  }) {
3467
    final value = _readProp(key, target, warmUp);
8✔
3468

3469
    if (value is InputBorder) return value;
8✔
3470

3471
    if (value == null) return defaultValue;
3472

3473
    switch (value) {
3474
      case Map<String, dynamic>():
8✔
3475
        if (envAttributeWarmUpEnabled) {
3476
          if (warmUp) {
3477
            return _inputBorderFromMap(value);
4✔
3478
          } else {
3479
            return _json[key] = _inputBorderFromMap(value);
×
3480
          }
3481
        } else {
3482
          return _json[key] = _inputBorderFromMap(value);
8✔
3483
        }
3484
      default:
3485
        return defaultValue;
3486
    }
3487
  }
3488

3489
  /// Retrieves an [InputDecoration] value from the JSON map for the given [key].
3490
  ///
3491
  /// Looks up the value associated with [key] in the JSON. If the value is already an [InputDecoration],
3492
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into an [InputDecoration].
3493
  /// Otherwise, it returns [defaultValue].
3494
  ///
3495
  /// - [key]: The key to look up in the JSON map. Defaults to 'decoration'.
3496
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
3497
  ///
3498
  /// Returns:
3499
  /// - An [InputDecoration] if the value is valid or can be parsed.
3500
  /// - [defaultValue] if the value is not a valid [InputDecoration] or cannot be parsed.
3501
  /// - `null` if both the value and [defaultValue] are null.
3502
  @preferInline
8✔
3503
  InputDecoration? inputDecoration({
3504
    String key = FlutterPropertyKeys.inputDecoration,
3505
    InputDecoration? defaultValue,
3506
    Object? target,
3507
    bool warmUp = false,
3508
  }) {
3509
    final value = _readProp(key, target, warmUp);
8✔
3510

3511
    if (value is InputDecoration) return value;
8✔
3512

3513
    if (value == null) return defaultValue;
3514

3515
    switch (value) {
3516
      case Map<String, dynamic>():
8✔
3517
        if (envAttributeWarmUpEnabled) {
3518
          if (warmUp) {
3519
            return _inputDecorationFromMap(value);
4✔
3520
          } else {
3521
            return _json[key] = _inputDecorationFromMap(value);
×
3522
          }
3523
        } else {
3524
          return _json[key] = _inputDecorationFromMap(value);
8✔
3525
        }
3526
      default:
3527
        return defaultValue;
3528
    }
3529
  }
3530

3531
  @preferInline
8✔
3532
  TextInputType? textInputType({
3533
    String key = FlutterPropertyKeys.keyboardType,
3534
    TextInputType? defaultValue,
3535
    Object? target,
3536
    bool warmUp = false,
3537
  }) {
3538
    final value = _readProp(key, target, warmUp);
8✔
3539

3540
    if (value is TextInputType) return value;
8✔
3541

3542
    if (value == null) return defaultValue;
3543

3544
    switch (value) {
3545
      case String():
8✔
3546
        if (envAttributeWarmUpEnabled) {
3547
          if (warmUp) {
3548
            return _textInputTypeStringLookupTable[value];
4✔
3549
          } else {
3550
            return _json[key] = _textInputTypeStringLookupTable[value];
×
3551
          }
3552
        } else {
3553
          return _json[key] = _textInputTypeStringLookupTable[value];
8✔
3554
        }
3555
      case int():
4✔
3556
        if (envAttributeWarmUpEnabled) {
3557
          if (warmUp) {
3558
            return _textInputTypeIntLookupTable[value];
×
3559
          } else {
3560
            return _json[key] = _textInputTypeIntLookupTable[value];
×
3561
          }
3562
        } else {
3563
          return _json[key] = _textInputTypeIntLookupTable[value];
8✔
3564
        }
3565
      default:
3566
        return defaultValue;
3567
    }
3568
  }
3569

3570
  /// Parses a [VisualDensity] from a JSON map.
3571
  ///
3572
  /// The map should contain the following keys:
3573
  /// - 'horizontal': A double value.
3574
  /// - 'vertical': A double value.
3575
  ///
3576
  /// - [value]: The JSON map to parse.
3577
  /// Returns a [VisualDensity] created from the map.
3578
  VisualDensity _visualDensityFromMap(Map<String, dynamic> value) {
8✔
3579
    final source = DuitDataSource(value);
8✔
3580
    return VisualDensity(
8✔
3581
      horizontal: source.getDouble(
8✔
3582
        key: "horizontal",
3583
        defaultValue: 0.0,
3584
      ),
3585
      vertical: source.getDouble(
8✔
3586
        key: "vertical",
3587
        defaultValue: 0.0,
3588
      ),
3589
    );
3590
  }
3591

3592
  /// Retrieves a [VisualDensity] value from the JSON map for the given [key].
3593
  ///
3594
  /// Looks up the value associated with [key] in the JSON. If the value is already a [VisualDensity],
3595
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [VisualDensity].
3596
  /// Otherwise, it returns [defaultValue].
3597
  ///
3598
  /// - [key]: The key to look up in the JSON map. Defaults to 'visualDensity'.
3599
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to VisualDensity.normal.
3600
  ///
3601
  /// Returns:
3602
  /// - A [VisualDensity] if the value is valid or can be parsed.
3603
  /// - [defaultValue] if the value is not a valid [VisualDensity] or cannot be parsed.
3604
  /// - `null` if both the value and [defaultValue] are null.
3605
  @preferInline
8✔
3606
  VisualDensity visualDensity({
3607
    String key = FlutterPropertyKeys.visualDensity,
3608
    VisualDensity defaultValue = const VisualDensity(),
3609
    Object? target,
3610
    bool warmUp = false,
3611
  }) {
3612
    final value = _readProp(key, target, warmUp);
8✔
3613

3614
    if (value is VisualDensity) return value;
8✔
3615

3616
    if (value == null) return defaultValue;
3617

3618
    switch (value) {
3619
      case Map<String, dynamic>():
8✔
3620
        if (envAttributeWarmUpEnabled) {
3621
          if (warmUp) {
3622
            return _visualDensityFromMap(value);
4✔
3623
          } else {
3624
            return _json[key] = _visualDensityFromMap(value);
×
3625
          }
3626
        } else {
3627
          return _json[key] = _visualDensityFromMap(value);
8✔
3628
        }
3629
      default:
3630
        return defaultValue;
3631
    }
3632
  }
3633

3634
  /// Retrieves a [ScrollViewKeyboardDismissBehavior] value from the JSON map for the given [key].
3635
  ///
3636
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ScrollViewKeyboardDismissBehavior],
3637
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3638
  /// Otherwise, it returns [defaultValue].
3639
  ///
3640
  /// - [key]: The key to look up in the JSON map. Defaults to 'keyboardDismissBehavior'.
3641
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to ScrollViewKeyboardDismissBehavior.manual.
3642
  ///
3643
  /// Returns:
3644
  /// - A [ScrollViewKeyboardDismissBehavior] if the value is valid or can be parsed.
3645
  /// - [defaultValue] if the value is not a valid [ScrollViewKeyboardDismissBehavior] or cannot be parsed.
3646
  /// - `null` if both the value and [defaultValue] are null.
3647
  @preferInline
8✔
3648
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior({
3649
    String key = FlutterPropertyKeys.keyboardDismissBehavior,
3650
    ScrollViewKeyboardDismissBehavior defaultValue =
3651
        ScrollViewKeyboardDismissBehavior.manual,
3652
    Object? target,
3653
    bool warmUp = false,
3654
  }) {
3655
    final value = _readProp(key, target, warmUp);
8✔
3656

3657
    if (value is ScrollViewKeyboardDismissBehavior) return value;
8✔
3658

3659
    if (value == null) return defaultValue;
3660

3661
    switch (value) {
3662
      case String():
8✔
3663
        if (envAttributeWarmUpEnabled) {
3664
          if (warmUp) {
3665
            return _keyboardDismissBehaviorStringLookupTable[value]!;
4✔
3666
          } else {
3667
            return _json[key] =
×
3668
                _keyboardDismissBehaviorStringLookupTable[value]!;
×
3669
          }
3670
        } else {
3671
          return _json[key] = _keyboardDismissBehaviorStringLookupTable[value]!;
8✔
3672
        }
3673
      case int():
4✔
3674
        if (envAttributeWarmUpEnabled) {
3675
          if (warmUp) {
3676
            return _keyboardDismissBehaviorIntLookupTable[value]!;
×
3677
          } else {
3678
            return _json[key] = _keyboardDismissBehaviorIntLookupTable[value]!;
×
3679
          }
3680
        } else {
3681
          return _json[key] = _keyboardDismissBehaviorIntLookupTable[value]!;
8✔
3682
        }
3683
      default:
3684
        return defaultValue;
3685
    }
3686
  }
3687

3688
  /// Retrieves a [ScrollPhysics] value from the JSON map for the given [key].
3689
  ///
3690
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ScrollPhysics],
3691
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3692
  /// Otherwise, it returns [defaultValue].
3693
  ///
3694
  /// - [key]: The key to look up in the JSON map. Defaults to 'physics'.
3695
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
3696
  ///
3697
  /// Returns:
3698
  /// - A [ScrollPhysics] if the value is valid or can be parsed.
3699
  /// - [defaultValue] if the value is not a valid [ScrollPhysics] or cannot be parsed.
3700
  /// - `null` if both the value and [defaultValue] are null.
3701
  @preferInline
8✔
3702
  ScrollPhysics? scrollPhysics({
3703
    String key = FlutterPropertyKeys.physics,
3704
    ScrollPhysics? defaultValue,
3705
    Object? target,
3706
    bool warmUp = false,
3707
  }) {
3708
    final value = _readProp(key, target, warmUp);
8✔
3709

3710
    if (value is ScrollPhysics) return value;
8✔
3711

3712
    if (value == null) return defaultValue;
3713

3714
    switch (value) {
3715
      case String():
8✔
3716
        if (envAttributeWarmUpEnabled) {
3717
          if (warmUp) {
3718
            return _scrollPhysicsStringLookupTable[value];
4✔
3719
          } else {
3720
            return _json[key] = _scrollPhysicsStringLookupTable[value];
×
3721
          }
3722
        } else {
3723
          return _json[key] = _scrollPhysicsStringLookupTable[value];
8✔
3724
        }
3725
      case int():
4✔
3726
        if (envAttributeWarmUpEnabled) {
3727
          if (warmUp) {
3728
            return _scrollPhysicsIntLookupTable[value];
×
3729
          } else {
3730
            return _json[key] = _scrollPhysicsIntLookupTable[value];
×
3731
          }
3732
        } else {
3733
          return _json[key] = _scrollPhysicsIntLookupTable[value];
8✔
3734
        }
3735
      default:
3736
        return defaultValue;
3737
    }
3738
  }
3739

3740
  /// Retrieves a [DragStartBehavior] value from the JSON map for the given [key].
3741
  ///
3742
  /// Looks up the value associated with [key] in the JSON. If the value is already a [DragStartBehavior],
3743
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3744
  /// Otherwise, it returns [defaultValue].
3745
  ///
3746
  /// - [key]: The key to look up in the JSON map. Defaults to 'dragStartBehavior'.
3747
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to DragStartBehavior.start.
3748
  ///
3749
  /// Returns:
3750
  /// - A [DragStartBehavior] if the value is valid or can be parsed.
3751
  /// - [defaultValue] if the value is not a valid [DragStartBehavior] or cannot be parsed.
3752
  /// - `null` if both the value and [defaultValue] are null.
3753
  @preferInline
8✔
3754
  DragStartBehavior dragStartBehavior({
3755
    String key = FlutterPropertyKeys.dragStartBehavior,
3756
    DragStartBehavior defaultValue = DragStartBehavior.start,
3757
    Object? target,
3758
    bool warmUp = false,
3759
  }) {
3760
    final value = _readProp(key, target, warmUp);
8✔
3761

3762
    if (value is DragStartBehavior) return value;
8✔
3763

3764
    if (value == null) return defaultValue;
3765

3766
    switch (value) {
3767
      case String():
8✔
3768
        if (envAttributeWarmUpEnabled) {
3769
          if (warmUp) {
3770
            return _dragStartBehaviorStringLookupTable[value]!;
4✔
3771
          } else {
3772
            return _json[key] = _dragStartBehaviorStringLookupTable[value]!;
×
3773
          }
3774
        } else {
3775
          return _json[key] = _dragStartBehaviorStringLookupTable[value]!;
8✔
3776
        }
3777
      case int():
4✔
3778
        if (envAttributeWarmUpEnabled) {
3779
          if (warmUp) {
3780
            return _dragStartBehaviorIntLookupTable[value]!;
×
3781
          } else {
3782
            return _json[key] = _dragStartBehaviorIntLookupTable[value]!;
×
3783
          }
3784
        } else {
3785
          return _json[key] = _dragStartBehaviorIntLookupTable[value]!;
8✔
3786
        }
3787
      default:
3788
        return defaultValue;
3789
    }
3790
  }
3791

3792
  /// Retrieves a [HitTestBehavior] value from the JSON map for the given [key].
3793
  ///
3794
  /// Looks up the value associated with [key] in the JSON. If the value is already a [HitTestBehavior],
3795
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
3796
  /// Otherwise, it returns [defaultValue].
3797
  ///
3798
  /// - [key]: The key to look up in the JSON map. Defaults to 'hitTestBehavior'.
3799
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to HitTestBehavior.deferToChild.
3800
  ///
3801
  /// Returns:
3802
  /// - A [HitTestBehavior] if the value is valid or can be parsed.
3803
  /// - [defaultValue] if the value is not a valid [HitTestBehavior] or cannot be parsed.
3804
  /// - `null` if both the value and [defaultValue] are null.
3805
  @preferInline
8✔
3806
  HitTestBehavior hitTestBehavior({
3807
    String key = FlutterPropertyKeys.hitTestBehavior,
3808
    HitTestBehavior defaultValue = HitTestBehavior.deferToChild,
3809
    Object? target,
3810
    bool warmUp = false,
3811
  }) {
3812
    final value = _readProp(key, target, warmUp);
8✔
3813

3814
    if (value is HitTestBehavior) return value;
8✔
3815

3816
    if (value == null) return defaultValue;
3817

3818
    switch (value) {
3819
      case String():
8✔
3820
        if (envAttributeWarmUpEnabled) {
3821
          if (warmUp) {
3822
            return _hitTestBehaviorStringLookupTable[value]!;
4✔
3823
          } else {
3824
            return _json[key] = _hitTestBehaviorStringLookupTable[value]!;
×
3825
          }
3826
        } else {
3827
          return _json[key] = _hitTestBehaviorStringLookupTable[value]!;
8✔
3828
        }
3829
      case int():
4✔
3830
        if (envAttributeWarmUpEnabled) {
3831
          if (warmUp) {
3832
            return _hitTestBehaviorIntLookupTable[value]!;
×
3833
          } else {
3834
            return _json[key] = _hitTestBehaviorIntLookupTable[value]!;
×
3835
          }
3836
        } else {
3837
          return _json[key] = _hitTestBehaviorIntLookupTable[value]!;
8✔
3838
        }
3839
      default:
3840
        return defaultValue;
3841
    }
3842
  }
3843

3844
  /// Parses a [RoundedRectangleBorder] from a JSON map.
3845
  ///
3846
  /// The map should contain the following keys:
3847
  /// - 'borderRadius': A double value.
3848
  /// - 'borderSide': A [BorderSide] value.
3849
  ///
3850
  /// - [value]: The JSON map to parse.
3851
  /// Returns a [RoundedRectangleBorder] created from the map.
3852
  @preferInline
4✔
3853
  static ShapeBorder _roundedRectangleBorderFromMap(
3854
    Map<String, dynamic> value,
3855
  ) {
3856
    final source = DuitDataSource(value);
4✔
3857
    return RoundedRectangleBorder(
4✔
3858
      borderRadius: source.borderRadius(),
4✔
3859
      side: source.borderSide(key: "borderSide"),
4✔
3860
    );
3861
  }
3862

3863
  /// Parses a [CircleBorder] from a JSON map.
3864
  ///
3865
  /// The map should contain the following keys:
3866
  /// - 'borderSide': A [BorderSide] value.
3867
  ///
3868
  /// - [value]: The JSON map to parse.
3869
  @preferInline
4✔
3870
  static ShapeBorder _circleBorderFromMap(
3871
    Map<String, dynamic> value,
3872
  ) {
3873
    final source = DuitDataSource(value);
4✔
3874
    return CircleBorder(
4✔
3875
      side: source.borderSide(key: "borderSide"),
4✔
3876
    );
3877
  }
3878

3879
  /// Parses a [StadiumBorder] from a JSON map.
3880
  ///
3881
  /// The map should contain the following keys:
3882
  /// - 'borderSide': A [BorderSide] value.
3883
  ///
3884
  /// - [value]: The JSON map to parse.
3885
  @preferInline
4✔
3886
  static ShapeBorder _stadiumBorderFromMap(
3887
    Map<String, dynamic> value,
3888
  ) {
3889
    final source = DuitDataSource(value);
4✔
3890
    return StadiumBorder(
4✔
3891
      side: source.borderSide(key: "borderSide"),
4✔
3892
    );
3893
  }
3894

3895
  /// Parses a [BeveledRectangleBorder] from a JSON map.
3896
  ///
3897
  /// The map should contain the following keys:
3898
  /// - 'borderRadius': A double value.
3899
  /// - 'borderSide': A [BorderSide] value.
3900
  ///
3901
  @preferInline
4✔
3902
  static ShapeBorder _beveledRectangleBorderFromMap(
3903
    Map<String, dynamic> value,
3904
  ) {
3905
    final source = DuitDataSource(value);
4✔
3906
    return BeveledRectangleBorder(
4✔
3907
      borderRadius: source.borderRadius(),
4✔
3908
      side: source.borderSide(key: "borderSide"),
4✔
3909
    );
3910
  }
3911

3912
  /// Parses a [ContinuousRectangleBorder] from a JSON map.
3913
  ///
3914
  /// The map should contain the following keys:
3915
  /// - 'borderRadius': A double value.
3916
  /// - 'borderSide': A [BorderSide] value.
3917
  ///
3918
  @preferInline
4✔
3919
  static ShapeBorder _continuousRectangleBorderFromMap(
3920
    Map<String, dynamic> value,
3921
  ) {
3922
    final source = DuitDataSource(value);
4✔
3923
    return ContinuousRectangleBorder(
4✔
3924
      borderRadius: source.borderRadius(),
4✔
3925
      side: source.borderSide(key: "borderSide"),
4✔
3926
    );
3927
  }
3928

3929
  /// Parses a [ShapeBorder] from a JSON map.
3930
  ///
3931
  /// The map should contain the following keys:
3932
  /// - 'type': A string value representing the type of shape border.
3933
  /// - 'borderRadius': A double value.
3934
  /// - 'borderSide': A [BorderSide] value.
3935
  ///
3936
  @preferInline
4✔
3937
  static ShapeBorder _shapeBorderFromMap(Map<String, dynamic> value) {
3938
    final json = DuitDataSource(value);
4✔
3939
    final type = json.getString(key: "type");
4✔
3940
    return _shapeBorderTypeStringLookupTable[type]?.call(value) ??
8✔
3941
        const RoundedRectangleBorder();
3942
  }
3943

3944
  /// Retrieves a [ShapeBorder] value from the JSON map for the given [key].
3945
  ///
3946
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ShapeBorder],
3947
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [ShapeBorder].
3948
  /// Otherwise, it returns [defaultValue].
3949
  ///
3950
  /// - [key]: The key to look up in the JSON map. Defaults to 'shape'.
3951
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
3952
  ///
3953
  /// Returns:
3954
  /// - A [ShapeBorder] if the value is valid or can be parsed.
3955
  /// - [defaultValue] if the value is not a valid [ShapeBorder] or cannot be parsed.
3956
  /// - `null` if both the value and [defaultValue] are null.
3957
  @preferInline
4✔
3958
  ShapeBorder? shapeBorder({
3959
    String key = FlutterPropertyKeys.shape,
3960
    ShapeBorder? defaultValue,
3961
    Object? target,
3962
    bool warmUp = false,
3963
  }) {
3964
    final value = _readProp(key, target, warmUp);
4✔
3965

3966
    if (value is ShapeBorder) return value;
4✔
3967

3968
    if (value == null) return defaultValue;
3969

3970
    switch (value) {
3971
      case Map<String, dynamic>():
4✔
3972
        if (envAttributeWarmUpEnabled) {
3973
          if (warmUp) {
3974
            return _shapeBorderFromMap(value);
×
3975
          } else {
3976
            return _json[key] = _shapeBorderFromMap(value);
×
3977
          }
3978
        } else {
3979
          return _json[key] = _shapeBorderFromMap(value);
8✔
3980
        }
3981
      default:
3982
        return defaultValue;
3983
    }
3984
  }
3985

3986
  /// Parses a [Border] from a JSON map.
3987
  ///
3988
  /// The map should contain the following keys:
3989
  /// - 'borderSide': A [BorderSide] value.
3990
  ///
3991
  /// - [value]: The JSON map to parse.
3992
  @preferInline
8✔
3993
  Border _borderFromMap(Map<String, dynamic> value) {
3994
    final data = DuitDataSource(value);
8✔
3995
    return Border.fromBorderSide(data.borderSide());
16✔
3996
  }
3997

3998
  /// Retrieves a [Border] value from the JSON map for the given [key].
3999
  ///
4000
  /// Looks up the value associated with [key] in the JSON. If the value is already a [Border],
4001
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [Border].
4002
  /// Otherwise, it returns [defaultValue].
4003
  ///
4004
  /// - [key]: The key to look up in the JSON map. Defaults to 'border'.
4005
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
4006
  ///
4007
  /// Returns:
4008
  /// - A [Border] if the value is valid or can be parsed.
4009
  /// - [defaultValue] if the value is not a valid [Border] or cannot be parsed.
4010
  /// - `null` if both the value and [defaultValue] are null.
4011
  @preferInline
8✔
4012
  Border? border({
4013
    String key = FlutterPropertyKeys.border,
4014
    Border? defaultValue,
4015
    Object? target,
4016
    bool warmUp = false,
4017
  }) {
4018
    final value = _readProp(key, target, warmUp);
8✔
4019

4020
    if (value is Border) return value;
8✔
4021

4022
    switch (value) {
4023
      case Map<String, dynamic>():
8✔
4024
        if (envAttributeWarmUpEnabled) {
4025
          if (warmUp) {
4026
            return _borderFromMap(value);
4✔
4027
          } else {
4028
            return _json[key] = _borderFromMap(value);
×
4029
          }
4030
        } else {
4031
          return _json[key] = _borderFromMap(value);
8✔
4032
        }
4033
      default:
4034
        return defaultValue;
4035
    }
4036
  }
4037

4038
  /// Retrieves a [BorderRadius] value from the JSON map for the given [key].
4039
  ///
4040
  /// Looks up the value associated with [key] in the JSON. If the value is already a [BorderRadius],
4041
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [BorderRadius].
4042
  /// Otherwise, it returns [defaultValue].
4043
  ///
4044
  /// - [key]: The key to look up in the JSON map. Defaults to 'borderRadius'.
4045
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to BorderRadius.zero.
4046
  ///
4047
  /// Returns:
4048
  /// - A [BorderRadius] if the value is valid or can be parsed.
4049
  /// - [defaultValue] if the value is not a valid [BorderRadius] or cannot be parsed.
4050
  /// - `null` if both the value and [defaultValue] are null.
4051
  @preferInline
8✔
4052
  BorderRadius borderRadius({
4053
    String key = FlutterPropertyKeys.borderRadius,
4054
    BorderRadius defaultValue = BorderRadius.zero,
4055
    Object? target,
4056
    bool warmUp = false,
4057
  }) {
4058
    final value = _readProp(key, target, warmUp);
8✔
4059

4060
    if (value is BorderRadius) return value;
8✔
4061

4062
    if (value == null) return defaultValue;
4063

4064
    switch (value) {
4065
      case Map<String, dynamic>():
8✔
4066
        if (envAttributeWarmUpEnabled) {
4067
          if (warmUp) {
4068
            return _borderRadiusFromMap(value);
×
4069
          } else {
4070
            return _json[key] = _borderRadiusFromMap(value);
×
4071
          }
4072
        } else {
4073
          return _json[key] = _borderRadiusFromMap(value);
8✔
4074
        }
4075
      case num():
8✔
4076
        if (envAttributeWarmUpEnabled) {
4077
          if (warmUp) {
4078
            return BorderRadius.circular(value.toDouble());
8✔
4079
          } else {
4080
            return _json[key] = BorderRadius.circular(value.toDouble());
×
4081
          }
4082
        } else {
4083
          return _json[key] = BorderRadius.circular(value.toDouble());
12✔
4084
        }
4085
      default:
4086
        return defaultValue;
4087
    }
4088
  }
4089

4090
  @preferInline
4✔
4091
  BorderRadius _borderRadiusFromMap(Map<String, dynamic> value) {
4092
    switch (value) {
4093
      case {
4094
          "topLeft": DuitDataSource? topLeft,
8✔
4095
          "topRight": DuitDataSource? topRight,
8✔
4096
          "bottomLeft": DuitDataSource? bottomLeft,
8✔
4097
          "bottomRight": DuitDataSource? bottomRight,
8✔
4098
        }:
4099
        return BorderRadius.only(
4✔
4100
          topLeft: topLeft != null ? topLeft.radius() : Radius.zero,
4✔
4101
          topRight: topRight != null ? topRight.radius() : Radius.zero,
4✔
4102
          bottomLeft: bottomLeft != null ? bottomLeft.radius() : Radius.zero,
4✔
4103
          bottomRight: bottomRight != null ? bottomRight.radius() : Radius.zero,
4✔
4104
        );
4105
      case {
4106
          "top": DuitDataSource? top,
8✔
4107
          "bottom": DuitDataSource? bottom,
8✔
4108
        }:
4109
        return BorderRadius.vertical(
4✔
4110
          top: top != null ? top.radius() : Radius.zero,
4✔
4111
          bottom: bottom != null ? bottom.radius() : Radius.zero,
4✔
4112
        );
4113
      case {
4114
          "left": DuitDataSource? left,
8✔
4115
          "right": DuitDataSource? right,
8✔
4116
        }:
4117
        return BorderRadius.horizontal(
4✔
4118
          left: left != null ? left.radius() : Radius.zero,
4✔
4119
          right: right != null ? right.radius() : Radius.zero,
4✔
4120
        );
4121
      case {
4122
          "radius": DuitDataSource? radius,
8✔
4123
        }:
4124
        return BorderRadius.all(
4✔
4125
          radius != null ? radius.radius() : Radius.zero,
4✔
4126
        );
4127
      default:
4128
        return BorderRadius.zero;
4129
    }
4130
  }
4131

4132
  @preferInline
4✔
4133
  Radius radius({
4134
    String key = FlutterPropertyKeys.radius,
4135
    Radius defaultValue = Radius.zero,
4136
    Object? target,
4137
    bool warmUp = false,
4138
  }) {
4139
    final value = _readProp(key, target, warmUp);
4✔
4140

4141
    if (value is Radius) return value;
4✔
4142

4143
    if (value == null) return defaultValue;
4144

4145
    switch (value) {
4146
      case List<num>():
4✔
4147
        if (envAttributeWarmUpEnabled) {
4148
          if (warmUp) {
4149
            return Radius.elliptical(
×
4150
              value[0].toDouble(),
×
4151
              value[1].toDouble(),
×
4152
            );
4153
          } else {
4154
            return _json[key] = Radius.elliptical(
×
4155
              value[0].toDouble(),
×
4156
              value[1].toDouble(),
×
4157
            );
4158
          }
4159
        } else {
4160
          return _json[key] = Radius.elliptical(
8✔
4161
            value[0].toDouble(),
8✔
4162
            value[1].toDouble(),
8✔
4163
          );
4164
        }
4165
      case num():
4✔
4166
        if (envAttributeWarmUpEnabled) {
4167
          if (warmUp) {
4168
            return Radius.circular(
×
4169
              value.toDouble(),
×
4170
            );
4171
          } else {
4172
            return _json[key] = Radius.circular(
×
4173
              value.toDouble(),
×
4174
            );
4175
          }
4176
        } else {
4177
          return _json[key] = Radius.circular(
8✔
4178
            value.toDouble(),
4✔
4179
          );
4180
        }
4181
      default:
4182
        return defaultValue;
4183
    }
4184
  }
4185

4186
  /// Retrieves a [FloatingActionButtonLocation] value from the JSON map for the given [key].
4187
  ///
4188
  /// Looks up the value associated with [key] in the JSON. If the value is already a [FloatingActionButtonLocation],
4189
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4190
  /// Otherwise, it returns [defaultValue].
4191
  ///
4192
  /// - [key]: The key to look up in the JSON map. Defaults to 'floatingActionButtonLocation'.
4193
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
4194
  ///
4195
  /// Returns:
4196
  /// - A [FloatingActionButtonLocation] if the value is valid or can be parsed.
4197
  /// - [defaultValue] if the value is not a valid [FloatingActionButtonLocation] or cannot be parsed.
4198
  /// - `null` if both the value and [defaultValue] are null.
4199
  @preferInline
4✔
4200
  FloatingActionButtonLocation? fabLocation({
4201
    String key = FlutterPropertyKeys.floatingActionButtonLocation,
4202
    FloatingActionButtonLocation? defaultValue,
4203
    Object? target,
4204
    bool warmUp = false,
4205
  }) {
4206
    final value = _readProp(key, target, warmUp);
4✔
4207

4208
    if (value is FloatingActionButtonLocation) return value;
4✔
4209

4210
    if (value == null) return defaultValue;
4211

4212
    switch (value) {
4213
      case String():
4✔
4214
        if (envAttributeWarmUpEnabled) {
4215
          if (warmUp) {
4216
            return _fabLocationStringLookupTable[value];
×
4217
          } else {
4218
            return _json[key] = _fabLocationStringLookupTable[value];
×
4219
          }
4220
        } else {
4221
          return _json[key] = _fabLocationStringLookupTable[value];
8✔
4222
        }
4223
      case int():
4✔
4224
        if (envAttributeWarmUpEnabled) {
4225
          if (warmUp) {
4226
            return _fabLocationIntLookupTable[value];
×
4227
          } else {
4228
            return _json[key] = _fabLocationIntLookupTable[value];
×
4229
          }
4230
        } else {
4231
          return _json[key] = _fabLocationIntLookupTable[value];
8✔
4232
        }
4233
      default:
4234
        return defaultValue;
4235
    }
4236
  }
4237

4238
  /// A list of widget states in order of priority for resolving widget state properties.
4239
  ///
4240
  /// This list defines the order in which widget states are checked when resolving widget state properties.
4241
  /// The states are ordered from the most specific to the least specific, ensuring that the most relevant
4242
  /// state is used when multiple states are present.
4243
  ///
4244
  static const _statePriority = [
4245
    WidgetState.disabled,
4246
    WidgetState.error,
4247
    WidgetState.selected,
4248
    WidgetState.pressed,
4249
    WidgetState.hovered,
4250
    WidgetState.focused,
4251
    WidgetState.dragged,
4252
  ];
4253

4254
  /// Retrieves a [WidgetStateProperty] value from the JSON map for the given [key].
4255
  ///
4256
  /// Looks up the value associated with [key] in the JSON. If the value is already a [WidgetStateProperty],
4257
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [WidgetStateProperty].
4258
  /// Otherwise, it returns [defaultValue].
4259
  ///
4260
  /// - [key]: The key to look up in the JSON map.
4261
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
4262
  ///
4263
  /// Returns:
4264
  /// - A [WidgetStateProperty] if the value is valid or can be parsed.
4265
  /// - [defaultValue] if the value is not a valid [WidgetStateProperty] or cannot be parsed.
4266
  @preferInline
4✔
4267
  WidgetStateProperty<T?>? widgetStateProperty<T>({
4268
    required String key,
4269
    WidgetStateProperty<T?>? defaultValue,
4270
  }) {
4271
    final value = _json[key];
4✔
4272

4273
    if (value == null) return defaultValue;
4274

4275
    if (value is WidgetStateProperty<T>) {
4✔
4276
      return value;
4277
    }
4278

4279
    if (value is Map<String, dynamic>) {
4✔
4280
      final data = DuitDataSource(value);
4✔
4281
      return WidgetStateProperty.resolveWith(
4✔
4282
        (states) => _resolveForState<T>(
8✔
4283
          states,
4284
          data,
4285
        ),
4286
      );
4287
    }
4288
    return null;
4289
  }
4290

4291
  /// Resolves a widget state value of type [T] from the given [states] and [data].
4292
  ///
4293
  /// This method iterates through the priority list of widget states and attempts to resolve
4294
  /// the value of type [T] for each state. It returns the first resolved value that is not null.
4295
  ///
4296
  /// - [states]: A set of widget states to check.
4297
  /// - [data]: The data source containing the widget state properties.
4298
  @preferInline
4✔
4299
  T? _resolveForState<T>(Set<WidgetState> states, DuitDataSource data) {
4300
    for (final state in _statePriority) {
8✔
4301
      if (states.contains(state)) {
4✔
4302
        final result = _resolveWidgetStateValue<T>(data, state);
4✔
4303
        if (result != null) return result;
4304
      }
4305
    }
4306
    return null;
4307
  }
4308

4309
  /// Resolves a widget state value of type [T] from the given [data] and [state].
4310
  ///
4311
  /// This method attempts to resolve the value of type [T] for the given [state] using the [data] source.
4312
  /// It returns the resolved value if it is not null, otherwise returns null.
4313
  ///
4314
  /// - [data]: The data source containing the widget state properties.
4315
  @preferInline
4✔
4316
  T? _resolveWidgetStateValue<T>(DuitDataSource data, WidgetState state) {
4317
    switch (T) {
4318
      case Color:
4✔
4319
        return data.parseColor(key: state.name) as T;
8✔
4320
      case EdgeInsetsGeometry:
4✔
4321
        return data.edgeInsets(key: state.name) as T;
8✔
4322
      case Size:
4✔
4323
        return data.size(state.name) as T;
8✔
4324
      case double:
4✔
4325
        return data.tryGetDouble(key: state.name) as T;
8✔
4326
      case OutlinedBorder:
4✔
4327
        return data.shapeBorder(key: state.name) as T;
8✔
4328
      case TextStyle:
4✔
4329
        return data.textStyle(key: state.name) as T;
8✔
4330
      case BorderSide:
4✔
4331
        return data.borderSide(key: state.name) as T;
8✔
4332
      default:
4333
        return null;
4334
    }
4335
  }
4336

4337
  /// Parses a [ButtonStyle] from a JSON map.
4338
  ///
4339
  /// The map should contain the following keys:
4340
  /// - 'textStyle': A [TextStyle] value.
4341
  /// - 'backgroundColor': A [Color] value.
4342
  /// - 'foregroundColor': A [Color] value.
4343
  /// - 'overlayColor': A [Color] value.
4344
  /// - 'shadowColor': A [Color] value.
4345
  /// - 'surfaceTintColor': A [Color] value.
4346
  /// - 'elevation': A double value.
4347
  /// - 'padding': A [EdgeInsetsGeometry] value.
4348
  /// - 'minimumSize': A [Size] value.
4349
  /// - 'maximumSize': A [Size] value.
4350
  /// - 'iconColor': A [Color] value.
4351
  /// - 'iconSize': A double value.
4352
  /// - 'side': A [BorderSide] value.
4353
  /// - 'shape': A [OutlinedBorder] value.
4354
  /// - 'visualDensity': A [VisualDensity] value.
4355
  /// - 'tapTargetSize': A [MaterialTapTargetSize] value.
4356
  /// - 'animationDuration': A [Duration] value.
4357
  /// - 'enableFeedback': A boolean value.
4358
  /// - 'alignment': A [AlignmentGeometry] value.
4359
  ///
4360
  /// - [value]: The JSON map to parse.
4361
  /// Returns a [ButtonStyle] created from the map.
4362
  @preferInline
4✔
4363
  ButtonStyle _buttonStyleFromMap(Map<String, dynamic> value) {
4364
    final data = DuitDataSource(value);
4✔
4365
    return ButtonStyle(
4✔
4366
      textStyle: data.widgetStateProperty<TextStyle>(key: "textStyle"),
4✔
4367
      backgroundColor: data.widgetStateProperty<Color>(key: "backgroundColor"),
4✔
4368
      foregroundColor: data.widgetStateProperty<Color>(key: "foregroundColor"),
4✔
4369
      overlayColor: data.widgetStateProperty<Color>(key: "overlayColor"),
4✔
4370
      shadowColor: data.widgetStateProperty<Color>(key: "shadowColor"),
4✔
4371
      surfaceTintColor:
4372
          data.widgetStateProperty<Color>(key: "surfaceTintColor"),
4✔
4373
      elevation: data.widgetStateProperty<double>(key: "elevation"),
4✔
4374
      padding: data.widgetStateProperty<EdgeInsetsGeometry>(key: "padding"),
4✔
4375
      minimumSize: data.widgetStateProperty<Size>(key: "minimumSize"),
4✔
4376
      maximumSize: data.widgetStateProperty<Size>(key: "maximumSize"),
4✔
4377
      iconColor: data.widgetStateProperty<Color>(key: "iconColor"),
4✔
4378
      iconSize: data.widgetStateProperty<double>(key: "iconSize"),
4✔
4379
      side: data.widgetStateProperty<BorderSide>(key: "side"),
4✔
4380
      shape: data.widgetStateProperty<OutlinedBorder>(key: "shape"),
4✔
4381
      visualDensity: data.visualDensity(key: "visualDensity"),
4✔
4382
      tapTargetSize: data.materialTapTargetSize(key: "tapTargetSize"),
4✔
4383
      animationDuration: data.duration(key: "animationDuration"),
4✔
4384
      enableFeedback: data.tryGetBool("enableFeedback"),
4✔
4385
      alignment: data.alignment(key: "alignment"),
4✔
4386
    );
4387
  }
4388

4389
  /// Retrieves a [ButtonStyle] value from the JSON map for the given [key].
4390
  ///
4391
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ButtonStyle],
4392
  /// it is returned as is. If the value is a [Map<String, dynamic>], it attempts to parse it into a [ButtonStyle].
4393
  /// Otherwise, it returns [defaultValue].
4394
  ///
4395
  /// - [key]: The key to look up in the JSON map. Defaults to 'style'.
4396
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
4397
  ///
4398
  /// Returns:
4399
  /// - A [ButtonStyle] if the value is valid or can be parsed.
4400
  /// - [defaultValue] if the value is not a valid [ButtonStyle] or cannot be parsed.
4401
  /// - `null` if both the value and [defaultValue] are null.
4402
  @preferInline
4✔
4403
  ButtonStyle? buttonStyle({
4404
    String key = "style",
4405
    ButtonStyle? defaultValue,
4406
  }) {
4407
    final value = _json[key];
4✔
4408

4409
    if (value is ButtonStyle) return value;
4✔
4410

4411
    if (value == null) return defaultValue;
4412

4413
    switch (value) {
4414
      case Map<String, dynamic>():
4✔
4415
        return _json[key] = _buttonStyleFromMap(value);
8✔
4416
      default:
4417
        return defaultValue;
4418
    }
4419
  }
4420

4421
  /// Returns a list of child objects from the JSON structure by the given key.
4422
  ///
4423
  /// This method looks up the [key] (default is 'childObjects') in the JSON and expects
4424
  /// a list of child objects (List<Map<String, dynamic>>). If such objects are found, they are
4425
  /// added to the internal buffer '_listContentBuffer', and the original key is cleared (json[key] = null).
4426
  /// This prevents the same objects from being added multiple times on repeated calls.
4427
  ///
4428
  /// Returns the accumulated list of child objects (List<Map<String, dynamic>>)
4429
  /// stored in the '_listContentBuffer'. If there are no child objects, returns an empty list.
4430
  @preferInline
4✔
4431
  List<Map<String, dynamic>> childObjects({
4432
    String key = "childObjects",
4433
  }) {
4434
    final children = _json[key];
4✔
4435
    final List<Map<String, dynamic>> cachedChildren =
4436
        _json["_listContentBuffer"] ?? [];
8✔
4437

4438
    if (children != null && children is List) {
4✔
4439
      cachedChildren.addAll(children.cast<Map<String, dynamic>>());
8✔
4440
      _json[key] = null;
4✔
4441
      _json["_listContentBuffer"] = cachedChildren;
4✔
4442
    }
4443

4444
    return cachedChildren;
4445
  }
4446

4447
  /// Retrieves a [ThemeOverrideRule] value from the JSON map for the given [key].
4448
  ///
4449
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ThemeOverrideRule],
4450
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4451
  /// Otherwise, it returns [defaultValue].
4452
  ///
4453
  /// - [key]: The key to look up in the JSON map. Defaults to 'overrideRule'.
4454
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to ThemeOverrideRule.themeOverlay.
4455
  ///
4456
  /// Returns:
4457
  /// - A [ThemeOverrideRule] if the value is valid or can be parsed.
4458
  /// - [defaultValue] if the value is not a valid [ThemeOverrideRule] or cannot be parsed.
4459
  /// - `null` if both the value and [defaultValue] are null.
4460
  @preferInline
4✔
4461
  ThemeOverrideRule themeOverrideRule({
4462
    String key = FlutterPropertyKeys.overrideRule,
4463
    ThemeOverrideRule defaultValue = ThemeOverrideRule.themeOverlay,
4464
    Object? target,
4465
    bool warmUp = false,
4466
  }) {
4467
    final value = _readProp(key, target, warmUp);
4✔
4468

4469
    if (value is ThemeOverrideRule) return value;
4✔
4470

4471
    if (value == null) return defaultValue;
4472

4473
    switch (value) {
4474
      case String():
4✔
4475
        if (envAttributeWarmUpEnabled) {
4476
          if (warmUp) {
4477
            return _themeOverrideRuleStringLookupTable[value] ?? defaultValue;
×
4478
          } else {
4479
            return _json[key] =
×
4480
                _themeOverrideRuleStringLookupTable[value] ?? defaultValue;
×
4481
          }
4482
        } else {
4483
          return _json[key] =
4✔
4484
              _themeOverrideRuleStringLookupTable[value] ?? defaultValue;
4✔
4485
        }
4486
      case int():
4✔
4487
        if (envAttributeWarmUpEnabled) {
4488
          if (warmUp) {
4489
            return _themeOverrideRuleIntLookupTable[value] ?? defaultValue;
×
4490
          } else {
4491
            return _json[key] =
×
4492
                _themeOverrideRuleIntLookupTable[value] ?? defaultValue;
×
4493
          }
4494
        } else {
4495
          return _json[key] =
4✔
4496
              _themeOverrideRuleIntLookupTable[value] ?? defaultValue;
4✔
4497
        }
4498
      default:
4499
        return defaultValue;
4500
    }
4501
  }
4502

4503
  /// Creates a deep copy of a list of dynamic values.
4504
  ///
4505
  /// This method recursively copies all nested objects, lists, and primitive values
4506
  /// to create a completely independent copy of the original list.
4507
  ///
4508
  /// Returns a new List<dynamic> that is a deep copy of the original list.
4509
  @preferInline
4✔
4510
  List<dynamic> _copyList(List<dynamic> source) {
4511
    final result = [];
4✔
4512
    for (final item in source) {
8✔
4513
      if (item is Map<String, dynamic>) {
4✔
4514
        result.add(_copyMap(item));
8✔
4515
      } else if (item is List) {
4✔
4516
        result.add(_copyList(item));
8✔
4517
      } else {
4518
        result.add(item);
4✔
4519
      }
4520
    }
4521
    return result;
4522
  }
4523

4524
  /// Creates a deep copy of a map of string keys to dynamic values.
4525
  ///
4526
  /// This method recursively copies all nested objects, lists, and primitive values
4527
  /// to create a completely independent copy of the original map.
4528
  ///
4529
  /// Returns a new Map<String, dynamic> that is a deep copy of the original map.
4530
  @preferInline
4✔
4531
  Map<String, dynamic> _copyMap(Map<String, dynamic> source) {
4532
    final result = <String, dynamic>{};
4✔
4533
    for (final entry in source.entries) {
8✔
4534
      final key = entry.key;
4✔
4535
      final value = entry.value;
4✔
4536

4537
      if (value is Map<String, dynamic>) {
4✔
4538
        result[key] = _copyMap(value);
8✔
4539
      } else if (value is List) {
4✔
4540
        result[key] = _copyList(value);
8✔
4541
      } else {
4542
        result[key] = value;
4✔
4543
      }
4544
    }
4545
    return result;
4546
  }
4547

4548
  /// Creates a deep copy of the current JSON data structure.
4549
  ///
4550
  /// This method recursively copies all nested objects, lists, and primitive values
4551
  /// to create a completely independent copy of the original data structure.
4552
  ///
4553
  /// Returns a new Map<String, dynamic> that is a deep copy of the current json.
4554
  @preferInline
4✔
4555
  Map<String, dynamic> deepCopy() => _copyMap(_json);
4✔
4556

4557
  /// Retrieves an [AnimationInterval] value from the JSON map for the given [key].
4558
  ///
4559
  /// Looks up the value associated with [key] in the JSON. If the value is already an [AnimationInterval],
4560
  /// it is returned as is. If the value is a [Map<String, dynamic>] or [List<num>], it attempts to parse it into an [AnimationInterval].
4561
  /// Otherwise, it returns [defaultValue].
4562
  ///
4563
  /// - [key]: The key to look up in the JSON map. Defaults to 'interval'.
4564
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to AnimationInterval(0.0, 1.0).
4565
  ///
4566
  /// Returns:
4567
  /// - An [AnimationInterval] if the value is valid or can be parsed.
4568
  /// - [defaultValue] if the value is not a valid [AnimationInterval] or cannot be parsed.
4569
  @preferInline
8✔
4570
  AnimationInterval animationInterval({
4571
    String key = FlutterPropertyKeys.interval,
4572
    AnimationInterval defaultValue = const AnimationInterval(0.0, 1.0),
4573
    Object? target,
4574
    bool warmUp = false,
4575
  }) {
4576
    final value = _readProp(key, target, warmUp);
8✔
4577

4578
    if (value is AnimationInterval) return value;
8✔
4579

4580
    if (value == null) return defaultValue;
4581

4582
    switch (value) {
4583
      case Map<String, dynamic>():
8✔
4584
        if (envAttributeWarmUpEnabled) {
4585
          if (warmUp) {
4586
            return AnimationInterval(
4✔
4587
              value["begin"] ?? 0.0,
4✔
4588
              value["end"] ?? 1.0,
4✔
4589
            );
4590
          } else {
4591
            return _json[key] = AnimationInterval(
×
4592
              value["begin"] ?? 0.0,
×
4593
              value["end"] ?? 1.0,
×
4594
            );
4595
          }
4596
        } else {
4597
          return _json[key] = AnimationInterval(
8✔
4598
            value["begin"] ?? 0.0,
4✔
4599
            value["end"] ?? 1.0,
4✔
4600
          );
4601
        }
4602
      case List<num>():
4✔
4603
        if (envAttributeWarmUpEnabled) {
4604
          if (warmUp) {
4605
            return AnimationInterval(
×
4606
              value[0].toDouble(),
×
4607
              value[1].toDouble(),
×
4608
            );
4609
          } else {
4610
            return _json[key] = AnimationInterval(
×
4611
              value[0].toDouble(),
×
4612
              value[1].toDouble(),
×
4613
            );
4614
          }
4615
        } else {
4616
          return _json[key] = AnimationInterval(
8✔
4617
            value[0].toDouble(),
8✔
4618
            value[1].toDouble(),
8✔
4619
          );
4620
        }
4621
      default:
4622
        return defaultValue;
4623
    }
4624
  }
4625

4626
  /// Retrieves an [AnimationTrigger] value from the JSON map for the given [key].
4627
  ///
4628
  /// Looks up the value associated with [key] in the JSON. If the value is already an [AnimationTrigger],
4629
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4630
  /// Otherwise, it returns [defaultValue].
4631
  ///
4632
  /// - [key]: The key to look up in the JSON map. Defaults to 'trigger'.
4633
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to AnimationTrigger.onEnter.
4634
  ///
4635
  /// Returns:
4636
  /// - An [AnimationTrigger] if the value is valid or can be parsed.
4637
  /// - [defaultValue] if the value is not a valid [AnimationTrigger] or cannot be parsed.
4638
  @preferInline
8✔
4639
  AnimationTrigger animationTrigger({
4640
    String key = FlutterPropertyKeys.trigger,
4641
    AnimationTrigger defaultValue = AnimationTrigger.onEnter,
4642
    Object? target,
4643
    bool warmUp = false,
4644
  }) {
4645
    final value = _readProp(key, target, warmUp);
8✔
4646

4647
    if (value is AnimationTrigger) return value;
8✔
4648

4649
    if (value == null) return defaultValue;
4650

4651
    switch (value) {
4652
      case String():
8✔
4653
        if (envAttributeWarmUpEnabled) {
4654
          if (warmUp) {
4655
            return _animationTriggerStringLookupTable[value]!;
4✔
4656
          } else {
4657
            return _json[key] = _animationTriggerStringLookupTable[value]!;
×
4658
          }
4659
        } else {
4660
          return _json[key] = _animationTriggerStringLookupTable[value]!;
8✔
4661
        }
4662
      case int():
4✔
4663
        if (envAttributeWarmUpEnabled) {
4664
          if (warmUp) {
4665
            return _animationTriggerIntLookupTable[value]!;
×
4666
          } else {
4667
            return _json[key] = _animationTriggerIntLookupTable[value]!;
×
4668
          }
4669
        } else {
4670
          return _json[key] = _animationTriggerIntLookupTable[value]!;
8✔
4671
        }
4672
      default:
4673
        return defaultValue;
4674
    }
4675
  }
4676

4677
  /// Retrieves an [AnimationMethod] value from the JSON map for the given [key].
4678
  ///
4679
  /// Looks up the value associated with [key] in the JSON. If the value is already an [AnimationMethod],
4680
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4681
  /// Otherwise, it returns [defaultValue].
4682
  ///
4683
  /// - [key]: The key to look up in the JSON map. Defaults to 'method'.
4684
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to AnimationMethod.forward.
4685
  ///
4686
  /// Returns:
4687
  /// - An [AnimationMethod] if the value is valid or can be parsed.
4688
  /// - [defaultValue] if the value is not a valid [AnimationMethod] or cannot be parsed.
4689
  @preferInline
8✔
4690
  AnimationMethod animationMethod({
4691
    String key = FlutterPropertyKeys.method,
4692
    AnimationMethod defaultValue = AnimationMethod.forward,
4693
    Object? target,
4694
    bool warmUp = false,
4695
  }) {
4696
    final value = _readProp(key, target, warmUp);
8✔
4697

4698
    if (value is AnimationMethod) return value;
8✔
4699

4700
    if (value == null) return defaultValue;
4701

4702
    switch (value) {
4703
      case String():
8✔
4704
        if (envAttributeWarmUpEnabled) {
4705
          if (warmUp) {
4706
            return _animationMethodStringLookupTable[value]!;
×
4707
          } else {
4708
            return _json[key] = _animationMethodStringLookupTable[value]!;
×
4709
          }
4710
        } else {
4711
          return _json[key] = _animationMethodStringLookupTable[value]!;
8✔
4712
        }
4713
      case int():
8✔
4714
        if (envAttributeWarmUpEnabled) {
4715
          if (warmUp) {
4716
            return _animationMethodIntLookupTable[value]!;
4✔
4717
          } else {
4718
            return _json[key] = _animationMethodIntLookupTable[value]!;
×
4719
          }
4720
        } else {
4721
          return _json[key] = _animationMethodIntLookupTable[value]!;
8✔
4722
        }
4723
      default:
4724
        return defaultValue;
4725
    }
4726
  }
4727

4728
  /// Retrieves a [TweenType] value from the JSON map for the given [key].
4729
  ///
4730
  /// Looks up the value associated with [key] in the JSON. If the value is already a [TweenType],
4731
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4732
  /// Otherwise, it returns [defaultValue].
4733
  ///
4734
  /// - [key]: The key to look up in the JSON map. Defaults to 'type'.
4735
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to TweenType.tween.
4736
  ///
4737
  /// Returns:
4738
  /// - A [TweenType] if the value is valid or can be parsed.
4739
  /// - [defaultValue] if the value is not a valid [TweenType] or cannot be parsed.
4740
  @preferInline
4✔
4741
  TweenType tweenType({
4742
    String key = "type",
4743
    TweenType defaultValue = TweenType.tween,
4744
  }) {
4745
    final value = _json[key];
4✔
4746

4747
    if (value is TweenType) return value;
4✔
4748

4749
    if (value == null) return defaultValue;
4750

4751
    switch (value) {
4752
      case String():
4✔
4753
        return _json[key] = _tweenTypeStringLookupTable[value]!;
8✔
4754
      case int():
4✔
4755
        return _json[key] = _tweenTypeIntLookupTable[value]!;
8✔
4756
      default:
4757
        return defaultValue;
4758
    }
4759
  }
4760

4761
  /// Retrieves a list of [DuitTweenDescription] values from the JSON map for the given [key].
4762
  ///
4763
  /// Looks up the value associated with [key] in the JSON. If the value is already a [List<Map<String, dynamic>>],
4764
  /// it is returned as is. If the value is a [List<dynamic>], it attempts to parse it into a [List<DuitTweenDescription>].
4765
  /// Otherwise, it returns [defaultValue].
4766
  ///
4767
  /// - [key]: The key to look up in the JSON map. Defaults to 'tweenDescriptions'.
4768
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to [].
4769
  ///
4770
  /// Returns:
4771
  /// - A [List<DuitTweenDescription>] if the value is valid or can be parsed.
4772
  /// - [defaultValue] if the value is not a valid [List<DuitTweenDescription>] or cannot be parsed.
4773
  /// - `null` if both the value and [defaultValue] are null.
4774
  @preferInline
4✔
4775
  List<DuitTweenDescription> tweens({
4776
    String key = "tweenDescriptions",
4777
  }) {
4778
    final value = _json[key];
4✔
4779

4780
    if (value is List) {
4✔
4781
      final list = <DuitTweenDescription>[];
4✔
4782

4783
      for (final tweenDescription in value) {
8✔
4784
        if (tweenDescription is DuitTweenDescription) {
4✔
4785
          list.add(tweenDescription);
×
4786
          continue;
4787
        }
4788
        if (tweenDescription is! Map<String, dynamic>) continue;
4✔
4789

4790
        final tweenData = DuitDataSource(tweenDescription);
4✔
4791
        final tweenType = tweenData.tweenType();
4✔
4792

4793
        final tweenObj = switch (tweenType) {
4794
          TweenType.tween => TweenDescription(
8✔
4795
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4796
              duration: tweenData.duration(),
4✔
4797
              begin: tweenData.getDouble(key: "begin"),
4✔
4798
              end: tweenData.getDouble(key: "end"),
4✔
4799
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4800
              trigger: tweenData.animationTrigger(),
4✔
4801
              method: tweenData.animationMethod(),
4✔
4802
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4803
              interval: tweenData.animationInterval(),
4✔
4804
            ),
4805
          TweenType.colorTween => ColorTweenDescription(
8✔
4806
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4807
              duration: tweenData.duration(),
4✔
4808
              begin: tweenData.parseColor(key: "begin"),
4✔
4809
              end: tweenData.parseColor(key: "end"),
4✔
4810
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4811
              trigger: tweenData.animationTrigger(),
4✔
4812
              method: tweenData.animationMethod(),
4✔
4813
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4814
              interval: tweenData.animationInterval(),
4✔
4815
            ),
4816
          TweenType.textStyleTween => TextStyleTweenDescription(
8✔
4817
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4818
              duration: tweenData.duration(),
4✔
4819
              begin: tweenData.textStyle(
4✔
4820
                key: "begin",
4821
                defaultValue: const TextStyle(),
4822
              )!,
4823
              end: tweenData.textStyle(
4✔
4824
                key: "end",
4825
                defaultValue: const TextStyle(),
4826
              )!,
4827
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4828
              trigger: tweenData.animationTrigger(),
4✔
4829
              method: tweenData.animationMethod(),
4✔
4830
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4831
              interval: tweenData.animationInterval(),
4✔
4832
            ),
4833
          TweenType.decorationTween => DecorationTweenDescription(
8✔
4834
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4835
              duration: tweenData.duration(),
4✔
4836
              begin: tweenData.decoration(
4✔
4837
                key: "begin",
4838
                defaultValue: const BoxDecoration(),
4839
              )!,
4840
              end: tweenData.decoration(
4✔
4841
                key: "end",
4842
                defaultValue: const BoxDecoration(),
4843
              )!,
4844
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4845
              trigger: tweenData.animationTrigger(),
4✔
4846
              method: tweenData.animationMethod(),
4✔
4847
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4848
              interval: tweenData.animationInterval(),
4✔
4849
            ),
4850
          TweenType.alignmentTween => AlignmentTweenDescription(
8✔
4851
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4852
              duration: tweenData.duration(),
4✔
4853
              begin: tweenData.alignment(
4✔
4854
                key: "begin",
4855
                defaultValue: Alignment.center,
4856
              )!,
4857
              end: tweenData.alignment(
4✔
4858
                key: "end",
4859
                defaultValue: Alignment.center,
4860
              )!,
4861
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4862
              trigger: tweenData.animationTrigger(),
4✔
4863
              method: tweenData.animationMethod(),
4✔
4864
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4865
              interval: tweenData.animationInterval(),
4✔
4866
            ),
4867
          TweenType.sizeTween => SizeTweenDescription(
8✔
4868
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4869
              duration: tweenData.duration(),
4✔
4870
              begin: tweenData.size("begin"),
4✔
4871
              end: tweenData.size("end"),
4✔
4872
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4873
              trigger: tweenData.animationTrigger(),
4✔
4874
              method: tweenData.animationMethod(),
4✔
4875
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4876
              interval: tweenData.animationInterval(),
4✔
4877
            ),
4878
          TweenType.edgeInsetsTween => EdgeInsetsTweenDescription(
8✔
4879
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4880
              duration: tweenData.duration(),
4✔
4881
              begin: tweenData.edgeInsets(
4✔
4882
                key: "begin",
4883
                defaultValue: EdgeInsets.zero,
4884
              )!,
4885
              end: tweenData.edgeInsets(
4✔
4886
                key: "end",
4887
                defaultValue: EdgeInsets.zero,
4888
              )!,
4889
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4890
              trigger: tweenData.animationTrigger(),
4✔
4891
              method: tweenData.animationMethod(),
4✔
4892
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4893
              interval: tweenData.animationInterval(),
4✔
4894
            ),
4895
          TweenType.boxConstraintsTween => BoxConstraintsTweenDescription(
8✔
4896
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4897
              duration: tweenData.duration(),
4✔
4898
              begin: tweenData.boxConstraints(
4✔
4899
                key: "begin",
4900
                defaultValue: const BoxConstraints(),
4901
              )!,
4902
              end: tweenData.boxConstraints(
4✔
4903
                key: "end",
4904
                defaultValue: const BoxConstraints(),
4905
              )!,
4906
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4907
              trigger: tweenData.animationTrigger(),
4✔
4908
              method: tweenData.animationMethod(),
4✔
4909
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4910
              interval: tweenData.animationInterval(),
4✔
4911
            ),
4912
          TweenType.borderTween => BorderTweenDescription(
8✔
4913
              animatedPropKey: tweenData.getString(key: "animatedPropKey"),
4✔
4914
              duration: tweenData.duration(),
4✔
4915
              begin:
4916
                  tweenData.border(key: "begin", defaultValue: const Border())!,
4✔
4917
              end: tweenData.border(key: "end", defaultValue: const Border())!,
4✔
4918
              curve: tweenData.curve(defaultValue: Curves.linear)!,
4✔
4919
              trigger: tweenData.animationTrigger(),
4✔
4920
              method: tweenData.animationMethod(),
4✔
4921
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4922
              interval: tweenData.animationInterval(),
4✔
4923
            ),
4924
          TweenType.group => TweenDescriptionGroup(
8✔
4925
              duration: tweenData.duration(),
4✔
4926
              groupId: tweenData.getString(key: "groupId"),
4✔
4927
              tweens: tweenData.tweens(key: "tweens"),
4✔
4928
              method: tweenData.animationMethod(),
4✔
4929
              reverseOnRepeat: tweenData.getBool("reverseOnRepeat"),
4✔
4930
              trigger: tweenData.animationTrigger(),
4✔
4931
            ),
4932
        } as DuitTweenDescription;
4933

4934
        list.add(tweenObj);
4✔
4935
      }
4936

4937
      return list;
4938
    }
4939

4940
    return [];
4✔
4941
  }
4942

4943
  /// Retrieves a [CollapseMode] value from the JSON map for the given [key].
4944
  ///
4945
  /// Looks up the value associated with [key] in the JSON. If the value is already a [CollapseMode],
4946
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
4947
  /// Otherwise, it returns [defaultValue].
4948
  ///
4949
  /// - [key]: The key to look up in the JSON map. Defaults to 'collapseMode'.
4950
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to CollapseMode.parallax.
4951
  ///
4952
  /// Returns:
4953
  /// - A [CollapseMode] if the value is valid or can be parsed.
4954
  /// - [defaultValue] if the value is not a valid [CollapseMode] or cannot be parsed.
4955
  @preferInline
8✔
4956
  CollapseMode collapseMode({
4957
    String key = FlutterPropertyKeys.collapseMode,
4958
    CollapseMode defaultValue = CollapseMode.parallax,
4959
    Object? target,
4960
    bool warmUp = false,
4961
  }) {
4962
    final value = _readProp(key, target, warmUp);
8✔
4963

4964
    if (value is CollapseMode) return value;
8✔
4965

4966
    if (value == null) return defaultValue;
4967

4968
    switch (value) {
4969
      case String():
8✔
4970
        if (envAttributeWarmUpEnabled) {
4971
          if (warmUp) {
4972
            return _collapseModeStringLookupTable[value]!;
4✔
4973
          } else {
4974
            return _json[key] = _collapseModeStringLookupTable[value]!;
×
4975
          }
4976
        } else {
4977
          return _json[key] = _collapseModeStringLookupTable[value]!;
8✔
4978
        }
4979
      case int():
4✔
4980
        if (envAttributeWarmUpEnabled) {
4981
          if (warmUp) {
4982
            return _collapseModeIntLookupTable[value]!;
×
4983
          } else {
4984
            return _json[key] = _collapseModeIntLookupTable[value]!;
×
4985
          }
4986
        } else {
4987
          return _json[key] = _collapseModeIntLookupTable[value]!;
8✔
4988
        }
4989
      default:
4990
        return defaultValue;
4991
    }
4992
  }
4993

4994
  /// Retrieves a list of [StretchMode] values from the JSON map for the given [key].
4995
  ///
4996
  /// Looks up the value associated with [key] in the JSON. If the value is already a [List<StretchMode>],
4997
  /// it is returned as is. If the value is a [List<String>] or [List<int>], it is converted using the lookup tables.
4998
  /// Otherwise, it returns [defaultValue].
4999
  ///
5000
  /// - [key]: The key to look up in the JSON map. Defaults to 'stretchMode'.
5001
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to [StretchMode.zoomBackground].
5002
  ///
5003
  /// Returns:
5004
  /// - A [List<StretchMode>] if the value is valid or can be parsed.
5005
  /// - [defaultValue] if the value is not a valid [List<StretchMode>] or cannot be parsed.
5006
  /// - `null` if both the value and [defaultValue] are null.
5007
  @preferInline
8✔
5008
  List<StretchMode> stretchModes({
5009
    String key = FlutterPropertyKeys.stretchModes,
5010
    List<StretchMode> defaultValue = const [
5011
      StretchMode.zoomBackground,
5012
    ],
5013
    Object? target,
5014
    bool warmUp = false,
5015
  }) {
5016
    final value = _readProp(key, target, warmUp);
8✔
5017

5018
    if (value is List<StretchMode>) return value;
8✔
5019

5020
    if (value == null) return defaultValue;
5021

5022
    if (value is List<String>) {
8✔
5023
      final list = <StretchMode>[];
4✔
5024
      for (final item in value) {
8✔
5025
        final stretchMode = _stretchModeStringLookupTable[item];
4✔
5026
        if (stretchMode != null) {
5027
          list.add(stretchMode);
4✔
5028
        }
5029
      }
5030

5031
      if (envAttributeWarmUpEnabled) {
5032
        if (warmUp) {
5033
          return list.isNotEmpty ? list : defaultValue;
×
5034
        } else {
5035
          return _json[key] = list.isNotEmpty ? list : defaultValue;
×
5036
        }
5037
      } else {
5038
        return _json[key] = list.isNotEmpty ? list : defaultValue;
8✔
5039
      }
5040
    }
5041

5042
    if (value is List<int>) {
8✔
5043
      final list = <StretchMode>[];
4✔
5044
      for (final item in value) {
8✔
5045
        final stretchMode = _stretchModeIntLookupTable[item];
4✔
5046
        if (stretchMode != null) {
5047
          list.add(stretchMode);
4✔
5048
        }
5049
      }
5050

5051
      if (envAttributeWarmUpEnabled) {
5052
        if (warmUp) {
5053
          return list.isNotEmpty ? list : defaultValue;
×
5054
        } else {
5055
          return _json[key] = list.isNotEmpty ? list : defaultValue;
×
5056
        }
5057
      } else {
5058
        return _json[key] = list.isNotEmpty ? list : defaultValue;
8✔
5059
      }
5060
    }
5061

5062
    return defaultValue;
5063
  }
5064

5065
  /// Retrieves a [ExecutionModifier] value from the JSON map for the given [key].
5066
  ///
5067
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ExecutionModifier],
5068
  /// it is returned as is. If the value is a [String] or [int], it is converted using the lookup tables.
5069
  /// Otherwise, it returns [defaultValue].
5070
  ///
5071
  /// - [key]: The key to look up in the JSON map. Defaults to 'executionModifier'.
5072
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to ExecutionModifier.throttle.
5073
  ///
5074
  /// Returns:
5075
  /// - A [ExecutionModifier] if the value is valid or can be parsed.
5076
  /// - [defaultValue] if the value is not a valid [ExecutionModifier] or cannot be parsed.
5077
  @preferInline
8✔
5078
  ExecutionModifier _executionModifier({
5079
    String key = FlutterPropertyKeys.modifier,
5080
    ExecutionModifier defaultValue = ExecutionModifier.debounce,
5081
    Object? target,
5082
    bool warmUp = false,
5083
  }) {
5084
    final value = _readProp(key, target, warmUp);
8✔
5085

5086
    if (value is ExecutionModifier) return value;
8✔
5087

5088
    if (value == null) return defaultValue;
5089

5090
    switch (value) {
5091
      case String():
8✔
5092
        if (envAttributeWarmUpEnabled) {
5093
          if (warmUp) {
5094
            return _executionModifierStringLookupTable[value]!;
×
5095
          } else {
5096
            return _json[key] = _executionModifierStringLookupTable[value]!;
×
5097
          }
5098
        } else {
5099
          return _json[key] = _executionModifierStringLookupTable[value]!;
8✔
5100
        }
5101
      case int():
8✔
5102
        if (envAttributeWarmUpEnabled) {
5103
          if (warmUp) {
5104
            return _executionModifierIntLookupTable[value]!;
×
5105
          } else {
5106
            return _json[key] = _executionModifierIntLookupTable[value]!;
×
5107
          }
5108
        } else {
5109
          return _json[key] = _executionModifierIntLookupTable[value]!;
8✔
5110
        }
5111
      default:
5112
        return defaultValue;
5113
    }
5114
  }
5115

5116
  /// Retrieves a [FocusNode] from the JSON map for the given [key].
5117
  ///
5118
  /// Looks up the value associated with [key] in the JSON. If the value is already a [FocusNode],
5119
  /// it is returned as is. If the value is a `Map<String, dynamic>`, it attempts to construct
5120
  /// a [FocusNode] using the provided map. If the value is `null`, [defaultValue] is returned.
5121
  ///
5122
  /// - [key]: The key to look up in the JSON map. Defaults to [FlutterPropertyKeys.focusNode].
5123
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to `null`.
5124
  /// - [target]: Optional object to override or supplement the lookup.
5125
  /// - [warmUp]: If `true` during attribute warm-up, skips writing back to the JSON.
5126
  ///
5127
  /// Returns:
5128
  /// - A [FocusNode] if the value is valid or can be parsed.
5129
  /// - [defaultValue] if the value is not a valid [FocusNode] or cannot be parsed.
5130
  @preferInline
8✔
5131
  FocusNode? focusNode({
5132
    String key = FlutterPropertyKeys.focusNode,
5133
    FocusNode? defaultValue,
5134
    Object? target,
5135
    bool warmUp = false,
5136
  }) {
5137
    final value = _readProp(key, target, warmUp);
8✔
5138

5139
    if (value is FocusNode) return value;
8✔
5140

5141
    if (value == null) return defaultValue;
5142

5143
    if (value is Map<String, dynamic>) {
8✔
5144
      if (envAttributeWarmUpEnabled) {
5145
        if (warmUp) {
5146
          return _focusNodeFromMap(value);
4✔
5147
        } else {
5148
          return _json[key] = _focusNodeFromMap(value);
×
5149
        }
5150
      } else {
5151
        return _json[key] = _focusNodeFromMap(value);
8✔
5152
      }
5153
    }
5154
    return defaultValue;
5155
  }
5156

5157
  /// Attempts to construct a [FocusNode] from a [Map<String, dynamic>] representation.
5158
  ///
5159
  /// This utility is used internally to parse a JSON-like map of properties and
5160
  /// build a [FocusNode] using values extracted from the map. It reads recognized focus node
5161
  /// properties such as `"debugLabel"`, `"skipTraversal"`, `"canRequestFocus"`,
5162
  /// `"descendantsAreFocusable"`, and `"descendantsAreTraversable"`, with appropriate
5163
  /// defaults as in the standard [FocusNode] constructor.
5164
  ///
5165
  /// Any property missing from the input [map] will fall back to the corresponding
5166
  /// default value provided by [FocusNode].
5167
  ///
5168
  /// Returns a new [FocusNode] instance with the configured properties,
5169
  /// or (in practice) throws if required types are invalid.
5170
  ///
5171
  /// Example:
5172
  /// ```
5173
  /// final node = _focusNodeFromMap({
5174
  ///   "debugLabel": "Main",
5175
  ///   "skipTraversal": true,
5176
  /// });
5177
  /// ```
5178
  @preferInline
8✔
5179
  FocusNode _focusNodeFromMap(Map<String, dynamic> map) {
5180
    final source = DuitDataSource(map);
8✔
5181

5182
    return FocusNode(
8✔
5183
      debugLabel: source.tryGetString("debugLabel"),
8✔
5184
      skipTraversal: source.getBool("skipTraversal"),
8✔
5185
      canRequestFocus: source.getBool(
8✔
5186
        "canRequestFocus",
5187
        defaultValue: true,
5188
      ),
5189
      descendantsAreFocusable: source.getBool(
8✔
5190
        "descendantsAreFocusable",
5191
        defaultValue: true,
5192
      ),
5193
      descendantsAreTraversable: source.getBool(
8✔
5194
        "descendantsAreTraversable",
5195
        defaultValue: true,
5196
      ),
5197
    );
5198
  }
5199

5200
  TraversalDirection? traversalDirection({
8✔
5201
    String key = FlutterPropertyKeys.traversalDirection,
5202
    TraversalDirection? defaultValue,
5203
    Object? target,
5204
    bool warmUp = false,
5205
  }) {
5206
    final value = _readProp(key, target, warmUp);
8✔
5207

5208
    if (value is TraversalDirection) return value;
8✔
5209

5210
    if (value == null) return defaultValue;
5211

5212
    switch (value) {
5213
      case String():
8✔
5214
        if (envAttributeWarmUpEnabled) {
5215
          if (warmUp) {
5216
            return _traversalDirectionStringLookupTable[value];
4✔
5217
          } else {
NEW
5218
            return _json[key] = _traversalDirectionStringLookupTable[value];
×
5219
          }
5220
        } else {
5221
          return _json[key] = _traversalDirectionStringLookupTable[value];
8✔
5222
        }
5223
      case int():
4✔
5224
        if (envAttributeWarmUpEnabled) {
5225
          if (warmUp) {
NEW
5226
            return _traversalDirectionIntLookupTable[value];
×
5227
          } else {
NEW
5228
            return _json[key] = _traversalDirectionIntLookupTable[value];
×
5229
          }
5230
        } else {
5231
          return _json[key] = _traversalDirectionIntLookupTable[value];
8✔
5232
        }
5233
      default:
5234
        return defaultValue;
5235
    }
5236
  }
5237

5238
  UnfocusDisposition unfocusDisposition({
14✔
5239
    String key = FlutterPropertyKeys.unfocusDisposition,
5240
    UnfocusDisposition defaultValue = UnfocusDisposition.scope,
5241
    Object? target,
5242
    bool warmUp = false,
5243
  }) {
5244
    final value = _readProp(key, target, warmUp);
8✔
5245

5246
    if (value is UnfocusDisposition) return value;
8✔
5247

5248
    if (value == null) return defaultValue;
5249

5250
    switch (value) {
5251
      case String():
8✔
5252
        if (envAttributeWarmUpEnabled) {
5253
          if (warmUp) {
5254
            return _unfocusDispositionStringLookupTable[value]!;
4✔
5255
          } else {
NEW
5256
            return _json[key] = _unfocusDispositionStringLookupTable[value]!;
×
5257
          }
5258
        } else {
5259
          return _json[key] = _unfocusDispositionStringLookupTable[value]!;
8✔
5260
        }
5261
      case int():
4✔
5262
        if (envAttributeWarmUpEnabled) {
5263
          if (warmUp) {
NEW
5264
            return _unfocusDispositionIntLookupTable[value]!;
×
5265
          } else {
NEW
5266
            return _json[key] = _unfocusDispositionIntLookupTable[value]!;
×
5267
          }
5268
        } else {
5269
          return _json[key] = _unfocusDispositionIntLookupTable[value]!;
8✔
5270
        }
5271
      default:
5272
        return defaultValue;
5273
    }
5274
  }
5275

5276
  /// Retrieves an [ExecutionOptions] value from the JSON map for the given [key].
5277
  ///
5278
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ExecutionOptions],
5279
  /// it is returned as is. If the value is a [Map<String, dynamic>], it is converted using the lookup tables.
5280
  /// Otherwise, it returns [defaultValue].
5281
  ///
5282
  /// - [key]: The key to look up in the JSON map. Defaults to 'options'.
5283
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
5284
  ///
5285
  /// Returns:
5286
  /// - An [ExecutionOptions] if the value is valid or can be parsed.
5287
  /// - [defaultValue] if the value is not a valid [ExecutionOptions] or cannot be parsed.
5288
  /// - `null` if both the value and [defaultValue] are null.
5289
  @preferInline
4✔
5290
  ExecutionOptions _executionOptionsFromMap(Map<String, dynamic> json) {
5291
    final source = DuitDataSource(json);
4✔
5292
    return ExecutionOptions(
4✔
5293
      modifier: source._executionModifier(),
4✔
5294
      duration: source.duration(),
4✔
5295
    );
5296
  }
5297

5298
  /// Retrieves an [ExecutionOptions] value from the JSON map for the given [key].
5299
  ///
5300
  /// Looks up the value associated with [key] in the JSON. If the value is already a [ExecutionOptions],
5301
  /// it is returned as is. If the value is a [Map<String, dynamic>], it is converted using the lookup tables.
5302
  /// Otherwise, it returns [defaultValue].
5303
  ///
5304
  /// - [key]: The key to look up in the JSON map. Defaults to 'options'.
5305
  /// - [defaultValue]: The value to return if the key is not found or cannot be resolved. Defaults to null.
5306
  ///
5307
  /// Returns:
5308
  /// - An [ExecutionOptions] if the value is valid or can be parsed.
5309
  /// - [defaultValue] if the value is not a valid [ExecutionOptions] or cannot be parsed.
5310
  /// - `null` if both the value and [defaultValue] are null.
5311
  @preferInline
7✔
5312
  ExecutionOptions? executionOptions({
3✔
5313
    String key = "options",
5314
    ExecutionOptions? defaultValue,
5315
  }) {
5316
    final value = _json[key];
4✔
5317

5318
    if (value is ExecutionOptions) return value;
4✔
5319

5320
    if (value == null) return defaultValue;
5321

5322
    switch (value) {
5323
      case Map<String, dynamic>():
4✔
5324
        return _json[key] = _executionOptionsFromMap(value);
8✔
5325
      default:
5326
        return defaultValue;
5327
    }
5328
  }
5329

5330
  /// The dispatch map for attribute keys to their corresponding handler functions.
5331
  ///
5332
  /// This map associates each supported [FlutterPropertyKeys] value with a function
5333
  /// that is responsible for parsing, transforming, or resolving the attribute value
5334
  /// for that key. The handler functions are used by the attribute warm-up and
5335
  /// dispatching mechanisms to convert raw JSON or dynamic values into strongly-typed
5336
  /// Dart/Flutter objects as required by the framework.
5337
  ///
5338
  /// Each entry in the map is a key-value pair where:
5339
  /// - The key is a [String] representing a property key (typically from [FlutterPropertyKeys]).
5340
  /// - The value is a function of type [_DispatchFn], which takes the following parameters:
5341
  ///   - `self`: The current [DuitDataSource] instance.
5342
  ///   - `k`: The property key as a [String].
5343
  ///   - `d`: The default value for the property (if any).
5344
  ///   - `t`: The target value to be parsed or transformed.
5345
  ///   - `w`: A [bool] indicating whether attribute warm-up is enabled.
5346
  ///
5347
  /// The handler function returns the parsed or resolved value for the property,
5348
  /// or the original value if no transformation is required.
5349
  ///
5350
  /// This map is central to the attribute dispatching logic, allowing for
5351
  /// extensible and maintainable mapping between property keys and their
5352
  /// resolution logic. It is used internally by method such as [_dispatchCall]
5353
  /// to dynamically resolve property values at runtime.
5354
  ///
5355
  /// Example usage:
5356
  /// ```dart
5357
  /// final result = _dispatchMap['color']!(this, 'color', null, '#FFFFFF', true);
5358
  /// // result is a Color object parsed from the hex string
5359
  /// ```
5360
  static final Map<String, _DispatchFn> _dispatchMap = {
12✔
5361
    FlutterPropertyKeys.style: _dispatchStyleKeyEntryCall,
5362
    FlutterPropertyKeys.decoration: _dispatchDecorationKeyEntryCall,
5363
    FlutterPropertyKeys.color: (self, k, t, w) =>
4✔
5364
        self.tryParseColor(key: k, target: t, warmUp: w),
4✔
5365
    FlutterPropertyKeys.duration: (self, k, t, w) =>
4✔
5366
        self.duration(key: k, target: t, warmUp: w),
4✔
5367
    FlutterPropertyKeys.textAlign: (self, k, t, w) =>
4✔
5368
        self.textAlign(key: k, target: t, warmUp: w),
4✔
5369
    FlutterPropertyKeys.textDirection: (self, k, t, w) =>
4✔
5370
        self.textDirection(key: k, target: t, warmUp: w),
4✔
5371
    FlutterPropertyKeys.textOverflow: (self, k, t, w) =>
4✔
5372
        self.textOverflow(key: k, target: t, warmUp: w),
4✔
5373
    FlutterPropertyKeys.clipBehavior: (self, k, t, w) =>
4✔
5374
        self.clipBehavior(key: k, target: t, warmUp: w),
4✔
5375
    FlutterPropertyKeys.padding: (self, k, t, w) =>
4✔
5376
        self.edgeInsets(key: k, target: t, warmUp: w),
4✔
5377
    FlutterPropertyKeys.margin: (self, k, t, w) =>
4✔
5378
        self.edgeInsets(key: k, target: t, warmUp: w),
4✔
5379
    FlutterPropertyKeys.curve: (self, k, t, w) =>
4✔
5380
        self.curve(key: k, target: t, warmUp: w),
4✔
5381
    FlutterPropertyKeys.textWidthBasis: (self, k, t, w) =>
4✔
5382
        self.textWidthBasis(key: k, target: t, warmUp: w),
4✔
5383
    FlutterPropertyKeys.textBaseline: (self, k, t, w) =>
4✔
5384
        self.textBaseline(key: k, target: t, warmUp: w),
4✔
5385
    FlutterPropertyKeys.offset: (self, k, t, w) =>
4✔
5386
        self.offset(key: k, target: t, warmUp: w),
4✔
5387
    FlutterPropertyKeys.boxShadow: (self, k, t, w) =>
4✔
5388
        self.boxShadow(key: k, target: t, warmUp: w),
4✔
5389
    FlutterPropertyKeys.decorationStyle: (self, k, t, w) =>
4✔
5390
        self.textDecorationStyle(key: k, target: t, warmUp: w),
4✔
5391
    FlutterPropertyKeys.fontWeight: (self, k, t, w) =>
4✔
5392
        self.fontWeight(key: k, target: t, warmUp: w),
4✔
5393
    FlutterPropertyKeys.fontStyle: (self, k, t, w) =>
4✔
5394
        self.fontStyle(key: k, target: t, warmUp: w),
4✔
5395
    FlutterPropertyKeys.textSpan: (self, k, t, w) =>
4✔
5396
        self.textSpan(key: k, target: t, warmUp: w),
4✔
5397
    FlutterPropertyKeys.textHeightBehavior: (self, k, t, w) =>
4✔
5398
        self.textHeightBehavior(key: k, target: t, warmUp: w),
4✔
5399
    FlutterPropertyKeys.textScaler: (self, k, t, w) =>
4✔
5400
        self.textScaler(key: k, target: t, warmUp: w),
4✔
5401
    FlutterPropertyKeys.strutStyle: (self, k, t, w) =>
4✔
5402
        self.strutStyle(key: k, target: t, warmUp: w),
4✔
5403
    FlutterPropertyKeys.leadingDistribution: (self, k, t, w) =>
4✔
5404
        self.textLeadingDistribution(key: k, target: t, warmUp: w),
4✔
5405
    FlutterPropertyKeys.direction: (self, k, t, w) =>
4✔
5406
        self.axis(key: k, target: t, warmUp: w),
4✔
5407
    FlutterPropertyKeys.scrollDirection: (self, k, t, w) =>
4✔
5408
        self.axis(key: k, target: t, warmUp: w),
4✔
5409
    FlutterPropertyKeys.mainAxis: (self, k, t, w) =>
4✔
5410
        self.axis(key: k, target: t, warmUp: w),
4✔
5411
    FlutterPropertyKeys.wrapCrossAlignment: (self, k, t, w) =>
4✔
5412
        self.wrapCrossAlignment(key: k, target: t, warmUp: w),
4✔
5413
    FlutterPropertyKeys.wrapAlignment: (self, k, t, w) =>
4✔
5414
        self.wrapAlignment(key: k, target: t, warmUp: w),
4✔
5415
    FlutterPropertyKeys.runAlignment: (self, k, t, w) =>
4✔
5416
        self.wrapAlignment(key: k, target: t, warmUp: w),
4✔
5417
    FlutterPropertyKeys.constraints: (self, k, t, w) =>
4✔
5418
        self.boxConstraints(key: k, target: t, warmUp: w),
4✔
5419
    FlutterPropertyKeys.stackFit: (self, k, t, w) =>
4✔
5420
        self.stackFit(key: k, target: t, warmUp: w),
4✔
5421
    FlutterPropertyKeys.overflowBoxFit: (self, k, t, w) =>
4✔
5422
        self.overflowBoxFit(key: k, target: t, warmUp: w),
4✔
5423
    FlutterPropertyKeys.alignment: (self, k, t, w) =>
4✔
5424
        self.alignment(key: k, target: t, warmUp: w),
4✔
5425
    FlutterPropertyKeys.alignmentDirectional: (self, k, t, w) =>
4✔
5426
        self.alignmentDirectional(key: k, target: t, warmUp: w),
4✔
5427
    FlutterPropertyKeys.persistentFooterAlignment: (self, k, t, w) =>
4✔
5428
        self.alignmentDirectional(key: k, target: t, warmUp: w),
4✔
5429
    FlutterPropertyKeys.mainAxisAlignment: (self, k, t, w) =>
4✔
5430
        self.mainAxisAlignment(key: k, target: t, warmUp: w),
4✔
5431
    FlutterPropertyKeys.crossAxisAlignment: (self, k, t, w) =>
4✔
5432
        self.crossAxisAlignment(key: k, target: t, warmUp: w),
4✔
5433
    FlutterPropertyKeys.mainAxisSize: (self, k, t, w) =>
4✔
5434
        self.mainAxisSize(key: k, target: t, warmUp: w),
4✔
5435
    FlutterPropertyKeys.allowedInteraction: (self, k, t, w) =>
4✔
5436
        self.sliderInteraction(key: k, target: t, warmUp: w),
4✔
5437
    FlutterPropertyKeys.materialTapTargetSize: (self, k, t, w) =>
4✔
5438
        self.materialTapTargetSize(key: k, target: t, warmUp: w),
4✔
5439
    FlutterPropertyKeys.filterQuality: (self, k, t, w) =>
4✔
5440
        self.filterQuality(key: k, target: t, warmUp: w),
4✔
5441
    FlutterPropertyKeys.repeat: (self, k, t, w) =>
4✔
5442
        self.imageRepeat(key: k, target: t, warmUp: w),
4✔
5443
    FlutterPropertyKeys.fit: (self, k, t, w) =>
4✔
5444
        self.boxFit(key: k, target: t, warmUp: w),
4✔
5445
    FlutterPropertyKeys.byteData: (self, k, t, w) =>
4✔
5446
        self.uint8List(key: k, target: t, warmUp: w),
4✔
5447
    FlutterPropertyKeys.blendMode: (self, k, t, w) =>
4✔
5448
        self.blendMode(key: k, target: t, warmUp: w),
4✔
5449
    FlutterPropertyKeys.tileMode: (self, k, t, w) =>
4✔
5450
        self.tileMode(key: k, target: t, warmUp: w),
4✔
5451
    FlutterPropertyKeys.filter: (self, k, t, w) =>
4✔
5452
        self.imageFilter(key: k, target: t, warmUp: w),
4✔
5453
    FlutterPropertyKeys.verticalDirection: (self, k, t, w) =>
4✔
5454
        self.verticalDirection(key: k, target: t, warmUp: w),
4✔
5455
    FlutterPropertyKeys.shape: (self, k, t, w) =>
4✔
5456
        self.boxShape(key: k, target: t, warmUp: w),
4✔
5457
    FlutterPropertyKeys.border: (self, k, t, w) =>
4✔
5458
        self.border(key: k, target: t, warmUp: w),
4✔
5459
    FlutterPropertyKeys.side: (self, k, t, w) =>
4✔
5460
        self.borderSide(key: k, target: t, warmUp: w),
4✔
5461
    FlutterPropertyKeys.borderSide: (self, k, t, w) =>
4✔
5462
        self.borderSide(key: k, target: t, warmUp: w),
4✔
5463
    FlutterPropertyKeys.inputBorder: (self, k, t, w) =>
4✔
5464
        self.inputBorder(key: k, target: t, warmUp: w),
4✔
5465
    FlutterPropertyKeys.enabledBorder: (self, k, t, w) =>
4✔
5466
        self.inputBorder(key: k, target: t, warmUp: w),
4✔
5467
    FlutterPropertyKeys.errorBorder: (self, k, t, w) =>
4✔
5468
        self.inputBorder(key: k, target: t, warmUp: w),
4✔
5469
    FlutterPropertyKeys.focusedBorder: (self, k, t, w) =>
4✔
5470
        self.inputBorder(key: k, target: t, warmUp: w),
4✔
5471
    FlutterPropertyKeys.focusedErrorBorder: (self, k, t, w) =>
4✔
5472
        self.inputBorder(key: k, target: t, warmUp: w),
4✔
5473
    FlutterPropertyKeys.keyboardType: (self, k, t, w) =>
4✔
5474
        self.textInputType(key: k, target: t, warmUp: w),
4✔
5475
    FlutterPropertyKeys.borderRadius: (self, k, t, w) =>
4✔
5476
        self.borderRadius(key: k, target: t, warmUp: w),
4✔
5477
    FlutterPropertyKeys.inputDecoration: (self, k, t, w) =>
4✔
5478
        self.inputDecoration(key: k, target: t, warmUp: w),
4✔
5479
    FlutterPropertyKeys.visualDensity: (self, k, t, w) =>
4✔
5480
        self.visualDensity(key: k, target: t, warmUp: w),
4✔
5481
    FlutterPropertyKeys.keyboardDismissBehavior: (self, k, t, w) =>
4✔
5482
        self.keyboardDismissBehavior(key: k, target: t, warmUp: w),
4✔
5483
    FlutterPropertyKeys.physics: (self, k, t, w) =>
4✔
5484
        self.scrollPhysics(key: k, target: t, warmUp: w),
4✔
5485
    FlutterPropertyKeys.dragStartBehavior: (self, k, t, w) =>
4✔
5486
        self.dragStartBehavior(key: k, target: t, warmUp: w),
4✔
5487
    FlutterPropertyKeys.hitTestBehavior: (self, k, t, w) =>
4✔
5488
        self.hitTestBehavior(key: k, target: t, warmUp: w),
4✔
5489
    FlutterPropertyKeys.interval: (self, k, t, w) =>
4✔
5490
        self.animationInterval(key: k, target: t, warmUp: w),
4✔
5491
    FlutterPropertyKeys.trigger: (self, k, t, w) =>
4✔
5492
        self.animationTrigger(key: k, target: t, warmUp: w),
4✔
5493
    FlutterPropertyKeys.method: (self, k, t, w) =>
4✔
5494
        self.animationMethod(key: k, target: t, warmUp: w),
4✔
5495
    FlutterPropertyKeys.collapseMode: (self, k, t, w) =>
4✔
5496
        self.collapseMode(key: k, target: t, warmUp: w),
4✔
5497
    FlutterPropertyKeys.stretchModes: (self, k, t, w) =>
4✔
5498
        self.stretchModes(key: k, target: t, warmUp: w),
4✔
5499
    FlutterPropertyKeys.modifier: (self, k, t, w) =>
4✔
5500
        self._executionModifier(key: k, target: t, warmUp: w),
4✔
5501
    FlutterPropertyKeys.focusNode: (self, k, t, w) =>
4✔
5502
        self.focusNode(key: k, target: t, warmUp: w),
4✔
5503
    FlutterPropertyKeys.traversalDirection: (self, k, t, w) =>
4✔
5504
        self.traversalDirection(key: k, target: t, warmUp: w),
4✔
5505
    FlutterPropertyKeys.unfocusDisposition: (self, k, t, w) =>
4✔
5506
        self.unfocusDisposition(key: k, target: t, warmUp: w),
4✔
5507
  };
5508

5509
  /// A specialized dispatcher for transforming objects stored under the "style" key
5510
  @preferInline
4✔
5511
  static dynamic _dispatchStyleKeyEntryCall(
5512
    DuitDataSource self,
5513
    String key,
5514
    Object? target,
5515
    bool warmUp,
5516
  ) {
5517
    if (target is TextStyle) return target;
4✔
5518

5519
    return switch (target) {
5520
      Map<String, dynamic>() => self.textStyle(
8✔
5521
          key: key,
5522
          target: target,
5523
          warmUp: warmUp,
5524
        ),
5525
      String() => self.borderStyle(
8✔
5526
          key: key,
5527
          target: target,
5528
          warmUp: warmUp,
5529
        ),
UNCOV
5530
      int() => self.borderStyle(
×
5531
          key: key,
5532
          target: target,
5533
          warmUp: warmUp,
5534
        ),
5535
      _ => null,
5536
    };
5537
  }
5538

5539
  @preferInline
4✔
5540
  static dynamic _dispatchDecorationKeyEntryCall(
5541
    DuitDataSource self,
5542
    String key,
5543
    Object? target,
5544
    bool warmUp,
5545
  ) {
5546
    if (target is Decoration) return target;
4✔
5547
    if (target is TextDecoration) return target;
4✔
5548

5549
    return switch (target) {
5550
      Map<String, dynamic>() => self.decoration(
8✔
5551
          key: key,
5552
          target: target,
5553
          warmUp: warmUp,
5554
        ),
5555
      String() => self.textDecoration(
8✔
5556
          key: key,
5557
          target: target,
5558
          warmUp: warmUp,
5559
        ),
5560
      int() => self.textDecoration(
×
5561
          key: key,
5562
          target: target,
5563
          warmUp: warmUp,
5564
        ),
5565
      _ => null,
5566
    };
5567
  }
5568

5569
  @preferInline
4✔
5570
  dynamic _dispatchCall(String key, Object? target) {
5571
    final fn = _dispatchMap[key];
8✔
5572

5573
    if (fn == null) {
5574
      return target;
5575
    } else {
5576
      return fn.call(this, key, target, true);
4✔
5577
    }
5578
  }
5579

5580
  //Proxy for _dispatchCall
5581
  @visibleForTesting
4✔
5582
  dynamic dispatchCall(String key, Object? target) =>
5583
      _dispatchCall(key, target);
4✔
5584

5585
  static Object? _handleKVPair(Object? key, Object? value) {
4✔
5586
    if (FlutterPropertyKeys.values.contains(key)) {
4✔
5587
      return DuitDataSource(const <String, dynamic>{})
4✔
5588
          ._dispatchCall(key! as String, value);
4✔
5589
    } else {
5590
      return value;
5591
    }
5592
  }
5593

5594
  // Returns the json reviver function.
5595
  //
5596
  // If attribute warm up is enabled, it returns the function.
5597
  // Otherwise, it returns null.
5598
  //
5599
  // The json reviver function is used to parse the JSON data to Dart/Flutter types.
5600
  static Object? Function(Object? key, Object? value)? get jsonReviver {
4✔
5601
    if (envAttributeWarmUpEnabled) {
5602
      return _handleKVPair;
5603
    } else {
5604
      return null;
5605
    }
5606
  }
5607
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc