mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	refactor(web): remove events from clickOutside action (#9943)
This commit is contained in:
		
							parent
							
								
									5af67d159f
								
							
						
					
					
						commit
						d1135db8cf
					
				@ -1,19 +1,12 @@
 | 
			
		||||
import { matchesShortcut } from '$lib/actions/shortcut';
 | 
			
		||||
import type { ActionReturn } from 'svelte/action';
 | 
			
		||||
 | 
			
		||||
interface Attributes {
 | 
			
		||||
  /** @deprecated */
 | 
			
		||||
  'on:outclick'?: (e: CustomEvent) => void;
 | 
			
		||||
  /** @deprecated **/
 | 
			
		||||
  'on:escape'?: (e: CustomEvent) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Options {
 | 
			
		||||
  onOutclick?: () => void;
 | 
			
		||||
  onEscape?: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function clickOutside(node: HTMLElement, options: Options = {}): ActionReturn<void, Attributes> {
 | 
			
		||||
export function clickOutside(node: HTMLElement, options: Options = {}): ActionReturn {
 | 
			
		||||
  const { onOutclick, onEscape } = options;
 | 
			
		||||
 | 
			
		||||
  const handleClick = (event: MouseEvent) => {
 | 
			
		||||
@ -22,11 +15,7 @@ export function clickOutside(node: HTMLElement, options: Options = {}): ActionRe
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (onOutclick) {
 | 
			
		||||
      onOutclick();
 | 
			
		||||
    } else {
 | 
			
		||||
      node.dispatchEvent(new CustomEvent('outclick'));
 | 
			
		||||
    }
 | 
			
		||||
    onOutclick?.();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleKey = (event: KeyboardEvent) => {
 | 
			
		||||
@ -37,8 +26,6 @@ export function clickOutside(node: HTMLElement, options: Options = {}): ActionRe
 | 
			
		||||
    if (onEscape) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      onEscape();
 | 
			
		||||
    } else {
 | 
			
		||||
      node.dispatchEvent(new CustomEvent('escape'));
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -126,7 +126,7 @@
 | 
			
		||||
                />
 | 
			
		||||
 | 
			
		||||
                {#if selectedMenuUser === user}
 | 
			
		||||
                  <ContextMenu {...position} on:outclick={() => (selectedMenuUser = null)}>
 | 
			
		||||
                  <ContextMenu {...position} onClose={() => (selectedMenuUser = null)}>
 | 
			
		||||
                    {#if role === AlbumUserRole.Viewer}
 | 
			
		||||
                      <MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Editor)} text="Allow edits" />
 | 
			
		||||
                    {:else}
 | 
			
		||||
 | 
			
		||||
@ -201,8 +201,7 @@
 | 
			
		||||
                  <button
 | 
			
		||||
                    type="button"
 | 
			
		||||
                    class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
 | 
			
		||||
                    use:clickOutside
 | 
			
		||||
                    on:outclick={() => (showDeleteReaction[index] = false)}
 | 
			
		||||
                    use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
 | 
			
		||||
                    on:click={() => handleDeleteReaction(reaction, index)}
 | 
			
		||||
                  >
 | 
			
		||||
                    Remove
 | 
			
		||||
@ -254,8 +253,7 @@
 | 
			
		||||
                    <button
 | 
			
		||||
                      type="button"
 | 
			
		||||
                      class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
 | 
			
		||||
                      use:clickOutside
 | 
			
		||||
                      on:outclick={() => (showDeleteReaction[index] = false)}
 | 
			
		||||
                      use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
 | 
			
		||||
                      on:click={() => handleDeleteReaction(reaction, index)}
 | 
			
		||||
                    >
 | 
			
		||||
                      Remove
 | 
			
		||||
 | 
			
		||||
@ -795,7 +795,6 @@
 | 
			
		||||
      <DeleteAssetDialog
 | 
			
		||||
        size={1}
 | 
			
		||||
        on:cancel={() => (isShowDeleteConfirmation = false)}
 | 
			
		||||
        on:escape={() => (isShowDeleteConfirmation = false)}
 | 
			
		||||
        on:confirm={() => deleteAsset()}
 | 
			
		||||
      />
 | 
			
		||||
    {/if}
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@
 | 
			
		||||
  $: renderedSelectedOption = renderOption(selectedOption);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div use:clickOutside on:outclick={handleClickOutside} on:escape={handleClickOutside}>
 | 
			
		||||
<div use:clickOutside={{ onOutclick: handleClickOutside, onEscape: handleClickOutside }}>
 | 
			
		||||
  <!-- BUTTON TITLE -->
 | 
			
		||||
  <LinkButton on:click={() => (showMenu = true)} fullwidth {title}>
 | 
			
		||||
    <div class="flex place-items-center gap-2 text-sm">
 | 
			
		||||
 | 
			
		||||
@ -87,7 +87,7 @@
 | 
			
		||||
 | 
			
		||||
{#if showContextMenu}
 | 
			
		||||
  <Portal target="body">
 | 
			
		||||
    <ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
 | 
			
		||||
    <ContextMenu {...contextMenuPosition} onClose={() => onMenuExit()}>
 | 
			
		||||
      <MenuOption on:click={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text="Hide person" />
 | 
			
		||||
      <MenuOption on:click={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text="Change name" />
 | 
			
		||||
      <MenuOption
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@
 | 
			
		||||
  import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
 | 
			
		||||
  import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
 | 
			
		||||
  import { getAssetControlContext } from '../asset-select-control-bar.svelte';
 | 
			
		||||
  import { createEventDispatcher } from 'svelte';
 | 
			
		||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
			
		||||
  import { mdiTimerSand, mdiDeleteOutline } from '@mdi/js';
 | 
			
		||||
  import { type OnDelete, deleteAssets } from '$lib/utils/actions';
 | 
			
		||||
@ -14,10 +13,6 @@
 | 
			
		||||
 | 
			
		||||
  const { clearSelect, getOwnedAssets } = getAssetControlContext();
 | 
			
		||||
 | 
			
		||||
  const dispatch = createEventDispatcher<{
 | 
			
		||||
    escape: void;
 | 
			
		||||
  }>();
 | 
			
		||||
 | 
			
		||||
  let isShowConfirmation = false;
 | 
			
		||||
  let loading = false;
 | 
			
		||||
 | 
			
		||||
@ -40,11 +35,6 @@
 | 
			
		||||
    isShowConfirmation = false;
 | 
			
		||||
    loading = false;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const escape = () => {
 | 
			
		||||
    dispatch('escape');
 | 
			
		||||
    isShowConfirmation = false;
 | 
			
		||||
  };
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if menuItem}
 | 
			
		||||
@ -60,6 +50,5 @@
 | 
			
		||||
    size={getOwnedAssets().size}
 | 
			
		||||
    on:confirm={handleDelete}
 | 
			
		||||
    on:cancel={() => (isShowConfirmation = false)}
 | 
			
		||||
    on:escape={escape}
 | 
			
		||||
  />
 | 
			
		||||
{/if}
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@
 | 
			
		||||
  setContext(() => (showContextMenu = false));
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div use:clickOutside on:outclick={() => (showContextMenu = false)}>
 | 
			
		||||
<div use:clickOutside={{ onOutclick: () => (showContextMenu = false) }}>
 | 
			
		||||
  <CircleIconButton {title} {icon} on:click={handleShowMenu} />
 | 
			
		||||
  {#if showContextMenu}
 | 
			
		||||
    <ContextMenu {...contextMenuPosition}>
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
  export let y = 0;
 | 
			
		||||
 | 
			
		||||
  export let menuElement: HTMLDivElement | undefined = undefined;
 | 
			
		||||
  export let onClose: (() => void) | undefined = undefined;
 | 
			
		||||
 | 
			
		||||
  let left: number;
 | 
			
		||||
  let top: number;
 | 
			
		||||
@ -36,9 +37,7 @@
 | 
			
		||||
  style:top="{top}px"
 | 
			
		||||
  style:left="{left}px"
 | 
			
		||||
  role="menu"
 | 
			
		||||
  use:clickOutside
 | 
			
		||||
  on:outclick
 | 
			
		||||
  on:escape
 | 
			
		||||
  use:clickOutside={{ onOutclick: onClose, onEscape: onClose }}
 | 
			
		||||
>
 | 
			
		||||
  <div class="flex flex-col rounded-lg">
 | 
			
		||||
    <slot />
 | 
			
		||||
 | 
			
		||||
@ -49,14 +49,7 @@
 | 
			
		||||
      on:contextmenu|preventDefault={reopenContextMenu}
 | 
			
		||||
      role="presentation"
 | 
			
		||||
    >
 | 
			
		||||
      <ContextMenu
 | 
			
		||||
        {x}
 | 
			
		||||
        {y}
 | 
			
		||||
        {direction}
 | 
			
		||||
        on:outclick={closeContextMenu}
 | 
			
		||||
        on:escape={closeContextMenu}
 | 
			
		||||
        bind:menuElement={contextMenuElement}
 | 
			
		||||
      >
 | 
			
		||||
      <ContextMenu {x} {y} {direction} onClose={closeContextMenu} bind:menuElement={contextMenuElement}>
 | 
			
		||||
        <slot />
 | 
			
		||||
      </ContextMenu>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
@ -114,9 +114,10 @@
 | 
			
		||||
        {/if}
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
          use:clickOutside
 | 
			
		||||
          on:outclick={() => (shouldShowAccountInfoPanel = false)}
 | 
			
		||||
          on:escape={() => (shouldShowAccountInfoPanel = false)}
 | 
			
		||||
          use:clickOutside={{
 | 
			
		||||
            onOutclick: () => (shouldShowAccountInfoPanel = false),
 | 
			
		||||
            onEscape: () => (shouldShowAccountInfoPanel = false),
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <button
 | 
			
		||||
            type="button"
 | 
			
		||||
 | 
			
		||||
@ -467,7 +467,7 @@
 | 
			
		||||
              <CircleIconButton title="Download" on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
 | 
			
		||||
 | 
			
		||||
              {#if isOwned}
 | 
			
		||||
                <div use:clickOutside on:outclick={() => (viewMode = ViewMode.VIEW)}>
 | 
			
		||||
                <div use:clickOutside={{ onOutclick: () => (viewMode = ViewMode.VIEW) }}>
 | 
			
		||||
                  <CircleIconButton title="Album options" on:click={handleOpenAlbumOptions} icon={mdiDotsVertical} />
 | 
			
		||||
                  {#if viewMode === ViewMode.ALBUM_OPTIONS}
 | 
			
		||||
                    <ContextMenu {...contextMenuPosition}>
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,6 @@
 | 
			
		||||
  import { preferences, user } from '$lib/stores/user.store';
 | 
			
		||||
 | 
			
		||||
  let { isViewing: showAssetViewer } = assetViewingStore;
 | 
			
		||||
  let handleEscapeKey = false;
 | 
			
		||||
  const assetStore = new AssetStore({ isArchived: false, withStacked: true, withPartners: true });
 | 
			
		||||
  const assetInteractionStore = createAssetInteractionStore();
 | 
			
		||||
  const { isMultiSelectState, selectedAssets } = assetInteractionStore;
 | 
			
		||||
@ -43,10 +42,6 @@
 | 
			
		||||
    if ($showAssetViewer) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (handleEscapeKey) {
 | 
			
		||||
      handleEscapeKey = false;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if ($isMultiSelectState) {
 | 
			
		||||
      assetInteractionStore.clearMultiselect();
 | 
			
		||||
      return;
 | 
			
		||||
@ -79,11 +74,7 @@
 | 
			
		||||
      <ChangeDate menuItem />
 | 
			
		||||
      <ChangeLocation menuItem />
 | 
			
		||||
      <ArchiveAction menuItem onArchive={(assetIds) => assetStore.removeAssets(assetIds)} />
 | 
			
		||||
      <DeleteAssets
 | 
			
		||||
        menuItem
 | 
			
		||||
        on:escape={() => (handleEscapeKey = true)}
 | 
			
		||||
        onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)}
 | 
			
		||||
      />
 | 
			
		||||
      <DeleteAssets menuItem onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)} />
 | 
			
		||||
      <hr />
 | 
			
		||||
      <AssetJobActions />
 | 
			
		||||
    </AssetSelectContextMenu>
 | 
			
		||||
 | 
			
		||||
@ -397,7 +397,7 @@
 | 
			
		||||
 | 
			
		||||
                  {#if showContextMenu}
 | 
			
		||||
                    <Portal target="body">
 | 
			
		||||
                      <ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
 | 
			
		||||
                      <ContextMenu {...contextMenuPosition} onClose={() => onMenuExit()}>
 | 
			
		||||
                        <MenuOption on:click={() => onRenameClicked()} text={`Rename`} />
 | 
			
		||||
 | 
			
		||||
                        {#if selectedLibrary}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user