inkpen 0.7.1
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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.rubocop.yml +8 -0
- data/.yardopts +11 -0
- data/CLAUDE.md +141 -0
- data/README.md +409 -0
- data/Rakefile +19 -0
- data/app/assets/javascripts/inkpen/controllers/editor_controller.js +2050 -0
- data/app/assets/javascripts/inkpen/controllers/sticky_toolbar_controller.js +667 -0
- data/app/assets/javascripts/inkpen/controllers/toolbar_controller.js +693 -0
- data/app/assets/javascripts/inkpen/export/html.js +637 -0
- data/app/assets/javascripts/inkpen/export/index.js +30 -0
- data/app/assets/javascripts/inkpen/export/markdown.js +697 -0
- data/app/assets/javascripts/inkpen/export/pdf.js +372 -0
- data/app/assets/javascripts/inkpen/extensions/advanced_table.js +640 -0
- data/app/assets/javascripts/inkpen/extensions/block_commands.js +300 -0
- data/app/assets/javascripts/inkpen/extensions/block_gutter.js +338 -0
- data/app/assets/javascripts/inkpen/extensions/callout.js +303 -0
- data/app/assets/javascripts/inkpen/extensions/columns.js +403 -0
- data/app/assets/javascripts/inkpen/extensions/database.js +990 -0
- data/app/assets/javascripts/inkpen/extensions/document_section.js +352 -0
- data/app/assets/javascripts/inkpen/extensions/drag_handle.js +407 -0
- data/app/assets/javascripts/inkpen/extensions/embed.js +629 -0
- data/app/assets/javascripts/inkpen/extensions/enhanced_image.js +566 -0
- data/app/assets/javascripts/inkpen/extensions/export_commands.js +271 -0
- data/app/assets/javascripts/inkpen/extensions/file_attachment.js +593 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/index.js +58 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table.js +638 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table_cell.js +100 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table_header.js +100 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_constants.js +152 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_helpers.js +254 -0
- data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_menu.js +282 -0
- data/app/assets/javascripts/inkpen/extensions/preformatted.js +239 -0
- data/app/assets/javascripts/inkpen/extensions/section.js +281 -0
- data/app/assets/javascripts/inkpen/extensions/section_title.js +126 -0
- data/app/assets/javascripts/inkpen/extensions/slash_commands.js +439 -0
- data/app/assets/javascripts/inkpen/extensions/table_of_contents.js +474 -0
- data/app/assets/javascripts/inkpen/extensions/toggle_block.js +332 -0
- data/app/assets/javascripts/inkpen/index.js +87 -0
- data/app/assets/stylesheets/inkpen/advanced_table.css +514 -0
- data/app/assets/stylesheets/inkpen/animations.css +626 -0
- data/app/assets/stylesheets/inkpen/block_gutter.css +265 -0
- data/app/assets/stylesheets/inkpen/callout.css +359 -0
- data/app/assets/stylesheets/inkpen/columns.css +314 -0
- data/app/assets/stylesheets/inkpen/database.css +658 -0
- data/app/assets/stylesheets/inkpen/document_section.css +305 -0
- data/app/assets/stylesheets/inkpen/drag_drop.css +220 -0
- data/app/assets/stylesheets/inkpen/editor.css +652 -0
- data/app/assets/stylesheets/inkpen/embed.css +468 -0
- data/app/assets/stylesheets/inkpen/enhanced_image.css +453 -0
- data/app/assets/stylesheets/inkpen/export.css +499 -0
- data/app/assets/stylesheets/inkpen/file_attachment.css +347 -0
- data/app/assets/stylesheets/inkpen/footnotes.css +136 -0
- data/app/assets/stylesheets/inkpen/inkpen_table.css +608 -0
- data/app/assets/stylesheets/inkpen/preformatted.css +215 -0
- data/app/assets/stylesheets/inkpen/search_replace.css +58 -0
- data/app/assets/stylesheets/inkpen/section.css +236 -0
- data/app/assets/stylesheets/inkpen/slash_menu.css +252 -0
- data/app/assets/stylesheets/inkpen/sticky_toolbar.css +314 -0
- data/app/assets/stylesheets/inkpen/toc.css +386 -0
- data/app/assets/stylesheets/inkpen/toggle.css +260 -0
- data/app/helpers/inkpen/editor_helper.rb +114 -0
- data/app/views/inkpen/_editor.html.erb +139 -0
- data/config/importmap.rb +170 -0
- data/docs/.DS_Store +0 -0
- data/docs/CHANGELOG.md +571 -0
- data/docs/FEATURES.md +436 -0
- data/docs/ROADMAP.md +3029 -0
- data/docs/VISION.md +235 -0
- data/docs/extensions/INKPEN_TABLE.md +482 -0
- data/docs/thinking/CORRECTED_NO_VUE.md +756 -0
- data/docs/thinking/EXECUTIVE_SUMMARY.md +403 -0
- data/docs/thinking/INKPEN_CODE_SAMPLES.md +1479 -0
- data/docs/thinking/INKPEN_MASTER_GUIDE.md +891 -0
- data/docs/thinking/README_START_HERE.md +341 -0
- data/lib/inkpen/configuration.rb +175 -0
- data/lib/inkpen/editor.rb +204 -0
- data/lib/inkpen/engine.rb +32 -0
- data/lib/inkpen/extensions/base.rb +109 -0
- data/lib/inkpen/extensions/code_block_syntax.rb +177 -0
- data/lib/inkpen/extensions/document_section.rb +111 -0
- data/lib/inkpen/extensions/forced_document.rb +183 -0
- data/lib/inkpen/extensions/mention.rb +155 -0
- data/lib/inkpen/extensions/preformatted.rb +111 -0
- data/lib/inkpen/extensions/section.rb +139 -0
- data/lib/inkpen/extensions/slash_commands.rb +100 -0
- data/lib/inkpen/extensions/table.rb +182 -0
- data/lib/inkpen/extensions/task_list.rb +145 -0
- data/lib/inkpen/sticky_toolbar.rb +157 -0
- data/lib/inkpen/toolbar.rb +145 -0
- data/lib/inkpen/version.rb +5 -0
- data/lib/inkpen.rb +101 -0
- data/sig/inkpen.rbs +4 -0
- metadata +165 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { Node, mergeAttributes } from "@tiptap/core"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Toggle Block Extension for TipTap
|
|
5
|
+
*
|
|
6
|
+
* Collapsible/expandable block with a clickable header and nested content.
|
|
7
|
+
* Uses native HTML5 <details> and <summary> elements.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Click arrow or summary to expand/collapse
|
|
11
|
+
* - Editable summary text
|
|
12
|
+
* - Nested block content
|
|
13
|
+
* - Keyboard shortcuts for toggling
|
|
14
|
+
* - Smooth animations
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* editor.commands.insertToggle()
|
|
18
|
+
* editor.commands.toggleOpen()
|
|
19
|
+
*
|
|
20
|
+
* @since 0.3.3
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Toggle Summary - the clickable header
|
|
24
|
+
export const ToggleSummary = Node.create({
|
|
25
|
+
name: "toggleSummary",
|
|
26
|
+
|
|
27
|
+
content: "inline*",
|
|
28
|
+
defining: true,
|
|
29
|
+
selectable: false,
|
|
30
|
+
|
|
31
|
+
parseHTML() {
|
|
32
|
+
return [{ tag: "summary" }]
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
renderHTML({ HTMLAttributes }) {
|
|
36
|
+
return [
|
|
37
|
+
"summary",
|
|
38
|
+
mergeAttributes(HTMLAttributes, { class: "inkpen-toggle__summary" }),
|
|
39
|
+
0
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
addKeyboardShortcuts() {
|
|
44
|
+
return {
|
|
45
|
+
// Enter in summary creates content below, not new summary
|
|
46
|
+
Enter: ({ editor }) => {
|
|
47
|
+
const { state } = editor
|
|
48
|
+
const { $from } = state.selection
|
|
49
|
+
|
|
50
|
+
// Check if we're in a toggle summary
|
|
51
|
+
if ($from.parent.type.name === "toggleSummary") {
|
|
52
|
+
// Find the toggle block
|
|
53
|
+
const togglePos = $from.before($from.depth - 1)
|
|
54
|
+
const toggleNode = state.doc.nodeAt(togglePos)
|
|
55
|
+
|
|
56
|
+
if (toggleNode && toggleNode.type.name === "toggleBlock") {
|
|
57
|
+
// Insert paragraph after summary, inside toggle content
|
|
58
|
+
const summaryEnd = togglePos + 1 + $from.parent.nodeSize
|
|
59
|
+
return editor.chain()
|
|
60
|
+
.insertContentAt(summaryEnd, { type: "paragraph" })
|
|
61
|
+
.focus(summaryEnd + 1)
|
|
62
|
+
.run()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Backspace at start of empty summary deletes the toggle
|
|
69
|
+
Backspace: ({ editor }) => {
|
|
70
|
+
const { state } = editor
|
|
71
|
+
const { $from, empty } = state.selection
|
|
72
|
+
|
|
73
|
+
if (!empty) return false
|
|
74
|
+
|
|
75
|
+
// Check if at start of toggle summary
|
|
76
|
+
if ($from.parent.type.name === "toggleSummary" && $from.parentOffset === 0) {
|
|
77
|
+
// If summary is empty, delete the whole toggle block
|
|
78
|
+
if ($from.parent.textContent === "") {
|
|
79
|
+
const togglePos = $from.before($from.depth - 1)
|
|
80
|
+
const toggleNode = state.doc.nodeAt(togglePos)
|
|
81
|
+
|
|
82
|
+
if (toggleNode) {
|
|
83
|
+
return editor.chain()
|
|
84
|
+
.deleteRange({ from: togglePos, to: togglePos + toggleNode.nodeSize })
|
|
85
|
+
.run()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Toggle Block - the container with details/summary structure
|
|
96
|
+
export const ToggleBlock = Node.create({
|
|
97
|
+
name: "toggleBlock",
|
|
98
|
+
|
|
99
|
+
group: "block",
|
|
100
|
+
content: "toggleSummary block*",
|
|
101
|
+
defining: true,
|
|
102
|
+
|
|
103
|
+
addOptions() {
|
|
104
|
+
return {
|
|
105
|
+
defaultOpen: true,
|
|
106
|
+
HTMLAttributes: {
|
|
107
|
+
class: "inkpen-toggle"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
addAttributes() {
|
|
113
|
+
return {
|
|
114
|
+
open: {
|
|
115
|
+
default: this.options.defaultOpen,
|
|
116
|
+
parseHTML: element => element.hasAttribute("open"),
|
|
117
|
+
renderHTML: attributes => (attributes.open ? { open: "open" } : {})
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
parseHTML() {
|
|
123
|
+
return [
|
|
124
|
+
{ tag: "details.inkpen-toggle" },
|
|
125
|
+
{ tag: "details" }
|
|
126
|
+
]
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
renderHTML({ HTMLAttributes }) {
|
|
130
|
+
return [
|
|
131
|
+
"details",
|
|
132
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
133
|
+
0
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
addNodeView() {
|
|
138
|
+
return ({ node, getPos, editor }) => {
|
|
139
|
+
// Create details element
|
|
140
|
+
const details = document.createElement("details")
|
|
141
|
+
details.className = "inkpen-toggle"
|
|
142
|
+
|
|
143
|
+
if (node.attrs.open) {
|
|
144
|
+
details.setAttribute("open", "open")
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Toggle indicator (arrow)
|
|
148
|
+
const indicator = document.createElement("span")
|
|
149
|
+
indicator.className = "inkpen-toggle__indicator"
|
|
150
|
+
indicator.setAttribute("contenteditable", "false")
|
|
151
|
+
indicator.innerHTML = `<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
|
152
|
+
<path d="M4 2l4 4-4 4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
153
|
+
</svg>`
|
|
154
|
+
|
|
155
|
+
// Handle toggle via indicator click
|
|
156
|
+
indicator.addEventListener("click", (e) => {
|
|
157
|
+
e.preventDefault()
|
|
158
|
+
e.stopPropagation()
|
|
159
|
+
|
|
160
|
+
if (typeof getPos === "function") {
|
|
161
|
+
const pos = getPos()
|
|
162
|
+
if (pos !== undefined) {
|
|
163
|
+
editor.chain()
|
|
164
|
+
.focus()
|
|
165
|
+
.command(({ tr }) => {
|
|
166
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
167
|
+
...node.attrs,
|
|
168
|
+
open: !details.hasAttribute("open")
|
|
169
|
+
})
|
|
170
|
+
return true
|
|
171
|
+
})
|
|
172
|
+
.run()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// Content wrapper
|
|
178
|
+
const content = document.createElement("div")
|
|
179
|
+
content.className = "inkpen-toggle__content"
|
|
180
|
+
|
|
181
|
+
details.appendChild(indicator)
|
|
182
|
+
details.appendChild(content)
|
|
183
|
+
|
|
184
|
+
// Prevent native toggle behavior (we handle it ourselves)
|
|
185
|
+
details.addEventListener("toggle", (e) => {
|
|
186
|
+
// Sync the attribute with ProseMirror state
|
|
187
|
+
if (typeof getPos === "function") {
|
|
188
|
+
const pos = getPos()
|
|
189
|
+
if (pos !== undefined) {
|
|
190
|
+
const currentNode = editor.state.doc.nodeAt(pos)
|
|
191
|
+
if (currentNode && currentNode.attrs.open !== details.open) {
|
|
192
|
+
editor.chain()
|
|
193
|
+
.command(({ tr }) => {
|
|
194
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
195
|
+
...currentNode.attrs,
|
|
196
|
+
open: details.open
|
|
197
|
+
})
|
|
198
|
+
return true
|
|
199
|
+
})
|
|
200
|
+
.run()
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
dom: details,
|
|
208
|
+
contentDOM: content,
|
|
209
|
+
update: (updatedNode) => {
|
|
210
|
+
if (updatedNode.type.name !== "toggleBlock") return false
|
|
211
|
+
|
|
212
|
+
if (updatedNode.attrs.open) {
|
|
213
|
+
details.setAttribute("open", "open")
|
|
214
|
+
} else {
|
|
215
|
+
details.removeAttribute("open")
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return true
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
addCommands() {
|
|
225
|
+
return {
|
|
226
|
+
insertToggle: (attributes = {}) => ({ commands }) => {
|
|
227
|
+
return commands.insertContent({
|
|
228
|
+
type: this.name,
|
|
229
|
+
attrs: {
|
|
230
|
+
open: attributes.open !== undefined ? attributes.open : this.options.defaultOpen
|
|
231
|
+
},
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: "toggleSummary",
|
|
235
|
+
content: attributes.summary
|
|
236
|
+
? [{ type: "text", text: attributes.summary }]
|
|
237
|
+
: []
|
|
238
|
+
},
|
|
239
|
+
{ type: "paragraph" }
|
|
240
|
+
]
|
|
241
|
+
})
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
setToggle: () => ({ commands, state }) => {
|
|
245
|
+
const { $from } = state.selection
|
|
246
|
+
const text = $from.parent.textContent
|
|
247
|
+
|
|
248
|
+
return commands.insertContent({
|
|
249
|
+
type: this.name,
|
|
250
|
+
attrs: { open: true },
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: "toggleSummary",
|
|
254
|
+
content: text ? [{ type: "text", text }] : []
|
|
255
|
+
},
|
|
256
|
+
{ type: "paragraph" }
|
|
257
|
+
]
|
|
258
|
+
})
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
toggleOpen: () => ({ state, dispatch }) => {
|
|
262
|
+
const { $from } = state.selection
|
|
263
|
+
|
|
264
|
+
// Find the toggle block
|
|
265
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
266
|
+
const node = $from.node(d)
|
|
267
|
+
if (node.type.name === "toggleBlock") {
|
|
268
|
+
if (dispatch) {
|
|
269
|
+
const pos = $from.before(d)
|
|
270
|
+
const tr = state.tr.setNodeMarkup(pos, undefined, {
|
|
271
|
+
...node.attrs,
|
|
272
|
+
open: !node.attrs.open
|
|
273
|
+
})
|
|
274
|
+
dispatch(tr)
|
|
275
|
+
}
|
|
276
|
+
return true
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return false
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
expandToggle: () => ({ state, dispatch }) => {
|
|
283
|
+
const { $from } = state.selection
|
|
284
|
+
|
|
285
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
286
|
+
const node = $from.node(d)
|
|
287
|
+
if (node.type.name === "toggleBlock" && !node.attrs.open) {
|
|
288
|
+
if (dispatch) {
|
|
289
|
+
const pos = $from.before(d)
|
|
290
|
+
const tr = state.tr.setNodeMarkup(pos, undefined, {
|
|
291
|
+
...node.attrs,
|
|
292
|
+
open: true
|
|
293
|
+
})
|
|
294
|
+
dispatch(tr)
|
|
295
|
+
}
|
|
296
|
+
return true
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return false
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
collapseToggle: () => ({ state, dispatch }) => {
|
|
303
|
+
const { $from } = state.selection
|
|
304
|
+
|
|
305
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
306
|
+
const node = $from.node(d)
|
|
307
|
+
if (node.type.name === "toggleBlock" && node.attrs.open) {
|
|
308
|
+
if (dispatch) {
|
|
309
|
+
const pos = $from.before(d)
|
|
310
|
+
const tr = state.tr.setNodeMarkup(pos, undefined, {
|
|
311
|
+
...node.attrs,
|
|
312
|
+
open: false
|
|
313
|
+
})
|
|
314
|
+
dispatch(tr)
|
|
315
|
+
}
|
|
316
|
+
return true
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return false
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
addKeyboardShortcuts() {
|
|
325
|
+
return {
|
|
326
|
+
"Mod-Shift-t": () => this.editor.commands.insertToggle(),
|
|
327
|
+
"Mod-Enter": () => this.editor.commands.toggleOpen()
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
export default ToggleBlock
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Inkpen - TipTap-based rich text editor for Rails
|
|
2
|
+
// Entry point for importmap
|
|
3
|
+
|
|
4
|
+
import { Application } from "@hotwired/stimulus"
|
|
5
|
+
import EditorController from "inkpen/controllers/editor_controller"
|
|
6
|
+
import ToolbarController from "inkpen/controllers/toolbar_controller"
|
|
7
|
+
import StickyToolbarController from "inkpen/controllers/sticky_toolbar_controller"
|
|
8
|
+
|
|
9
|
+
// ============================================
|
|
10
|
+
// IMPORTANT: Register controllers IMMEDIATELY before any async code
|
|
11
|
+
// This ensures controllers are available when Stimulus scans the DOM
|
|
12
|
+
// ============================================
|
|
13
|
+
const application = window.Stimulus || Application.start()
|
|
14
|
+
|
|
15
|
+
application.register("inkpen--editor", EditorController)
|
|
16
|
+
application.register("inkpen--toolbar", ToolbarController)
|
|
17
|
+
application.register("inkpen--sticky-toolbar", StickyToolbarController)
|
|
18
|
+
|
|
19
|
+
// TipTap extensions (static imports)
|
|
20
|
+
import { Section } from "inkpen/extensions/section"
|
|
21
|
+
import { Preformatted } from "inkpen/extensions/preformatted"
|
|
22
|
+
import { SlashCommands } from "inkpen/extensions/slash_commands"
|
|
23
|
+
import { BlockGutter } from "inkpen/extensions/block_gutter"
|
|
24
|
+
import { DragHandle } from "inkpen/extensions/drag_handle"
|
|
25
|
+
import { ToggleBlock, ToggleSummary } from "inkpen/extensions/toggle_block"
|
|
26
|
+
import { Columns, Column } from "inkpen/extensions/columns"
|
|
27
|
+
import { Callout } from "inkpen/extensions/callout"
|
|
28
|
+
import { BlockCommands } from "inkpen/extensions/block_commands"
|
|
29
|
+
import { EnhancedImage } from "inkpen/extensions/enhanced_image"
|
|
30
|
+
import { FileAttachment } from "inkpen/extensions/file_attachment"
|
|
31
|
+
import { Embed } from "inkpen/extensions/embed"
|
|
32
|
+
import { AdvancedTable, AdvancedTableRow, AdvancedTableCell, AdvancedTableHeader } from "inkpen/extensions/advanced_table"
|
|
33
|
+
import { TableOfContents } from "inkpen/extensions/table_of_contents"
|
|
34
|
+
import { Database } from "inkpen/extensions/database"
|
|
35
|
+
import { DocumentSection } from "inkpen/extensions/document_section"
|
|
36
|
+
import { SectionTitle } from "inkpen/extensions/section_title"
|
|
37
|
+
|
|
38
|
+
// InkpenTable is loaded lazily to prevent import failures from breaking the library
|
|
39
|
+
let InkpenTable, InkpenTableRow, InkpenTableCell, InkpenTableHeader
|
|
40
|
+
try {
|
|
41
|
+
const mod = await import("inkpen/extensions/inkpen_table")
|
|
42
|
+
InkpenTable = mod.InkpenTable
|
|
43
|
+
InkpenTableRow = mod.InkpenTableRow
|
|
44
|
+
InkpenTableCell = mod.InkpenTableCell
|
|
45
|
+
InkpenTableHeader = mod.InkpenTableHeader
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.warn("Inkpen: InkpenTable extension not available:", e.message)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Export controllers
|
|
51
|
+
export { EditorController, ToolbarController, StickyToolbarController }
|
|
52
|
+
|
|
53
|
+
// Export extensions for custom use
|
|
54
|
+
export {
|
|
55
|
+
Section,
|
|
56
|
+
DocumentSection,
|
|
57
|
+
SectionTitle,
|
|
58
|
+
Preformatted,
|
|
59
|
+
SlashCommands,
|
|
60
|
+
BlockGutter,
|
|
61
|
+
DragHandle,
|
|
62
|
+
ToggleBlock,
|
|
63
|
+
ToggleSummary,
|
|
64
|
+
Columns,
|
|
65
|
+
Column,
|
|
66
|
+
Callout,
|
|
67
|
+
BlockCommands,
|
|
68
|
+
EnhancedImage,
|
|
69
|
+
FileAttachment,
|
|
70
|
+
Embed,
|
|
71
|
+
// InkpenTable - Notion-style enhanced tables (recommended)
|
|
72
|
+
InkpenTable,
|
|
73
|
+
InkpenTableRow,
|
|
74
|
+
InkpenTableCell,
|
|
75
|
+
InkpenTableHeader,
|
|
76
|
+
// AdvancedTable - Legacy (use InkpenTable instead)
|
|
77
|
+
AdvancedTable,
|
|
78
|
+
AdvancedTableRow,
|
|
79
|
+
AdvancedTableCell,
|
|
80
|
+
AdvancedTableHeader,
|
|
81
|
+
TableOfContents,
|
|
82
|
+
Database
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Export functionality is available separately:
|
|
86
|
+
// import { ExportCommands } from "inkpen/extensions/export_commands"
|
|
87
|
+
// import { exportToMarkdown, ... } from "inkpen/export"
|