cli-menu icon indicating copy to clipboard operation
cli-menu copied to clipboard

Grouped items

Open jtreminio opened this issue 6 years ago • 2 comments

SplitItem radio works well:

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;

require_once(__DIR__ . '/../vendor/autoload.php');

$menu = (new CliMenuBuilder)
    ->setTitle('Header 1')
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->addRadioItem('Item 1-A', function() {})
            ->addRadioItem('Item 1-B', function() {})
            ->addRadioItem('Item 1-C', function() {})
        ;
    })
    ->build();

$menu->open();

But it's not possible to have multiple groups of RadioItem within the same menu level:

$menu = (new CliMenuBuilder)
    ->addStaticItem('Header 1')
    ->addRadioItem('Item 1-A', function() {})
    ->addRadioItem('Item 1-B', function() {})
    ->addRadioItem('Item 1-C', function() {})
    ->addLineBreak('---')
    ->addStaticItem('Header 2')
    ->addRadioItem('Item 2-A', function() {})
    ->addRadioItem('Item 2-B', function() {})
    ->addRadioItem('Item 2-C', function() {})
    ->build();

$menu->open();

Peek 2019-12-20 19-15

Similarly, I want to be able to group non-RadioItem items together.

I'm thinking a non-styled container item that can take any number of MenuItemInterface items.

It has the following API:

  • addItem()
  • addItems()
  • setItems()
  • removeItem()

If it contains no items, the parent CliMenu displays nothing - it is only a container of items and has no styling of its own, nor does it affect the UI.

If it has items, it behaves as if those items were defined in-line with the parent menu.

Example:

$menu = (new CliMenuBuilder)
    ->addStaticItem('Header 1')
    ->addGroup(function (CliMenuBuilder $b) {
        $b->addRadioItem('Item 1-A', function() {})
            ->addRadioItem('Item 1-B', function() {})
            ->addRadioItem('Item 1-C', function() {})
        ;
    })
    ->addLineBreak('---')
    ->addStaticItem('Header 2')
    ->addGroup(function (CliMenuBuilder $b) {
        $b->addRadioItem('Item 2-A', function() {})
            ->addRadioItem('Item 2-B', function() {})
            ->addRadioItem('Item 2-C', function() {})
        ;
    })
    ->build();

$menu->open();

This would look identical to the GIF above.

If no items are defined,

$menu = (new CliMenuBuilder)
    ->addStaticItem('Header 1')
    ->addGroup(function (CliMenuBuilder $b) {
        $b->addRadioItem('Item 1-A', function() {})
            ->addRadioItem('Item 1-B', function() {})
            ->addRadioItem('Item 1-C', function() {})
        ;
    })
    ->addLineBreak('---')
    ->addStaticItem('Header 2')
    ->addGroup(function (CliMenuBuilder $b) {
    })
    ->build();

$menu->open();

then it acts as if the group isn't defined at all:

image

This will help group RadioItems in a vertical manner (without needing to use SplitItem), and allow grouping other item types for non-Menu work.

In addition, I would suggest changing RadioItem::getSelectAction() to use this group feature to disable other items within the same group, vs using SplitItem.

If the radio item does not belong to a group, behave as it already does and toggle off other radio items within the same CliMenu object.

edit:

Thinking about this, for initial PR it would be good to keep it simple and not give this class any styling at all. Simply a container, nothing else, but I could see it expending to keeping its own copy of styles and applying them to any children items.

So this would basically end up being a submenu that's visible on the current menu without needing to select an item to view the children items within.

jtreminio avatar Dec 21 '19 01:12 jtreminio

Seems SplitItem handles item selection differently since it displays data horizontally, so it keeps a different selected index to the rest of the parent menu.

jtreminio avatar Dec 21 '19 02:12 jtreminio

It sounds like a logical next step. If was already thinking of this myself. It could have getChecked() method which returns the checked items. If we can implement this in a nice clean way without lots of special casing and touching lots of files I'd be happy to include it.

AydinHassan avatar Dec 21 '19 12:12 AydinHassan