CaptainCodeman / svelte-headlessui

HeadlessUI components for Svelte
https://captaincodeman.github.io/svelte-headlessui/
MIT License
529 stars 25 forks source link

Multiple Disclosure elements on the page. #84

Closed sideshot closed 6 months ago

sideshot commented 6 months ago

I'm running into a problem trying to put multiple disclosures on the same page.

For instance, I have multiple filter blocks. Adding them in a loop worked, but the 'store' value was unreachable. Can you recommend a solution?

I managed to create this to make it work.

    filters = filters.map((filter) => {
        const disclosure = createDisclosure({ label: filter.name });
        let expanded = false;

        disclosure.subscribe((value) => {
            expanded = value.expanded;
        });

        return { ...filter, disclosure, expanded };
    });
        {#each filters as section}
            <div class="border-t border-gray-200 px-4 py-6">
                <h3 class="-mx-2 -my-3 flow-root">
                    <button
                        use:section.disclosure.button
                        on:click={section.disclosure.toggle}
                        class="flex w-full items-center justify-between bg-white px-2 py-3 text-gray-400 hover:text-gray-500"
                    >
                        <span class="font-medium text-gray-900">{section.name}</span>
                        <span class="ml-6 flex items-center">
                            {#if !section.expanded}
                                <Plus class="h-5 w-5" aria-hidden="true" />
                            {:else}
                                <Minus class="h-5 w-5" aria-hidden="true" />
                            {/if}
                        </span>
                    </button>
                </h3>
                {#if section.expanded}
                    <div use:section.disclosure.panel class="pt-6">
                        {#each section.options as option, optionIdx}
                            <div class="flex items-center">
                                <input
                                    id={`filter-mobile-${section.id}-${optionIdx}`}
                                    name={`${section.id}[]`}
                                    value={option.value}
                                    type="checkbox"
                                    checked={option.checked}
                                    class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                                />
                                <label
                                    for={`filter-mobile-${section.id}-${optionIdx}`}
                                    class="ml-3 min-w-0 flex-1 text-gray-500">{option.label}</label
                                >
                            </div>
                        {/each}
                    </div>
                {/if}
            </div>
        {/each}

demo data

const filters = [
        {
            id: 'color',
            name: 'Color',
            options: [
                { value: 'white', label: 'White', checked: false },
                { value: 'beige', label: 'Beige', checked: false },
                { value: 'blue', label: 'Blue', checked: true },
                { value: 'brown', label: 'Brown', checked: false },
                { value: 'green', label: 'Green', checked: false },
                { value: 'purple', label: 'Purple', checked: false }
            ]
        },
        {
            id: 'category',
            name: 'Category',
            options: [
                { value: 'new-arrivals', label: 'New Arrivals', checked: false },
                { value: 'sale', label: 'Sale', checked: false },
                { value: 'travel', label: 'Travel', checked: true },
                { value: 'organization', label: 'Organization', checked: false },
                { value: 'accessories', label: 'Accessories', checked: false }
            ]
        },
        {
            id: 'size',
            name: 'Size',
            options: [
                { value: '2l', label: '2L', checked: false },
                { value: '6l', label: '6L', checked: false },
                { value: '12l', label: '12L', checked: false },
                { value: '18l', label: '18L', checked: false },
                { value: '20l', label: '20L', checked: false },
                { value: '40l', label: '40L', checked: true }
            ]
        }
    ];
CaptainCodeman commented 6 months ago

I always like to creating a child component for each item in any loop -in my experience it usually results in simpler code rather than trying to do too much in the containing component.

sideshot commented 6 months ago

do you happen to have an example of how you would do that in a loop to create the child components, and then use the child comp .expanded feature?

CaptainCodeman commented 6 months ago

You'll move most of the code to a child component which will create the disclosure for each item passed in then just have:

{#each filters as section}
  <Section {section} />
{/each}
sideshot commented 6 months ago

{smh}

Perfect! Thanks!