mirror of https://github.com/logseq/logseq
Enhance (Whiteboards): Paste and dnd behavior (also add a placeholder to shape labels) (#8753)
* fix: paste shape * enhance: add label placeholder * fix: don't create portal on ref click * enhance: allow ref dragging * fix: create line binding on drop * enhance: allow creating url based elements on droppull/8768/head
parent
91e89ef2d6
commit
82e5abf9e0
|
@ -511,11 +511,6 @@
|
|||
(:db/id page-entity)
|
||||
:page))
|
||||
|
||||
(whiteboard-handler/inside-portal? (.-target e))
|
||||
(whiteboard-handler/add-new-block-portal-shape!
|
||||
page-name
|
||||
(whiteboard-handler/closest-shape (.-target e)))
|
||||
|
||||
whiteboard-page?
|
||||
(route-handler/redirect-to-whiteboard! page-name)
|
||||
|
||||
|
@ -546,7 +541,9 @@
|
|||
(str " page-property-key block-property")
|
||||
untitled? (str " opacity-50"))
|
||||
:data-ref page-name
|
||||
:on-mouse-down (fn [e] (open-page-ref e page-name redirect-page-name page-name-in-block contents-page? whiteboard-page?))
|
||||
:draggable true
|
||||
:on-drag-start (fn [e] (editor-handler/block->data-transfer! page-name e))
|
||||
:on-mouse-up (fn [e] (open-page-ref e page-name redirect-page-name page-name-in-block contents-page? whiteboard-page?))
|
||||
:on-key-up (fn [e] (when (and e (= (.-key e) "Enter"))
|
||||
(open-page-ref e page-name redirect-page-name page-name-in-block contents-page? whiteboard-page?)))}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ import { LogseqContext, LogseqContextValue } from '../lib/logseq-context'
|
|||
|
||||
const isValidURL = (url: string) => {
|
||||
try {
|
||||
new URL(url)
|
||||
return true
|
||||
const parsedUrl = new URL(url)
|
||||
return parsedUrl.host && ['http:', 'https:'].includes(parsedUrl.protocol)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
@ -105,17 +105,17 @@ const handleCreatingShapes = async (
|
|||
const existingAsset = Object.values(app.assets).find(asset => asset.src === url)
|
||||
if (existingAsset) {
|
||||
return existingAsset as VideoImageAsset
|
||||
} else {
|
||||
// Create a new asset for this image
|
||||
const asset: VideoImageAsset = {
|
||||
id: uniqueId(),
|
||||
type: isVideo ? 'video' : 'image',
|
||||
src: url,
|
||||
size: await getSizeFromSrc(handlers.makeAssetUrl(url), isVideo),
|
||||
}
|
||||
return asset
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new asset for this image
|
||||
const asset: VideoImageAsset = {
|
||||
id: uniqueId(),
|
||||
type: isVideo ? 'video' : 'image',
|
||||
src: url,
|
||||
size: await getSizeFromSrc(handlers.makeAssetUrl(url), isVideo),
|
||||
}
|
||||
return asset
|
||||
}
|
||||
|
||||
async function createAssetsFromFiles(files: File[]) {
|
||||
const tasks = files
|
||||
|
@ -272,7 +272,7 @@ const handleCreatingShapes = async (
|
|||
}
|
||||
|
||||
async function tryCreateShapeFromURL(rawText: string) {
|
||||
if (isValidURL(rawText) && !(shiftKey || fromDrop)) {
|
||||
if (isValidURL(rawText) && !shiftKey) {
|
||||
if (YOUTUBE_REGEX.test(rawText)) {
|
||||
return [
|
||||
{
|
||||
|
@ -415,7 +415,7 @@ const handleCreatingShapes = async (
|
|||
}
|
||||
app.currentPage.updateBindings(Object.fromEntries(bindingsToCreate.map(b => [b.id, b])))
|
||||
|
||||
if (app.selectedShapesArray.length === 1 && allShapesToAdd.length === 1 && !fromDrop) {
|
||||
if (app.selectedShapesArray.length === 1 && allShapesToAdd.length === 1 && fromDrop) {
|
||||
const source = app.selectedShapesArray[0]
|
||||
const target = app.getShapeById(allShapesToAdd[0].id!)!
|
||||
app.createNewLineBinding(source, target)
|
||||
|
|
|
@ -77,7 +77,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
|
|||
const labelSize =
|
||||
label || isEditing
|
||||
? getTextLabelSize(
|
||||
label,
|
||||
label || "Enter text",
|
||||
{ fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
|
||||
6
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ import { TextAreaUtils } from './TextAreaUtils'
|
|||
|
||||
const stopPropagation = (e: KeyboardEvent | React.SyntheticEvent<any, Event>) => e.stopPropagation()
|
||||
|
||||
const placeholder = "Enter text"
|
||||
export interface TextLabelProps {
|
||||
font: string
|
||||
text: string
|
||||
|
@ -57,11 +58,7 @@ export const TextLabel = React.memo(function TextLabel({
|
|||
if (!(e.key === 'Meta' || e.metaKey)) {
|
||||
e.stopPropagation()
|
||||
} else if (e.key === 'z' && e.metaKey) {
|
||||
if (e.shiftKey) {
|
||||
document.execCommand('redo', false)
|
||||
} else {
|
||||
document.execCommand('undo', false)
|
||||
}
|
||||
document.execCommand(e.shiftKey ? 'redo' : 'undo', false)
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
return
|
||||
|
@ -92,8 +89,7 @@ export const TextLabel = React.memo(function TextLabel({
|
|||
|
||||
const handleFocus = React.useCallback(
|
||||
(e: React.FocusEvent<HTMLTextAreaElement>) => {
|
||||
if (!isEditing) return
|
||||
if (!rIsMounted.current) return
|
||||
if (!isEditing || !rIsMounted.current) return
|
||||
|
||||
if (document.activeElement === e.currentTarget) {
|
||||
e.currentTarget.select()
|
||||
|
@ -130,7 +126,7 @@ export const TextLabel = React.memo(function TextLabel({
|
|||
const elm = rInnerWrapper.current
|
||||
if (!elm) return
|
||||
const size = getTextLabelSize(
|
||||
text,
|
||||
text || placeholder,
|
||||
{ fontFamily: 'var(--ls-font-family)', fontSize, lineHeight: 1, fontWeight },
|
||||
4
|
||||
)
|
||||
|
@ -172,7 +168,7 @@ export const TextLabel = React.memo(function TextLabel({
|
|||
autoCorrect="false"
|
||||
autoSave="false"
|
||||
autoFocus
|
||||
placeholder=""
|
||||
placeholder={placeholder}
|
||||
spellCheck="true"
|
||||
wrap="off"
|
||||
dir="auto"
|
||||
|
|
|
@ -122,9 +122,8 @@ export class TLPage<S extends TLShape = TLShape, E extends TLEventMap = TLEventM
|
|||
private parseShapesArg<S>(shapes: S[] | string[]) {
|
||||
if (typeof shapes[0] === 'string') {
|
||||
return this.shapes.filter(shape => (shapes as string[]).includes(shape.id))
|
||||
} else {
|
||||
return shapes as S[]
|
||||
}
|
||||
return shapes as S[]
|
||||
}
|
||||
|
||||
@action removeShapes(...shapes: S[] | string[]) {
|
||||
|
|
Loading…
Reference in New Issue