Type IndicatorSet
This commit is contained in:
parent
0ad0ded2e2
commit
89d6231dad
|
@ -1,19 +1,19 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { isGridScreen, dndParent, dndSource } from "@/stores"
|
import { isGridScreen, dndParent, dndSource, dndIsDragging } from "@/stores"
|
||||||
import { DNDPlaceholderID } from "@/constants"
|
import { DNDPlaceholderID } from "@/constants"
|
||||||
import IndicatorSet from "./IndicatorSet.svelte"
|
import IndicatorSet from "./IndicatorSet.svelte"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !$isGridScreen}
|
|
||||||
<IndicatorSet
|
|
||||||
componentId={$dndParent}
|
|
||||||
color="var(--spectrum-global-color-static-green-400)"
|
|
||||||
zIndex={920}
|
|
||||||
prefix="Inside"
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $dndIsDragging}
|
{#if $dndIsDragging}
|
||||||
|
{#if !$isGridScreen}
|
||||||
|
<IndicatorSet
|
||||||
|
componentId={$dndParent}
|
||||||
|
color="var(--spectrum-global-color-static-green-400)"
|
||||||
|
zIndex={920}
|
||||||
|
prefix="Inside"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<IndicatorSet
|
<IndicatorSet
|
||||||
componentId={DNDPlaceholderID}
|
componentId={DNDPlaceholderID}
|
||||||
color="var(--spectrum-global-color-static-green-500)"
|
color="var(--spectrum-global-color-static-green-500)"
|
||||||
|
|
|
@ -1,32 +1,54 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import Indicator from "./Indicator.svelte"
|
import Indicator from "./Indicator.svelte"
|
||||||
import { builderStore } from "stores"
|
import { builderStore } from "stores"
|
||||||
import { memo, Utils } from "@budibase/frontend-core"
|
import { memo, Utils } from "@budibase/frontend-core"
|
||||||
|
|
||||||
export let componentId = null
|
export let componentId: string | undefined = undefined
|
||||||
export let color = null
|
export let color: string | undefined = undefined
|
||||||
export let zIndex = 900
|
export let zIndex: number = 900
|
||||||
export let prefix = null
|
export let prefix: string | undefined = undefined
|
||||||
export let allowResizeAnchors = false
|
export let allowResizeAnchors: boolean = false
|
||||||
export let background = null
|
export let background: string | undefined = undefined
|
||||||
export let animate = false
|
export let animate: boolean = false
|
||||||
export let text = null
|
export let text: string | undefined = undefined
|
||||||
export let icon = null
|
export let icon: string | undefined = undefined
|
||||||
|
|
||||||
|
interface IndicatorState {
|
||||||
|
visible: boolean
|
||||||
|
insideModal: boolean
|
||||||
|
insideSidePanel: boolean
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IndicatorSetState {
|
||||||
|
// Cached props
|
||||||
|
componentId?: string
|
||||||
|
color?: string
|
||||||
|
zIndex: number
|
||||||
|
prefix?: string
|
||||||
|
allowResizeAnchors: boolean
|
||||||
|
|
||||||
|
// Computed state
|
||||||
|
indicators: IndicatorState[]
|
||||||
|
text?: string
|
||||||
|
icon?: string
|
||||||
|
insideGrid: boolean
|
||||||
|
error: boolean
|
||||||
|
}
|
||||||
|
|
||||||
// Offset = 6 (clip-root padding) - 1 (half the border thickness)
|
|
||||||
const config = memo($$props)
|
const config = memo($$props)
|
||||||
const errorColor = "var(--spectrum-global-color-static-red-600)"
|
const errorColor = "var(--spectrum-global-color-static-red-600)"
|
||||||
const mutationObserver = new MutationObserver(() => debouncedUpdate())
|
const mutationObserver = new MutationObserver(() => debouncedUpdate())
|
||||||
const defaultState = () => ({
|
const defaultState = (): IndicatorSetState => ({
|
||||||
// Cached props
|
|
||||||
componentId,
|
componentId,
|
||||||
color,
|
color,
|
||||||
zIndex,
|
zIndex,
|
||||||
prefix,
|
prefix,
|
||||||
allowResizeAnchors,
|
allowResizeAnchors,
|
||||||
|
|
||||||
// Computed state
|
|
||||||
indicators: [],
|
indicators: [],
|
||||||
text,
|
text,
|
||||||
icon,
|
icon,
|
||||||
|
@ -34,13 +56,13 @@
|
||||||
error: false,
|
error: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
let interval
|
let interval: ReturnType<typeof setInterval>
|
||||||
let state = defaultState()
|
let state = defaultState()
|
||||||
let observingMutations = false
|
let observingMutations = false
|
||||||
let updating = false
|
let updating = false
|
||||||
let intersectionObservers = []
|
let intersectionObservers: IntersectionObserver[] = []
|
||||||
let callbackCount = 0
|
let callbackCount = 0
|
||||||
let nextState
|
let nextState: ReturnType<typeof defaultState>
|
||||||
|
|
||||||
$: componentId, reset()
|
$: componentId, reset()
|
||||||
$: visibleIndicators = state.indicators.filter(x => x.visible)
|
$: visibleIndicators = state.indicators.filter(x => x.visible)
|
||||||
|
@ -62,26 +84,33 @@
|
||||||
updating = false
|
updating = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const observeMutations = element => {
|
const getElements = (className: string): HTMLElement[] => {
|
||||||
mutationObserver.observe(element, {
|
return [...document.getElementsByClassName(className)]
|
||||||
|
.filter(el => el instanceof HTMLElement)
|
||||||
|
.slice(0, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
const observeMutations = (node: Node) => {
|
||||||
|
mutationObserver.observe(node, {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
})
|
})
|
||||||
observingMutations = true
|
observingMutations = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const createIntersectionCallback = idx => entries => {
|
const createIntersectionCallback =
|
||||||
if (callbackCount >= intersectionObservers.length) {
|
(idx: number) => (entries: IntersectionObserverEntry[]) => {
|
||||||
return
|
if (callbackCount >= intersectionObservers.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nextState.indicators[idx].visible =
|
||||||
|
nextState.indicators[idx].insideModal ||
|
||||||
|
nextState.indicators[idx].insideSidePanel ||
|
||||||
|
entries[0].isIntersecting
|
||||||
|
if (++callbackCount === intersectionObservers.length) {
|
||||||
|
state = nextState
|
||||||
|
updating = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nextState.indicators[idx].visible =
|
|
||||||
nextState.indicators[idx].insideModal ||
|
|
||||||
nextState.indicators[idx].insideSidePanel ||
|
|
||||||
entries[0].isIntersecting
|
|
||||||
if (++callbackCount === intersectionObservers.length) {
|
|
||||||
state = nextState
|
|
||||||
updating = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatePosition = () => {
|
const updatePosition = () => {
|
||||||
if (updating) {
|
if (updating) {
|
||||||
|
@ -93,7 +122,7 @@
|
||||||
state = defaultState()
|
state = defaultState()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let elements = document.getElementsByClassName(componentId)
|
let elements = getElements(componentId)
|
||||||
if (!elements.length) {
|
if (!elements.length) {
|
||||||
state = defaultState()
|
state = defaultState()
|
||||||
return
|
return
|
||||||
|
@ -134,11 +163,8 @@
|
||||||
// Extract valid children
|
// Extract valid children
|
||||||
// Sanity limit of active indicators
|
// Sanity limit of active indicators
|
||||||
if (!nextState.insideGrid) {
|
if (!nextState.insideGrid) {
|
||||||
elements = document.getElementsByClassName(`${componentId}-dom`)
|
elements = getElements(`${componentId}-dom`)
|
||||||
}
|
}
|
||||||
elements = Array.from(elements)
|
|
||||||
.filter(x => x != null)
|
|
||||||
.slice(0, 100)
|
|
||||||
const multi = elements.length > 1
|
const multi = elements.length > 1
|
||||||
|
|
||||||
// If there aren't any nodes then reset
|
// If there aren't any nodes then reset
|
||||||
|
@ -148,15 +174,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const device = document.getElementById("app-root")
|
const device = document.getElementById("app-root")
|
||||||
|
if (!device) {
|
||||||
|
throw "app-root node not found"
|
||||||
|
}
|
||||||
const deviceBounds = device.getBoundingClientRect()
|
const deviceBounds = device.getBoundingClientRect()
|
||||||
nextState.indicators = elements.map((element, idx) => {
|
nextState.indicators = elements.map((element, idx) => {
|
||||||
const elBounds = element.getBoundingClientRect()
|
const elBounds = element.getBoundingClientRect()
|
||||||
let indicator = {
|
let indicator: IndicatorState = {
|
||||||
top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset),
|
top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset),
|
||||||
left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset),
|
left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset),
|
||||||
width: Math.round(elBounds.width + 2),
|
width: Math.round(elBounds.width + 2),
|
||||||
height: Math.round(elBounds.height + 2),
|
height: Math.round(elBounds.height + 2),
|
||||||
visible: true,
|
visible: true,
|
||||||
|
insideModal: false,
|
||||||
|
insideSidePanel: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If observing more than one node then we need to use an intersection
|
// If observing more than one node then we need to use an intersection
|
||||||
|
|
Loading…
Reference in New Issue