Skip to content

Commit

Permalink
Image Quick Fix - Dropdown Click outside
Browse files Browse the repository at this point in the history
  • Loading branch information
ayazemre committed Dec 7, 2024
1 parent f9aedd0 commit 84bd503
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 44 deletions.
2 changes: 1 addition & 1 deletion fluid-ui-svelte/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fluid-ui-svelte",
"version": "0.1.6",
"version": "0.1.7",
"author": {
"name": "Emre Ayaz",
"email": "emreayaz@frostium.io",
Expand Down
22 changes: 19 additions & 3 deletions fluid-ui-svelte/src/lib/components/Dropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,53 @@
import Container from "$lib/primitives/Container.svelte";
import Button from "$lib/primitives/Button.svelte";
import type { Snippet } from "svelte";
import type { DropdownOptions } from "$lib/types.js";
let {
class: className,
triggerClass,
contentClass,
overrideDefaultStyling = false,
isOpen = $bindable(false),
shouldCloseOnClickOutside = true,
dropdownTrigger,
dropdownContent,
triggerRawElement,
contentRawElement,
}: {
class?: string;
triggerClass?: string;
contentClass?: string;
overrideDefaultStyling?: boolean;
isOpen?: boolean;
shouldCloseOnClickOutside: boolean;
dropdownTrigger: Snippet<[options: { isOpen: boolean; toggleDropdown: Function }]>;
dropdownContent: Snippet<[options: { isOpen: boolean; toggleDropdown: Function }]>;
triggerRawElement: HTMLElement;
contentRawElement: HTMLElement;
} = $props();
const componentOptions = {
const componentOptions: DropdownOptions = {
isOpen,
toggleDropdown: () => {
isOpen = !isOpen;
},
};
if (shouldCloseOnClickOutside) {
document.addEventListener("click", (e) => {
if (isOpen && e.target) {
if (!triggerRawElement.contains(e.target as HTMLElement) && !contentRawElement.contains(e.target as HTMLElement)) {
isOpen = false;
}
}
});
}
</script>

<Container class={(overrideDefaultStyling ? "" : "fluid-dropdown") + (className ? ` ${className}` : "")} overrideDefaultStyling={true}>
<Container bind:rawElement={triggerRawElement} class={(overrideDefaultStyling ? "" : "fluid-dropdown") + (className ? ` ${className}` : "")} overrideDefaultStyling={true}>
<Container class={(overrideDefaultStyling ? "" : "fluid-dropdown-trigger") + (triggerClass ? ` ${triggerClass}` : "")} overrideDefaultStyling>
{@render dropdownTrigger(componentOptions)}
</Container>
<Container overrideDefaultStyling class={(overrideDefaultStyling ? "" : "fluid-dropdown-content") + (contentClass ? ` ${contentClass}` : "")}>
<Container bind:rawElement={contentRawElement} overrideDefaultStyling class={(overrideDefaultStyling ? "" : "fluid-dropdown-content") + (contentClass ? ` ${contentClass}` : "")}>
{#if isOpen}
{@render dropdownContent(componentOptions)}
{/if}
Expand Down
4 changes: 4 additions & 0 deletions fluid-ui-svelte/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//Types

export type { DropdownOptions as DropdownOptions } from "$lib/types.ts";

// Primitives
export { default as Link } from "$lib/primitives/Link.svelte";
export { default as Button } from "$lib/primitives/Button.svelte";
Expand Down
14 changes: 8 additions & 6 deletions fluid-ui-svelte/src/lib/primitives/Container.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,48 @@
import type { Snippet } from "svelte";
import type { HTMLAttributes } from "svelte/elements";
const {
let {
containerType = "div",
class: className = "",
overrideDefaultStyling = false,
children,
rawElement = $bindable(),
...restProps
}: {
containerType?: "div" | "section" | "aside" | "nav" | "footer";
class?: string;
overrideDefaultStyling?: boolean;
children?: Snippet;
rawElement?: HTMLElement;
} & HTMLAttributes<HTMLElement> = $props();
</script>

{#if containerType == "div"}
<div {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
<div bind:this={rawElement} {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
{#if children}
{@render children()}
{/if}
</div>
{:else if containerType == "section"}
<section {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
<section bind:this={rawElement} {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
{#if children}
{@render children()}
{/if}
</section>
{:else if containerType == "aside"}
<aside {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
<aside bind:this={rawElement} {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
{#if children}
{@render children()}
{/if}
</aside>
{:else if containerType == "nav"}
<nav {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
<nav bind:this={rawElement} {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
{#if children}
{@render children()}
{/if}
</nav>
{:else if containerType == "footer"}
<footer {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
<footer bind:this={rawElement} {...restProps} class={(overrideDefaultStyling ? "" : "fluid-container") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "")}>
{#if children}
{@render children()}
{/if}
Expand Down
48 changes: 18 additions & 30 deletions fluid-ui-svelte/src/lib/primitives/Image.svelte
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
<script lang="ts">
import type { Snippet } from "svelte";
import type { HTMLImgAttributes } from "svelte/elements";
const {
let {
class: className,
loadingSnippet,
errorSnippet,
noPlaceholders = false,
placeholderSnippet,
overrideDefaultStyling = false,
rawElement,
...restProps
}: {
class?: string;
loadingSnippet?: Snippet;
errorSnippet?: Snippet;
placeholderSnippet?: Snippet;
noPlaceholders?: boolean;
overrideDefaultStyling?: boolean;
rawElement?: HTMLElement;
} & Omit<HTMLImgAttributes, "onerror" | "onload"> = $props();
let status = $state("loading");
let status: "loading" | "done" | "failed" = $state("loading");
</script>

{#if noPlaceholders}
<img
{...restProps}
onerror={() => {
status = "failed";
console.log(status);
}}
onload={() => {
status = "done";
console.log(status);
}}
class={(overrideDefaultStyling ? "" : "fluid-image") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "") + (status == "loading" ? " invisible" : "")}
/>
{:else if status == "loading" || status == "done"}
<div class={"fluid-image-loading" + (status === "done" ? " hidden" : "")}>
{#if status == "failed"}
{#if placeholderSnippet}
<div class="fluid-image-error">
{@render placeholderSnippet()}
</div>
{:else}
<p>Image not loaded, provide placeholder.</p>
{/if}
{:else if status == "loading" || "done"}
<div class={"fluid-image-loading" + status !== "loading" ? " hidden" : ""}>
{#if loadingSnippet}
{@render loadingSnippet()}
{:else}
<p>No loading snippet provided.</p>
<p>Image loading, provide placeholder.</p>
{/if}
</div>

<img
bind:this={rawElement}
{...restProps}
onerror={() => {
status = "failed";
Expand All @@ -53,12 +49,4 @@
}}
class={(overrideDefaultStyling ? "" : "fluid-image") + (className ? (overrideDefaultStyling ? `${className}` : ` ${className}`) : "") + (status == "loading" ? " invisible" : "")}
/>
{:else if status == "failed"}
<div class="fluid-image-error">
{#if errorSnippet}
{@render errorSnippet()}
{:else}
<p>No error snippet provided.</p>
{/if}
</div>
{/if}
1 change: 1 addition & 0 deletions fluid-ui-svelte/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type DropdownOptions = { isOpen: boolean; toggleDropdown: Function; };
8 changes: 4 additions & 4 deletions fluid-ui-svelte/src/routes/images/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
<Container>
<Text textType={"p"} textValue="Image Fail"></Text>
<Container class="w-24 h-24 overflow-clip">
<Image src="none" noPlaceholders={true}></Image>
<Image src="none"></Image>
</Container>
</Container>
<Container>
<Text textType={"p"} textValue="Image Success"></Text>
<Container class="w-24 h-24 overflow-clip">
<Image loading="lazy" src="https://picsum.photos/200" noPlaceholders={true}></Image>
<Image loading="lazy" src="https://picsum.photos/200"></Image>
</Container>
</Container>
<Container>
Expand All @@ -33,7 +33,7 @@
<Container>
<Text textType={"p"} textValue="Image Fail with Error Handling Custom Error"></Text>
<Container class="w-24 h-24 overflow-clip">
<Image src="none" errorSnippet={imageFailedElement}></Image>
<Image src="none" placeholderSnippet={imagePlaceholder}></Image>
</Container>
</Container>
<Container>
Expand All @@ -48,6 +48,6 @@
{#snippet imageLoadingElement()}
<Text textValue="loading"></Text>
{/snippet}
{#snippet imageFailedElement()}
{#snippet imagePlaceholder()}
<Text textValue="error"></Text>
{/snippet}

0 comments on commit 84bd503

Please sign in to comment.