Merge pull request #903 from appwrite/fix-tooltip-arrow

fix: tooltip arrows
This commit is contained in:
Torsten Dittmann
2024-03-06 12:12:03 +01:00
committed by GitHub
9 changed files with 134 additions and 105 deletions
+46 -24
View File
@@ -15,6 +15,8 @@
export let wrapperFullWidth = false;
export let fixed = false;
export let display = 'block';
export let arrowSize = 10;
export let isPopover = false;
const dispatch = createEventDispatcher<{
blur: undefined;
@@ -33,13 +35,14 @@
{
name: 'arrow',
options: {
element: arrow
element: arrow,
padding: arrowSize * 1.75
}
},
{
name: 'offset',
options: {
offset: [0, noArrow ? 0 : 6]
offset: [-arrowSize, noArrow ? 0 : arrowSize / 1.5]
}
},
{
@@ -113,10 +116,15 @@
<div
class="drop-tooltip"
class:u-width-full-line={fullWidth}
bind:this={tooltip}
class:u-width-full-line={fullWidth}
style:--arrow-size={`${arrowSize}px`}
style:z-index="10">
<div class="drop-arrow" class:u-hide={!show || (show && noArrow)} bind:this={arrow} />
<div
class="drop-arrow"
class:is-popover={isPopover}
class:u-hide={!show || (show && noArrow)}
bind:this={arrow} />
{#if show}
<slot name="list" />
{/if}
@@ -124,36 +132,50 @@
<!-- svelte-ignore css-unused-selector -->
<style global lang="scss">
.drop-tooltip[data-popper-placement^='top'] > .drop-arrow {
bottom: -4px;
}
.drop-tooltip[data-popper-placement^='bottom'] > .drop-arrow {
top: -4px;
}
.drop-tooltip[data-popper-placement^='left'] > .drop-arrow {
right: -4px;
}
.drop-tooltip[data-popper-placement^='right'] > .drop-arrow {
left: -4px;
.drop-arrow.is-popover {
--drop-arrow-pop-over-bg-color: var(--color-neutral-90);
body.theme-light & {
--drop-arrow-pop-over-bg-color: var(--color-neutral-0);
}
}
.drop-arrow,
.drop-arrow::before {
position: absolute;
width: 8px;
height: 8px;
z-index: -1;
width: var(--arrow-size);
height: var(--arrow-size);
z-index: 1;
--drop-arrow-border: 1px solid hsl(var(--color-neutral-85));
--drop-arrow-bg-color: hsl(var(--drop-arrow-pop-over-bg-color, var(--color-neutral-105)));
body.theme-light & {
--drop-arrow-border: 1px solid hsl(var(--color-neutral-10));
--drop-arrow-bg-color: hsl(var(--drop-arrow-pop-over-bg-color, var(--color-neutral-0)));
}
}
.drop-arrow::before {
content: '';
transform: rotate(45deg);
background: hsl(var(--color-neutral-85));
background: var(--drop-arrow-bg-color);
}
body.theme-light & {
background: hsl(var(--color-neutral-10));
.drop-tooltip[data-popper-placement^='top'] > .drop-arrow {
bottom: calc(var(--arrow-size) / -2);
&::before {
border-bottom: var(--drop-arrow-border);
border-right: var(--drop-arrow-border);
border-bottom-right-radius: 25%;
}
}
.drop-tooltip[data-popper-placement^='bottom'] > .drop-arrow {
top: calc(var(--arrow-size) / -2);
&::before {
border-top: var(--drop-arrow-border);
border-left: var(--drop-arrow-border);
border-top-left-radius: 25%;
}
}
</style>
+9 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { FormItem, Helper, Label } from '.';
import { Drop } from '$lib/components';
@@ -14,7 +14,8 @@
export let autofocus = false;
export let autocomplete = false;
export let maxlength: number = null;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
export let fullWidth = false;
// https://www.geeksforgeeks.org/how-to-validate-a-domain-name-using-regular-expression/
@@ -52,8 +53,8 @@
<FormItem {fullWidth}>
<Label {required} hide={!showLabel} for={id}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -68,8 +69,10 @@
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--card-border-radius="var(--border-radius-small)"
style:--p-card-padding=".75rem"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
+9 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { FormItem, Helper, Label } from '.';
import NullCheckbox from './nullCheckbox.svelte';
import { Drop } from '$lib/components';
@@ -17,7 +17,8 @@
export let autofocus = false;
export let autocomplete = false;
export let tooltip: string = null;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
export let fullWidth = false;
let element: HTMLInputElement;
@@ -61,8 +62,8 @@
<FormItem {fullWidth}>
<Label {required} {optionalText} {tooltip} hide={!showLabel} for={id}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -77,8 +78,10 @@
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--card-border-radius="var(--border-radius-small)"
style:--p-card-padding=".75rem"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
+9 -6
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { Drop, Trim } from '$lib/components';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { Helper, Label } from '.';
export let label: string = null;
@@ -13,7 +13,8 @@
export let optionalText: string = null;
export let tooltip: string = null;
export let error: string = null;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
let input: HTMLInputElement;
let hovering = false;
@@ -96,8 +97,8 @@
<div>
{#if label}
<Label {required} {optionalText} {tooltip} hide={!label}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -112,8 +113,10 @@
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--card-border-radius="var(--border-radius-small)"
style:--p-card-padding=".75rem"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
+9 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { FormItem, Helper, Label } from '.';
import { Drop } from '$lib/components';
@@ -16,7 +16,8 @@
export let showPasswordButton = false;
export let minlength = 8;
export let maxlength: number = null;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
export let fullWidth = false;
let element: HTMLInputElement;
@@ -52,8 +53,8 @@
<FormItem {fullWidth}>
<Label {required} hide={!showLabel} for={id}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show={showPopover} display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show={showPopover} display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -68,8 +69,10 @@
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--card-border-radius="var(--border-radius-small)"
style:--p-card-padding=".75rem"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
+9 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { FormItem, Helper, Label } from '.';
import { Drop } from '$lib/components';
@@ -14,7 +14,8 @@
export let autofocus = false;
export let autocomplete = false;
export let maxlength: number = null;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
export let fullWidth = false;
const pattern = String.raw`^\+?[1-9]\d{1,14}$`;
@@ -51,8 +52,8 @@
<FormItem {fullWidth}>
<Label {required} hide={!showLabel} for={id}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -67,8 +68,10 @@
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--card-border-radius="var(--border-radius-small)"
style:--p-card-padding=".75rem"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
+10 -7
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount } from 'svelte';
import { SvelteComponent, onMount } from 'svelte';
import { FormItem, FormItemPart, Helper, Label } from '.';
import NullCheckbox from './nullCheckbox.svelte';
import TextCounter from './textCounter.svelte';
@@ -23,7 +23,8 @@
export let maxlength: number = null;
export let tooltip: string = null;
export let isMultiple = false;
export let isPopoverDefined = true;
export let popover: typeof SvelteComponent<unknown> = null;
export let popoverProps: Record<string, unknown> = {};
let element: HTMLInputElement;
let error: string;
@@ -77,8 +78,8 @@
<svelte:component this={wrapper} {fullWidth}>
{#if label}
<Label {required} {hideRequired} {tooltip} {optionalText} hide={!showLabel} for={id}>
{label}{#if $$slots.popover && isPopoverDefined}
<Drop bind:show display="inline-block">
{label}{#if popover}
<Drop isPopover bind:show display="inline-block">
<!-- TODO: make unclicked icon greyed out and hover and clicked filled -->
&nbsp;<button
type="button"
@@ -88,13 +89,15 @@
<span
class="icon-info"
aria-hidden="true"
style="font-size: var(--icon-size-small)" />
style:font-size="var(--icon-size-small)" />
</button>
<svelte:fragment slot="list">
<div
class="dropped card u-max-width-250"
style="--p-card-padding: .75rem; box-shadow:var(--shadow-large);">
<slot name="popover" />
style:--p-card-padding=".75rem"
style:--card-border-radius="var(--border-radius-small)"
style:box-shadow="var(--shadow-large)">
<svelte:component this={popover} {...popoverProps} />
</div>
</svelte:fragment>
</Drop>
@@ -2,7 +2,7 @@
import { ImagePreview } from '$lib/components';
export let lines = [];
export let popoverImage: { src: { dark: string; light: string }; alt: string } | null = null;
export let image: { src: { dark: string; light: string }; alt: string } | null = null;
</script>
<div class="u-flex-vertical u-gap-16">
@@ -10,11 +10,8 @@
<p>{@html line}</p>
{/each}
{#if popoverImage}
<ImagePreview
darkSrc={popoverImage.src.dark}
lightSrc={popoverImage.src.light}
alt={popoverImage.alt} />
{#if image}
<ImagePreview darkSrc={image.src.dark} lightSrc={image.src.light} alt={image.alt} />
{/if}
</div>
@@ -41,7 +41,18 @@
>;
export let fullWidth = false;
let popoverImage = input.popoverImage;
const popover = input.popover ? PopoverContent : null;
const popoverProps = getPopoverProps(input);
function getPopoverProps(input: ProviderInput) {
if (!input.popover) {
return {};
}
return {
lines: input.popover,
image: input.popoverImage
};
}
</script>
{#if input.type === 'text'}
@@ -51,13 +62,10 @@
placeholder={input.placeholder}
required={!input.optional}
tooltip={input.tooltip}
isPopoverDefined={input.popover !== undefined}
{popover}
{popoverProps}
{fullWidth}
bind:value={params[input.name]}>
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputText>
bind:value={params[input.name]} />
{:else if input.type === 'password'}
<InputPassword
id={input.name}
@@ -65,13 +73,10 @@
placeholder={input.placeholder}
required={!input.optional}
showPasswordButton
isPopoverDefined={input.popover !== undefined}
{popover}
{popoverProps}
{fullWidth}
bind:value={params[input.name]}>
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputPassword>
bind:value={params[input.name]} />
{:else if input.type === 'email'}
<InputEmail
id={input.name}
@@ -79,52 +84,39 @@
placeholder={input.placeholder}
required={!input.optional}
tooltip={input.tooltip}
isPopoverDefined={input.popover !== undefined}
{popover}
{popoverProps}
{fullWidth}
bind:value={params[input.name]}>
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputEmail>
bind:value={params[input.name]} />
{:else if input.type === 'domain'}
<InputDomain
id={input.name}
label={input.label}
placeholder={input.placeholder}
required={!input.optional}
isPopoverDefined={input.popover !== undefined}
{popover}
{popoverProps}
{fullWidth}
bind:value={params[input.name]}>
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputDomain>
bind:value={params[input.name]} />
{:else if input.type === 'phone'}
<InputPhone
id={input.name}
label={input.label}
placeholder={input.placeholder}
required={!input.optional}
isPopoverDefined={input.popover !== undefined}
{popover}
{popoverProps}
{fullWidth}
bind:value={params[input.name]}>
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputPhone>
bind:value={params[input.name]} />
{:else if input.type === 'file'}
<InputFile
label={input.label}
allowedFileExtensions={input.allowedFileExtensions}
required={!input.optional}
tooltip={input.tooltip}
isPopoverDefined={input.popover !== undefined}
bind:files={files[input.name]}>
{fullWidth}
<svelte:fragment slot="popover">
<PopoverContent lines={input.popover} {popoverImage} />
</svelte:fragment>
</InputFile>
{popover}
{popoverProps}
bind:files={files[input.name]} />
{:else if input.type === 'switch'}
<InputSwitch label={input.label} id={input.name} bind:value={params[input.name]}>
<svelte:fragment slot="description">