UX Enhancements and custom positioning behaviour for the popover
This commit is contained in:
parent
7492a70bcf
commit
13f6fed101
|
@ -17,6 +17,7 @@ export default function positionDropdown(element, opts) {
|
||||||
maxWidth,
|
maxWidth,
|
||||||
useAnchorWidth,
|
useAnchorWidth,
|
||||||
offset = 5,
|
offset = 5,
|
||||||
|
customUpdate,
|
||||||
} = opts
|
} = opts
|
||||||
if (!anchor) {
|
if (!anchor) {
|
||||||
return
|
return
|
||||||
|
@ -32,33 +33,42 @@ export default function positionDropdown(element, opts) {
|
||||||
left: null,
|
left: null,
|
||||||
top: null,
|
top: null,
|
||||||
}
|
}
|
||||||
// Determine vertical styles
|
|
||||||
if (align === "right-outside") {
|
|
||||||
styles.top = anchorBounds.top
|
|
||||||
} else if (window.innerHeight - anchorBounds.bottom < (maxHeight || 100)) {
|
|
||||||
styles.top = anchorBounds.top - elementBounds.height - offset
|
|
||||||
styles.maxHeight = maxHeight || 240
|
|
||||||
} else {
|
|
||||||
styles.top = anchorBounds.bottom + offset
|
|
||||||
styles.maxHeight =
|
|
||||||
maxHeight || window.innerHeight - anchorBounds.bottom - 20
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine horizontal styles
|
if (typeof customUpdate === "function") {
|
||||||
if (!maxWidth && useAnchorWidth) {
|
styles = customUpdate(anchorBounds, elementBounds, styles)
|
||||||
styles.maxWidth = anchorBounds.width
|
|
||||||
}
|
|
||||||
if (useAnchorWidth) {
|
|
||||||
styles.minWidth = anchorBounds.width
|
|
||||||
}
|
|
||||||
if (align === "right") {
|
|
||||||
styles.left = anchorBounds.left + anchorBounds.width - elementBounds.width
|
|
||||||
} else if (align === "right-outside") {
|
|
||||||
styles.left = anchorBounds.right + offset
|
|
||||||
} else if (align === "left-outside") {
|
|
||||||
styles.left = anchorBounds.left - elementBounds.width - offset
|
|
||||||
} else {
|
} else {
|
||||||
styles.left = anchorBounds.left
|
// Determine vertical styles
|
||||||
|
if (align === "right-outside") {
|
||||||
|
styles.top = anchorBounds.top
|
||||||
|
} else if (
|
||||||
|
window.innerHeight - anchorBounds.bottom <
|
||||||
|
(maxHeight || 100)
|
||||||
|
) {
|
||||||
|
styles.top = anchorBounds.top - elementBounds.height - offset
|
||||||
|
styles.maxHeight = maxHeight || 240
|
||||||
|
} else {
|
||||||
|
styles.top = anchorBounds.bottom + offset
|
||||||
|
styles.maxHeight =
|
||||||
|
maxHeight || window.innerHeight - anchorBounds.bottom - 20
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine horizontal styles
|
||||||
|
if (!maxWidth && useAnchorWidth) {
|
||||||
|
styles.maxWidth = anchorBounds.width
|
||||||
|
}
|
||||||
|
if (useAnchorWidth) {
|
||||||
|
styles.minWidth = anchorBounds.width
|
||||||
|
}
|
||||||
|
if (align === "right") {
|
||||||
|
styles.left =
|
||||||
|
anchorBounds.left + anchorBounds.width - elementBounds.width
|
||||||
|
} else if (align === "right-outside") {
|
||||||
|
styles.left = anchorBounds.right + offset
|
||||||
|
} else if (align === "left-outside") {
|
||||||
|
styles.left = anchorBounds.left - elementBounds.width - offset
|
||||||
|
} else {
|
||||||
|
styles.left = anchorBounds.left
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply styles
|
// Apply styles
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
export let animate = true
|
export let animate = true
|
||||||
export let customZindex
|
export let customZindex
|
||||||
|
|
||||||
|
export let handlePostionUpdate
|
||||||
export let showPopover = true
|
export let showPopover = true
|
||||||
export let clickOutsideOverride = false
|
export let clickOutsideOverride = false
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@
|
||||||
maxWidth,
|
maxWidth,
|
||||||
useAnchorWidth,
|
useAnchorWidth,
|
||||||
offset,
|
offset,
|
||||||
|
customUpdate: handlePostionUpdate,
|
||||||
}}
|
}}
|
||||||
use:clickOutside={{
|
use:clickOutside={{
|
||||||
callback: dismissible ? handleOutsideClick : () => {},
|
callback: dismissible ? handleOutsideClick : () => {},
|
||||||
|
|
|
@ -3,15 +3,30 @@
|
||||||
import { dndzone } from "svelte-dnd-action"
|
import { dndzone } from "svelte-dnd-action"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
import { setContext } from "svelte"
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
export let items = []
|
export let items = []
|
||||||
export let showHandle = true
|
export let showHandle = true
|
||||||
export let highlighted
|
|
||||||
export let listType
|
export let listType
|
||||||
export let listTypeProps = {}
|
export let listTypeProps = {}
|
||||||
export let listItemKey
|
export let listItemKey
|
||||||
export let draggable = true
|
export let draggable = true
|
||||||
|
|
||||||
|
let store = writable({
|
||||||
|
selected: null,
|
||||||
|
actions: {
|
||||||
|
select: id => {
|
||||||
|
store.update(state => ({
|
||||||
|
...state,
|
||||||
|
selected: id,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
setContext("draggable", store)
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const flipDurationMs = 150
|
const flipDurationMs = 150
|
||||||
|
|
||||||
|
@ -66,7 +81,7 @@
|
||||||
{#each draggableItems as draggable (draggable.id)}
|
{#each draggableItems as draggable (draggable.id)}
|
||||||
<li
|
<li
|
||||||
bind:this={anchors[draggable.id]}
|
bind:this={anchors[draggable.id]}
|
||||||
class:highlighted={draggable.id === highlighted}
|
class:highlighted={draggable.id === $store.selected}
|
||||||
>
|
>
|
||||||
<div class="left-content">
|
<div class="left-content">
|
||||||
{#if showHandle}
|
{#if showHandle}
|
||||||
|
@ -113,7 +128,8 @@
|
||||||
border-bottom: 1px solid
|
border-bottom: 1px solid
|
||||||
var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid));
|
var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid));
|
||||||
}
|
}
|
||||||
.list-wrap > li:hover {
|
.list-wrap > li:hover,
|
||||||
|
li.highlighted {
|
||||||
background-color: var(
|
background-color: var(
|
||||||
--spectrum-table-row-background-color-hover,
|
--spectrum-table-row-background-color-hover,
|
||||||
var(--spectrum-alias-highlight-hover)
|
var(--spectrum-alias-highlight-hover)
|
||||||
|
@ -135,7 +151,4 @@
|
||||||
padding-left: var(--spacing-s);
|
padding-left: var(--spacing-s);
|
||||||
padding-right: var(--spacing-s);
|
padding-right: var(--spacing-s);
|
||||||
}
|
}
|
||||||
li.highlighted {
|
|
||||||
background-color: pink;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,17 +4,24 @@
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import ComponentSettingsSection from "../../../../../pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
|
import ComponentSettingsSection from "../../../../../pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
export let anchor
|
export let anchor
|
||||||
export let field
|
export let field
|
||||||
export let componentBindings
|
export let componentBindings
|
||||||
export let bindings
|
export let bindings
|
||||||
|
|
||||||
|
const draggable = getContext("draggable")
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let popover
|
let popover
|
||||||
let drawers = []
|
let drawers = []
|
||||||
let sudoComponentInstance
|
let sudoComponentInstance
|
||||||
|
let open = false
|
||||||
|
|
||||||
|
$: if (open && $draggable.selected && $draggable.selected != field._id) {
|
||||||
|
popover.hide()
|
||||||
|
}
|
||||||
|
|
||||||
$: if (field) {
|
$: if (field) {
|
||||||
sudoComponentInstance = field
|
sudoComponentInstance = field
|
||||||
|
@ -61,7 +68,10 @@
|
||||||
hoverable
|
hoverable
|
||||||
size="S"
|
size="S"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
popover.show()
|
if (!open) {
|
||||||
|
popover.show()
|
||||||
|
open = true
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -69,11 +79,37 @@
|
||||||
bind:this={popover}
|
bind:this={popover}
|
||||||
on:open={() => {
|
on:open={() => {
|
||||||
drawers = []
|
drawers = []
|
||||||
|
$draggable.actions.select(field._id)
|
||||||
|
}}
|
||||||
|
on:close={() => {
|
||||||
|
open = false
|
||||||
|
if ($draggable.selected == field._id) {
|
||||||
|
$draggable.actions.select()
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
{anchor}
|
{anchor}
|
||||||
align="left-outside"
|
align="left-outside"
|
||||||
showPopover={drawers.length == 0}
|
showPopover={drawers.length == 0}
|
||||||
clickOutsideOverride={drawers.length > 0}
|
clickOutsideOverride={drawers.length > 0}
|
||||||
|
maxHeight={600}
|
||||||
|
handlePostionUpdate={(anchorBounds, eleBounds, cfg) => {
|
||||||
|
let { left, top } = cfg
|
||||||
|
let percentageOffset = 30
|
||||||
|
// left-outside
|
||||||
|
left = anchorBounds.left - eleBounds.width - 5
|
||||||
|
|
||||||
|
// shift up from the anchor, if space allows
|
||||||
|
let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset
|
||||||
|
let defaultTop = anchorBounds.top - offsetPos
|
||||||
|
|
||||||
|
if (window.innerHeight - defaultTop < eleBounds.height) {
|
||||||
|
top = window.innerHeight - eleBounds.height - 5
|
||||||
|
} else {
|
||||||
|
top = anchorBounds.top - offsetPos
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...cfg, left, top }
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span class="popover-wrap">
|
<span class="popover-wrap">
|
||||||
<Layout noPadding noGap>
|
<Layout noPadding noGap>
|
||||||
|
|
Loading…
Reference in New Issue