Update relationship cells to use popovers

This commit is contained in:
Andrew Kingston 2024-04-24 20:26:58 +01:00
parent 377cd97f4b
commit 23bd635a8b
6 changed files with 70 additions and 59 deletions

View File

@ -93,7 +93,14 @@
</div> </div>
{#if isOpen} {#if isOpen}
<GridPopover open={isOpen} {anchor} {gridID} {invertX} on:close={close}> <GridPopover
open={isOpen}
{anchor}
{gridID}
{invertX}
maxHeight={null}
on:close={close}
>
<div class="dropzone"> <div class="dropzone">
<Dropzone <Dropzone
{value} {value}

View File

@ -112,7 +112,7 @@
</div> </div>
{#if isOpen} {#if isOpen}
<GridPopover open={isOpen} {anchor} {invertX} {gridID} on:close={close}> <GridPopover {anchor} {invertX} maxHeight={null} on:close={close}>
<CoreDatePickerPopoverContents <CoreDatePickerPopoverContents
value={parsedValue} value={parsedValue}
useKeyboardShortcuts={false} useKeyboardShortcuts={false}

View File

@ -121,8 +121,8 @@
</div> </div>
{#if isOpen} {#if isOpen}
<GridPopover open={isOpen} {anchor} {gridID} {invertX} on:close={close}> <GridPopover {anchor} {invertX} on:close={close}>
<div class="options" on:wheel={e => e.stopPropagation()}> <div class="options">
{#each options as option, idx} {#each options as option, idx}
{@const color = optionColors[option] || getOptionColor(option)} {@const color = optionColors[option] || getOptionColor(option)}
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
@ -219,10 +219,6 @@
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
align-items: stretch; align-items: stretch;
max-height: var(--max-cell-render-overflow);
overflow-y: auto;
min-width: 200px;
max-width: 400px;
} }
.option { .option {
flex: 0 0 var(--default-row-height); flex: 0 0 var(--default-row-height);

View File

@ -1,8 +1,9 @@
<script> <script>
import { getColor } from "../lib/utils" import { getColor } from "../lib/utils"
import { onMount, getContext } from "svelte" import { onMount, getContext } from "svelte"
import { Icon, Input, ProgressCircle, clickOutside } from "@budibase/bbui" import { Icon, Input, ProgressCircle } from "@budibase/bbui"
import { debounce } from "../../../utils/utils" import { debounce } from "../../../utils/utils"
import GridPopover from "../overlays/GridPopover.svelte"
const { API, dispatch, cache } = getContext("grid") const { API, dispatch, cache } = getContext("grid")
@ -17,6 +18,7 @@
export let contentLines = 1 export let contentLines = 1
export let searchFunction = API.searchTable export let searchFunction = API.searchTable
export let primaryDisplay export let primaryDisplay
export let gridID
const color = getColor(0) const color = getColor(0)
@ -27,8 +29,8 @@
let candidateIndex let candidateIndex
let lastSearchId let lastSearchId
let searching = false let searching = false
let valuesHeight = 0
let container let container
let anchor
$: oneRowOnly = schema?.relationshipType === "one-to-many" $: oneRowOnly = schema?.relationshipType === "one-to-many"
$: editable = focused && !readonly $: editable = focused && !readonly
@ -125,7 +127,6 @@
const open = async () => { const open = async () => {
isOpen = true isOpen = true
valuesHeight = container.getBoundingClientRect().height
// Find the primary display for the related table // Find the primary display for the related table
if (!primaryDisplay) { if (!primaryDisplay) {
@ -240,6 +241,7 @@
class:focused class:focused
class:invertY class:invertY
style="--color:{color};" style="--color:{color};"
bind:this={anchor}
> >
<div class="container" bind:this={container}> <div class="container" bind:this={container}>
<div <div
@ -250,11 +252,7 @@
{#each value || [] as relationship} {#each value || [] as relationship}
{#if relationship[primaryDisplay] || relationship.primaryDisplay} {#if relationship[primaryDisplay] || relationship.primaryDisplay}
<div class="badge"> <div class="badge">
<span <span>
on:click={editable
? () => showRelationship(relationship._id)
: null}
>
{readable( {readable(
relationship[primaryDisplay] || relationship.primaryDisplay relationship[primaryDisplay] || relationship.primaryDisplay
)} )}
@ -282,16 +280,11 @@
</div> </div>
{/if} {/if}
</div> </div>
</div>
{#if isOpen} {#if isOpen}
<div <GridPopover open={isOpen} {anchor} {gridID} {invertX} on:close={close}>
class="dropdown" <div class="dropdown" on:wheel|stopPropagation>
class:invertX
class:invertY
on:wheel|stopPropagation
use:clickOutside={close}
style="--values-height:{valuesHeight}px;"
>
<div class="search"> <div class="search">
<Input <Input
autofocus autofocus
@ -327,8 +320,8 @@
</div> </div>
{/if} {/if}
</div> </div>
{/if} </GridPopover>
</div> {/if}
<style> <style>
.wrapper { .wrapper {
@ -426,10 +419,6 @@
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.editable .values .badge span:hover {
cursor: pointer;
text-decoration: underline;
}
.add { .add {
background: var(--spectrum-global-color-gray-200); background: var(--spectrum-global-color-gray-200);
@ -446,30 +435,9 @@
} }
.dropdown { .dropdown {
position: absolute;
top: 100%;
left: 0;
width: 100%;
max-height: calc(
var(--max-cell-render-overflow) + var(--row-height) - var(--values-height)
);
background: var(--grid-background-alt);
border: var(--cell-border);
box-shadow: 0 0 20px -4px rgba(0, 0, 0, 0.15);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
padding: 0 0 8px 0;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
.dropdown.invertY {
transform: translateY(-100%);
top: -1px;
}
.dropdown.invertX {
left: auto;
right: 0;
} }
.searching { .searching {
@ -497,7 +465,8 @@
cursor: pointer; cursor: pointer;
} }
.result .badge { .result .badge {
max-width: calc(100% - 30px); flex: 1 1 auto;
overflow: hidden;
} }
.search { .search {
@ -505,7 +474,6 @@
display: flex; display: flex;
align-items: center; align-items: center;
margin: 4px var(--cell-padding); margin: 4px var(--cell-padding);
width: calc(100% - 2 * var(--cell-padding));
} }
.search :global(.spectrum-Textfield) { .search :global(.spectrum-Textfield) {
min-width: 0; min-width: 0;

View File

@ -11,4 +11,9 @@ export const NewRowID = "new"
export const BlankRowID = "blank" export const BlankRowID = "blank"
export const RowPageSize = 100 export const RowPageSize = 100
export const FocusedCellMinOffset = 48 export const FocusedCellMinOffset = 48
// Popovers
export const PopoverMinWidth = 200
export const PopoverMaxWidth = 400
export const PopoverMaxHeight = 236
export const MaxCellRenderOverflow = 222 export const MaxCellRenderOverflow = 222

View File

@ -1,23 +1,51 @@
<script> <script>
import { Popover, clickOutside } from "@budibase/bbui" import { Popover, clickOutside } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher, getContext } from "svelte"
import {
PopoverMinWidth,
PopoverMaxWidth,
PopoverMaxHeight,
} from "../lib/constants"
export let open
export let anchor export let anchor
export let invertX export let invertX
export let gridID export let minWidth = PopoverMinWidth
export let maxWidth = PopoverMaxWidth
export let maxHeight = PopoverMaxHeight
const { gridID } = getContext("grid")
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
$: style = buildStyles(minWidth, maxWidth, maxHeight)
const buildStyles = (minWidth, maxWidth, maxHeight) => {
let style = ""
if (minWidth != null) {
style += `min-width: ${minWidth}px;`
}
if (maxWidth != null) {
style += `max-width: ${maxWidth}px;`
}
if (maxHeight != null) {
style += `max-height: ${maxHeight}px;`
}
return style
}
</script> </script>
<Popover <Popover
bind:open open
{anchor} {anchor}
align={invertX ? "right" : "left"} align={invertX ? "right" : "left"}
portalTarget="#{gridID} .grid-popover-container" portalTarget="#{gridID} .grid-popover-container"
offset={1} offset={1}
> >
<div use:clickOutside={() => dispatch("close")}> <div
class="grid-popover-contents"
{style}
use:clickOutside={() => dispatch("close")}
on:wheel={e => e.stopPropagation()}
>
<slot /> <slot />
</div> </div>
</Popover> </Popover>
@ -26,5 +54,12 @@
:global(.grid-popover-container .spectrum-Popover) { :global(.grid-popover-container .spectrum-Popover) {
background: var(--grid-background-alt); background: var(--grid-background-alt);
border: var(--cell-border); border: var(--cell-border);
min-width: none;
max-width: none;
overflow: hidden;
}
.grid-popover-contents {
overflow-y: auto;
overflow-x: hidden;
} }
</style> </style>