diff --git a/src/Enums/RolesEnum.php b/src/Enums/RolesEnum.php index 337c479..0039d72 100644 --- a/src/Enums/RolesEnum.php +++ b/src/Enums/RolesEnum.php @@ -4,12 +4,24 @@ enum RolesEnum: string { - case APP_MENU = 'appMenu'; + case APP_MENU = 'appMenu'; // macOS case FILE_MENU = 'fileMenu'; case EDIT_MENU = 'editMenu'; case VIEW_MENU = 'viewMenu'; case WINDOW_MENU = 'windowMenu'; + case HELP = 'help'; // macOS + case UNDO = 'undo'; + case REDO = 'redo'; + case CUT = 'cut'; + case COPY = 'copy'; + case PASTE = 'paste'; + case PASTE_STYLE = 'pasteAndMatchStyle'; + case RELOAD = 'reload'; + case HIDE = 'hide'; // macOS + case MINIMIZE = 'minimize'; + case CLOSE = 'close'; case QUIT = 'quit'; case TOGGLE_FULL_SCREEN = 'togglefullscreen'; case TOGGLE_DEV_TOOLS = 'toggleDevTools'; + case ABOUT = 'about'; } diff --git a/src/Events/Menu/MenuItemClicked.php b/src/Events/Menu/MenuItemClicked.php index d9daa74..961ed1c 100644 --- a/src/Events/Menu/MenuItemClicked.php +++ b/src/Events/Menu/MenuItemClicked.php @@ -12,7 +12,7 @@ class MenuItemClicked implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; - public function __construct(public array $item) {} + public function __construct(public array $item, public array $combo = []) {} public function broadcastOn() { diff --git a/src/Facades/Menu.php b/src/Facades/Menu.php new file mode 100644 index 0000000..e12c2cb --- /dev/null +++ b/src/Facades/Menu.php @@ -0,0 +1,51 @@ +label = $label; } } diff --git a/src/Menu/Items/Event.php b/src/Menu/Items/Event.php deleted file mode 100644 index 02af55e..0000000 --- a/src/Menu/Items/Event.php +++ /dev/null @@ -1,17 +0,0 @@ - 'event', - 'event' => $this->event, - 'label' => $this->label, - ]); - } -} diff --git a/src/Menu/Items/Link.php b/src/Menu/Items/Link.php index ec5a1cd..3655574 100644 --- a/src/Menu/Items/Link.php +++ b/src/Menu/Items/Link.php @@ -6,12 +6,22 @@ class Link extends MenuItem { protected string $type = 'link'; + protected bool $openInBrowser = false; + public function __construct(protected string $url, protected ?string $label, protected ?string $accelerator = null) {} + public function openInBrowser(bool $openInBrowser = true): self + { + $this->openInBrowser = $openInBrowser; + + return $this; + } + public function toArray(): array { return array_merge(parent::toArray(), [ 'url' => $this->url, + 'openInBrowser' => $this->openInBrowser, ]); } } diff --git a/src/Menu/Items/MenuItem.php b/src/Menu/Items/MenuItem.php index 34d41ba..7fe9051 100644 --- a/src/Menu/Items/MenuItem.php +++ b/src/Menu/Items/MenuItem.php @@ -3,11 +3,15 @@ namespace Native\Laravel\Menu\Items; use Native\Laravel\Contracts\MenuItem as MenuItemContract; +use Native\Laravel\Facades\Menu as MenuFacade; +use Native\Laravel\Menu\Menu; abstract class MenuItem implements MenuItemContract { protected string $type = 'normal'; + protected ?string $id = null; + protected ?string $label = null; protected ?string $sublabel = null; @@ -18,15 +22,33 @@ abstract class MenuItem implements MenuItemContract protected ?string $toolTip = null; + protected ?Menu $submenu = null; + protected bool $isEnabled = true; protected bool $isVisible = true; protected bool $isChecked = false; - public function enabled($enabled = true): self + protected ?string $event = null; + + public function enabled(): self + { + $this->isEnabled = true; + + return $this; + } + + public function disabled(): self + { + $this->isEnabled = false; + + return $this; + } + + public function id(string $id): self { - $this->isEnabled = $enabled; + $this->id = $id; return $this; } @@ -66,6 +88,11 @@ public function accelerator(string $accelerator): self return $this; } + public function hotkey(string $hotkey): self + { + return $this->accelerator($hotkey); + } + public function checked($checked = true): self { $this->isChecked = $checked; @@ -73,18 +100,34 @@ public function checked($checked = true): self return $this; } - public function toolTip(string $toolTip): self + public function tooltip(string $toolTip): self { $this->toolTip = $toolTip; return $this; } + public function submenu(MenuItemContract ...$items): self + { + $this->submenu = MenuFacade::make(...$items); + + return $this; + } + + public function event(string $event): self + { + $this->event = $event; + + return $this; + } + public function toArray(): array { return array_filter([ 'type' => $this->type, + 'id' => $this->id, 'label' => $this->label, + 'event' => $this->event, 'sublabel' => $this->sublabel, 'toolTip' => $this->toolTip, 'enabled' => $this->isEnabled, @@ -92,6 +135,7 @@ public function toArray(): array 'checked' => $this->isChecked, 'accelerator' => $this->accelerator, 'icon' => $this->icon, + 'submenu' => $this->submenu?->toArray(), ], fn ($value) => $value !== null); } } diff --git a/src/Menu/Items/Radio.php b/src/Menu/Items/Radio.php index 63587a2..0751522 100644 --- a/src/Menu/Items/Radio.php +++ b/src/Menu/Items/Radio.php @@ -6,8 +6,11 @@ class Radio extends MenuItem { protected string $type = 'radio'; - public function __construct(string $label) - { + public function __construct( + string $label, + protected bool $isChecked = false, + protected ?string $accelerator = null + ) { $this->label = $label; } } diff --git a/src/Menu/Menu.php b/src/Menu/Menu.php index 47a81b0..c97a30d 100644 --- a/src/Menu/Menu.php +++ b/src/Menu/Menu.php @@ -3,31 +3,20 @@ namespace Native\Laravel\Menu; use Illuminate\Support\Traits\Conditionable; +use JsonSerializable; use Native\Laravel\Client\Client; use Native\Laravel\Contracts\MenuItem; -use Native\Laravel\Enums\RolesEnum; -use Native\Laravel\Menu\Items\Checkbox; -use Native\Laravel\Menu\Items\Event; -use Native\Laravel\Menu\Items\Label; -use Native\Laravel\Menu\Items\Link; -use Native\Laravel\Menu\Items\Role; -use Native\Laravel\Menu\Items\Separator; -class Menu implements MenuItem +class Menu implements JsonSerializable, MenuItem { use Conditionable; protected array $items = []; - protected string $prepend = ''; + protected string $label = ''; public function __construct(protected Client $client) {} - public static function new(): static - { - return new static(new Client); - } - public function register(): void { $items = $this->toArray()['submenu']; @@ -37,81 +26,11 @@ public function register(): void ]); } - public function prepend(string $prepend): self - { - $this->prepend = $prepend; - - return $this; - } - - public function submenu(string $header, Menu $submenu): static - { - return $this->add($submenu->prepend($header)); - } - - public function separator(): static - { - return $this->add(new Separator); - } - - public function quit(): static - { - return $this->add(new Role(RolesEnum::QUIT)); - } - public function label(string $label): self { - return $this->add(new Label($label)); - } - - public function checkbox(string $label, bool $checked = false, ?string $hotkey = null): self - { - return $this->add(new Checkbox($label, $checked, $hotkey)); - } - - public function event(string $event, string $text, ?string $hotkey = null): self - { - return $this->add(new Event($event, $text, $hotkey)); - } - - public function link(string $url, string $text, ?string $hotkey = null): self - { - return $this->add(new Link($url, $text, $hotkey)); - } + $this->label = $label; - public function appMenu(): static - { - return $this->add(new Role(RolesEnum::APP_MENU)); - } - - public function fileMenu($label = 'File'): static - { - return $this->add(new Role(RolesEnum::FILE_MENU, $label)); - } - - public function editMenu($label = 'Edit'): static - { - return $this->add(new Role(RolesEnum::EDIT_MENU, $label)); - } - - public function viewMenu($label = 'View'): static - { - return $this->add(new Role(RolesEnum::VIEW_MENU, $label)); - } - - public function windowMenu($label = 'Window'): static - { - return $this->add(new Role(RolesEnum::WINDOW_MENU, $label)); - } - - public function toggleFullscreen(): static - { - return $this->add(new Role(RolesEnum::TOGGLE_FULL_SCREEN)); - } - - public function toggleDevTools(): static - { - return $this->add(new Role(RolesEnum::TOGGLE_DEV_TOOLS)); + return $this; } public function add(MenuItem $item): self @@ -123,12 +42,18 @@ public function add(MenuItem $item): self public function toArray(): array { - $items = collect($this->items)->map(fn (MenuItem $item) => $item->toArray())->toArray(); - $label = $this->prepend; + $items = collect($this->items) + ->map(fn (MenuItem $item) => $item->toArray()) + ->toArray(); return [ - 'label' => $label, + 'label' => $this->label, 'submenu' => $items, ]; } + + public function jsonSerialize(): array + { + return $this->toArray(); + } } diff --git a/src/Menu/MenuBuilder.php b/src/Menu/MenuBuilder.php new file mode 100644 index 0000000..52ca3c9 --- /dev/null +++ b/src/Menu/MenuBuilder.php @@ -0,0 +1,165 @@ +client); + + foreach ($items as $item) { + $menu->add($item); + } + + return $menu; + } + + public function create(MenuItem ...$items): void + { + $this->make(...$items) + ->register(); + } + + public function default(): void + { + $this->create( + $this->app(), + $this->file(), + $this->edit(), + $this->view(), + $this->window(), + ); + } + + public function label(string $label): Items\Label + { + return new Items\Label($label); + } + + public function checkbox(string $label, bool $checked = false, ?string $hotkey = null): Items\Checkbox + { + return new Items\Checkbox($label, $checked, $hotkey); + } + + public function radio(string $label, bool $checked = false, ?string $hotkey = null): Items\Radio + { + return new Items\Radio($label, $checked, $hotkey); + } + + public function link(string $url, ?string $label = null, ?string $hotkey = null): Items\Link + { + return new Items\Link($url, $label, $hotkey); + } + + public function route(string $route, ?string $label = null, ?string $hotkey = null): Items\Link + { + return new Items\Link(route($route), $label, $hotkey); + } + + public function app(): Items\Role + { + return new Items\Role(RolesEnum::APP_MENU); + } + + public function file(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::FILE_MENU, $label); + } + + public function edit(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::EDIT_MENU, $label); + } + + public function view(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::VIEW_MENU, $label); + } + + public function window(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::WINDOW_MENU, $label); + } + + public function separator(): Items\Separator + { + return new Items\Separator; + } + + public function fullscreen(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::TOGGLE_FULL_SCREEN, $label); + } + + public function devTools(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::TOGGLE_DEV_TOOLS, $label); + } + + public function undo(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::UNDO, $label); + } + + public function redo(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::REDO, $label); + } + + public function cut(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::CUT, $label); + } + + public function copy(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::COPY, $label); + } + + public function paste(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::PASTE, $label); + } + + public function pasteAndMatchStyle(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::PASTE_STYLE, $label); + } + + public function reload(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::RELOAD, $label); + } + + public function minimize(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::MINIMIZE, $label); + } + + public function close(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::CLOSE, $label); + } + + public function quit(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::QUIT, $label); + } + + public function help(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::HELP, $label); + } + + public function hide(?string $label = null): Items\Role + { + return new Items\Role(RolesEnum::HIDE, $label); + } +} diff --git a/tests/MenuBar/MenuBarTest.php b/tests/MenuBar/MenuBarTest.php index ec1c022..4b86aa9 100644 --- a/tests/MenuBar/MenuBarTest.php +++ b/tests/MenuBar/MenuBarTest.php @@ -1,7 +1,7 @@ set('nativephp-internal.api_url', 'https://jsonplaceholder.typicode.com/todos/1'); @@ -13,7 +13,10 @@ ->icon('nativephp.png') ->url('https://github.com/milwad-dev') ->withContextMenu( - Menu::new()->label('My Application')->quit(), + Menu::make( + Menu::label('My Application'), + Menu::quit(), + ), ); $menuBarArray = $menuBar->toArray();