skeletonlabs / skeleton

A complete design system and component solution, built on Tailwind.
https://skeleton.dev
MIT License
4.89k stars 305 forks source link

X of N selections #2071

Open Elliott-Green opened 11 months ago

Elliott-Green commented 11 months ago

Describe the feature in detail (code, mocks, or screenshots encouraged)

Feature

Radio-'like' buttons whereby the user is selecting 'x' number of items from a 'n' number of multi-selectable items.

Solves problem

The closest components which match the above objective pattern is Listboxes, but they do not have config to span horizontally.

Problem solution

Developer MUST provides options array of whatever type they want, an image is somewhat expected to be on each object. Developer MAY provide optional overrides for the component User CAN select items on the UI which on:click which populates choices array. Developer MUST be able to fetch the user selection from a store?

Future component config

Feature Scratch Preview

xofn

Feature Scratch

<script lang="ts">
    let userActionChoice: string;
    $: userActionChoice = 'select';

    let nonSelectedCard = 'card text-xs rounded-xl card-hover';
    let selectedCard = 'card text-xs rounded-xl card-hover variant-glass-success';

    $: options = [
        {
            title: 'Burger',
            img: 'https://s7d1.scene7.com/is/image/mcdonalds/mcdonalds-BigTasty-sept-promo:1-4-product-tile-desktop'
        },
        {
            title: 'Dippers',
            img: 'https://s7d1.scene7.com/is/image/mcdonalds/mcdonalds-Mozzarella-Dippers-sept-promo:1-4-product-tile-desktop'
        },
        {
            title: 'Wrap',
            img: 'https://s7d1.scene7.com/is/image/mcdonalds/mcdonalds-Caesar-and-bacon-chicken-one-grilled:1-4-product-tile-desktop'
        }
    ];

    $: choices = [];

    function toggleSelection(x: number) {
        const index = choices.indexOf(x);
        if (index !== -1) {
            choices = [...choices.slice(0, index), ...choices.slice(index + 1)];
        } else {
            choices = [...choices, x];
        }
    }
</script>

<div class="grid variant-glass-surface pb-20">
    <div class="p-4 flex flex-col gap-3">
        {#if userActionChoice == 'select'}
            <div>
                <h2>Debug</h2>
                <p class="text-lg font-semibold mb-2">Selections {choices.length}/{options.length}</p>
                <p class="text-lg font-semibold mb-2">
                    Latest selection {choices[choices.length - 1] ? choices[choices.length - 1]?.title : '?'}
                </p>
            </div>

            <div class="grid grid-cols-1 sm:grid-cols-3 gap-3">
                {#each options as x (x)}
                    <div
                        class={choices.includes(x) ? selectedCard : nonSelectedCard}
                        on:click={() => toggleSelection(x)}
                    >
                        <header class="r">
                            <img src={x.img} alt="Image" class="bg-cover rounded-tl-xl rounded-tr-xl" />
                        </header>
                        <footer class="card-footer p-3" />

                        <div class="text-right pr-2 pb-2 font-bold"><p>{x.title}</p></div>
                    </div>
                {/each}
            </div>
        {/if}
    </div>
</div>

What type of pull request would this be?

New Feature

Provide relevant links or additional information.

Recommended to create custom component : https://discord.com/channels/1003691521280856084/1151213014721241128/1154254737995223060 Recommended to share custom component : https://discord.com/channels/1003691521280856084/1025279710609014805/1155547630978486273

endigo9740 commented 11 months ago

@Elliott-Green given the broad scope of application of this type of interface, a component might be too rigid. But I think something like our Scroll Containers under the Tailwind > Blocks section might be relevant here: https://www.skeleton.dev/elements/scroll-containers

We could illustrate the general approach we use for several of our core components, such as listboxes and radio groups. We use the same mechanism for both - which involves dynamic radio/checkbox inputs embedded within the components themselves.

Essentially teach the concept, as we feel it's really solid in practice. Both in or outside a proper form.

Elliott-Green commented 11 months ago

Whatever you think will best!