@editneo/react 0.1.1 → 0.1.2
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/README.md +81 -40
- package/dist/EditableBlock.d.ts.map +1 -1
- package/dist/EditableBlock.js +123 -15
- package/dist/EditableBlock.js.map +1 -1
- package/dist/NeoCanvas.d.ts.map +1 -1
- package/dist/NeoCanvas.js +33 -8
- package/dist/NeoCanvas.js.map +1 -1
- package/dist/NeoEditor.d.ts +12 -4
- package/dist/NeoEditor.d.ts.map +1 -1
- package/dist/NeoEditor.js +51 -15
- package/dist/NeoEditor.js.map +1 -1
- package/dist/blocks/ListBlock.d.ts.map +1 -1
- package/dist/blocks/ListBlock.js +17 -1
- package/dist/blocks/ListBlock.js.map +1 -1
- package/dist/components/Aeropeak.d.ts +3 -1
- package/dist/components/Aeropeak.d.ts.map +1 -1
- package/dist/components/Aeropeak.js +46 -24
- package/dist/components/Aeropeak.js.map +1 -1
- package/dist/components/CursorOverlay.d.ts +4 -1
- package/dist/components/CursorOverlay.d.ts.map +1 -1
- package/dist/components/CursorOverlay.js +113 -10
- package/dist/components/CursorOverlay.js.map +1 -1
- package/dist/components/PDFDropZone.d.ts.map +1 -1
- package/dist/components/PDFDropZone.js +23 -33
- package/dist/components/PDFDropZone.js.map +1 -1
- package/dist/components/SlashMenu.d.ts.map +1 -1
- package/dist/components/SlashMenu.js +50 -46
- package/dist/components/SlashMenu.js.map +1 -1
- package/dist/hooks.d.ts +25 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +19 -6
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/package.json +23 -5
|
@@ -1,42 +1,41 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import { useState, useEffect, useContext } from 'react';
|
|
3
|
+
import { useStore } from 'zustand';
|
|
4
|
+
import { EditorContext } from '../NeoEditor';
|
|
4
5
|
export const SlashMenu = ({ customCommands = [], filter, menuComponent: MenuComponent }) => {
|
|
5
|
-
const
|
|
6
|
+
const context = useContext(EditorContext);
|
|
7
|
+
if (!context)
|
|
8
|
+
return null;
|
|
9
|
+
const addBlock = useStore(context.store, (s) => s.addBlock);
|
|
10
|
+
const selection = useStore(context.store, (s) => s.selection);
|
|
6
11
|
const [isOpen, setIsOpen] = useState(false);
|
|
7
12
|
const [query, setQuery] = useState('');
|
|
8
13
|
const [position, setPosition] = useState(null);
|
|
9
14
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
10
|
-
// Default Commands
|
|
15
|
+
// Default Commands — (#18) pass selection.blockId as afterId
|
|
11
16
|
const defaultCommands = [
|
|
12
|
-
{ key: 'paragraph', label: 'Paragraph', execute: (
|
|
13
|
-
{ key: 'heading-1', label: 'Heading 1', execute: (
|
|
14
|
-
{ key: 'heading-2', label: 'Heading 2', execute: (
|
|
15
|
-
{ key: 'heading-3', label: 'Heading 3', execute: (
|
|
16
|
-
{ key: 'bullet-list', label: 'Bulleted List', execute: (
|
|
17
|
-
{ key: 'ordered-list', label: 'Ordered List', execute: (
|
|
18
|
-
{ key: 'todo-list', label: 'To-do List', execute: (
|
|
19
|
-
{ key: 'quote', label: 'Quote', execute: (
|
|
20
|
-
{ key: 'code-block', label: 'Code Block', execute: (
|
|
21
|
-
{ key: 'divider', label: 'Divider', execute: (
|
|
22
|
-
{ key: 'callout', label: 'Callout', execute: (
|
|
23
|
-
{ key: 'image', label: 'Image', execute: (
|
|
17
|
+
{ key: 'paragraph', label: 'Paragraph', execute: () => addBlock('paragraph', selection.blockId) },
|
|
18
|
+
{ key: 'heading-1', label: 'Heading 1', execute: () => addBlock('heading-1', selection.blockId) },
|
|
19
|
+
{ key: 'heading-2', label: 'Heading 2', execute: () => addBlock('heading-2', selection.blockId) },
|
|
20
|
+
{ key: 'heading-3', label: 'Heading 3', execute: () => addBlock('heading-3', selection.blockId) },
|
|
21
|
+
{ key: 'bullet-list', label: 'Bulleted List', execute: () => addBlock('bullet-list', selection.blockId) },
|
|
22
|
+
{ key: 'ordered-list', label: 'Ordered List', execute: () => addBlock('ordered-list', selection.blockId) },
|
|
23
|
+
{ key: 'todo-list', label: 'To-do List', execute: () => addBlock('todo-list', selection.blockId) },
|
|
24
|
+
{ key: 'quote', label: 'Quote', execute: () => addBlock('quote', selection.blockId) },
|
|
25
|
+
{ key: 'code-block', label: 'Code Block', execute: () => addBlock('code-block', selection.blockId) },
|
|
26
|
+
{ key: 'divider', label: 'Divider', execute: () => addBlock('divider', selection.blockId) },
|
|
27
|
+
{ key: 'callout', label: 'Callout', execute: () => addBlock('callout', selection.blockId) },
|
|
28
|
+
{ key: 'image', label: 'Image', execute: () => addBlock('image', selection.blockId) },
|
|
24
29
|
];
|
|
25
30
|
const allCommands = [...defaultCommands, ...customCommands].filter(cmd => filter ? filter(cmd) : true);
|
|
26
31
|
const filteredCommands = allCommands.filter(cmd => cmd.label.toLowerCase().includes(query.toLowerCase()));
|
|
27
|
-
// Detect '/' key
|
|
28
32
|
useEffect(() => {
|
|
29
33
|
const handleKeyDown = (e) => {
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
// This logic is flawed for a real rich text editor without proper input interception
|
|
33
|
-
// Typically the `EditableBlock` handles triggering `onSlash` callback.
|
|
34
|
-
// For this implementation, we will rely on a custom event dispatch or simple global listener
|
|
35
|
-
// if `useEditor` allowed subscribing to slash events.
|
|
36
|
-
// Let's implement a simple listener on the document that checks if active element is our editor
|
|
37
|
-
// This is "good enough" for the demo level.
|
|
34
|
+
var _a;
|
|
35
|
+
// (#17) Detect '/' and preventDefault so it doesn't appear in the block
|
|
38
36
|
if (e.key === '/' && !isOpen) {
|
|
39
|
-
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
const sel = (_a = window.getSelection) === null || _a === void 0 ? void 0 : _a.call(window);
|
|
40
39
|
if (sel && sel.rangeCount > 0) {
|
|
41
40
|
const range = sel.getRangeAt(0);
|
|
42
41
|
const rect = range.getBoundingClientRect();
|
|
@@ -44,8 +43,6 @@ export const SlashMenu = ({ customCommands = [], filter, menuComponent: MenuComp
|
|
|
44
43
|
setIsOpen(true);
|
|
45
44
|
setQuery('');
|
|
46
45
|
setSelectedIndex(0);
|
|
47
|
-
// We don't preventDefault so the '/' is typed,
|
|
48
|
-
// usually we want to capture it.
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
else if (isOpen) {
|
|
@@ -54,53 +51,60 @@ export const SlashMenu = ({ customCommands = [], filter, menuComponent: MenuComp
|
|
|
54
51
|
}
|
|
55
52
|
else if (e.key === 'ArrowDown') {
|
|
56
53
|
e.preventDefault();
|
|
57
|
-
setSelectedIndex(i => (i + 1) % filteredCommands.length);
|
|
54
|
+
setSelectedIndex(i => (i + 1) % Math.max(filteredCommands.length, 1));
|
|
58
55
|
}
|
|
59
56
|
else if (e.key === 'ArrowUp') {
|
|
60
57
|
e.preventDefault();
|
|
61
|
-
setSelectedIndex(i => (i - 1 + filteredCommands.length) % filteredCommands.length);
|
|
58
|
+
setSelectedIndex(i => (i - 1 + filteredCommands.length) % Math.max(filteredCommands.length, 1));
|
|
62
59
|
}
|
|
63
60
|
else if (e.key === 'Enter') {
|
|
64
61
|
e.preventDefault();
|
|
65
62
|
if (filteredCommands[selectedIndex]) {
|
|
66
|
-
filteredCommands[selectedIndex].execute(
|
|
63
|
+
filteredCommands[selectedIndex].execute(null);
|
|
67
64
|
setIsOpen(false);
|
|
68
65
|
}
|
|
69
66
|
}
|
|
70
67
|
else if (e.key === 'Backspace') {
|
|
71
|
-
//
|
|
68
|
+
// (#16) Update query on backspace
|
|
69
|
+
if (query.length > 0) {
|
|
70
|
+
setQuery(q => q.slice(0, -1));
|
|
71
|
+
setSelectedIndex(0);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
setIsOpen(false);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
|
|
78
|
+
// (#16) Capture typed characters into query for filtering
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
setQuery(q => q + e.key);
|
|
81
|
+
setSelectedIndex(0);
|
|
72
82
|
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
const handleInput = (e) => {
|
|
76
|
-
if (isOpen) {
|
|
77
|
-
// Update query based on text after slash?
|
|
78
|
-
// Complex to do globally.
|
|
79
|
-
// Ideally `EditableBlock` passes the query.
|
|
80
83
|
}
|
|
81
84
|
};
|
|
82
85
|
document.addEventListener('keydown', handleKeyDown);
|
|
83
86
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
84
|
-
}, [isOpen, filteredCommands, selectedIndex,
|
|
87
|
+
}, [isOpen, filteredCommands, selectedIndex, query, addBlock, selection.blockId]);
|
|
85
88
|
if (!isOpen || !position)
|
|
86
89
|
return null;
|
|
87
90
|
if (MenuComponent) {
|
|
88
|
-
return _jsx(MenuComponent, { commands: filteredCommands, position: position, onSelect: (cmd) => cmd.execute(
|
|
91
|
+
return _jsx(MenuComponent, { commands: filteredCommands, position: position, onSelect: (cmd) => { cmd.execute(null); setIsOpen(false); } });
|
|
89
92
|
}
|
|
90
93
|
return (_jsxs("div", { className: "neo-slash-menu", style: {
|
|
91
94
|
position: 'fixed',
|
|
92
95
|
top: position.y,
|
|
93
96
|
left: position.x,
|
|
94
97
|
zIndex: 1000,
|
|
95
|
-
backgroundColor: '
|
|
96
|
-
|
|
98
|
+
backgroundColor: '#ffffff',
|
|
99
|
+
color: '#1f2937',
|
|
100
|
+
border: '1px solid #e5e7eb',
|
|
97
101
|
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
|
98
102
|
borderRadius: '6px',
|
|
99
103
|
width: '240px',
|
|
100
104
|
maxHeight: '300px',
|
|
101
105
|
overflowY: 'auto'
|
|
102
|
-
}, children: [filteredCommands.map((cmd, index) => (_jsxs("div", { onClick: () => {
|
|
103
|
-
cmd.execute(
|
|
106
|
+
}, children: [query && (_jsxs("div", { style: { padding: '4px 12px', fontSize: '0.8em', color: '#9ca3af', borderBottom: '1px solid #f3f4f6' }, children: ["Filtering: ", query] })), filteredCommands.map((cmd, index) => (_jsxs("div", { onClick: () => {
|
|
107
|
+
cmd.execute(null);
|
|
104
108
|
setIsOpen(false);
|
|
105
109
|
}, style: {
|
|
106
110
|
padding: '8px 12px',
|
|
@@ -110,6 +114,6 @@ export const SlashMenu = ({ customCommands = [], filter, menuComponent: MenuComp
|
|
|
110
114
|
alignItems: 'center',
|
|
111
115
|
gap: '8px',
|
|
112
116
|
fontSize: '0.9em'
|
|
113
|
-
}, onMouseEnter: () => setSelectedIndex(index), children: [cmd.icon && _jsx("span", { className: "neo-cmd-icon", children: cmd.icon }), _jsx("span", { children: cmd.label })] }, cmd.key))), filteredCommands.length === 0 && (_jsx("div", { style: { padding: '8px 12px', color: '#
|
|
117
|
+
}, onMouseEnter: () => setSelectedIndex(index), children: [cmd.icon && _jsx("span", { className: "neo-cmd-icon", children: cmd.icon }), _jsx("span", { children: cmd.label })] }, cmd.key))), filteredCommands.length === 0 && (_jsx("div", { style: { padding: '8px 12px', color: '#9ca3af', fontSize: '0.9em' }, children: "No results" }))] }));
|
|
114
118
|
};
|
|
115
119
|
//# sourceMappingURL=SlashMenu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlashMenu.js","sourceRoot":"","sources":["../../src/components/SlashMenu.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"SlashMenu.js","sourceRoot":"","sources":["../../src/components/SlashMenu.tsx"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Primary hook for interacting with the current editor instance.
|
|
3
|
+
* Must be called inside a <NeoEditor />.
|
|
4
|
+
* Returns all store state and actions for the enclosing editor only.
|
|
5
|
+
*/
|
|
1
6
|
export declare const useEditor: () => {
|
|
2
7
|
insertBlock: (type: import("@editneo/core").BlockType, afterId?: string | null) => void;
|
|
3
8
|
blocks: Record<string, import("@editneo/core").NeoBlock>;
|
|
@@ -10,16 +15,36 @@ export declare const useEditor: () => {
|
|
|
10
15
|
endOffset: number;
|
|
11
16
|
};
|
|
12
17
|
addBlock: (type: import("@editneo/core").BlockType, afterId?: string | null) => void;
|
|
18
|
+
insertFullBlock: (block: import("@editneo/core").NeoBlock, afterId?: string | null) => void;
|
|
19
|
+
insertFullBlocks: (blocks: import("@editneo/core").NeoBlock[], afterId?: string | null) => void;
|
|
13
20
|
updateBlock: (id: string, partial: Partial<import("@editneo/core").NeoBlock>) => void;
|
|
14
21
|
deleteBlock: (id: string) => void;
|
|
22
|
+
moveBlock: (id: string, afterId: string | null) => void;
|
|
23
|
+
setBlockType: (id: string, newType: import("@editneo/core").BlockType) => void;
|
|
15
24
|
toggleMark: (mark: keyof Pick<import("@editneo/core").Span, "bold" | "italic" | "underline" | "strike" | "code">) => void;
|
|
25
|
+
setLink: (url: string | null) => void;
|
|
16
26
|
undo: () => void;
|
|
17
27
|
redo: () => void;
|
|
28
|
+
exportJSON: () => {
|
|
29
|
+
blocks: Record<string, import("@editneo/core").NeoBlock>;
|
|
30
|
+
rootBlocks: string[];
|
|
31
|
+
};
|
|
32
|
+
importJSON: (data: {
|
|
33
|
+
blocks: Record<string, import("@editneo/core").NeoBlock>;
|
|
34
|
+
rootBlocks: string[];
|
|
35
|
+
}) => void;
|
|
18
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Focused hook that subscribes only to the selection state,
|
|
39
|
+
* minimizing re-renders in components that don't need the full document.
|
|
40
|
+
*/
|
|
19
41
|
export declare const useSelection: () => {
|
|
20
42
|
blockId: string | null;
|
|
21
43
|
startOffset: number;
|
|
22
44
|
endOffset: number;
|
|
23
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* Returns the current sync connection status.
|
|
48
|
+
*/
|
|
24
49
|
export declare const useSyncStatus: () => "connected" | "disconnected";
|
|
25
50
|
//# sourceMappingURL=hooks.d.ts.map
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;+DAPD,CAAC;sEAGsB,CAAC;0EAEhC,CAAC;;;;;;;;;;;;;;;;;CAeb,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;CAMxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,oCAGzB,CAAC"}
|
package/dist/hooks.js
CHANGED
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
import { useContext } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
3
|
import { EditorContext } from './NeoEditor';
|
|
4
|
+
/**
|
|
5
|
+
* Primary hook for interacting with the current editor instance.
|
|
6
|
+
* Must be called inside a <NeoEditor />.
|
|
7
|
+
* Returns all store state and actions for the enclosing editor only.
|
|
8
|
+
*/
|
|
4
9
|
export const useEditor = () => {
|
|
5
|
-
const store = useEditorStore();
|
|
6
10
|
const context = useContext(EditorContext);
|
|
7
11
|
if (!context) {
|
|
8
12
|
throw new Error('useEditor must be used within a NeoEditor');
|
|
9
13
|
}
|
|
14
|
+
const store = useStore(context.store);
|
|
10
15
|
return {
|
|
11
16
|
...store,
|
|
12
|
-
// Add specific editor methods here that might combine store + sync
|
|
13
17
|
insertBlock: store.addBlock, // Alias for DX
|
|
14
|
-
// exportJSON implementation would go here
|
|
15
18
|
};
|
|
16
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Focused hook that subscribes only to the selection state,
|
|
22
|
+
* minimizing re-renders in components that don't need the full document.
|
|
23
|
+
*/
|
|
17
24
|
export const useSelection = () => {
|
|
18
|
-
|
|
25
|
+
const context = useContext(EditorContext);
|
|
26
|
+
if (!context) {
|
|
27
|
+
throw new Error('useSelection must be used within a NeoEditor');
|
|
28
|
+
}
|
|
29
|
+
return useStore(context.store, (state) => state.selection);
|
|
19
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Returns the current sync connection status.
|
|
33
|
+
*/
|
|
20
34
|
export const useSyncStatus = () => {
|
|
21
35
|
const context = useContext(EditorContext);
|
|
22
|
-
// Placeholder - needs SyncManager to expose status observable
|
|
23
36
|
return (context === null || context === void 0 ? void 0 : context.syncManager) ? 'connected' : 'disconnected';
|
|
24
37
|
};
|
|
25
38
|
//# sourceMappingURL=hooks.js.map
|
package/dist/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAE1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEtC,OAAO;QACL,GAAG,KAAK;QACR,WAAW,EAAE,KAAK,CAAC,QAAQ,EAAE,eAAe;KAC7C,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAkB,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,WAAW,EAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC;AAC7D,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
export * from './NeoEditor';
|
|
2
2
|
export * from './NeoCanvas';
|
|
3
3
|
export * from './EditableBlock';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './BlockRenderer';
|
|
5
|
+
export * from './blocks/HeadingBlock';
|
|
6
|
+
export * from './blocks/ListBlock';
|
|
7
|
+
export * from './blocks/MediaBlock';
|
|
8
|
+
export * from './blocks/CodeBlock';
|
|
9
|
+
export * from './blocks/QuoteBlock';
|
|
10
|
+
export * from './blocks/CalloutBlock';
|
|
11
|
+
export * from './blocks/DividerBlock';
|
|
5
12
|
export * from './components';
|
|
13
|
+
export * from './hooks';
|
|
6
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,cAAc,CAAC;AAG7B,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
// Components
|
|
1
2
|
export * from './NeoEditor';
|
|
2
3
|
export * from './NeoCanvas';
|
|
3
4
|
export * from './EditableBlock';
|
|
4
|
-
export * from './
|
|
5
|
+
export * from './BlockRenderer';
|
|
6
|
+
// Block Components (#20)
|
|
7
|
+
export * from './blocks/HeadingBlock';
|
|
8
|
+
export * from './blocks/ListBlock';
|
|
9
|
+
export * from './blocks/MediaBlock';
|
|
10
|
+
export * from './blocks/CodeBlock';
|
|
11
|
+
export * from './blocks/QuoteBlock';
|
|
12
|
+
export * from './blocks/CalloutBlock';
|
|
13
|
+
export * from './blocks/DividerBlock';
|
|
14
|
+
// Interactive UI
|
|
5
15
|
export * from './components';
|
|
16
|
+
// Hooks
|
|
17
|
+
export * from './hooks';
|
|
6
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,yBAAyB;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AAEtC,iBAAiB;AACjB,cAAc,cAAc,CAAC;AAE7B,QAAQ;AACR,cAAc,SAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editneo/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React components for EditNeo — NeoEditor, Aeropeak, SlashMenu, and more",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"files": ["dist"],
|
|
8
16
|
"scripts": {
|
|
9
17
|
"build": "tsc",
|
|
@@ -14,19 +22,29 @@
|
|
|
14
22
|
},
|
|
15
23
|
"dependencies": {
|
|
16
24
|
"@editneo/core": "*",
|
|
17
|
-
"@editneo/pdf": "*",
|
|
18
|
-
"@editneo/sync": "*",
|
|
19
25
|
"@tanstack/react-virtual": "^3.0.0",
|
|
20
26
|
"zustand": "^4.5.1"
|
|
21
27
|
},
|
|
22
28
|
"peerDependencies": {
|
|
23
29
|
"react": "^18.0.0 || ^19.0.0",
|
|
24
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
30
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
31
|
+
"@editneo/sync": "^0.1.0",
|
|
32
|
+
"@editneo/pdf": "^0.1.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"@editneo/sync": {
|
|
36
|
+
"optional": true
|
|
37
|
+
},
|
|
38
|
+
"@editneo/pdf": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
25
41
|
},
|
|
26
42
|
"devDependencies": {
|
|
27
43
|
"typescript": "^5.3.3",
|
|
28
44
|
"@types/react": "^18.2.0",
|
|
29
|
-
"@types/react-dom": "^18.2.0"
|
|
45
|
+
"@types/react-dom": "^18.2.0",
|
|
46
|
+
"@editneo/sync": "*",
|
|
47
|
+
"@editneo/pdf": "*"
|
|
30
48
|
},
|
|
31
49
|
"license": "MIT"
|
|
32
50
|
}
|