feat(apps): copy paste across apps

This commit is contained in:
Ruben Fiszel
2023-06-05 03:18:46 +02:00
parent be3b596502
commit f71ac4b8f4
7 changed files with 73 additions and 54 deletions
@@ -3,7 +3,6 @@
import Tooltip from '$lib/components/Tooltip.svelte'
import { Clipboard } from 'lucide-svelte'
import { getContext } from 'svelte'
import { get } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
import { copyToClipboard } from '../../../../utils'
import Button from '../../../common/button/Button.svelte'
@@ -11,12 +10,7 @@
import { initConfig, initOutput } from '../../editor/appUtils'
import { components } from '../../editor/component'
import type { AppInput } from '../../inputType'
import type {
AppEditorContext,
AppViewerContext,
ComponentCustomCSS,
RichConfigurations
} from '../../types'
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import ResolveConfig from '../helpers/ResolveConfig.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
@@ -39,8 +33,6 @@
const { app, worldStore, mode, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
const editorcontext = getContext<AppEditorContext>('AppEditorContext')
let result: string | undefined = undefined
if (componentInput?.type == 'template' && !isCodeInjection(componentInput.eval)) {
@@ -133,7 +125,7 @@
function onInput(e: Event) {
const target = e.target as HTMLTextAreaElement
if (target.value) {
if (target.value != undefined) {
$componentControl[id]?.setCode?.(target.value)
autosize()
}
@@ -210,14 +202,6 @@
componentInput?.type == 'template'
? 'cursor-text'
: ''}"
on:click={() => {
if ($mode === 'dnd' && componentInput?.type == 'template') {
let ontextfocus = editorcontext?.ontextfocus
if (ontextfocus) {
get(ontextfocus)?.()
}
}
}}
>
<svelte:element
this={component}
@@ -73,7 +73,6 @@
$: lastInput && $worldStore && debounce(handleConnection)
const debounceTemplate = async () => {
console.log('template')
let nvalue = await getValue(lastInput)
if (!deepEqual(nvalue, value)) {
value = nvalue
@@ -23,7 +23,7 @@
outputs?.result?.set(v, true)
}
$: result && outputs && setOutput(result)
$: result != undefined && outputs && setOutput(result)
</script>
<InitializeComponent {id} />
@@ -111,7 +111,6 @@
setContext<AppEditorContext>('AppEditorContext', {
history,
pickVariableCallback,
ontextfocus: writable(undefined),
movingcomponents: writable(undefined),
selectedComponentInEditor: writable(undefined)
})
@@ -10,6 +10,7 @@
import { push } from '$lib/history'
import { sendUserToast } from '$lib/toast'
import { gridColumns } from '../../gridUtils'
import { copyToClipboard } from '$lib/utils'
const { app, selectedComponent, focusedGrid, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
@@ -17,8 +18,8 @@
const { history, movingcomponents } = getContext<AppEditorContext>('AppEditorContext')
let tempGridItems: GridItem[] | undefined = undefined
let copiedGridItems: GridItem[] | undefined = undefined
const ITEM_TYPE = 'wm-grid-items'
function getSortedGridItemsOfChildren(): GridItem[] {
if (!$focusedGrid) {
return $app.grid
@@ -127,14 +128,33 @@
}
}
function handleCopy(event: KeyboardEvent) {
async function handleCopy(event: KeyboardEvent) {
if (!$selectedComponent) {
return
}
tempGridItems = undefined
copiedGridItems = $selectedComponent
const copiedGridItems = $selectedComponent
.map((x) => findGridItem($app, x))
.filter((x) => x != undefined) as GridItem[]
copyGridItemsToClipboard(copiedGridItems)
}
function copyGridItemsToClipboard(items: GridItem[]) {
let allSubgrids = {}
for (let item of items) {
let subgrids = getAllSubgridsAndComponentIds($app, item.data)[0]
for (let key of subgrids) {
allSubgrids[key] = $app.subgrids?.[key]
}
}
let success = copyToClipboard(
JSON.stringify({ type: ITEM_TYPE, items, subgrids: allSubgrids }),
false
)
if (!success) {
sendUserToast('Could not copy to clipboard. Are you in an unsecure context?', true)
}
}
function handleCut(event: KeyboardEvent) {
@@ -147,7 +167,7 @@
let gridItems = $selectedComponent
.map((x) => findGridItem($app, x))
.filter((x) => x != undefined) as GridItem[]
copiedGridItems = gridItems
copyGridItemsToClipboard(gridItems)
if (!gridItems) {
return
@@ -157,9 +177,34 @@
tempGridItems = gridItems
}
function handlePaste(event: KeyboardEvent) {
export async function handlePaste(event: ClipboardEvent) {
let classes = event.target?.['className']
if (
(typeof classes === 'string' && classes.includes('inputarea')) ||
['INPUT', 'TEXTAREA'].includes(document.activeElement?.tagName!)
) {
return
}
event.preventDefault()
push(history, $app)
$movingcomponents = undefined
let copiedGridItems: GridItem[] | undefined = undefined
let subgrids = $app.subgrids ?? {}
const txt = event?.clipboardData?.getData('text')
if (txt) {
try {
const parsed = JSON.parse(txt)
if (parsed.type == ITEM_TYPE) {
copiedGridItems = parsed.items
subgrids = parsed.subgrids ?? subgrids
console.log('subgrids', subgrids)
} else {
copiedGridItems = undefined
}
} catch {}
}
if (tempGridItems != undefined) {
for (let tempGridItem of tempGridItems) {
if (
@@ -190,14 +235,14 @@
tempGridItem.id
)
}
copiedGridItems = tempGridItems
copyGridItemsToClipboard(tempGridItems)
$selectedComponent = tempGridItems.map((x) => x.id)
tempGridItems = undefined
} else if (copiedGridItems) {
let nitems: string[] = []
for (let copiedGridItem of copiedGridItems) {
let newItem = copyComponent(copiedGridItem, $focusedGrid)
let newItem = copyComponent(copiedGridItem, $focusedGrid, subgrids)
newItem && nitems.push(newItem)
}
$selectedComponent = nitems.map((x) => x)
@@ -206,7 +251,12 @@
$app = $app
}
function copyComponent(item: GridItem, parentGrid: FocusedGrid | undefined, doNotVisit?: string) {
function copyComponent(
item: GridItem,
parentGrid: FocusedGrid | undefined,
subgrids: Record<string, GridItem[]>,
doNotVisit?: string
) {
if (item.id === doNotVisit) {
return
}
@@ -217,17 +267,17 @@
Object.fromEntries(gridColumns.map((column) => [column, item[column]]))
)
if ($app.subgrids && item.data.numberOfSubgrids) {
for (let i = 0; i < item.data.numberOfSubgrids; i++) {
$app.subgrids[`${item.id}-${i}`].forEach((subgridItem) => {
copyComponent(
subgridItem,
{ parentComponentId: newItem, subGridIndex: i },
doNotVisit ?? newItem
)
})
}
for (let i = 0; i < (item?.data?.numberOfSubgrids ?? 0); i++) {
subgrids[`${item.id}-${i}`].forEach((subgridItem) => {
copyComponent(
subgridItem,
{ parentComponentId: newItem, subGridIndex: i },
subgrids,
doNotVisit ?? newItem
)
})
}
return newItem
}
@@ -271,12 +321,6 @@
}
break
case 'v':
if (event.ctrlKey || event.metaKey) {
handlePaste(event)
}
break
case 'x':
if (event.ctrlKey || event.metaKey) {
handleCut(event)
@@ -289,4 +333,4 @@
}
</script>
<svelte:window on:keydown={keydown} />
<svelte:window on:keydown={keydown} on:paste={handlePaste} />
@@ -37,8 +37,6 @@
export let noGrid = false
export let duplicateMoveAllowed = true
let editor: TemplateEditor | undefined = undefined
const {
app,
runnableComponents,
@@ -52,10 +50,7 @@
componentControl
} = getContext<AppViewerContext>('AppViewerContext')
const { history, ontextfocus, movingcomponents } =
getContext<AppEditorContext>('AppEditorContext')
$: editor && ($ontextfocus = () => editor?.focus())
const { history, movingcomponents } = getContext<AppEditorContext>('AppEditorContext')
function removeGridElement() {
push(history, $app)
@@ -174,7 +169,6 @@
{:else if componentSettings.item.data.componentInput.type === 'template' && componentSettings.item.data.componentInput !== undefined}
<div class="py-1 min-h-[28px] rounded border border-1 border-gray-500">
<TemplateEditor
bind:this={editor}
fontSize={12}
bind:code={componentSettings.item.data.componentInput.eval}
{extraLib}
@@ -206,7 +206,6 @@ export type AppViewerContext = {
export type AppEditorContext = {
history: History<App> | undefined
pickVariableCallback: Writable<((path: string) => void) | undefined>
ontextfocus: Writable<(() => void) | undefined>
selectedComponentInEditor: Writable<string | undefined>
movingcomponents: Writable<string[] | undefined>
}