Skip to content

Commit 1ca7a20

Browse files
committed
Component Instances #38
1 parent 5b80004 commit 1ca7a20

File tree

9 files changed

+155
-17
lines changed

9 files changed

+155
-17
lines changed

lib/src/api/field_access.dart

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ sealed class FieldAccess<T extends Object?> {
6060

6161
final DefaultFieldValueCallback<T>? _defaultValue;
6262

63+
/// Whether the field requires layout when changed.
64+
final bool requiresLayout;
65+
6366
/// The default value of the field.
6467
DefaultFieldValueCallback<T>? get getDefaultValue => _defaultValue;
6568

6669
/// The serialized value of the field.
67-
dynamic serialize(T? obj) => obj;
70+
Object? serialize(T? obj) => obj;
6871

6972
/// The dynamic key type of the field, used by the dynamic settings panel to
7073
/// determine the type of the field to be displayed and modified.
@@ -95,6 +98,7 @@ sealed class FieldAccess<T extends Object?> {
9598
this.getValue,
9699
this.setter, {
97100
DefaultFieldValueCallback<T>? defaultValue,
101+
this.requiresLayout = false,
98102
}) : _defaultValue = defaultValue;
99103
}
100104

@@ -107,6 +111,7 @@ final class StringFieldAccess extends FieldAccess<String> {
107111
super.getValue,
108112
super.setter, {
109113
super.defaultValue,
114+
super.requiresLayout,
110115
});
111116

112117
@override
@@ -127,22 +132,23 @@ final class NumFieldAccess<Number extends num?> extends FieldAccess<Number> {
127132
this.min,
128133
this.max,
129134
super.defaultValue,
135+
super.requiresLayout,
130136
});
131137

132138
@override
133139
String get dynamicKeyType => getValue() is double ? 'double' : 'int';
134140

135141
/// The minimum value of the field.
136-
final FieldGetterCallback<Number>? min;
142+
final Number? min;
137143

138144
/// The maximum value of the field.
139-
final FieldGetterCallback<Number>? max;
145+
final Number? max;
140146

141147
@override
142148
Map<String, dynamic> get supplementarySchema => {
143149
if (getValue() is double) 'fractionDigits': 2,
144-
if (min case FieldGetterCallback<Number> min) 'min': min(),
145-
if (max case FieldGetterCallback<Number> max) 'max': max(),
150+
if (min case Number min) 'min': min,
151+
if (max case Number max) 'max': max,
146152
};
147153

148154
@override
@@ -158,6 +164,7 @@ final class BoolFieldAccess extends FieldAccess<bool> {
158164
super.getValue,
159165
super.setter, {
160166
super.defaultValue,
167+
super.requiresLayout,
161168
});
162169

163170
@override
@@ -177,6 +184,7 @@ final class ObjectFieldAccess<T extends FieldsHolder> extends FieldAccess<T> {
177184
super.getValue,
178185
super.setter, {
179186
super.defaultValue,
187+
super.requiresLayout,
180188
});
181189

182190
@override
@@ -198,21 +206,27 @@ final class TextStyleFieldAccess<T extends TextProp> extends FieldAccess<T> {
198206
super.getValue,
199207
super.setter, {
200208
super.defaultValue,
209+
super.requiresLayout,
201210
});
202211

203212
@override
204213
String get dynamicKeyType => 'text-style';
205214

215+
@override
216+
Object? serialize(TextProp? obj) => obj?.toJson();
217+
206218
@override
207219
void setValue(Object? value) {
208220
if (T == StartEndProp) {
209221
final StartEndProp? typedValue = switch (value) {
222+
StartEndProp prop => prop,
210223
Map() => StartEndProp.fromJson(value),
211224
_ => null,
212225
};
213226
if (typedValue != null) setter(typedValue as T);
214227
} else if (T == TextProp) {
215228
final TextProp? typedValue = switch (value) {
229+
TextProp prop => prop,
216230
Map() => TextProp.fromJson(value),
217231
_ => null,
218232
};
@@ -230,13 +244,14 @@ final class IconFieldAccess extends FieldAccess<MultiSourceIconModel> {
230244
super.getValue,
231245
super.setter, {
232246
super.defaultValue,
247+
super.requiresLayout,
233248
});
234249

235250
@override
236251
String get dynamicKeyType => 'icon';
237252

238253
@override
239-
dynamic serialize(MultiSourceIconModel? obj) => obj?.toJson();
254+
Object? serialize(MultiSourceIconModel? obj) => obj?.toJson();
240255

241256
@override
242257
void setValue(Object? value) {
@@ -259,6 +274,7 @@ final class EnumFieldAccess<T extends Enum> extends FieldAccess<T> {
259274
super.setter, {
260275
required super.defaultValue,
261276
required FieldOptionsGetter<T> options,
277+
super.requiresLayout,
262278
}) : getOptions = options;
263279

264280
/// The options of the field.
@@ -268,7 +284,7 @@ final class EnumFieldAccess<T extends Enum> extends FieldAccess<T> {
268284
String get dynamicKeyType => 'options';
269285

270286
@override
271-
dynamic serialize(T? obj) => obj?.name;
287+
Object? serialize(T? obj) => obj?.name;
272288

273289
@override
274290
Map<String, dynamic> get supplementarySchema => {
@@ -297,6 +313,7 @@ final class IterableFieldAccess<T> extends FieldAccess<List<T>> {
297313
super.setter,
298314
this.itemLabel, {
299315
super.defaultValue,
316+
super.requiresLayout,
300317
});
301318

302319
/// The label of an item in this iterable.
@@ -353,7 +370,7 @@ final class ColorFieldAccess<T extends ColorRGB> extends FieldAccess<T?> {
353370
String get dynamicKeyType => 'color';
354371

355372
@override
356-
dynamic serialize(ColorRGB? obj) => obj?.toJson();
373+
Object? serialize(ColorRGB? obj) => obj?.toJson();
357374

358375
@override
359376
void setValue(Object? value) {
@@ -420,7 +437,7 @@ final class VariantAccess extends FieldAccess<String> {
420437
String get dynamicKeyType => 'options';
421438

422439
@override
423-
dynamic serialize(String? obj) => obj;
440+
Object? serialize(String? obj) => obj;
424441

425442
@override
426443
Map<String, dynamic> get supplementarySchema => {

lib/src/api/mixins.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,23 @@ mixin BlendMixin on BaseNode {
284284
this.inkWell = inkWell;
285285
}
286286

287+
@override
288+
FieldsMap generateFields() => {
289+
...super.generateFields(),
290+
'effects': IterableFieldAccess<Effect>(
291+
'Effects',
292+
'A list of fills applied to the node.',
293+
() => effects,
294+
(value) => effects = value,
295+
(item) => switch (item.type) {
296+
EffectType.innerShadow => 'Inner Shadow',
297+
EffectType.dropShadow => 'Drop Shadow',
298+
EffectType.layerBlur => 'Layer Blur',
299+
EffectType.backgroundBlur => 'Background Blur',
300+
},
301+
),
302+
};
303+
287304
@override
288305
String toString() =>
289306
"${super.toString()}\n Blend(${"opacity: $opacity, isMask: $isMask, effects: $effects, blendMode: $blendMode, inkWell: $inkWell"})";
@@ -644,6 +661,7 @@ mixin GeometryMixin on BaseNode {
644661
'strokes': IterableFieldAccess<PaintModel>(
645662
'Strokes',
646663
'A list of strokes applied to the node.',
664+
requiresLayout: true,
647665
() => strokes,
648666
(value) => strokes = value,
649667
(item) => switch (item.type) {
@@ -725,6 +743,17 @@ mixin ClipMixin on BaseNode {
725743
}) {
726744
this.clipsContent = clipsContent;
727745
}
746+
747+
@override
748+
FieldsMap generateFields() => {
749+
...super.generateFields(),
750+
'clipsContent': BoolFieldAccess(
751+
'Clip Content',
752+
'Clip the content outside.',
753+
() => clipsContent,
754+
(value) => clipsContent = value,
755+
),
756+
};
728757
}
729758

730759
/// Adds border shape properties to a node enabling the node to have differently
@@ -1009,6 +1038,29 @@ mixin RowColumnMixin on BaseNode {
10091038
this.mainAxisAlignment = mainAxisAlignment;
10101039
this.crossAxisAlignment = crossAxisAlignment;
10111040
}
1041+
1042+
@override
1043+
FieldsMap generateFields() => {
1044+
...super.generateFields(),
1045+
'mainAxisAlignment': EnumFieldAccess<MainAxisAlignmentC>(
1046+
'Main Axis Alignment',
1047+
'Alignment of the children along the main axis.',
1048+
() => mainAxisAlignment,
1049+
(value) => mainAxisAlignment = value,
1050+
defaultValue: () => MainAxisAlignmentC.center,
1051+
options: () => MainAxisAlignmentC.values,
1052+
requiresLayout: true,
1053+
),
1054+
'crossAxisAlignment': EnumFieldAccess<CrossAxisAlignmentC>(
1055+
'Cross Axis Alignment',
1056+
'Alignment of the children along the cross axis.',
1057+
() => crossAxisAlignment,
1058+
(value) => crossAxisAlignment = value,
1059+
defaultValue: () => CrossAxisAlignmentC.center,
1060+
options: () => CrossAxisAlignmentC.values,
1061+
requiresLayout: true,
1062+
),
1063+
};
10121064
}
10131065

10141066
/// A mixin that allows node behave like a placeholder for other nodes.

lib/src/api/models/effect.dart

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:codelessly_json_annotation/codelessly_json_annotation.dart';
22
import 'package:equatable/equatable.dart';
33

4+
import '../field_access.dart';
45
import '../generate_id.dart';
56
import '../mixins.dart';
67
import 'models.dart';
@@ -43,33 +44,33 @@ Object? _readId(Map json, String key) => json[key] ?? generateId();
4344

4445
/// A visual effect such as a shadow or blur.
4546
@JsonSerializable()
46-
class Effect with EquatableMixin, SerializableMixin {
47+
class Effect with EquatableMixin, SerializableMixin, FieldsHolder {
4748
@JsonKey(readValue: _readId)
4849

4950
/// Unique identifier of the effect.
5051
final String id;
5152

5253
/// Type of effect.
53-
final EffectType type;
54+
EffectType type;
5455

5556
/// Whether the affect is visible.
56-
final bool visible;
57+
bool visible;
5758

5859
/// Radius of the effect.
59-
final double radius;
60+
double radius;
6061

6162
/// The shadow spread, before blur is applied.
62-
final double? spread;
63+
double? spread;
6364

6465
/// The color of the shadow.
65-
final ColorRGBA? color;
66+
ColorRGBA? color;
6667

6768
/// Blend mode of the shadow.
6869
@JsonKey(unknownEnumValue: BlendModeC.srcOver)
69-
final BlendModeC? blendMode;
70+
BlendModeC? blendMode;
7071

7172
/// How far the shadow is projected in the x and y directions.
72-
final Vec? offset;
73+
Vec? offset;
7374

7475
/// Creates new [Effect] with given data.
7576
Effect({
@@ -174,6 +175,42 @@ class Effect with EquatableMixin, SerializableMixin {
174175
}
175176
}
176177

178+
@override
179+
FieldsMap generateFields() => {
180+
...super.generateFields(),
181+
'color': ColorFieldAccess<ColorRGBA>(
182+
'Color',
183+
'The color of the effect.',
184+
() => color,
185+
(value) => color = value,
186+
),
187+
'offsetX': NumFieldAccess<double?>(
188+
'Offset X',
189+
'How far the shadow is projected in the x and y directions.',
190+
() => offset?.x,
191+
(value) => offset = Vec(value ?? 0, offset?.y ?? 0),
192+
),
193+
'offsetY': NumFieldAccess<double?>(
194+
'Offset Y',
195+
'How far the shadow is projected in the x and y directions.',
196+
() => offset?.y,
197+
(value) => offset = Vec(offset?.x ?? 0, value ?? 0),
198+
),
199+
'spread': NumFieldAccess<double?>(
200+
'Spread',
201+
'The shadow spread, before blur is applied.',
202+
() => spread,
203+
(value) => spread = value,
204+
),
205+
'radius': NumFieldAccess<double>(
206+
'Radius',
207+
'Radius of the effect.',
208+
() => radius,
209+
(value) => radius = value,
210+
min: 0,
211+
),
212+
};
213+
177214
@override
178215
List<Object?> get props => [
179216
id,

lib/src/api/nodes/base_node.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,23 @@ abstract class BaseNode
749749
positioningMode = PositioningMode.align;
750750
}
751751

752+
@override
753+
FieldsMap generateFields() => {
754+
...super.generateFields(),
755+
'visible': BoolFieldAccess(
756+
'Visible',
757+
'Whether this widget is visible or not.',
758+
() => visible,
759+
(value) => visible = value,
760+
),
761+
'enabled': BoolFieldAccess(
762+
'Exclude',
763+
'Whether this widget is enabled or not.',
764+
() => !enabled,
765+
(value) => enabled = !value,
766+
),
767+
};
768+
752769
@override
753770
List<Object?> get props => [id];
754771
}

0 commit comments

Comments
 (0)