Skip to content

Commit 0df8a70

Browse files
committed
Merge branch 'develop' of github.com:Harbour-Enterprises/SuperDoc into develop
2 parents c98f48b + 649663b commit 0df8a70

87 files changed

Lines changed: 3067 additions & 396 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Trigger Documentation Update
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
# Trigger when extensions change
9+
- 'packages/super-editor/src/extensions/**/*.js'
10+
# - 'packages/super-editor/src/core/**/*.js'
11+
# - 'packages/super-editor/src/components/**/*.js'
12+
workflow_dispatch: # Manual trigger
13+
14+
jobs:
15+
trigger-docs:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Trigger Documentation Repository Update
19+
run: |
20+
# Set the required variables
21+
repo_owner="Harbour-Enterprises"
22+
repo_name="SuperDoc-Docs"
23+
event_type="docs-update"
24+
25+
curl -L \
26+
-X POST \
27+
-H "Accept: application/vnd.github+json" \
28+
-H "Authorization: Bearer ${{ secrets.SUPERDOC_PAT }}" \
29+
-H "X-GitHub-Api-Version: 2022-11-28" \
30+
https://api.github.com/repos/$repo_owner/$repo_name/dispatches \
31+
-d "{\"event_type\": \"$event_type\"}"
32+
33+
- name: Notify Success
34+
if: success()
35+
run: echo "✅ Documentation update triggered successfully"

eslint.config.docs.mjs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import jsdoc from 'eslint-plugin-jsdoc';
2+
3+
export default [
4+
{
5+
files: ['packages/super-editor/src/extensions/**/*.js'],
6+
plugins: {
7+
jsdoc
8+
},
9+
rules: {
10+
// Require minimal JSDoc for extensions
11+
'jsdoc/require-jsdoc': ['warn', {
12+
publicOnly: true,
13+
require: {
14+
FunctionDeclaration: false,
15+
MethodDefinition: false,
16+
ClassDeclaration: false,
17+
ArrowFunctionExpression: false,
18+
FunctionExpression: false
19+
},
20+
contexts: [
21+
// Document the extension module
22+
'ExportNamedDeclaration > VariableDeclaration > VariableDeclarator > CallExpression[callee.property.name="create"]'
23+
24+
// Note: We document commands/helpers with @param/@returns
25+
// inside addCommands/addHelpers, not with require-jsdoc
26+
]
27+
}],
28+
29+
// When JSDoc exists, validate it's correct
30+
'jsdoc/require-param': 'error', // All params must be documented
31+
'jsdoc/require-param-type': 'error', // @param must have {Type}
32+
'jsdoc/check-param-names': 'error', // @param names must match
33+
'jsdoc/check-types': 'error', // Valid type syntax (string not String)
34+
35+
// Optional - we use @returns {Function} or skip it
36+
'jsdoc/require-returns': 'off',
37+
'jsdoc/require-returns-type': 'off',
38+
39+
// Don't require descriptions if obvious
40+
'jsdoc/require-param-description': 'off',
41+
'jsdoc/require-returns-description': 'off',
42+
'jsdoc/require-description': 'off',
43+
44+
// Don't require examples - nice to have but not essential
45+
'jsdoc/require-example': 'off',
46+
47+
// Simple formatting
48+
'jsdoc/require-hyphen-before-param-description': 'off', // Optional: @param {Type} name - Description
49+
50+
// Allow types from our .d.ts files and common types
51+
'jsdoc/no-undefined-types': ['warn', {
52+
definedTypes: [
53+
// Allow any type that starts with capital letter (likely imported)
54+
'/^[A-Z]/',
55+
56+
// Common utility types
57+
'Partial', 'Required', 'Readonly', 'Pick', 'Omit',
58+
59+
// Built-in types
60+
'Function', 'Object', 'Array', 'Promise',
61+
62+
// DOM
63+
'HTMLElement', 'Element', 'Event'
64+
]
65+
}],
66+
67+
// Don't enforce these
68+
'jsdoc/valid-types': 'off', // We use TypeScript syntax
69+
'jsdoc/check-tag-names': 'off', // Allow @module, @typedef, etc.
70+
'jsdoc/check-alignment': 'off', // Don't worry about alignment
71+
'jsdoc/multiline-blocks': 'off' // Allow single or multi-line
72+
},
73+
settings: {
74+
jsdoc: {
75+
mode: 'typescript', // Understand TypeScript syntax in JSDoc
76+
preferredTypes: {
77+
object: 'Object', // Use Object not object
78+
array: 'Array', // Use Array not array
79+
'Array.<>': 'Array<>', // Use Array<Type> not Array.<Type>
80+
}
81+
}
82+
}
83+
}
84+
];
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SuperDoc - Programmatic Text Selection Example
2+
3+
See it here: https://www.superdoc.dev/?demo=programmatic-text-selection
4+
5+
This React-based example shows how SuperDoc can select text in a document relative to the cursor's position.
6+
7+
- Based on character count: https://github.com/Harbour-Enterprises/SuperDoc/blob/develop/examples/programmatic-text-selection/src/App.jsx#L30
8+
- Or, just grab the whole line: https://github.com/Harbour-Enterprises/SuperDoc/blob/develop/examples/programmatic-text-selection/src/App.jsx#L43
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"dirname": "programmatic-text-selection",
3+
"tags": [
4+
"editing",
5+
"viewing",
6+
"react"
7+
],
8+
"title": "Programmatic Text Selection"
9+
}
104 KB
Loading
5.02 MB
Binary file not shown.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>SuperDoc React Example</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.jsx"></script>
11+
</body>
12+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "react-superdoc-example",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite"
8+
},
9+
"dependencies": {
10+
"@harbour-enterprises/superdoc": "^0.11.13",
11+
"react": "^19.0.0",
12+
"react-dom": "^19.0.0"
13+
},
14+
"devDependencies": {
15+
"@vitejs/plugin-react": "^4.0.4",
16+
"vite": "^7.0.5",
17+
"prosemirror-state": "^1.4.3"
18+
}
19+
}
67.3 KB
Binary file not shown.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { useRef, useState } from 'react';
2+
import { TextSelection } from 'prosemirror-state';
3+
import DocumentEditor from './components/DocumentEditor';
4+
5+
function App() {
6+
const [documentFile, setDocumentFile] = useState(null);
7+
const [showLengthInput, setShowLengthInput] = useState(true);
8+
const selectionMethodRef = useRef('length');
9+
const selectionLengthRef = useRef(10);
10+
const fileInputRef = useRef(null);
11+
const editorRef = useRef(null);
12+
13+
const handleFileChange = (event) => {
14+
const file = event.target.files?.[0];
15+
if (file) {
16+
setDocumentFile(file);
17+
}
18+
};
19+
20+
const handleEditorReady = (editor) => {
21+
console.log('SuperDoc editor is ready', editor);
22+
editorRef.current = editor;
23+
};
24+
25+
const getCurrentSelection = () => {
26+
const { view } = editorRef.current.activeEditor;
27+
return view.state.selection;
28+
};
29+
30+
const getLengthBasedPositions = () => {
31+
const selection = getCurrentSelection();
32+
const { view } = editorRef.current.activeEditor;
33+
const currentPos = selection.from;
34+
const selectionLength = selectionLengthRef.current;
35+
const docLength = view.state.doc.content.size;
36+
37+
return {
38+
from: currentPos,
39+
to: Math.min(currentPos + selectionLength, docLength)
40+
};
41+
};
42+
43+
const getLineBasedPositions = () => {
44+
const selection = getCurrentSelection();
45+
const { $from } = selection;
46+
return {
47+
from: $from.start(),
48+
to: $from.end()
49+
};
50+
};
51+
52+
const applySelection = (from, to) => {
53+
const activeEditor = editorRef.current.activeEditor;
54+
const { view } = activeEditor;
55+
56+
const newSelection = TextSelection.create(view.state.doc, from, to);
57+
const tr = view.state.tr.setSelection(newSelection);
58+
const state = view.state.apply(tr);
59+
view.updateState(state);
60+
61+
activeEditor.commands.setUnderline();
62+
};
63+
64+
const handleSelection = (getPositions) => {
65+
const { from, to } = getPositions();
66+
applySelection(from, to);
67+
};
68+
69+
const handleLengthSelection = () => handleSelection(getLengthBasedPositions);
70+
const handleLineSelection = () => handleSelection(getLineBasedPositions);
71+
72+
const handleSelectionClick = () => {
73+
if (selectionMethodRef.current === 'length') {
74+
handleLengthSelection();
75+
} else {
76+
handleLineSelection();
77+
}
78+
};
79+
80+
return (
81+
<div className="app">
82+
<header>
83+
<h1>SuperDoc Example</h1>
84+
<button onClick={() => fileInputRef.current?.click()}>
85+
Load Document
86+
</button>
87+
<div className="selection-controls">
88+
<div className="selection-group">
89+
<label htmlFor="selectionMethod">Selection method:</label>
90+
<select
91+
id="selectionMethod"
92+
defaultValue={selectionMethodRef.current}
93+
onChange={(e) => {
94+
selectionMethodRef.current = e.target.value;
95+
setShowLengthInput(e.target.value === 'length');
96+
}}
97+
>
98+
<option value="length">By Length</option>
99+
<option value="line">By Line</option>
100+
</select>
101+
102+
{/* hide input when not needed */}
103+
{showLengthInput && (
104+
<>
105+
<label htmlFor="selectionLength">Characters:</label>
106+
<input
107+
id="selectionLength"
108+
type="number"
109+
defaultValue={selectionLengthRef.current}
110+
onChange={(e) => selectionLengthRef.current = Number(e.target.value)}
111+
min="1"
112+
max="1000"
113+
/>
114+
</>
115+
)}
116+
117+
<button onClick={handleSelectionClick}>
118+
Select and underline
119+
</button>
120+
</div>
121+
</div>
122+
<input
123+
type="file"
124+
ref={fileInputRef}
125+
accept=".docx, application/vnd.openxmlformats-officedocument.wordprocessingml.document"
126+
onChange={handleFileChange}
127+
style={{ display: 'none' }}
128+
/>
129+
</header>
130+
131+
<main>
132+
<DocumentEditor
133+
initialData={documentFile}
134+
onEditorReady={handleEditorReady}
135+
/>
136+
</main>
137+
138+
<style jsx>{`
139+
.app {
140+
height: 100vh;
141+
display: flex;
142+
flex-direction: column;
143+
}
144+
header {
145+
padding: 1rem;
146+
background: #f5f5f5;
147+
display: flex;
148+
align-items: center;
149+
gap: 1rem;
150+
}
151+
header button {
152+
padding: 0.5rem 1rem;
153+
background: #1355ff;
154+
color: white;
155+
border: none;
156+
border-radius: 4px;
157+
cursor: pointer;
158+
}
159+
header button:hover {
160+
background: #0044ff;
161+
}
162+
.selection-controls {
163+
display: flex;
164+
align-items: center;
165+
gap: 1rem;
166+
}
167+
.selection-group {
168+
display: flex;
169+
align-items: center;
170+
gap: 0.5rem;
171+
padding: 0.5rem;
172+
border: 1px solid #ddd;
173+
border-radius: 4px;
174+
background: #fafafa;
175+
}
176+
.selection-group > label:first-child {
177+
font-weight: bold;
178+
font-size: 0.9rem;
179+
color: #333;
180+
}
181+
.selection-controls label {
182+
font-size: 0.9rem;
183+
}
184+
.selection-controls input[type="number"] {
185+
width: 80px;
186+
padding: 0.3rem;
187+
border: 1px solid #ccc;
188+
border-radius: 4px;
189+
}
190+
.selection-controls select {
191+
padding: 0.3rem;
192+
border: 1px solid #ccc;
193+
border-radius: 4px;
194+
background: white;
195+
}
196+
main {
197+
flex: 1;
198+
min-height: 0;
199+
}
200+
`}</style>
201+
</div>
202+
);
203+
}
204+
205+
export default App;

0 commit comments

Comments
 (0)