Add new long form text cell
This commit is contained in:
parent
aefdfabe39
commit
125febdd5a
|
@ -2,23 +2,36 @@
|
|||
import { getContext, onMount } from "svelte"
|
||||
import { get } from "svelte/store"
|
||||
|
||||
const { rows, rand, selectedCellId, columns, selectedCellRow, stickyColumn, selectedCellAPI } =
|
||||
getContext("sheet")
|
||||
const {
|
||||
rows,
|
||||
selectedCellId,
|
||||
columns,
|
||||
selectedCellRow,
|
||||
stickyColumn,
|
||||
selectedCellAPI,
|
||||
} = getContext("sheet")
|
||||
|
||||
const handleKeyDown = e => {
|
||||
const api = get(selectedCellAPI)
|
||||
if (!api) {
|
||||
return
|
||||
}
|
||||
|
||||
// Always capture escape and blur any selected cell
|
||||
// Always intercept certain key presses
|
||||
if (e.key === "Escape") {
|
||||
api?.blur()
|
||||
api.blur()
|
||||
} else if (e.key === "Tab") {
|
||||
api.blur()
|
||||
changeSelectedColumn(1)
|
||||
}
|
||||
|
||||
// Pass the key event to the selected cell and let it decide whether to
|
||||
// capture it or not
|
||||
const handled = api?.onKeyDown?.(e)
|
||||
const handled = api.onKeyDown?.(e)
|
||||
if (handled) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
|
||||
// Handle the key ourselves
|
||||
switch (e.key) {
|
||||
|
@ -39,7 +52,7 @@
|
|||
break
|
||||
case "Enter":
|
||||
focusSelectedCell()
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
// Handles a wheel even and updates the scroll offsets
|
||||
const handleWheel = e => {
|
||||
console.log("wheel scrol!")
|
||||
e.preventDefault()
|
||||
const modifier = e.ctrlKey || e.metaKey
|
||||
let x = modifier ? e.deltaY : e.deltaX
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<div>[MISSING]</div>
|
|
@ -2,7 +2,7 @@
|
|||
import { getContext } from "svelte"
|
||||
import SheetCell from "./SheetCell.svelte"
|
||||
import { Icon, Popover, Menu, MenuItem } from "@budibase/bbui"
|
||||
import { getIconForField } from "../utils"
|
||||
import { getColumnIcon } from "../utils"
|
||||
|
||||
export let column
|
||||
export let idx
|
||||
|
@ -17,7 +17,7 @@
|
|||
renderedColumns,
|
||||
dispatch,
|
||||
config,
|
||||
ui
|
||||
ui,
|
||||
} = getContext("sheet")
|
||||
|
||||
let anchor
|
||||
|
@ -99,7 +99,7 @@
|
|||
>
|
||||
<Icon
|
||||
size="S"
|
||||
name={getIconForField(column)}
|
||||
name={getColumnIcon(column)}
|
||||
color={`var(--spectrum-global-color-gray-600)`}
|
||||
/>
|
||||
<div class="name">
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<script>
|
||||
import { onMount, tick } from "svelte"
|
||||
|
||||
export let value
|
||||
export let selected = false
|
||||
export let onChange
|
||||
export let readonly = false
|
||||
export let api
|
||||
|
||||
let textarea
|
||||
let isOpen = false
|
||||
|
||||
$: editable = selected && !readonly
|
||||
$: {
|
||||
if (!selected) {
|
||||
isOpen = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleChange = e => {
|
||||
onChange(e.target.value)
|
||||
console.log(e.target.value)
|
||||
}
|
||||
|
||||
const onKeyDown = () => {
|
||||
return isOpen
|
||||
}
|
||||
|
||||
const open = async () => {
|
||||
isOpen = true
|
||||
await tick()
|
||||
textarea.focus()
|
||||
textarea.setSelectionRange(0, 0)
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
textarea?.blur()
|
||||
isOpen = false
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
api = {
|
||||
focus: () => open(),
|
||||
blur: () => close(),
|
||||
onKeyDown,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if isOpen}
|
||||
<textarea
|
||||
bind:this={textarea}
|
||||
value={value || ""}
|
||||
on:change={handleChange}
|
||||
on:wheel|stopPropagation
|
||||
/>
|
||||
{:else}
|
||||
<div class="long-form-cell" on:click={editable ? open : null} class:editable>
|
||||
<div class="value">
|
||||
{value || ""}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.long-form-cell {
|
||||
flex: 1 1 auto;
|
||||
padding: 0 var(--cell-padding);
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.long-form-cell.editable:hover {
|
||||
cursor: text;
|
||||
}
|
||||
.value {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
textarea {
|
||||
padding: var(--cell-padding);
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: var(--cell-background);
|
||||
font-size: var(--cell-font-size);
|
||||
font-family: var(--font-sans);
|
||||
color: inherit;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
width: calc(100% + 100px);
|
||||
height: calc(5 * var(--cell-height) + 1px);
|
||||
border: var(--cell-border);
|
||||
box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
|
@ -183,17 +183,18 @@
|
|||
);
|
||||
}
|
||||
.options {
|
||||
min-width: 100%;
|
||||
min-width: calc(100% + 2px);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.15);
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
max-height: calc(6 * var(--cell-height) - 1px);
|
||||
max-height: calc(5 * var(--cell-height) + 1px);
|
||||
overflow-y: auto;
|
||||
border: var(--cell-border);
|
||||
}
|
||||
.option {
|
||||
flex: 0 0 var(--cell-height);
|
||||
|
|
|
@ -4,13 +4,22 @@ import MultiSelectCell from "./cells/MultiSelectCell.svelte"
|
|||
import NumberCell from "./cells/NumberCell.svelte"
|
||||
import RelationshipCell from "./cells/RelationshipCell.svelte"
|
||||
import TextCell from "./cells/TextCell.svelte"
|
||||
import BlankCell from "./cells/BlankCell.svelte"
|
||||
import LongFormCell from "./cells/LongFormCell.svelte"
|
||||
|
||||
const TypeComponentMap = {
|
||||
text: TextCell,
|
||||
options: OptionsCell,
|
||||
datetime: DateCell,
|
||||
barcodeqr: BlankCell,
|
||||
longform: LongFormCell,
|
||||
array: MultiSelectCell,
|
||||
number: NumberCell,
|
||||
boolean: BlankCell,
|
||||
attachment: BlankCell,
|
||||
link: RelationshipCell,
|
||||
formula: BlankCell,
|
||||
json: BlankCell,
|
||||
}
|
||||
export const getCellRenderer = column => {
|
||||
return TypeComponentMap[column?.schema?.type] || TextCell
|
||||
|
|
|
@ -5,10 +5,10 @@ export const getColor = (idx, opacity = 0.3) => {
|
|||
return `hsla(${((idx + 1) * 222) % 360}, 90%, 75%, ${opacity})`
|
||||
}
|
||||
|
||||
const DataTypeIconMap = {
|
||||
const TypeIconMap = {
|
||||
text: "Text",
|
||||
options: "Dropdown",
|
||||
datetime: "Date",
|
||||
text: "Text",
|
||||
barcodeqr: "Camera",
|
||||
longform: "TextAlignLeft",
|
||||
array: "Dropdown",
|
||||
|
@ -20,7 +20,7 @@ const DataTypeIconMap = {
|
|||
json: "Brackets",
|
||||
}
|
||||
|
||||
export const getIconForField = field => {
|
||||
const type = field.schema.type
|
||||
return DataTypeIconMap[type] || "Text"
|
||||
export const getColumnIcon = column => {
|
||||
const type = column.schema.type
|
||||
return TypeIconMap[type] || "Text"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue