@estiva-app/ui 0.68.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LinkChips.d.ts.map +1 -1
- package/dist/editor.js +10 -4
- package/dist/editor.js.map +2 -2
- package/package.json +1 -1
- package/registry.json +1 -1
- package/src/LinkChips.mdx +8 -6
- package/src/LinkChips.test.tsx +43 -0
- package/src/LinkChips.ts +15 -6
package/package.json
CHANGED
package/registry.json
CHANGED
package/src/LinkChips.mdx
CHANGED
|
@@ -21,10 +21,10 @@ recognise, or has not answered for yet, stays text.
|
|
|
21
21
|
|
|
22
22
|
- A document that is only read → **RichText**, whose text already says which
|
|
23
23
|
runs are chips.
|
|
24
|
-
-
|
|
25
|
-
author's
|
|
26
|
-
(
|
|
27
|
-
|
|
24
|
+
- A link on words (a composer's Link button, a URL pasted over selected
|
|
25
|
+
words) → it stays the author's link, not a chip. A link whose text is its
|
|
26
|
+
own URL (an autolink, a link mark's paste rule) is that URL, and becomes
|
|
27
|
+
its chip.
|
|
28
28
|
|
|
29
29
|
## How
|
|
30
30
|
|
|
@@ -47,10 +47,12 @@ LinkChips.configure({
|
|
|
47
47
|
never turns into a chip while it is being typed. A pasted URL is whole: it
|
|
48
48
|
is asked about and becomes its chip at once, with the caret at its end, so
|
|
49
49
|
**ReferenceMenu** can open its menu.
|
|
50
|
-
- A URL in code
|
|
50
|
+
- A URL in code or in a code block stays text, and so does a link on words.
|
|
51
51
|
- Each URL is asked about once, and one editor asks about at most `limit`
|
|
52
52
|
(24 by default), the first ones: an answer can cost the app a query.
|
|
53
|
-
-
|
|
53
|
+
- A pasted URL's chip is its own undo step: undo gives the URL back, and a
|
|
54
|
+
second undo takes the paste away. A typed URL's chip is not a step: undo
|
|
55
|
+
takes back what was typed.
|
|
54
56
|
|
|
55
57
|
## What it owns
|
|
56
58
|
|
package/src/LinkChips.test.tsx
CHANGED
|
@@ -175,4 +175,47 @@ describe('LinkChips', () => {
|
|
|
175
175
|
await tick()
|
|
176
176
|
expect(ed.getText()).toBe(`${URL_} `)
|
|
177
177
|
})
|
|
178
|
+
|
|
179
|
+
it('makes a pasted URL its chip as its own undo step: undo gives the URL back, then takes the paste away', async () => {
|
|
180
|
+
const ed = make(para({ type: 'text', text: 'See ' }), new Map([[URL_, V]]))
|
|
181
|
+
await tick()
|
|
182
|
+
ed.view.dispatch(ed.state.tr.setSelection(TextSelection.create(ed.state.doc, ed.state.doc.content.size - 1)))
|
|
183
|
+
ed.view.pasteText(URL_, new Event('paste') as ClipboardEvent)
|
|
184
|
+
expect(inline(ed).map((n) => n.type)).toEqual(['text', 'reference'])
|
|
185
|
+
ed.commands.undo()
|
|
186
|
+
expect(inline(ed)).toEqual([{ type: 'text', text: `See ${URL_}` }])
|
|
187
|
+
ed.commands.undo()
|
|
188
|
+
expect(inline(ed)).toEqual([{ type: 'text', text: 'See ' }])
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('makes a pasted URL answered later its own undo step too', async () => {
|
|
192
|
+
const known = new Map<string, string>()
|
|
193
|
+
const ed = make(para({ type: 'text', text: 'See ' }), known)
|
|
194
|
+
await tick()
|
|
195
|
+
ed.view.dispatch(ed.state.tr.setSelection(TextSelection.create(ed.state.doc, ed.state.doc.content.size - 1)))
|
|
196
|
+
ed.view.pasteText(URL_, new Event('paste') as ClipboardEvent)
|
|
197
|
+
expect(inline(ed)).toEqual([{ type: 'text', text: `See ${URL_}` }])
|
|
198
|
+
known.set(URL_, V)
|
|
199
|
+
refreshLinkChips(ed)
|
|
200
|
+
expect(inline(ed)[1].type).toBe('reference')
|
|
201
|
+
ed.commands.undo()
|
|
202
|
+
expect(inline(ed)).toEqual([{ type: 'text', text: `See ${URL_}` }])
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('turns a link whose text is its own URL into its chip, and leaves a link on words', async () => {
|
|
206
|
+
editor = new Editor({
|
|
207
|
+
// A composer's link mark: an autolink, or its paste rule, links a bare URL to itself.
|
|
208
|
+
extensions: [StarterKit.configure({ link: { autolink: false, openOnClick: false } }), BlockId, ReferenceNode, LinkChips.configure({ referenceOf: (url) => (url === URL_ ? V : undefined), ask: null })],
|
|
209
|
+
content: para(
|
|
210
|
+
{ type: 'text', text: URL_, marks: [{ type: 'link', attrs: { href: URL_ } }, { type: 'bold' }] },
|
|
211
|
+
{ type: 'text', text: ' and ' },
|
|
212
|
+
{ type: 'text', text: 'the words', marks: [{ type: 'link', attrs: { href: URL_ } }] },
|
|
213
|
+
),
|
|
214
|
+
})
|
|
215
|
+
await tick()
|
|
216
|
+
const [chip, , words] = inline(editor)
|
|
217
|
+
expect(chip.type).toBe('reference')
|
|
218
|
+
expect(chip.attrs).toMatchObject({ uri: V, href: URL_, marks: ['bold'] })
|
|
219
|
+
expect(words).toMatchObject({ type: 'text', text: 'the words' })
|
|
220
|
+
})
|
|
178
221
|
})
|
package/src/LinkChips.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* still at its end — where `ReferenceMenu` opens its menu.
|
|
20
20
|
*/
|
|
21
21
|
import { Extension, type Editor } from '@tiptap/core'
|
|
22
|
+
import { closeHistory } from '@tiptap/pm/history'
|
|
22
23
|
import type { Node as PmNode } from '@tiptap/pm/model'
|
|
23
24
|
import { Plugin, PluginKey, type EditorState, type Selection, type Transaction } from '@tiptap/pm/state'
|
|
24
25
|
|
|
@@ -111,9 +112,14 @@ export function findLinkChips(doc: PmNode, selection: Selection | null, referenc
|
|
|
111
112
|
return false
|
|
112
113
|
}
|
|
113
114
|
if (!node.isText || !node.text) return true
|
|
114
|
-
// A URL in code is literal
|
|
115
|
-
if (node.marks.some((m) => m.type.spec.code || m.type.name === 'code'
|
|
116
|
-
|
|
115
|
+
// A URL in code is literal.
|
|
116
|
+
if (node.marks.some((m) => m.type.spec.code || m.type.name === 'code')) return false
|
|
117
|
+
// A link on words is the link's. A link whose text is its own URL — an editor's autolink, or its paste rule — is
|
|
118
|
+
// that URL, as a document reads one (protocol's `inlineToEditor`): its chip, with the link mark left behind.
|
|
119
|
+
const link = node.marks.find((m) => m.type.name === 'link')
|
|
120
|
+
if (link && !(link.attrs.href === node.text && /^https?:\/\//.test(node.text))) return false
|
|
121
|
+
const runs = link ? [{ url: node.text, from: 0, to: node.text.length, end: node.text.length }] : urlRuns(node.text)
|
|
122
|
+
for (const run of runs) {
|
|
117
123
|
const from = pos + run.from
|
|
118
124
|
const to = pos + run.to
|
|
119
125
|
// Being typed or selected: the caret inside it or at its end (`https://a.` is still being typed), or a
|
|
@@ -123,7 +129,7 @@ export function findLinkChips(doc: PmNode, selection: Selection | null, referenc
|
|
|
123
129
|
const typing = selection && selection.to > from && selection.from <= pos + run.end
|
|
124
130
|
if (typing && !(selection.empty && wasPasted)) continue
|
|
125
131
|
const uri = referenceOf?.(run.url)
|
|
126
|
-
if (uri) found.chips.push({ from, to, url: run.url, uri, marks: node.marks.map((m) => m.type.name), pasted: wasPasted })
|
|
132
|
+
if (uri) found.chips.push({ from, to, url: run.url, uri, marks: node.marks.filter((m) => m !== link).map((m) => m.type.name), pasted: wasPasted })
|
|
127
133
|
else open.add(run.url)
|
|
128
134
|
}
|
|
129
135
|
return false
|
|
@@ -145,9 +151,12 @@ function apply(state: EditorState, found: Found): Transaction | null {
|
|
|
145
151
|
for (const chip of [...found.chips].reverse()) {
|
|
146
152
|
tr.replaceWith(chip.from, chip.to, type.create({ uri: chip.uri, href: chip.url, marks: chip.marks }))
|
|
147
153
|
}
|
|
148
|
-
// Not a step of the person's: undo takes back what they typed, not the chip it became.
|
|
149
154
|
// Whether a pasted URL became its chip: `ReferenceMenu` opens on that one, never on a URL typed by hand.
|
|
150
|
-
|
|
155
|
+
const pasted = found.chips.some((chip) => chip.pasted)
|
|
156
|
+
tr.setMeta(CHIPS_MADE, { pasted })
|
|
157
|
+
// A pasted URL's chip is its own undo step, so Ctrl+Z gives the URL back rather than taking the paste away (OPT-19,
|
|
158
|
+
// as Peek's pasted link did). Any other chip is not a step of the person's: undo takes back what they typed.
|
|
159
|
+
return pasted ? closeHistory(tr) : tr.setMeta('addToHistory', false)
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
/**
|