Skip to content

Commit 137c926

Browse files
Refactor
1 parent 8d54a5f commit 137c926

File tree

7 files changed

+300
-228
lines changed

7 files changed

+300
-228
lines changed

src/components/Item.svelte

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import Collapse from './Collapse.svelte'
66
import ItemMenu from './ItemMenu.svelte'
77
import { itemStore } from '../stores/itemStore.js'
8+
import { parseStatusPrefix } from '../utils/serializer.js'
89
import { focusItem, focusDescription } from '../utils/focus.js'
910
1011
export let item
@@ -117,13 +118,11 @@
117118
118119
function handleTextChange(event) {
119120
const rawText = event.detail.value
120-
const match = rawText.match(/^\[(x| )\]\s?/)
121+
const statusInfo = parseStatusPrefix(rawText)
121122
122-
if (match) {
123-
console.log('[Item] Checkbox detected via text match:', match[0], 'in item:', item.id)
124-
const hasCheckbox = true
125-
const completed = match[1] === 'x'
126-
const text = rawText.slice(match[0].length)
123+
if (statusInfo.matched && statusInfo.hasCheckbox) {
124+
console.log('[Item] Checkbox detected via text match in item:', item.id)
125+
const { text, hasCheckbox, completed } = statusInfo
127126
itemStore.updateItem(item.id, { text, hasCheckbox, completed })
128127
} else {
129128
// console.log('[Item] No checkbox match in text:', rawText)

src/components/List.svelte

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import RichEditor from './RichEditor.svelte'
55
import { itemStore } from '../stores/itemStore.js'
66
import { generateId } from '../utils/id.js'
7+
import { parseStatusPrefix } from '../utils/serializer.js'
78
import { focusItem, focusDescription, getItemAbove, getItemBelow, flattenVisible } from '../utils/focus.js'
89
import { get } from 'svelte/store'
910
@@ -219,13 +220,12 @@
219220
220221
function handleTitleTextChange(event) {
221222
const rawText = event.detail.value
222-
const match = rawText.match(/^\[(x| )\]\s?/)
223+
const statusInfo = parseStatusPrefix(rawText)
223224
224-
if (match) {
225-
console.log('[List] Checkbox detected via title match:', match[0], 'in item:', item.id)
226-
const hasCheckbox = true
227-
const completed = match[1] === 'x'
228-
const text = rawText.slice(match[0].length)
225+
// Only handle explicit checkboxes ([ ] or [x]) to match original behavior
226+
if (statusInfo.matched && statusInfo.hasCheckbox) {
227+
console.log('[List] Checkbox detected via title match in item:', item.id)
228+
const { text, hasCheckbox, completed } = statusInfo
229229
itemStore.updateItem(item.id, { text, hasCheckbox, completed })
230230
} else {
231231
itemStore.updateItem(item.id, { text: rawText })

src/components/RichEditor.svelte

Lines changed: 16 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
<script>
22
import { onMount, onDestroy, createEventDispatcher } from 'svelte'
33
import { Editor } from '@tiptap/core'
4-
import StarterKit from '@tiptap/starter-kit'
5-
import BubbleMenu from '@tiptap/extension-bubble-menu'
6-
import Placeholder from '@tiptap/extension-placeholder'
7-
import Link from '@tiptap/extension-link'
8-
import { Markdown } from 'tiptap-markdown'
9-
import { HashtagExtension } from '../extensions/HashtagExtension.js'
10-
import { HighlightSearchExtension } from '../extensions/HighlightSearchExtension.js'
11-
import { KeyboardExtension } from '../extensions/KeyboardExtension.js'
12-
import { CheckboxExtension } from '../extensions/CheckboxExtension.js'
13-
import { AutocompleteExtension } from '../extensions/AutocompleteExtension.js'
14-
import { ItemReferenceExtension } from '../extensions/ItemReferenceExtension.js'
4+
5+
import { getExtensions } from './RichEditorExtensions.js'
156
import AutocompleteMenu from './AutocompleteMenu.svelte'
167
import LinkModal from './LinkModal.svelte'
178
import { allHashtags } from '../stores/hashtagStore.js'
@@ -101,118 +92,20 @@
10192
}
10293
10394
onMount(() => {
104-
const extensions = [
105-
StarterKit.configure({
106-
heading: false,
107-
blockquote: false,
108-
codeBlock: false,
109-
horizontalRule: false,
110-
bulletList: false,
111-
orderedList: false,
112-
listItem: false,
113-
hardBreak: isDescription
114-
}),
115-
Link.configure({
116-
openOnClick: true,
117-
autolink: true
118-
}),
119-
Markdown.configure({
120-
html: true,
121-
transformPastedText: true,
122-
transformCopiedText: true
123-
}),
124-
HashtagExtension.configure({
125-
onHashtagClick: handleHashtagClick
126-
}),
127-
HighlightSearchExtension.configure({
128-
phrase: highlightPhrase
129-
}),
130-
KeyboardExtension.configure({
131-
isDescription,
132-
onEnter: () => {
133-
if (isDescription) {
134-
dispatch('exitdescription')
135-
} else {
136-
dispatch('newbullet')
137-
}
138-
},
139-
onShiftEnter: () => {
140-
if (!isDescription) {
141-
dispatch('description')
142-
}
143-
},
144-
onCommandEnter: () => {
145-
dispatch('togglecomplete')
146-
},
147-
onDelete: () => {
148-
dispatch('delete')
149-
},
150-
onForceDelete: () => {
151-
dispatch('forcedelete')
152-
},
153-
onTab: () => {
154-
if (isDescription) {
155-
editor?.commands.insertContent('\t')
156-
} else {
157-
dispatch('indent')
158-
}
159-
},
160-
onShiftTab: () => {
161-
if (!isDescription) {
162-
dispatch('outdent')
163-
}
164-
},
165-
onArrowUp: () => {
166-
dispatch('selectup')
167-
},
168-
onArrowDown: () => {
169-
dispatch('selectdown')
170-
},
171-
onShiftArrowUp: () => {
172-
dispatch('shiftselectup')
173-
},
174-
onShiftArrowDown: () => {
175-
dispatch('shiftselectdown')
176-
}
177-
}),
178-
CheckboxExtension.configure({
179-
onCheckboxToggle: (checked) => {
180-
dispatch('checkboxtoggle', { checked })
181-
},
182-
onCheckboxRemoved: () => {
183-
dispatch('checkboxremoved')
184-
},
185-
onCheckboxAdded: (checked) => {
186-
dispatch('checkboxadded', { checked })
187-
}
188-
}),
189-
AutocompleteExtension.configure({
190-
triggers: [
191-
{ char: '#', pattern: /#([\w-]*)$/ },
192-
{ char: '@', pattern: /@([\w\s-]*)$/ }
193-
],
194-
onTrigger: handleAutocomplete,
195-
onHide: handleAutocompleteHide
196-
}),
197-
ItemReferenceExtension.configure({
198-
onItemRefClick: handleItemRefClick,
199-
getItemText: getItemText
200-
}),
201-
BubbleMenu.configure({
202-
element: bubbleMenuElement,
203-
tippyOptions: {
204-
duration: 100
205-
}
206-
})
207-
]
208-
209-
if (showPlaceholder && placeholder) {
210-
extensions.push(
211-
Placeholder.configure({
212-
placeholder
213-
})
214-
)
215-
}
95+
const extensions = getExtensions({
96+
isDescription,
97+
highlightPhrase,
98+
dispatch,
99+
handleHashtagClick,
100+
handleAutocomplete,
101+
handleAutocompleteHide,
102+
handleItemRefClick,
103+
getItemText,
104+
bubbleMenuElement,
105+
showPlaceholder,
106+
placeholder,
107+
getEditor: () => editor
108+
})
216109
217110
editor = new Editor({
218111
element: editorElement,
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
2+
import StarterKit from '@tiptap/starter-kit'
3+
import BubbleMenu from '@tiptap/extension-bubble-menu'
4+
import Placeholder from '@tiptap/extension-placeholder'
5+
import Link from '@tiptap/extension-link'
6+
import { Markdown } from 'tiptap-markdown'
7+
import { HashtagExtension } from '../extensions/HashtagExtension.js'
8+
import { HighlightSearchExtension } from '../extensions/HighlightSearchExtension.js'
9+
import { KeyboardExtension } from '../extensions/KeyboardExtension.js'
10+
import { CheckboxExtension } from '../extensions/CheckboxExtension.js'
11+
import { AutocompleteExtension } from '../extensions/AutocompleteExtension.js'
12+
import { ItemReferenceExtension } from '../extensions/ItemReferenceExtension.js'
13+
14+
export function getExtensions({
15+
isDescription,
16+
highlightPhrase,
17+
dispatch,
18+
handleHashtagClick,
19+
handleAutocomplete,
20+
handleAutocompleteHide,
21+
handleItemRefClick,
22+
getItemText,
23+
bubbleMenuElement,
24+
showPlaceholder,
25+
placeholder,
26+
getEditor // function returning editor instance
27+
}) {
28+
const extensions = [
29+
StarterKit.configure({
30+
heading: false,
31+
blockquote: false,
32+
codeBlock: false,
33+
horizontalRule: false,
34+
bulletList: false,
35+
orderedList: false,
36+
listItem: false,
37+
hardBreak: isDescription
38+
}),
39+
Link.configure({
40+
openOnClick: true,
41+
autolink: true
42+
}),
43+
Markdown.configure({
44+
html: true,
45+
transformPastedText: true,
46+
transformCopiedText: true
47+
}),
48+
HashtagExtension.configure({
49+
onHashtagClick: handleHashtagClick
50+
}),
51+
HighlightSearchExtension.configure({
52+
phrase: highlightPhrase
53+
}),
54+
KeyboardExtension.configure({
55+
isDescription,
56+
onEnter: () => {
57+
if (isDescription) {
58+
dispatch('exitdescription')
59+
} else {
60+
dispatch('newbullet')
61+
}
62+
},
63+
onShiftEnter: () => {
64+
if (!isDescription) {
65+
dispatch('description')
66+
}
67+
},
68+
onCommandEnter: () => {
69+
dispatch('togglecomplete')
70+
},
71+
onDelete: () => {
72+
dispatch('delete')
73+
},
74+
onForceDelete: () => {
75+
dispatch('forcedelete')
76+
},
77+
onTab: () => {
78+
if (isDescription) {
79+
getEditor()?.commands.insertContent('\t')
80+
} else {
81+
dispatch('indent')
82+
}
83+
},
84+
onShiftTab: () => {
85+
if (!isDescription) {
86+
dispatch('outdent')
87+
}
88+
},
89+
onArrowUp: () => {
90+
dispatch('selectup')
91+
},
92+
onArrowDown: () => {
93+
dispatch('selectdown')
94+
},
95+
onShiftArrowUp: () => {
96+
dispatch('shiftselectup')
97+
},
98+
onShiftArrowDown: () => {
99+
dispatch('shiftselectdown')
100+
}
101+
}),
102+
CheckboxExtension.configure({
103+
onCheckboxToggle: (checked) => {
104+
dispatch('checkboxtoggle', { checked })
105+
},
106+
onCheckboxRemoved: () => {
107+
dispatch('checkboxremoved')
108+
},
109+
onCheckboxAdded: (checked) => {
110+
dispatch('checkboxadded', { checked })
111+
}
112+
}),
113+
AutocompleteExtension.configure({
114+
triggers: [
115+
{ char: '#', pattern: /#([\w-]*)$/ },
116+
{ char: '@', pattern: /@([\w\s-]*)$/ }
117+
],
118+
onTrigger: handleAutocomplete,
119+
onHide: handleAutocompleteHide
120+
}),
121+
ItemReferenceExtension.configure({
122+
onItemRefClick: handleItemRefClick,
123+
getItemText: getItemText
124+
}),
125+
BubbleMenu.configure({
126+
element: bubbleMenuElement,
127+
tippyOptions: {
128+
duration: 100
129+
}
130+
})
131+
]
132+
133+
if (showPlaceholder && placeholder) {
134+
extensions.push(
135+
Placeholder.configure({
136+
placeholder
137+
})
138+
)
139+
}
140+
141+
return extensions
142+
}

0 commit comments

Comments
 (0)