File size: 4,241 Bytes
6f91ce5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { react } from 'tldraw'
import { defaultPaperCardProps } from '../../shared/shapes.ts'
import { changes, watchBoard } from '../pinboard/changes.ts'
import { pinOffset } from '../widgets/notes.ts'
import { fakeEditor } from './fixtures/fakeEditor.ts'
import { cardUnder, dropNoteAt, gap, placeNote, registerPinNotes, UNPIN_GAP } from './pinNotes.ts'
import { boardToast } from './toast.ts'

// Two cards as getShapePageBounds gives them: Liu 2022's 172 × 70 card, drawn centred on a 48 px
// node at (100, 100); Tirosh 2016 sits 400 px to the right.
const liu = { id: 'shape:paper-liu', box: { x: 38, y: 89, w: 172, h: 70 } }
const tirosh = { id: 'shape:paper-tirosh', box: { x: 438, y: 89, w: 172, h: 70 } }
const cards = [liu, tirosh]
const note = (x: number, y: number) => ({ x, y, w: 160, h: 160 })

test('a point inside a card’s drawn box finds that card, even outside its node', () => {
	assert.equal(cardUnder({ x: 205, y: 95 }, cards)?.id, liu.id) // right of the node, still on the card
	assert.equal(cardUnder({ x: 215, y: 95 }, cards), null) // just past the card's right edge
	assert.equal(cardUnder({ x: 124, y: 160 }, cards), null) // just below it
	// overlapping cards: the one whose centre is nearest
	const close = { id: 'shape:paper-close', box: { x: 138, y: 89, w: 172, h: 70 } }
	assert.equal(cardUnder({ x: 190, y: 124 }, [liu, close])?.id, close.id)
})

test('a note whose centre is on a card pins to it; one beside it stays as it is', () => {
	assert.deepEqual(placeNote(note(50, 40), null, cards), { pin: liu.id }) // centre (130, 120)
	assert.deepEqual(placeNote(note(250, 40), null, cards), null)
	// a pinned note dropped on another paper moves to it
	assert.deepEqual(placeNote(note(450, 40), liu.id, cards), { pin: tirosh.id })
	// dropped on its own paper again, it's put back beside it
	assert.deepEqual(placeNote(note(50, 40), liu.id, cards), { pin: liu.id })
})

test('a pinned note comes loose only once it’s more than a card’s width from its paper', () => {
	assert.equal(UNPIN_GAP, 172)
	// the card's right edge is at x = 210: a gap of 172 keeps the pin, 173 doesn't
	assert.deepEqual(placeNote(note(210 + 172, 100), liu.id, [liu]), null)
	assert.deepEqual(placeNote(note(210 + 173, 100), liu.id, [liu]), { unpin: true })
	// below and to the left count too
	assert.deepEqual(placeNote(note(-400, 400), liu.id, [liu]), { unpin: true })
	// a free note far from everything stays free; a paper that's gone (hidden) keeps its pin
	assert.deepEqual(placeNote(note(1000, 1000), null, cards), null)
	assert.deepEqual(placeNote(note(1000, 1000), 'shape:paper-gone', cards), null)
})

test('gap between boxes is 0 when they touch and diagonal past a corner', () => {
	assert.equal(gap({ x: 0, y: 0, w: 10, h: 10 }, { x: 10, y: 0, w: 10, h: 10 }), 0)
	assert.equal(gap({ x: 0, y: 0, w: 10, h: 10 }, { x: 13, y: 14, w: 10, h: 10 }), 5)
})

test('the toolbar’s Note dropped on a paper is pinned once, beside the card, with one toast', () => {
	const props = defaultPaperCardProps('pmid:2', { authors: ['Yang Liu'], year: 2022, w: 48, h: 48 })
	const { editor, shapes, bindings, writes } = fakeEditor([{ id: liu.id, type: 'paper-card', x: 100, y: 100, props }])
	const toasts: string[] = []
	const stop = react('board toasts', () => {
		const shown = boardToast.get()
		if (shown) toasts.push(shown.text)
	})
	const cleanups = [watchBoard(editor, 'b_drop'), registerPinNotes(editor)]
	try {
		dropNoteAt(editor, { x: 124, y: 124 }) // the middle of Liu 2022's node
		assert.deepEqual(
			writes.filter((w) => w.includes('binding')),
			['create binding note-pin']
		)
		const [pin] = [...bindings.values()]
		const { dx, dy } = pinOffset(props, 0)
		assert.equal(pin.toId, liu.id)
		assert.deepEqual(pin.props, { dx, dy })
		const note = shapes.get(pin.fromId)!
		assert.deepEqual([note.x, note.y], [100 + dx, 100 + dy])
		assert.deepEqual(toasts, ['Note pinned to Liu 2022. It moves with the paper.'])
		assert.deepEqual(
			changes.get('b_drop').entries.map((e) => e.change),
			[{ type: 'note_added', noteId: note.id, text: '', paperId: 'pmid:2' }]
		)
	} finally {
		stop()
		cleanups.forEach((cleanup) => cleanup())
	}
})