diff --git a/composer.json b/composer.json index 4556db4..7d20ce1 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "scripts": { "phpstan": "./vendor/bin/phpstan analyse --memory-limit=2G", "test": "./vendor/bin/pest", + "test:coverage": "./vendor/bin/pest --coverage --min=100", "style": "./vendor/bin/pint" }, "config": { diff --git a/src/Enums/WidgetSide.php b/src/Enums/WidgetSide.php new file mode 100644 index 0000000..186a74b --- /dev/null +++ b/src/Enums/WidgetSide.php @@ -0,0 +1,36 @@ += 0, 'offset must be greater than or equal to 0'); + assert($offset <= 1, 'offset must be less than or equal to 1'); + + return match ($this) { + WidgetSide::Top => [ + 'x' => $offset, + 'y' => 0, + ], + WidgetSide::Bottom => [ + 'x' => $offset, + 'y' => 1, + ], + WidgetSide::Left => [ + 'x' => 0, + 'y' => $offset, + ], + WidgetSide::Right => [ + 'x' => 1, + 'y' => $offset, + ], + }; + } +} diff --git a/src/MiroClipboardData.php b/src/MiroClipboardData.php index 8cf7552..724bbbe 100644 --- a/src/MiroClipboardData.php +++ b/src/MiroClipboardData.php @@ -3,6 +3,7 @@ namespace MiroClipboard; use MiroClipboard\Objects\MiroGroup; +use MiroClipboard\Objects\MiroLine; use MiroClipboard\Objects\MiroObject; use MiroClipboard\Utility\Makeable; @@ -41,6 +42,12 @@ public function addObject(MiroObject $object): static { if ($object instanceof MiroGroup) { return $this->addGroup($object); + } elseif ($object instanceof MiroLine) { + foreach ($object->getAdditionalObjects() as $obj) { + if (!$this->findObject($obj)) { + $this->objects[] = $obj; + } + } } $this->objects[] = $object; @@ -87,7 +94,19 @@ public function getObjects(): array return $this->objects; } - public static function parse(string $data): MiroClipboardData + public function findObject(int|MiroObject $object): false|MiroObject + { + $searchId = is_int($object) ? $object : $object->getId(); + foreach ($this->objects as $existing) { + if ($existing->getId() === $searchId) { + return $existing; + } + } + + return false; + } + + public static function parse(string|array $data): MiroClipboardData { return MiroParser::parse($data); } diff --git a/src/MiroParser.php b/src/MiroParser.php index b93953a..65df4e9 100644 --- a/src/MiroParser.php +++ b/src/MiroParser.php @@ -5,8 +5,6 @@ use MiroClipboard\Enums\ObjectType; use MiroClipboard\Enums\WidgetType; use MiroClipboard\Exceptions\ParserNotResolvedException; -use MiroClipboard\Objects\MiroGroup; -use MiroClipboard\Objects\MiroObject; use MiroClipboard\Parsers\GroupParser; use MiroClipboard\Parsers\LineParser; use MiroClipboard\Parsers\MiroParserInterface; @@ -17,15 +15,19 @@ class MiroParser { /** - * @param string $data + * @param string|array $data * * @throws ParserNotResolvedException * * @return MiroClipboardData */ - public static function parse(string $data): MiroClipboardData + public static function parse(string|array $data): MiroClipboardData { - $arrayData = decodeMiroDataString($data); + if (is_string($data)) { + $arrayData = decodeMiroDataString($data); + } else { + $arrayData = $data; + } $newClipboardData = MiroClipboardData::make(); @@ -35,11 +37,9 @@ public static function parse(string $data): MiroClipboardData } foreach ($newClipboardData->getObjects() as $object) { - if (!$object instanceof MiroGroup) { - continue; + if (method_exists($object, 'resolveClipboardDataReferences')) { + $object->resolveClipboardDataReferences($newClipboardData); } - - self::resolveGroupReferences($newClipboardData, $object); } return $newClipboardData; @@ -64,23 +64,4 @@ private static function resolveWidgetParser(array $data): MiroParserInterface default => throw new ParserNotResolvedException($data['widgetData']['type'] ?? 'null'), }; } - - private static function resolveGroupReferences(MiroClipboardData $clipboardData, MiroGroup $group): void - { - $groupObjectIds = $group->toArray()['items']; - - $groupObjects = array_reduce( - $clipboardData->getObjects(), - function(array $ax, MiroObject $object) use ($groupObjectIds) { - if (in_array($object->toArray()['id'], $groupObjectIds)) { - $ax[] = $object; - } - - return $ax; - }, - [] - ); - - $group->setRawObjects($groupObjects); - } } diff --git a/src/Objects/MiroGroup.php b/src/Objects/MiroGroup.php index 6c1268e..612fc9c 100644 --- a/src/Objects/MiroGroup.php +++ b/src/Objects/MiroGroup.php @@ -3,6 +3,7 @@ namespace MiroClipboard\Objects; use MiroClipboard\Enums\ObjectType; +use MiroClipboard\MiroClipboardData; use MiroClipboard\Utility\Makeable; class MiroGroup extends MiroObject @@ -50,11 +51,25 @@ public function getObjects(): array } /** + * @param MiroClipboardData $clipboardData + * + * @return void + * * @internal */ - public function setRawObjects(array $objects): void + public function resolveClipboardDataReferences(MiroClipboardData $clipboardData): void { - $this->objects = $objects; + $this->objects = array_reduce( + $clipboardData->getObjects(), + function(array $ax, MiroObject $object) { + if (in_array($object->toArray()['id'], $this->ids)) { + $ax[] = $object; + } + + return $ax; + }, + [] + ); } public function toArray(): array diff --git a/src/Objects/MiroLine.php b/src/Objects/MiroLine.php index 5e7215e..14c6c10 100644 --- a/src/Objects/MiroLine.php +++ b/src/Objects/MiroLine.php @@ -2,7 +2,9 @@ namespace MiroClipboard\Objects; +use MiroClipboard\Enums\WidgetSide; use MiroClipboard\Enums\WidgetType; +use MiroClipboard\MiroClipboardData; use MiroClipboard\MiroWidget; use MiroClipboard\Styles\MiroLineStyle; use MiroClipboard\Utility\SetPropertiesFromArray; @@ -38,6 +40,9 @@ class MiroLine extends MiroWidget 'widgetIndex' => -1, ]; + protected ?MiroObject $toObject = null; + protected ?MiroObject $fromObject = null; + public function __construct() { parent::__construct(); @@ -79,6 +84,26 @@ public function end(float $x, float $y): static return $this; } + public function from(MiroObject $object, WidgetSide $widgetSide = WidgetSide::Right, float $offset = 0.5): static + { + $this->fromObject = $object; + + $this->primary['widgetIndex'] = $object->id; + $this->primary['point'] = $widgetSide->pointForSide($offset); + + return $this; + } + + public function to(MiroObject $object, WidgetSide $widgetSide = WidgetSide::Left, float $offset = 0.5): static + { + $this->toObject = $object; + + $this->secondary['widgetIndex'] = $object->id; + $this->secondary['point'] = $widgetSide->pointForSide($offset); + + return $this; + } + public function addPoint(float $x, float $y): static { $this->points[] = [ @@ -111,6 +136,39 @@ public function addText(MiroLineText $text): static return $this; } + /** + * Return a list of objects that *may* need to be added to the clipboard data + * + * @return array + * + * @internal + */ + public function getAdditionalObjects(): array + { + return array_filter([ + $this->fromObject, + $this->toObject, + ]); + } + + /** + * @param MiroClipboardData $clipboardData + * + * @return void + * + * @internal + */ + public function resolveClipboardDataReferences(MiroClipboardData $clipboardData): void + { + if ($this->primary['widgetIndex'] != -1 && ($existing = $clipboardData->findObject($this->primary['widgetIndex']))) { + $this->fromObject = $existing; + } + + if ($this->secondary['widgetIndex'] != -1 && ($existing = $clipboardData->findObject($this->secondary['widgetIndex']))) { + $this->toObject = $existing; + } + } + public function toArray(): array { return [ diff --git a/src/Objects/MiroObject.php b/src/Objects/MiroObject.php index a983829..afd2d2b 100644 --- a/src/Objects/MiroObject.php +++ b/src/Objects/MiroObject.php @@ -30,6 +30,16 @@ public function initialId(string $initialId): static return $this; } + public function getId(): int + { + return $this->id; + } + + public function getInitialId(): string + { + return $this->initialId; + } + public function toArray(): array { return [ diff --git a/src/Objects/MiroShape.php b/src/Objects/MiroShape.php index 3185069..a6b389b 100644 --- a/src/Objects/MiroShape.php +++ b/src/Objects/MiroShape.php @@ -41,7 +41,7 @@ class MiroShape extends MiroWidget private float $relativeRotation = 0; - public function __construct(ShapeType $shapeType) + public function __construct(ShapeType $shapeType = ShapeType::Square) { parent::__construct(); diff --git a/src/Styles/MiroShapeStyle.php b/src/Styles/MiroShapeStyle.php index 3de70bf..257a910 100644 --- a/src/Styles/MiroShapeStyle.php +++ b/src/Styles/MiroShapeStyle.php @@ -36,7 +36,7 @@ class MiroShapeStyle * * @var int */ - private int $brc = 15132390; // Black: 15132390 + private int $brc = 15132390; /** * The Border Thickness @@ -71,7 +71,7 @@ class MiroShapeStyle * * @var int */ - private int $tc = 15877926; + private int $tc = 1710618; private int $tsc = 1; diff --git a/tests/.pest/snapshots/Unit/DataFormatTest/encoding.snap b/tests/.pest/snapshots/Unit/DataFormatTest/encoding.snap index 2066780..18b21e5 100644 --- a/tests/.pest/snapshots/Unit/DataFormatTest/encoding.snap +++ b/tests/.pest/snapshots/Unit/DataFormatTest/encoding.snap @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/tests/.pest/snapshots/Unit/IntegrationTest/line_connecting_shape.snap b/tests/.pest/snapshots/Unit/IntegrationTest/line_connecting_shape.snap new file mode 100644 index 0000000..cb30b7e --- /dev/null +++ b/tests/.pest/snapshots/Unit/IntegrationTest/line_connecting_shape.snap @@ -0,0 +1,114 @@ +{ + "boardId": "line_connection", + "data": { + "meta": [], + "objects": [ + { + "id": 2, + "initialId": "2", + "type": 14, + "widgetData": { + "type": "shape", + "json": { + "size": { + "width": 100, + "height": 100 + }, + "_position": { + "offsetPx": { + "x": 0, + "y": 0 + } + }, + "scale": { + "scale": 1 + }, + "relativeScale": 1, + "rotation": { + "rotation": 0 + }, + "relativeRotation": 0, + "position": { + "x": 0, + "y": 0 + }, + "_parent": null, + "text": "1", + "style": "{\"st\":3,\"ss\":2,\"sc\":1710618,\"bc\":-1,\"bo\":1,\"brc\":15132390,\"brw\":2,\"bro\":1,\"brs\":2,\"ffn\":\"OpenSans\",\"tc\":1710618,\"tsc\":1,\"ta\":\"c\",\"tav\":\"m\",\"fs\":24,\"b\":null,\"i\":null,\"u\":null,\"s\":null,\"bsc\":1,\"VER\":\"2.1\",\"hl\":null}", + "shape": "3" + } + } + }, + { + "id": 3, + "initialId": "3", + "type": 14, + "widgetData": { + "type": "shape", + "json": { + "size": { + "width": 100, + "height": 100 + }, + "_position": { + "offsetPx": { + "x": 200, + "y": 0 + } + }, + "scale": { + "scale": 1 + }, + "relativeScale": 1, + "rotation": { + "rotation": 0 + }, + "relativeRotation": 0, + "position": { + "x": 0, + "y": 0 + }, + "_parent": null, + "text": "2", + "style": "{\"st\":3,\"ss\":2,\"sc\":1710618,\"bc\":-1,\"bo\":1,\"brc\":15132390,\"brw\":2,\"bro\":1,\"brs\":2,\"ffn\":\"OpenSans\",\"tc\":1710618,\"tsc\":1,\"ta\":\"c\",\"tav\":\"m\",\"fs\":24,\"b\":null,\"i\":null,\"u\":null,\"s\":null,\"bsc\":1,\"VER\":\"2.1\",\"hl\":null}", + "shape": "3" + } + } + }, + { + "id": 1, + "initialId": "1", + "type": 14, + "widgetData": { + "type": "line", + "json": { + "line": { + "captions": [] + }, + "points": [], + "primary": { + "point": { + "x": 1, + "y": 0 + }, + "positionType": 0, + "widgetIndex": 2 + }, + "secondary": { + "point": { + "x": 0, + "y": 1 + }, + "positionType": 0, + "widgetIndex": 3 + }, + "style": "{\"lc\":1710618,\"ls\":2,\"t\":2,\"lt\":2,\"a_start\":0,\"a_end\":0,\"VER\":\"2\",\"jump\":0}" + } + } + } + ] + }, + "host": "miro.com", + "version": 2, + "isProtected": false +} \ No newline at end of file diff --git a/tests/Unit/IntegrationTest.php b/tests/Unit/IntegrationTest.php index e55cb0e..68cf81d 100644 --- a/tests/Unit/IntegrationTest.php +++ b/tests/Unit/IntegrationTest.php @@ -1,21 +1,40 @@ type(WidgetType::Sticker); - expect(invade($data)->widgetType)->toBe(WidgetType::Sticker); -}); +test('line connecting shape', function() { + // This should create 2 squares with a line pointing between them. + // The line should be from the top left corner to the bottom right -test('set shape', function() { - $data = MiroWidget::make()->shape(); - expect($data)->toBeInstanceOf(MiroShape::class); -}); + $data = MiroClipboardData::make() + ->boardId('line_connection') + ->addObject( + MiroWidget::make() + ->id(1) + ->initialId(1) + ->line() + ->from( + MiroWidget::make() + ->id(2) + ->initialId(2) + ->shape() + ->text('1'), + WidgetSide::Right, + 0 + ) + ->to( + MiroWidget::make() + ->id(3) + ->initialId(3) + ->shape() + ->text('2') + ->offsetPosition(200, 0), + WidgetSide::Left, + 1 + ) + ); -test('set line', function() { - $data = MiroWidget::make()->line(); - expect($data)->toBeInstanceOf(MiroLine::class); + expect($data->toArray())->toMatchSnapshot(); }); diff --git a/tests/Unit/MiroLineTest.php b/tests/Unit/MiroLineTest.php index 0c8c394..5d1460a 100644 --- a/tests/Unit/MiroLineTest.php +++ b/tests/Unit/MiroLineTest.php @@ -3,27 +3,29 @@ use MiroClipboard\Enums\LineCap; use MiroClipboard\Enums\LinePattern; use MiroClipboard\Enums\LineType; +use MiroClipboard\MiroClipboardData; +use MiroClipboard\MiroWidget; use MiroClipboard\Objects\MiroLine; use MiroClipboard\Objects\MiroLineText; use MiroClipboard\Styles\MiroLineStyle; test('set start', function() { - $data = (new MiroLine(0, 'test'))->start(123, 123); + $data = (MiroLine::make())->start(123, 123); expect($data->toArray()['widgetData']['json']['primary']['point'])->toBe(['x' => 123.0, 'y' => 123.0]); }); test('set end', function() { - $data = (new MiroLine(0, 'test'))->end(123, 123); + $data = (MiroLine::make())->end(123, 123); expect($data->toArray()['widgetData']['json']['secondary']['point'])->toBe(['x' => 123.0, 'y' => 123.0]); }); test('add point', function() { - $data = (new MiroLine(0, 'test'))->addPoint(123, 123); + $data = (MiroLine::make())->addPoint(123, 123); expect($data->toArray()['widgetData']['json']['points'])->toBe([['x' => 123.0, 'y' => 123.0]]); }); test('set points', function() { - $data = (new MiroLine(0, 'test'))->setPoints([ + $data = (MiroLine::make())->setPoints([ ['x' => 100.0, 'y' => 100.0], ['x' => 123.0, 'y' => 123.0], ['x' => 456.0, 'y' => 456.0], @@ -35,8 +37,32 @@ expect($data->toArray()['widgetData']['json']['points'])->toBe([['x' => 123.0, 'y' => 123.0], ['x' => 456.0, 'y' => 456.0]]); }); +test('from', function() { + $object = MiroWidget::make()->shape(); + $data = (MiroLine::make())->from($object); + + expect($data->toArray()['widgetData']['json']['primary']['widgetIndex'])->toBe($object->getId()); +}); + +test('to', function() { + $object = MiroWidget::make()->shape(); + $data = (MiroLine::make())->to($object); + + expect($data->toArray()['widgetData']['json']['secondary']['widgetIndex'])->toBe($object->getId()); +}); + +test('to and from are added to clipboard data', function() { + $data = MiroClipboardData::make() + ->addObject(MiroWidget::make()->line() + ->from(MiroWidget::make()->shape()->text('1')) + ->to(MiroWidget::make()->shape()->text('2')) + ); + + expect($data->getObjects())->toHaveCount(3); +}); + test('add text', function() { - $data = (new MiroLine(0, 'test'))->addText( + $data = (MiroLine::make())->addText( MiroLineText::make('Hello', .5, .5) ->color('#FF0000') ->color(16711680) @@ -53,39 +79,39 @@ }); test('set jump style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->jump()); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->jump()); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['jump'])->toBe(1); }); test('set line type style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->type(LineType::Square)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->type(LineType::Square)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['lt'])->toBe(LineType::Square->value); }); test('set stroke weight style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->strokeWeight(4)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->strokeWeight(4)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['t'])->toBe(4); }); test('set color style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->color('#FF0000')); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->color('#FF0000')); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['lc'])->toBe(16711680); - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->color(16711680)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->color(16711680)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['lc'])->toBe(16711680); }); test('set start linecap style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->startingLinecap(LineCap::Circle)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->startingLinecap(LineCap::Circle)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['a_start'])->toBe(LineCap::Circle->value); }); test('set end linecap style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->endingLinecap(LineCap::CircleFilled)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->endingLinecap(LineCap::CircleFilled)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['a_end'])->toBe(LineCap::CircleFilled->value); }); test('set line pattern style', function() { - $data = (new MiroLine(0, 'test'))->style(fn(MiroLineStyle $style) => $style->pattern(LinePattern::Dotted)); + $data = (MiroLine::make())->style(fn(MiroLineStyle $style) => $style->pattern(LinePattern::Dotted)); expect(json_decode($data->toArray()['widgetData']['json']['style'], true)['ls'])->toBe(LinePattern::Dotted->value); }); diff --git a/tests/Unit/MiroWidgetTest.php b/tests/Unit/MiroWidgetTest.php new file mode 100644 index 0000000..f0da8fc --- /dev/null +++ b/tests/Unit/MiroWidgetTest.php @@ -0,0 +1,33 @@ +type(WidgetType::Sticker); + expect(invade($data)->widgetType)->toBe(WidgetType::Sticker); +}); + +test('set shape', function() { + $data = MiroWidget::make()->shape(); + expect($data)->toBeInstanceOf(MiroShape::class); +}); + +test('set line', function() { + $data = MiroWidget::make()->line(); + expect($data)->toBeInstanceOf(MiroLine::class); +}); + +test('get id', function() { + $data = MiroWidget::make()->id(1)->shape(); + + expect($data->getId())->toBe(1); +}); + +test('get initial id', function() { + $data = MiroWidget::make()->initialId(1)->shape(); + + expect($data->getInitialId())->toBe('1'); +}); diff --git a/tests/Unit/ParserTest.php b/tests/Unit/ParserTest.php index 673ea62..5f25b92 100644 --- a/tests/Unit/ParserTest.php +++ b/tests/Unit/ParserTest.php @@ -12,6 +12,7 @@ use MiroClipboard\MiroParser; use MiroClipboard\MiroWidget; use MiroClipboard\Objects\MiroGroup; +use MiroClipboard\Objects\MiroLine; use MiroClipboard\Objects\MiroLineText; use MiroClipboard\Objects\MiroShape; use MiroClipboard\Parsers\GroupParser; @@ -20,7 +21,7 @@ use MiroClipboard\Styles\MiroLineStyle; use MiroClipboard\Styles\MiroShapeStyle; -test('parse', function() { +test('parse string', function() { $shape = MiroWidget::make()->shape()->position(1.1, 1.1); $result = MiroParser::parse(MiroClipboardData::make()->addObject($shape)->toHTML()); @@ -29,6 +30,15 @@ expect($result->getObjects()[0]->toArray())->toBe($shape->toArray()); }); +test('parse array', function() { + $shape = MiroWidget::make()->shape()->position(1.1, 1.1); + + $result = MiroParser::parse(MiroClipboardData::make()->addObject($shape)->toArray()); + + expect($result)->toBeInstanceOf(MiroClipboardData::class); + expect($result->getObjects()[0]->toArray())->toBe($shape->toArray()); +}); + test('resolve parser', function() { $shape = MiroWidget::make()->shape(); expect(MiroParser::resolveParser($shape->toArray()))->toBeInstanceOf(ShapeParser::class); @@ -131,3 +141,21 @@ expect(invade($parsedData->getObjects()[2])->objects)->toHaveCount(2); }); + +test('line object to and from objects are set', function() { + $clipboardData = MiroClipboardData::make() + ->addObject(MiroLine::make()->id(1) + ->from(MiroWidget::make()->id(2)->shape()->text('hello')->position(100, 100)) + ->to(MiroWidget::make()->id(3)->shape()->text('world')->position(200, 200)) + ); + + $parsedData = MiroClipboardData::parse($clipboardData->toArray()); + + expect($parsedData->getObjects())->toHaveCount(3); + expect($parsedData->getObjects()[2])->toBeInstanceOf(MiroLine::class); + + $line = $parsedData->getObjects()[2]; + + expect(invade($line)->fromObject)->toBeInstanceOf(MiroShape::class); + expect(invade($line)->toObject)->toBeInstanceOf(MiroShape::class); +}); diff --git a/tests/Unit/explore.php b/tests/Unit/explore.php deleted file mode 100644 index 13b11d8..0000000 --- a/tests/Unit/explore.php +++ /dev/null @@ -1,81 +0,0 @@ -shape(ShapeType::Star) - ->text('Hello!') - ->scale(.5) - ->rotation(90) - ->offsetPosition(50, 50) - ->style(fn(MiroShapeStyle $style) => $style - ->backgroundColor('#FF0000') - ->textColor('#00FF00') - ); - - $line = MiroWidget::make() - ->line() - ->start(-100, 0) - ->addPoint(50, 50) - ->end(100, 100) - ->addText(MiroLineText::make('woooow', .75, .5)->rotated()) - ->addText(MiroLineText::make('123', .25, .5)) - ->style(fn(MiroLineStyle $style) => $style - ->color('#F0FF00') - ->startingLinecap(LineCap::Circle) - ->endingLinecap(LineCap::DiamondFilled) - ->strokeWeight(4) - ->type(LineType::Square) - ->jump() - ); - - dd( - MiroClipboardData::make() - ->addGroup([$shape, $line]) - ->toHTML() - ); - - dd( - MiroClipboardData::make() - ->addObject(MiroWidget::make() - ->line() - ->start(-100, 0) - ->addPoint(50, 50) - ->end(100, 100) - ->addText(MiroLineText::make('woooow', .75, .5)->rotated()) - ->addText(MiroLineText::make('123', .25, .5)) - ->style(fn(MiroLineStyle $style) => $style - ->color('#F0FF00') - ->startingLinecap(LineCap::Circle) - ->endingLinecap(LineCap::DiamondFilled) - ->strokeWeight(4) - ->type(LineType::Square) - ->jump() - ) - ) - ->toHTML() - ); - - dd( - MiroClipboardData::make() - ->addObject(MiroWidget::make() - ->shape(ShapeType::Star) - ->text('Hello!') - ->scale(.5) - ->rotation(90) - ->style(fn(MiroShapeStyle $style) => $style - ->backgroundColor('#FF0000') - ->textColor('#00FF00') - ) - ) - ->toHTML() - ); -});