Compare commits

...

9 Commits

Author SHA1 Message Date
Guilhem
04f7b03ad5 Merge remote-tracking branch 'origin/main' into glm/fix/frontend/prevent-multiple-menu-opening
# Conflicts:
#	frontend/src/lib/components/apps/components/display/AppMenu.svelte
2025-05-28 08:14:59 +02:00
Guilhem
25b0bf9ac7 Merge branch 'main' into glm/fix/frontend/prevent-multiple-menu-opening 2025-05-26 10:52:21 +02:00
Guilhem
3d714b5b6a Merge remote-tracking branch 'origin/main' into glm/fix/frontend/prevent-multiple-menu-opening
# Conflicts:
#	frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte
#	frontend/src/lib/components/meltComponents/Menu.svelte
2025-05-26 08:27:03 +02:00
Guilhem
e1dbc53052 fix dropdown behavior 2025-05-20 13:57:35 +02:00
Guilhem
0c5a2e663c Merge remote-tracking branch 'origin/main' into glm/fix/frontend/prevent-multiple-menu-opening 2025-05-20 12:32:20 +02:00
Guilhem
dddcb596c8 nit 2025-05-15 10:42:47 +02:00
Guilhem
42dc9a549b Merge branch 'main' into glm/fix/frontend/prevent-multiple-menu-opening 2025-05-15 10:21:41 +02:00
Guilhem
57bfa27e52 Merge branch 'main' into glm/fix/frontend/prevent-multiple-menu-opening 2025-05-13 10:25:41 +02:00
Guilhem
5313807f59 improve selector for click outside menu 2025-04-21 13:56:49 +01:00
4 changed files with 48 additions and 12 deletions

View File

@@ -38,6 +38,9 @@
export let isMenuItem: boolean = false
export let noInitialize = false
export let replaceCallback: boolean = false
export let modalId: string | undefined = undefined
export let onSuccess: (() => void) | undefined = undefined
export let modalWrapperClass: string | undefined = undefined
export let controls: { left: () => boolean; right: () => boolean | string } | undefined =
undefined
@@ -214,6 +217,7 @@
if (iterContext && listInputs) {
listInputs.set(id, inputOutput)
}
onSuccess?.()
}}
refreshOnStart={resolvedConfig.triggerOnAppLoad}
{replaceCallback}
@@ -282,6 +286,8 @@
}
confirmedCallback = undefined
}}
{modalId}
wrapperClass={modalWrapperClass}
>
<div class="flex flex-col w-full space-y-4">
<span>

View File

@@ -40,6 +40,8 @@
configuration
)
const modalId = crypto.randomUUID()
let css = initCss($app.css?.menucomponent, customCss)
let beforeIconComponent: any
@@ -103,6 +105,8 @@
justifyEnd={false}
class={resolvedConfig.fillContainer ? 'w-full h-full' : ''}
usePointerDownOutside={true}
clickOutsideExcludeIds={modalId ? [modalId] : []}
let:close
renderContent
>
<svelte:fragment slot="trigger" let:trigger>
@@ -166,6 +170,11 @@
componentInput={actionButton.componentInput}
noWFull={false}
isMenuItem={true}
{modalId}
onSuccess={() => {
close()
}}
modalWrapperClass="z-[7000]"
/>
</div>
{/if}

View File

@@ -13,6 +13,8 @@
loading?: boolean
open?: boolean
type?: 'danger' | 'reload'
modalId?: string
wrapperClass?: string
showIcon?: boolean
}
@@ -23,6 +25,8 @@
loading = false,
open = false,
type: _type,
modalId = undefined,
wrapperClass = '',
showIcon = true
}: Props = $props()
const type = $derived(_type ?? 'danger')
@@ -72,10 +76,16 @@
<svelte:window on:keydown|capture={onKeyDown} />
{#if open}
<!-- svelte-ignore a11y_interactive_supports_focus -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
transition:fadeFast|local
class={'absolute top-0 bottom-0 left-0 right-0 z-[5000]'}
class={twMerge('absolute top-0 bottom-0 left-0 right-0 z-[5000]', wrapperClass)}
role="dialog"
id={modalId}
onclick={(e) => {
e.stopPropagation()
}}
>
<div
class={classNames(

View File

@@ -15,12 +15,17 @@
export let createMenu: MenubarBuilders['createMenu']
export let invisible: boolean = false
export let usePointerDownOutside: boolean = false
export let clickOutsideExcludeIds: string[] = []
export let menuClass: string = ''
export let open = false
export let renderContent: boolean = false
// Use the passed createMenu function
const menu = createMenu({
const {
elements: { menu: menuElement, trigger, item },
ids: { menu: menuId },
states
} = createMenu({
positioning: {
placement,
fitViewport: true,
@@ -29,12 +34,6 @@
loop: true
})
//Melt
const {
elements: { trigger, menu: menuElement, item },
states
} = menu
const sync = createSync(states)
$: sync.open(open, (v) => (open = Boolean(v)))
@@ -43,7 +42,21 @@
}
async function getMenuElements(): Promise<HTMLElement[]> {
return Array.from(document.querySelectorAll('[data-menu]')) as HTMLElement[]
const elements: HTMLElement[] = []
const menuElement = document.getElementById($menuId)
if (menuElement) {
elements.push(menuElement as HTMLElement)
}
for (const id of clickOutsideExcludeIds) {
const element = document.getElementById(id)
if (element) {
elements.push(element as HTMLElement)
}
}
return elements
}
</script>
@@ -64,7 +77,6 @@
close()
}
}}
data-menu
>
<slot name="trigger" {trigger} />
</button>
@@ -73,7 +85,6 @@
{#if open || renderContent}
<div
use:melt={$menuElement}
data-menu
class={twMerge(
'z-[6000] border w-56 origin-top-right rounded-md shadow-md focus:outline-none overflow-y-auto',
lightMode ? 'bg-surface-inverse' : 'bg-surface',
@@ -83,7 +94,7 @@
on:click
>
<div class="py-1" style="max-height: {maxHeight}px; ">
<slot {item} {open} />
<slot {item} {open} {close} />
</div>
</div>
{/if}