laravel / prompts

Beautiful and user-friendly forms for your command-line PHP applications.
https://laravel.com/docs/prompts
MIT License
534 stars 94 forks source link

Feature suggestion: toggles #175

Open Plytas opened 1 month ago

Plytas commented 1 month ago

Laravel Prompts Version

n/a

Laravel Version

n/a

PHP Version

n/a

Operating System & Version

n/a

Terminal Application

n/a

Description

Similar to confirm() and/or multiselect() it would be nice to have toggle()/toggles() prompt, that would list options and and let you turn them off/on. The result would be an array of all options as keys and true/false as their values.

It's possible to do this using multiselect(), but you have to map the response yourself and visual toggle could be different.

Imagine a NotificationSettings model that stores bool flags in different columns.

Pseudo code:

$notificationSettings = NotificationSettings::first();

$options = [
    'app' => 'In app',
    'email' => 'By email',
    'mobile' => 'Mobile push notifications',
];

$defaults = array_map($options, fn(string $value, string $key) => $notificationSettings?->$key ?? false);
// [
//     'app' => true,
//     'email' => false,
//     'mobile' => true,
// ]

$settings = toggles(
    label: 'How would you like to receive notifications?',
    options: $options,
    defaults: $defaults
);
// [
//     'app' => true,
//     'email' => false,
//     'mobile' => false,
// ]

$notificationSettings->update($settings);

Steps To Reproduce

Nothing, just a feature suggestion.

Plytas commented 1 month ago

Here's how it can be done using multiselect() right now:

$notificationSettings = NotificationSettings::first();

$options = [
    'app' => 'In app',
    'email' => 'By email',
    'mobile' => 'Mobile push notifications',
];

$default = array_keys(array_filter($options, fn(string $key) => $notificationSettings?->{$key} ?? false, ARRAY_FILTER_USE_KEY));
// [
//     'app',
//     'mobile',
// ]

$settings = multiselect(
    label: 'Select settings',
    options: $options,
    default: $default,
    transform: fn(array $values) => Arr::map($options, fn($value, $key) => in_array($key, $values))
);
// [
//     'app' => true,
//     'email' => false,
//     'mobile' => false,
// ]

$notificationSettings->update($settings);

While it is possible, it's not as clean as proposed solution. Also, I imagine it would be more performant if it would interact with array keys directly rather than having to use transform and perform in_array() search like in this example.

I still don't like how $default is built in both options, perhaps there's a better solution for that?