@sethumadhavan004/ink-editor 0.0.2 → 0.0.4
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/index.css +6 -2
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.js +155 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2224,6 +2224,103 @@ var TabIndent = Extension.create({
|
|
|
2224
2224
|
}
|
|
2225
2225
|
});
|
|
2226
2226
|
|
|
2227
|
+
// src/extensions/SinglePageOverflow.ts
|
|
2228
|
+
import { Plugin as Plugin3, PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
2229
|
+
var pluginKey2 = new PluginKey3("singlePageOverflow");
|
|
2230
|
+
function getBodyHeightPx2(view, pageSize) {
|
|
2231
|
+
const card = view.dom.closest(".ink-page-card");
|
|
2232
|
+
if (card) {
|
|
2233
|
+
const style = window.getComputedStyle(card);
|
|
2234
|
+
const paddingTop = parseFloat(style.paddingTop);
|
|
2235
|
+
const paddingBottom = parseFloat(style.paddingBottom);
|
|
2236
|
+
const totalHeight = card.offsetHeight || 0;
|
|
2237
|
+
const bodyPx = totalHeight - paddingTop - paddingBottom;
|
|
2238
|
+
if (bodyPx > 0) return Math.floor(bodyPx / 28) * 28;
|
|
2239
|
+
}
|
|
2240
|
+
const d = PAGE_DIMENSIONS[pageSize];
|
|
2241
|
+
const PX_PER_MM2 = 3.7795;
|
|
2242
|
+
return Math.floor((d.heightMm - d.paddingTopMm - d.paddingBottomMm) * PX_PER_MM2 / 28) * 28;
|
|
2243
|
+
}
|
|
2244
|
+
function splitAtOverflow(doc, view, bodyHeightPx) {
|
|
2245
|
+
let baseY = null;
|
|
2246
|
+
let splitPos = null;
|
|
2247
|
+
doc.forEach((node, offset) => {
|
|
2248
|
+
if (splitPos !== null) return;
|
|
2249
|
+
const pos = offset + 1;
|
|
2250
|
+
if (pos >= doc.content.size) return;
|
|
2251
|
+
let bottom;
|
|
2252
|
+
try {
|
|
2253
|
+
const coords = view.coordsAtPos(pos);
|
|
2254
|
+
if (baseY === null) baseY = coords.top;
|
|
2255
|
+
const endPos = offset + node.nodeSize - 1;
|
|
2256
|
+
bottom = endPos > pos ? view.coordsAtPos(endPos).bottom : coords.bottom;
|
|
2257
|
+
} catch {
|
|
2258
|
+
return;
|
|
2259
|
+
}
|
|
2260
|
+
const relBottom = bottom - (baseY ?? bottom);
|
|
2261
|
+
if (relBottom > bodyHeightPx) {
|
|
2262
|
+
splitPos = offset;
|
|
2263
|
+
}
|
|
2264
|
+
});
|
|
2265
|
+
if (splitPos === null) return null;
|
|
2266
|
+
const schema = doc.type.schema;
|
|
2267
|
+
const fitsContent = doc.slice(0, splitPos).content;
|
|
2268
|
+
const overflowContent = doc.slice(splitPos).content;
|
|
2269
|
+
const fitsJson = schema.nodeFromJSON({ type: "doc", content: fitsContent.toJSON() ?? [] }).toJSON();
|
|
2270
|
+
const overflowJson = schema.nodeFromJSON({ type: "doc", content: overflowContent.toJSON() ?? [] }).toJSON();
|
|
2271
|
+
return { fitsJson, overflowJson };
|
|
2272
|
+
}
|
|
2273
|
+
var SinglePageOverflow = Extension.create({
|
|
2274
|
+
name: "singlePageOverflow",
|
|
2275
|
+
addOptions() {
|
|
2276
|
+
return {
|
|
2277
|
+
pageSize: "A4",
|
|
2278
|
+
onOverflow: () => {
|
|
2279
|
+
}
|
|
2280
|
+
};
|
|
2281
|
+
},
|
|
2282
|
+
addProseMirrorPlugins() {
|
|
2283
|
+
const { pageSize, onOverflow } = this.options;
|
|
2284
|
+
let rafId = null;
|
|
2285
|
+
function scheduleCheck(view) {
|
|
2286
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
2287
|
+
rafId = requestAnimationFrame(() => {
|
|
2288
|
+
rafId = null;
|
|
2289
|
+
if (view.isDestroyed) return;
|
|
2290
|
+
const bodyHeightPx = getBodyHeightPx2(view, pageSize);
|
|
2291
|
+
const result = splitAtOverflow(view.state.doc, view, bodyHeightPx);
|
|
2292
|
+
if (!result) return;
|
|
2293
|
+
const { fitsJson, overflowJson } = result;
|
|
2294
|
+
const schema = view.state.schema;
|
|
2295
|
+
const fitsDoc = schema.nodeFromJSON(fitsJson);
|
|
2296
|
+
const tr = view.state.tr.replaceWith(0, view.state.doc.content.size, fitsDoc.content);
|
|
2297
|
+
tr.setMeta("addToHistory", false);
|
|
2298
|
+
tr.setMeta("singlePageTrim", true);
|
|
2299
|
+
view.dispatch(tr);
|
|
2300
|
+
onOverflow(fitsJson, overflowJson);
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
return [
|
|
2304
|
+
new Plugin3({
|
|
2305
|
+
key: pluginKey2,
|
|
2306
|
+
view(editorView) {
|
|
2307
|
+
return {
|
|
2308
|
+
update(view, prevState) {
|
|
2309
|
+
if (view.state.doc.eq(prevState.doc) || view.state.tr?.getMeta?.("singlePageTrim")) return;
|
|
2310
|
+
if (view.state.doc.content.size !== prevState.doc.content.size || !view.state.doc.eq(prevState.doc)) {
|
|
2311
|
+
scheduleCheck(view);
|
|
2312
|
+
}
|
|
2313
|
+
},
|
|
2314
|
+
destroy() {
|
|
2315
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
2316
|
+
}
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
})
|
|
2320
|
+
];
|
|
2321
|
+
}
|
|
2322
|
+
});
|
|
2323
|
+
|
|
2227
2324
|
// src/components/PagedEditorContent.tsx
|
|
2228
2325
|
import { EditorContent } from "@tiptap/react";
|
|
2229
2326
|
|
|
@@ -2243,7 +2340,8 @@ import {
|
|
|
2243
2340
|
ListOrdered,
|
|
2244
2341
|
Indent,
|
|
2245
2342
|
Outdent,
|
|
2246
|
-
Rows
|
|
2343
|
+
Rows,
|
|
2344
|
+
FilePlus
|
|
2247
2345
|
} from "lucide-react";
|
|
2248
2346
|
|
|
2249
2347
|
// src/components/FontPicker.tsx
|
|
@@ -2376,7 +2474,7 @@ function ColorPanel({ colors, onChange, open, onToggle, onClose }) {
|
|
|
2376
2474
|
}
|
|
2377
2475
|
|
|
2378
2476
|
// src/components/FloatingToolbar.tsx
|
|
2379
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2477
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2380
2478
|
function Sep() {
|
|
2381
2479
|
return /* @__PURE__ */ jsx3("span", { className: "ink-toolbar-sep", "aria-hidden": "true" });
|
|
2382
2480
|
}
|
|
@@ -2388,7 +2486,9 @@ function FloatingToolbar({
|
|
|
2388
2486
|
font,
|
|
2389
2487
|
onFontChange,
|
|
2390
2488
|
colors,
|
|
2391
|
-
onColorsChange
|
|
2489
|
+
onColorsChange,
|
|
2490
|
+
toolbarStart,
|
|
2491
|
+
toolbarEnd
|
|
2392
2492
|
}) {
|
|
2393
2493
|
const [openPanel, setOpenPanel] = useState(null);
|
|
2394
2494
|
useEffect3(() => {
|
|
@@ -2479,10 +2579,26 @@ function FloatingToolbar({
|
|
|
2479
2579
|
isActive: () => ruled,
|
|
2480
2580
|
action: onToggleRuled
|
|
2481
2581
|
}]
|
|
2582
|
+
},
|
|
2583
|
+
{
|
|
2584
|
+
key: "addpage",
|
|
2585
|
+
configs: [{
|
|
2586
|
+
label: "Add page",
|
|
2587
|
+
icon: /* @__PURE__ */ jsx3(FilePlus, { size: iconSize }),
|
|
2588
|
+
isActive: () => false,
|
|
2589
|
+
action: () => {
|
|
2590
|
+
const end = editor.state.doc.content.size - 1;
|
|
2591
|
+
editor.chain().focus().insertContentAt(end, [{ type: "paragraph" }, { type: "paragraph" }]).run();
|
|
2592
|
+
}
|
|
2593
|
+
}]
|
|
2482
2594
|
}
|
|
2483
2595
|
];
|
|
2484
2596
|
const activeGroups = allGroups.filter((g) => buttons.includes(g.key));
|
|
2485
2597
|
return /* @__PURE__ */ jsx3("div", { className: "ink-floating-toolbar-wrap", children: /* @__PURE__ */ jsxs3("div", { className: "ink-floating-toolbar", role: "toolbar", "aria-label": "Text formatting", children: [
|
|
2598
|
+
toolbarStart && toolbarStart.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2599
|
+
toolbarStart.map((node, i) => /* @__PURE__ */ jsx3("span", { style: { display: "contents" }, children: node }, i)),
|
|
2600
|
+
/* @__PURE__ */ jsx3(Sep, {})
|
|
2601
|
+
] }),
|
|
2486
2602
|
activeGroups.map((group, gi) => /* @__PURE__ */ jsxs3("span", { className: "ink-toolbar-group", style: { display: "contents" }, children: [
|
|
2487
2603
|
group.configs.map((cfg) => /* @__PURE__ */ jsx3(
|
|
2488
2604
|
"button",
|
|
@@ -2518,7 +2634,11 @@ function FloatingToolbar({
|
|
|
2518
2634
|
onToggle: () => togglePanel("color"),
|
|
2519
2635
|
onClose: () => setOpenPanel(null)
|
|
2520
2636
|
}
|
|
2521
|
-
)
|
|
2637
|
+
),
|
|
2638
|
+
toolbarEnd && toolbarEnd.length > 0 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2639
|
+
/* @__PURE__ */ jsx3(Sep, {}),
|
|
2640
|
+
toolbarEnd.map((node, i) => /* @__PURE__ */ jsx3("span", { style: { display: "contents" }, children: node }, i))
|
|
2641
|
+
] })
|
|
2522
2642
|
] }) });
|
|
2523
2643
|
}
|
|
2524
2644
|
|
|
@@ -2534,7 +2654,10 @@ function PagedEditorContent({
|
|
|
2534
2654
|
font,
|
|
2535
2655
|
onFontChange,
|
|
2536
2656
|
colors,
|
|
2537
|
-
onColorsChange
|
|
2657
|
+
onColorsChange,
|
|
2658
|
+
toolbarStart,
|
|
2659
|
+
toolbarEnd,
|
|
2660
|
+
singlePage = false
|
|
2538
2661
|
}) {
|
|
2539
2662
|
const widthPx = getPageWidthPx(pageSize);
|
|
2540
2663
|
const bodyWidthPx = getBodyWidthPx(pageSize);
|
|
@@ -2545,7 +2668,7 @@ function PagedEditorContent({
|
|
|
2545
2668
|
return /* @__PURE__ */ jsxs4(
|
|
2546
2669
|
"div",
|
|
2547
2670
|
{
|
|
2548
|
-
className: "ink-page-wrap"
|
|
2671
|
+
className: `ink-page-wrap${singlePage ? " ink-page-wrap--single" : ""}`,
|
|
2549
2672
|
"data-theme": theme,
|
|
2550
2673
|
style: {
|
|
2551
2674
|
"--ink-bg": colors.canvasBg,
|
|
@@ -2566,7 +2689,9 @@ function PagedEditorContent({
|
|
|
2566
2689
|
font,
|
|
2567
2690
|
onFontChange,
|
|
2568
2691
|
colors,
|
|
2569
|
-
onColorsChange
|
|
2692
|
+
onColorsChange,
|
|
2693
|
+
toolbarStart,
|
|
2694
|
+
toolbarEnd
|
|
2570
2695
|
}
|
|
2571
2696
|
),
|
|
2572
2697
|
/* @__PURE__ */ jsx4(
|
|
@@ -2575,7 +2700,8 @@ function PagedEditorContent({
|
|
|
2575
2700
|
className: `ink-page-card${ruled ? " ink-ruled" : ""}`,
|
|
2576
2701
|
style: {
|
|
2577
2702
|
width: widthPx,
|
|
2578
|
-
|
|
2703
|
+
// In singlePage mode: fixed height + overflow hidden so content never visually spills
|
|
2704
|
+
...singlePage ? { height: pageHeightPx, overflow: "hidden" } : { minHeight: pageHeightPx },
|
|
2579
2705
|
padding: `${dims.paddingTopMm}mm ${dims.paddingRightMm}mm ${dims.paddingBottomMm}mm ${dims.paddingLeftMm}mm`,
|
|
2580
2706
|
["--ink-padding-top"]: `${dims.paddingTopMm}mm`,
|
|
2581
2707
|
["--ink-padding-right"]: `${dims.paddingRightMm}mm`,
|
|
@@ -2600,7 +2726,12 @@ function InkEditor({
|
|
|
2600
2726
|
theme = "parchment",
|
|
2601
2727
|
toolbar = DEFAULT_TOOLBAR,
|
|
2602
2728
|
initialFont = "cursive",
|
|
2603
|
-
initialColors
|
|
2729
|
+
initialColors,
|
|
2730
|
+
toolbarStart,
|
|
2731
|
+
toolbarEnd,
|
|
2732
|
+
singlePage = false,
|
|
2733
|
+
onOverflow,
|
|
2734
|
+
initialContent
|
|
2604
2735
|
}) {
|
|
2605
2736
|
const [ruled, setRuled] = useState2(false);
|
|
2606
2737
|
const [font, setFont] = useState2(initialFont);
|
|
@@ -2608,14 +2739,17 @@ function InkEditor({
|
|
|
2608
2739
|
...theme === "minimal" ? MINIMAL_DEFAULTS : PARCHMENT_DEFAULTS,
|
|
2609
2740
|
...initialColors
|
|
2610
2741
|
});
|
|
2742
|
+
const extensions = [
|
|
2743
|
+
StarterKit,
|
|
2744
|
+
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
|
2745
|
+
Underline2,
|
|
2746
|
+
TabIndent,
|
|
2747
|
+
...singlePage ? [SinglePageOverflow.configure({ pageSize, onOverflow: onOverflow ?? (() => {
|
|
2748
|
+
}) })] : [PageLayout.configure({ pageSize })]
|
|
2749
|
+
];
|
|
2611
2750
|
const editor = useEditor({
|
|
2612
|
-
extensions
|
|
2613
|
-
|
|
2614
|
-
PageLayout.configure({ pageSize }),
|
|
2615
|
-
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
|
2616
|
-
Underline2,
|
|
2617
|
-
TabIndent
|
|
2618
|
-
],
|
|
2751
|
+
extensions,
|
|
2752
|
+
content: initialContent ?? void 0,
|
|
2619
2753
|
onUpdate({ editor: editor2 }) {
|
|
2620
2754
|
onChange?.(editor2.getJSON());
|
|
2621
2755
|
}
|
|
@@ -2637,13 +2771,17 @@ function InkEditor({
|
|
|
2637
2771
|
font,
|
|
2638
2772
|
onFontChange: setFont,
|
|
2639
2773
|
colors,
|
|
2640
|
-
onColorsChange: setColors
|
|
2774
|
+
onColorsChange: setColors,
|
|
2775
|
+
toolbarStart,
|
|
2776
|
+
toolbarEnd,
|
|
2777
|
+
singlePage
|
|
2641
2778
|
}
|
|
2642
2779
|
);
|
|
2643
2780
|
}
|
|
2644
2781
|
export {
|
|
2645
2782
|
InkEditor,
|
|
2646
2783
|
MINIMAL_DEFAULTS,
|
|
2647
|
-
PARCHMENT_DEFAULTS
|
|
2784
|
+
PARCHMENT_DEFAULTS,
|
|
2785
|
+
SinglePageOverflow
|
|
2648
2786
|
};
|
|
2649
2787
|
//# sourceMappingURL=index.mjs.map
|