Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
## Unreleased

### Motion

- `MotionModel` on every node (`BaseNode.motion`): offset, scale, opacity,
rotation, 3D tilt with perspective and origin, an animated transition
(duration and curve), continuous spin, `loop` (restart or back and forth),
`enter`, `enterFrom`, `delayMs` and a bindable `replayKey`. Values bind as
`motion.<name>` variables.

### Triggers

- `timer` (`TriggerModel.intervalMs`) and `keyPress` (`TriggerModel.key`) on
canvases; `swipeLeft/Right/Up/Down` and `doubleTap` on frames, rectangles,
buttons, icons and text, beside `cursorEnter` and `cursorExit`. Trigger
JSON naming `hoverEnter` or `hoverExit` reads as `cursorEnter` and
`cursorExit` (`TriggerType.aliases`).

### Lists and sliders

- `ListViewProperties.stacked` (items drawn on top of each other) and `wrap`
with `wrapSpacing`, `wrapRunSpacing` and `wrapAlignment`.
- Sliders: `orientation` (vertical), `inverted`, thumb stroke, and a
`roundedRect` thumb shape with width, height and corners.
- Row/column JSON with `itemSpacing` is read as `spacing`.

### Variables and JSON

- JSON with a separate `formula` for a computed variable is read into its
value.
- Bindable `effectsVisible`, `strokeWeight`, `cornerRadius`, `fontWeight`
and a slider's `min`/`max` as property variables.
- `variableSyntaxIdentifierPattern` matches a `${= ...}` formula whole,
object literals included.
- `EdgeInsetsModel.fromJson` reads `{left, top, right, bottom}` and
`{horizontal, vertical}`; placeholders and lists read JSON without their
editor-only keys.

### New

- `SignatureNode` (`signature`), a draw-to-sign pad. Its value is the list
Expand Down
42 changes: 38 additions & 4 deletions lib/src/api/mixins.dart
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,22 @@ enum SliderTrackShapeEnum {
}
}

/// Represents the shape of a slider's thumb.
enum SliderThumbShapeEnum {
/// A circle of the slider's thumb radius.
circle,

/// A rectangle of the slider's thumb width and height with rounded
/// corners, like a fader cap.
roundedRect;

/// Display-able string representation of the enum.
String get prettify => switch (this) {
SliderThumbShapeEnum.circle => 'Circle',
SliderThumbShapeEnum.roundedRect => 'Rectangle',
};
}

/// When a slider shows its value indicator. Mirrors Flutter's
/// `ShowValueIndicator`.
enum ShowValueIndicatorC {
Expand Down Expand Up @@ -1045,8 +1061,9 @@ mixin PropertyVariableMixin on BaseNode {
/// Properties of the node that can be used in actions or can be changed by
/// an action.
///
/// Style properties (fill, stroke, opacity, width, height; a text's fill is
/// its color) can be set by
/// Style properties (fill, stroke, opacity, width, height, effectsVisible,
/// strokeWeight, cornerRadius; a text's fill is its color, and its
/// fontWeight a number from 100 to 900) can be set by
/// conditions, bound to variables or formulas, or changed by a set value
/// action, on any node that has them.
late final List<ValueModel> propertyVariables = [
Expand All @@ -1056,13 +1073,30 @@ mixin PropertyVariableMixin on BaseNode {
PaintValue(name: 'fill', value: geometry.fills.firstOrNull),
PaintValue(name: 'stroke', value: geometry.strokes.firstOrNull),
],
if (this case final TextNode text)
if (this case final TextNode text) ...[
PaintValue(
name: 'fill',
value: text.textMixedProps.firstOrNull?.fills.firstOrNull,
),
if (this case final BlendMixin blend)
IntValue(
name: 'fontWeight',
value:
((text.textMixedProps.firstOrNull?.fontName.weight?.index ?? 3) +
1) *
100,
),
],
if (this case final BlendMixin blend) ...[
DoubleValue(name: 'opacity', value: blend.opacity),
BoolValue(
name: 'effectsVisible',
value: blend.effects.every((effect) => effect.visible),
),
],
if (this case final GeometryMixin geometry)
DoubleValue(name: 'strokeWeight', value: geometry.strokeWeight),
if (this case final CornerMixin corner)
DoubleValue(name: 'cornerRadius', value: corner.cornerRadius.tl.x),
DoubleValue(name: 'width', value: basicBoxLocal.width),
DoubleValue(name: 'height', value: basicBoxLocal.height),
];
Expand Down
24 changes: 24 additions & 0 deletions lib/src/api/models/edge_insets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,24 @@ class EdgeInsetsModel with Equatable, DynamicSerializableMixin {
@override
List<Object> get props => [l, t, r, b];

static const Set<String> _longSideKeys = <String>{
'left',
'top',
'right',
'bottom',
'horizontal',
'vertical',
};

static double _side(Map<dynamic, dynamic> json, String side, String axis) =>
((json[side] ?? json[axis] ?? 0) as num).toDouble();

/// Factory constructor for creating a new [EdgeInsetsModel] instance
/// from JSON data.
///
/// Reads the stored forms (a number for all sides, `[horizontal,
/// vertical]`, `[l, t, r, b]`, `{l, t, r, b}`) and the spelled-out
/// `{left, top, right, bottom}` / `{horizontal, vertical}`.
factory EdgeInsetsModel.fromJson(dynamic json) {
return switch (json) {
num all => EdgeInsetsModel.all(all.toDouble()),
Expand All @@ -203,6 +219,14 @@ class EdgeInsetsModel with Equatable, DynamicSerializableMixin {
right: right.toDouble(),
bottom: bottom.toDouble(),
),
// Spelled-out sides, as Flutter names them; missing sides are 0.
Map<dynamic, dynamic> sides when sides.keys.any(_longSideKeys.contains) =>
EdgeInsetsModel.only(
left: _side(sides, 'left', 'horizontal'),
top: _side(sides, 'top', 'vertical'),
right: _side(sides, 'right', 'horizontal'),
bottom: _side(sides, 'bottom', 'vertical'),
),
_ => _$EdgeInsetsModelFromJson(json),
};
}
Expand Down
1 change: 1 addition & 0 deletions lib/src/api/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export 'input_border.dart';
export 'input_decoration.dart';
export 'letter_spacing.dart';
export 'line_height.dart';
export 'motion.dart';
export 'list_tile_control_affinity.dart';
export 'loop_animation.dart';
export 'navigation_bar_item.dart';
Expand Down
Loading
Loading