Skip to content

Commit 77bc14f

Browse files
committed
feat(json-crdt-peritext-ui): 🎸 improve clipboard action behavior
1 parent 4bfd16e commit 77bc14f

File tree

2 files changed

+38
-39
lines changed

2 files changed

+38
-39
lines changed

src/json-crdt-peritext-ui/events/defaults/PeritextEventDefaults.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export class PeritextEventDefaults implements PeritextEventHandlerMap {
272272
case 'text': {
273273
const text = range.text();
274274
clipboard.writeText(text)?.catch((err) => console.error(err));
275-
if (action === 'cut') editor.collapseCursors();
275+
if (action === 'cut') editor.collapseCursor(range);
276276
break;
277277
}
278278
case 'style': {
@@ -313,7 +313,7 @@ export class PeritextEventDefaults implements PeritextEventHandlerMap {
313313
break;
314314
}
315315
clipboard.writeText(text)?.catch((err) => console.error(err));
316-
if (action === 'cut') editor.collapseCursors();
316+
if (action === 'cut') editor.collapseCursor(range);
317317
break;
318318
}
319319
default: {
@@ -325,7 +325,7 @@ export class PeritextEventDefaults implements PeritextEventHandlerMap {
325325
} else {
326326
const data = transfer.toClipboard(range);
327327
clipboard.write(data as unknown as PeritextClipboardData<string>)?.catch((err) => console.error(err));
328-
if (action === 'cut') editor.collapseCursors();
328+
if (action === 'cut') editor.collapseCursor(range);
329329
}
330330
}
331331
}

src/json-crdt-peritext-ui/plugins/toolbar/state/index.tsx

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -349,56 +349,56 @@ export class ToolbarState implements UiLifeCycles {
349349
const iconJson = () => <Iconista width={16} height={16} set="tabler" icon="json" style={{opacity: 0.5}} />;
350350
const markdownAction: MenuItem = {
351351
name: 'Markdown',
352-
text: action + ' paste markdown md',
352+
text: action + ' markdown md',
353353
icon,
354354
right: iconMarkdown,
355355
onSelect: () => {
356-
et.buffer({...ctx.onBeforeAction?.(markdownAction), action, format: 'md'});
356+
et.buffer({...ctx.onBeforeAction?.(markdownAction, action), action, format: 'md'});
357357
},
358358
};
359359
const mdastAction: MenuItem = {
360360
name: 'MDAST',
361-
text: action + ' paste markdown md mdast',
361+
text: action + ' markdown md mdast',
362362
icon,
363363
right: iconMarkdown,
364364
onSelect: () => {
365-
et.buffer({...ctx.onBeforeAction?.(mdastAction), action, format: 'mdast'});
365+
et.buffer({...ctx.onBeforeAction?.(mdastAction, action), action, format: 'mdast'});
366366
},
367367
};
368368
const htmlAction: MenuItem = {
369369
name: 'HTML',
370-
text: action + ' paste html',
370+
text: action + ' html',
371371
icon,
372372
right: iconHtml,
373373
onSelect: () => {
374-
et.buffer({...ctx.onBeforeAction?.(htmlAction), action, format: 'html'});
374+
et.buffer({...ctx.onBeforeAction?.(htmlAction, action), action, format: 'html'});
375375
},
376376
};
377377
const hastAction: MenuItem = {
378378
name: 'HAST',
379-
text: action + ' paste html hast',
379+
text: action + ' html hast',
380380
icon,
381381
right: iconHtml,
382382
onSelect: () => {
383-
et.buffer({...ctx.onBeforeAction?.(hastAction), action, format: 'hast'});
383+
et.buffer({...ctx.onBeforeAction?.(hastAction, action), action, format: 'hast'});
384384
},
385385
};
386386
const jsonAction: MenuItem = {
387387
name: 'Range view',
388-
text: action + ' paste range view peritext',
388+
text: action + ' range view peritext',
389389
icon,
390390
right: iconJson,
391391
onSelect: () => {
392-
et.buffer({...ctx.onBeforeAction?.(jsonAction), action, format: 'json'});
392+
et.buffer({...ctx.onBeforeAction?.(jsonAction, action), action, format: 'json'});
393393
},
394394
};
395395
const jsonmlAction: MenuItem = {
396396
name: 'Fragment ML',
397-
text: action + ' paste peritext fragment ml node',
397+
text: action + ' peritext fragment ml node',
398398
icon,
399399
right: iconJson,
400400
onSelect: () => {
401-
et.buffer({...ctx.onBeforeAction?.(jsonmlAction), action, format: 'jsonml'});
401+
et.buffer({...ctx.onBeforeAction?.(jsonmlAction, action), action, format: 'jsonml'});
402402
},
403403
};
404404
const fragmentAction: MenuItem = {
@@ -407,7 +407,7 @@ export class ToolbarState implements UiLifeCycles {
407407
icon,
408408
right: () => <Iconista width={16} height={16} set="lucide" icon="text" style={{opacity: 0.5}} />,
409409
onSelect: () => {
410-
et.buffer({...ctx.onBeforeAction?.(fragmentAction), action, format: 'fragment'});
410+
et.buffer({...ctx.onBeforeAction?.(fragmentAction, action), action, format: 'fragment'});
411411
},
412412
};
413413
return {
@@ -446,7 +446,7 @@ export class ToolbarState implements UiLifeCycles {
446446
icon,
447447
right: iconMarkdown,
448448
onSelect: () => {
449-
et.buffer({...ctx.onBeforeAction?.(markdownAction), action: 'paste', format: 'md'});
449+
et.buffer({...ctx.onBeforeAction?.(markdownAction, 'paste'), action: 'paste', format: 'md'});
450450
},
451451
};
452452
const mdastAction: MenuItem = {
@@ -455,7 +455,7 @@ export class ToolbarState implements UiLifeCycles {
455455
icon,
456456
right: iconMarkdown,
457457
onSelect: () => {
458-
et.buffer({...ctx.onBeforeAction?.(mdastAction), action: 'paste', format: 'mdast'});
458+
et.buffer({...ctx.onBeforeAction?.(mdastAction, 'paste'), action: 'paste', format: 'mdast'});
459459
},
460460
};
461461
const htmlAction: MenuItem = {
@@ -464,7 +464,7 @@ export class ToolbarState implements UiLifeCycles {
464464
icon,
465465
right: iconHtml,
466466
onSelect: () => {
467-
et.buffer({...ctx.onBeforeAction?.(htmlAction), action: 'paste', format: 'html'});
467+
et.buffer({...ctx.onBeforeAction?.(htmlAction, 'paste'), action: 'paste', format: 'html'});
468468
},
469469
};
470470
const hastAction: MenuItem = {
@@ -473,7 +473,7 @@ export class ToolbarState implements UiLifeCycles {
473473
icon,
474474
right: iconHtml,
475475
onSelect: () => {
476-
et.buffer({...ctx.onBeforeAction?.(hastAction), action: 'paste', format: 'hast'});
476+
et.buffer({...ctx.onBeforeAction?.(hastAction, 'paste'), action: 'paste', format: 'hast'});
477477
},
478478
};
479479
const jsonAction: MenuItem = {
@@ -482,7 +482,7 @@ export class ToolbarState implements UiLifeCycles {
482482
icon,
483483
right: iconJson,
484484
onSelect: () => {
485-
et.buffer({...ctx.onBeforeAction?.(jsonAction), action: 'paste', format: 'json'});
485+
et.buffer({...ctx.onBeforeAction?.(jsonAction, 'paste'), action: 'paste', format: 'json'});
486486
},
487487
};
488488
const jsonmlAction: MenuItem = {
@@ -491,7 +491,7 @@ export class ToolbarState implements UiLifeCycles {
491491
icon,
492492
right: iconJson,
493493
onSelect: () => {
494-
et.buffer({...ctx.onBeforeAction?.(jsonmlAction), action: 'paste', format: 'jsonml'});
494+
et.buffer({...ctx.onBeforeAction?.(jsonmlAction, 'paste'), action: 'paste', format: 'jsonml'});
495495
},
496496
};
497497
return {
@@ -523,14 +523,14 @@ export class ToolbarState implements UiLifeCycles {
523523
name: 'Copy',
524524
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard-copy" />,
525525
onSelect: () => {
526-
et.buffer({...ctx.onBeforeAction?.(copyAction), action: 'copy'});
526+
et.buffer({...ctx.onBeforeAction?.(copyAction, 'copy'), action: 'copy'});
527527
},
528528
};
529529
const copyTextOnlyAction: MenuItem = {
530530
name: 'Copy text only',
531531
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard-copy" />,
532532
onSelect: () => {
533-
et.buffer({...ctx.onBeforeAction?.(copyTextOnlyAction), action: 'copy', format: 'text'});
533+
et.buffer({...ctx.onBeforeAction?.(copyTextOnlyAction, 'copy'), action: 'copy', format: 'text'});
534534
},
535535
};
536536
const children: MenuItem[] = [
@@ -542,7 +542,7 @@ export class ToolbarState implements UiLifeCycles {
542542
name: 'Copy style',
543543
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard-copy" />,
544544
onSelect: () => {
545-
et.buffer({...ctx.onBeforeAction?.(copyStyleAction), action: 'copy', format: 'style'});
545+
et.buffer({...ctx.onBeforeAction?.(copyStyleAction, 'copy'), action: 'copy', format: 'style'});
546546
},
547547
};
548548
children.push(copyStyleAction);
@@ -564,15 +564,15 @@ export class ToolbarState implements UiLifeCycles {
564564
danger: true,
565565
icon: () => <Iconista width={16} height={16} set="tabler" icon="scissors" />,
566566
onSelect: () => {
567-
et.buffer({...ctx.onBeforeAction?.(cutAction), action: 'cut'});
567+
et.buffer({...ctx.onBeforeAction?.(cutAction, 'cut'), action: 'cut'});
568568
},
569569
};
570570
const cutTextAction: MenuItem = {
571571
name: 'Cut text only',
572572
danger: true,
573573
icon: () => <Iconista width={16} height={16} set="tabler" icon="scissors" />,
574574
onSelect: () => {
575-
et.buffer({...ctx.onBeforeAction?.(cutTextAction), action: 'cut', format: 'text'});
575+
et.buffer({...ctx.onBeforeAction?.(cutTextAction, 'cut'), action: 'cut', format: 'text'});
576576
},
577577
};
578578
return {
@@ -594,14 +594,14 @@ export class ToolbarState implements UiLifeCycles {
594594
name: 'Paste',
595595
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard" />,
596596
onSelect: () => {
597-
et.buffer({...ctx.onBeforeAction?.(pasteAction), action: 'paste'});
597+
et.buffer({...ctx.onBeforeAction?.(pasteAction, 'paste'), action: 'paste'});
598598
},
599599
};
600600
const pasteTextAction: MenuItem = {
601601
name: 'Paste text',
602602
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard" />,
603603
onSelect: () => {
604-
et.buffer({...ctx.onBeforeAction?.(pasteTextAction), action: 'paste', format: 'text'});
604+
et.buffer({...ctx.onBeforeAction?.(pasteTextAction, 'paste'), action: 'paste', format: 'text'});
605605
},
606606
};
607607
const children: MenuItem[] = [
@@ -613,7 +613,7 @@ export class ToolbarState implements UiLifeCycles {
613613
name: 'Paste style',
614614
icon: () => <Iconista width={15} height={15} set="radix" icon="clipboard" />,
615615
onSelect: () => {
616-
et.buffer({...ctx.onBeforeAction?.(pasteStyleAction), action: 'paste', format: 'style'});
616+
et.buffer({...ctx.onBeforeAction?.(pasteStyleAction, 'paste'), action: 'paste', format: 'style'});
617617
},
618618
};
619619
children.push(pasteStyleAction);
@@ -1504,19 +1504,18 @@ export class ToolbarState implements UiLifeCycles {
15041504
name: 'Select block',
15051505
icon: () => <Iconista width={16} height={16} set="bootstrap" icon="cursor-text" />,
15061506
onSelect: () => {
1507-
et.cursor({
1508-
move: [
1509-
['anchor', 'block', -1],
1510-
['focus', 'block', 1],
1511-
],
1512-
});
1507+
let start = block.start.clone();
1508+
if (!start.isAbsStart()) start.step(1);
1509+
et.cursor({at: [start, block.end]});
15131510
},
15141511
},
15151512
this.clipboardMenu({
15161513
hideStyleActions: true,
1517-
onBeforeAction: (item) => {
1514+
onBeforeAction: (item, action) => {
1515+
let start = block.start.clone();
1516+
if (!start.isAbsStart() && (action === 'paste')) start.step(1);
15181517
return {
1519-
at: [block.start, block.end],
1518+
at: [start, block.end],
15201519
};
15211520
},
15221521
}),
@@ -1536,5 +1535,5 @@ export interface LeafBlockMenuCtx {
15361535

15371536
export interface ClipboardMenuCtx {
15381537
hideStyleActions?: boolean;
1539-
onBeforeAction?: (item: MenuItem) => (void | Partial<BufferDetail>);
1538+
onBeforeAction?: (item: MenuItem, action: 'cut' | 'copy' | 'paste') => (void | Partial<BufferDetail>);
15401539
}

0 commit comments

Comments
 (0)