robsontenorio / mary

Laravel Blade UI Components for Livewire 3
https://mary-ui.com
Other
804 stars 88 forks source link

Dropdown not working within a mary table cell #483

Closed Enrica-r closed 2 weeks ago

Enrica-r commented 3 weeks ago

maryUI version

1.31.0

daisyUI version

4.11.1

Livewire version

3.5.0

What browsers are affected?

Chrome, Microsoft Edge

What happened?

I use Mary table. In an action cell I want to use a dropdown component from Mary. I have two issues:

  1. The UL is clipped like overflow-hidden
  2. The UL opens on top of the trigger

The following picture shows how the dropdown opens. Only the last line of 4 list entries are showed: Dropdown within table cell UL clipped

The next picture shows the exact same built component outside of the table: Dropdown outside table cell

The behaviour is caused by the class overflow-x-auto in the top div (with x-data) within table component. If I remove it the dropdown works but x-scrolling doesn't work anymore. To set the overflow-y to another value doesn't help.

Thank you for helping.

robsontenorio commented 3 weeks ago

1) It opens on top because there is no enough space available on bottom (Alpine's anchor plugin) 2) Are you sure you don't have custom css on app.css for table or other elements, that is interfering ?

Enrica-r commented 3 weeks ago

Hi, no I don't have custom css in app.css.

But in the mean time I searched the internet about overflow-x and overflow-y. According to W3C standard a combination of overflow-x-auto and overflow-y-visible is not possible. If you set overflow-x-auto overflow-y is set to auto internally also.

I have found an open issue on W3C Github. #4092

The only solution is at this moment to have the absolute box outside the overflow-auto area and positon it near trigger button by javascript.

bestmomo commented 3 weeks ago

I got it working like this:

<?php

namespace Mary\View\Components;

use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;

class Dropdown extends Component
{
    public string $uuid;

    public function __construct(
        public ?string $label = null,
        public ?string $icon = 'o-chevron-down',
        public ?bool $right = false,
        public mixed $trigger = null
    ) {
        $this->uuid = "mary" . md5(serialize($this));
    }

    public function render(): View|Closure|string
    {
        return <<<'HTML'
            <div x-data="{ open: false }" class="relative dropdown">
                <!-- CUSTOM TRIGGER -->
                @if($trigger)
                    <div x-ref="dropdownButton" @click="open = !open" {{ $trigger->attributes->class(['cursor-pointer']) }}>
                        {{ $trigger }}
                    </div>
                @else
                    <div x-ref="dropdownButton" @click="open = !open" {{ $attributes->class(["btn normal-case cursor-pointer"]) }}>
                        {{ $label }}
                        <x-mary-icon :name="$icon" />
                    </div>
                @endif

                <template x-if="open">
                    <div
                        class="fixed inset-0 z-50 items-center justify-center"
                        @click="open = false"
                    >
                        <div
                            x-show="open"
                            x-transition:enter="transition ease-out duration-100"
                            x-transition:enter-start="opacity-0 scale-95"
                            x-transition:enter-end="opacity-100 scale-100"
                            x-transition:leave="transition ease-in duration-75"
                            x-transition:leave-start="opacity-100 scale-100"
                            x-transition:leave-end="opacity-0 scale-95"
                            class="absolute z-50 w-auto p-2 border shadow border-base-200 bg-base-100 dark:bg-base-200 rounded-box min-w-max menu"
                            :style="{'top': ($refs.dropdownButton.getBoundingClientRect().bottom + window.scrollY) + 'px', 'left': ($refs.dropdownButton.getBoundingClientRect().left + window.scrollX) + 'px'}"
                        >
                            <div wire:key="dropdown-slot-{{ $uuid }}">
                                {{ $slot }}
                            </div>
                        </div>
                    </div>
                </template>
            </div>
        HTML;
    }
}
robsontenorio commented 3 weeks ago

Please, send a PR so I can see the diff.

bestmomo commented 3 weeks ago

Done

robsontenorio commented 2 weeks ago

Due to CSS limitation https://github.com/w3c/csswg-drafts/issues/4092 , use this current workaround. Let me know if it works.

/** Table + Dropdown workaround due to CSS overflow limitations **/

table {
    @apply !static
}

table details.dropdown {
    @apply !static
}

To make sure that it will not mess up other things you can add a specific class on your tables.

<x-table class="myTable" ... />
/** Table + Dropdown workaround due to CSS overflow limitations **/

table.myTable {
    @apply !static
}

table.myTable details.dropdown {
    @apply !static
}