@turnix-co/konva-editor 2.0.1 → 2.0.3

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 CHANGED
@@ -1,66 +1,31 @@
1
1
  # @turnix-co/konva-editor
2
2
 
3
- A powerful, private multi-slide canvas editor built with React, Konva, and Redux. Features drawing tools, media support, recording capabilities, and more.
3
+ A powerful multi-slide canvas editor built with React and Konva. Create interactive presentations, whiteboards, and educational content with drawing, media, and recording capabilities.
4
4
 
5
- ## 🔒 Private Package
5
+ [![npm version](https://badge.fury.io/js/%40turnix-co%2Fkonva-editor.svg)](https://www.npmjs.com/package/@turnix-co/konva-editor)
6
6
 
7
- This package is **private** and only available to authorized Turnix team members via GitHub Packages.
7
+ ## Installation
8
8
 
9
- ## 📦 Installation
10
-
11
- ### For Team Members
12
-
13
- **Step 1:** Install the package from GitHub Packages:
14
- ```bash
15
- npm install @turnix-co/konva-editor --registry=https://npm.pkg.github.com --legacy-peer-deps
16
- ```
17
-
18
- **Step 2:** Install peer dependencies:
19
9
  ```bash
20
- npm install konva react-konva react-konva-utils
10
+ npm install @turnix-co/konva-editor
21
11
  ```
22
12
 
23
- **Why separate?** Konva has platform-specific code (browser vs Node.js). Installing it separately ensures Next.js correctly resolves the browser version and avoids SSR errors.
24
-
25
- ### Setup Authentication
26
-
27
- Contact your team lead for authentication credentials (.npmrc file).
28
-
29
- ## ⚠️ CRITICAL SETUP REQUIREMENTS
30
-
31
- **Before you start**, understand these requirements or features WON'T work:
32
-
33
- 1. **Layout Container Required**: Components MUST be wrapped in a div with:
34
- - `width: '100vw'` and `height: '100vh'`
35
- - `display: 'flex'` and `flexDirection: 'column'`
36
- - Canvas wrapper needs `flex: 1` and `position: 'relative'`
13
+ ### Peer Dependencies
37
14
 
38
- 2. **stageRef Required**: For video recording, you MUST:
39
- - Create a `stageRef` with `useRef<Konva.Stage | null>(null)`
40
- - Pass it to both `<Toolbar stageRef={stageRef} />` and `<Canvas onStageReady={...} />`
15
+ Install the required peer dependencies:
41
16
 
42
- 3. **CSS Import Required**: Import the package's CSS in your root layout
43
-
44
- ❌ **Common Mistakes** (these will break video recording):
45
- ```tsx
46
- // ❌ WRONG - No layout wrapper, no stageRef
47
- <ReduxProvider store={store}>
48
- <Toolbar />
49
- <Canvas />
50
- <SlideNavigation />
51
- </ReduxProvider>
17
+ ```bash
18
+ npm install konva react-konva react-konva-utils
52
19
  ```
53
20
 
54
- **Correct Setup** (see Quick Start below)
21
+ > **Note:** Konva has platform-specific code (browser vs Node.js). Installing it separately ensures Next.js correctly resolves the browser version and avoids SSR errors.
55
22
 
56
- ## 🚀 Quick Start
23
+ ## Quick Start
57
24
 
58
25
  ### 1. Import the CSS styles
59
26
 
60
27
  **IMPORTANT:** You must import the package's CSS file for components to display properly.
61
28
 
62
- In your root layout or main CSS file (e.g., `app/layout.tsx` or `app/globals.css`):
63
-
64
29
  ```tsx
65
30
  // In your layout.tsx or _app.tsx
66
31
  import '@turnix-co/konva-editor/styles.css';
@@ -71,11 +36,7 @@ Or in your CSS file:
71
36
  @import '@turnix-co/konva-editor/styles.css';
72
37
  ```
73
38
 
74
- ### 2. Create your editor page with auto-save
75
-
76
- **IMPORTANT:** To enable IndexedDB persistence (auto-save), you must call the `useSlidesPersistence()` hook.
77
-
78
- **CRITICAL FOR VIDEO RECORDING:** You MUST wrap components in a properly styled container for video recording to work correctly!
39
+ ### 2. Create your editor page
79
40
 
80
41
  ```tsx
81
42
  'use client';
@@ -94,7 +55,7 @@ import type Konva from 'konva';
94
55
 
95
56
  // Wrapper component to load persisted slides
96
57
  function PersistenceLoader({ children }: { children: React.ReactNode }) {
97
- useSlidesPersistence(); // This loads slides from IndexedDB on mount
58
+ useSlidesPersistence(); // Loads slides from IndexedDB on mount
98
59
  return <>{children}</>;
99
60
  }
100
61
 
@@ -104,17 +65,15 @@ export default function EditorPage() {
104
65
  return (
105
66
  <ReduxProvider store={store}>
106
67
  <PersistenceLoader>
107
- {/* CRITICAL: This wrapper is REQUIRED for video recording to work */}
108
68
  <div style={{
109
69
  width: '100vw',
110
70
  height: '100vh',
111
71
  display: 'flex',
112
72
  flexDirection: 'column',
113
- overflow: 'hidden' // Prevents scrollbars
73
+ overflow: 'hidden'
114
74
  }}>
115
75
  <Toolbar stageRef={stageRef} />
116
76
 
117
- {/* CRITICAL: Canvas wrapper needs flex: 1 and position: relative */}
118
77
  <div style={{ flex: 1, position: 'relative' }}>
119
78
  <Canvas onStageReady={(ref) => { stageRef.current = ref.current; }} />
120
79
  </div>
@@ -127,153 +86,70 @@ export default function EditorPage() {
127
86
  }
128
87
  ```
129
88
 
130
- **Important:**
131
- - Always add `'use client'` at the top!
132
- - Call `useSlidesPersistence()` inside `ReduxProvider` to enable auto-save
133
- - **MUST** have the wrapper div with `width: '100vw'` and `height: '100vh'`
134
- - **MUST** pass `stageRef` to both Toolbar and Canvas for recording to work
135
-
136
- ### 3. Add Publishing (Optional)
137
-
138
- The package includes **automatic data persistence via IndexedDB + Redux**:
139
- - **Auto-save**: Slides are automatically saved to browser storage on every change
140
- - **Auto-restore**: Slides are automatically loaded when the page refreshes
141
- - **No backend needed**: Data persists in the user's browser
142
-
143
- **How it works:**
144
- 1. `useSlidesPersistence()` hook loads slides from IndexedDB on mount
145
- 2. Redux middleware automatically saves changes to IndexedDB (500ms debounce)
146
- 3. Works completely offline - no server required!
147
-
148
- If you want to publish slides to your backend:
149
-
150
- ```tsx
151
- 'use client';
152
-
153
- import { useRef } from 'react';
154
- import {
155
- Canvas,
156
- Toolbar,
157
- SlideNavigation,
158
- PublishButton,
159
- ReduxProvider,
160
- store,
161
- useSlidesPersistence,
162
- type PublishProgress,
163
- type PublishResponse,
164
- type Slide
165
- } from '@turnix-co/konva-editor';
166
- import '@turnix-co/konva-editor/styles.css';
167
- import type Konva from 'konva';
168
-
169
- // Wrapper component for persistence
170
- function PersistenceLoader({ children }: { children: React.ReactNode }) {
171
- useSlidesPersistence();
172
- return <>{children}</>;
173
- }
174
-
175
- export default function EditorPage() {
176
- const stageRef = useRef<Konva.Stage | null>(null);
177
-
178
- // Your custom publish logic
179
- const handlePublish = async (
180
- slides: Slide[],
181
- onProgress?: (progress: PublishProgress) => void
182
- ): Promise<PublishResponse> => {
183
- // Update progress
184
- onProgress?.({
185
- current: 0,
186
- total: slides.length,
187
- status: 'Preparing slides...'
188
- });
189
-
190
- // Call your API endpoint
191
- const response = await fetch('/api/publish', {
192
- method: 'POST',
193
- headers: { 'Content-Type': 'application/json' },
194
- body: JSON.stringify({ slides })
195
- });
196
-
197
- const data = await response.json();
198
-
199
- onProgress?.({
200
- current: slides.length,
201
- total: slides.length,
202
- status: 'Published successfully!'
203
- });
204
-
205
- return {
206
- success: true,
207
- message: 'Slides published successfully!',
208
- projectId: data.id,
209
- url: data.url
210
- };
211
- };
89
+ ## Features
90
+
91
+ - **Multi-slide Support** - Create presentations with up to 20 slides
92
+ - **Freehand Drawing** - Smooth pen and brush tools with customizable colors and sizes
93
+ - **Shapes** - Rectangle, circle, triangle, arrow, and line shapes
94
+ - **Text** - Rich text with formatting options
95
+ - **Images** - Drag & drop, resize, rotate with context menu
96
+ - **Videos** - Upload and playback with thumbnail previews
97
+ - **Flashcards** - Interactive flashcard elements
98
+ - **Photo Frames** - Decorative frames with annotation support
99
+ - **Quiz Elements** - Multiple choice, true/false, short answer, long answer, fill-in-the-blanks
100
+ - **Audio Recording** - Record voice notes for individual objects
101
+ - **Screen Recording** - Record entire canvas with audio
102
+ - **Undo/Redo** - Full history management
103
+ - **Auto-save** - Automatic persistence with IndexedDB + Redux
104
+ - **Export** - Export slides as images
105
+
106
+ ## Components
212
107
 
213
- return (
214
- <ReduxProvider store={store}>
215
- <PersistenceLoader>
216
- {/* CRITICAL: This wrapper is REQUIRED */}
217
- <div style={{
218
- width: '100vw',
219
- height: '100vh',
220
- display: 'flex',
221
- flexDirection: 'column',
222
- overflow: 'hidden'
223
- }}>
224
- <Toolbar stageRef={stageRef} />
108
+ ### Core Components
225
109
 
226
- <div style={{ flex: 1, position: 'relative' }}>
227
- <Canvas onStageReady={(ref) => { stageRef.current = ref.current; }} />
228
- </div>
110
+ | Component | Description |
111
+ |-----------|-------------|
112
+ | `Canvas` | Main canvas component with drawing, images, videos, and text |
113
+ | `Toolbar` | Toolbar with drawing tools, colors, and actions |
114
+ | `SlideNavigation` | Multi-slide navigation and management |
115
+ | `ScreenRecorder` | Screen recording functionality |
116
+ | `PublishButton` | Customizable publish button with progress tracking |
117
+ | `EditorRoot` | Root wrapper that scopes styles (optional) |
229
118
 
230
- <SlideNavigation />
119
+ ### Redux Setup
231
120
 
232
- {/* Add PublishButton with your custom publish function */}
233
- <PublishButton
234
- onPublish={handlePublish}
235
- label="Save to Cloud"
236
- />
237
- </div>
238
- </PersistenceLoader>
239
- </ReduxProvider>
240
- );
241
- }
242
- ```
121
+ | Export | Description |
122
+ |--------|-------------|
123
+ | `ReduxProvider` | Redux provider (from react-redux) |
124
+ | `store` | Pre-configured Redux store |
125
+ | `useDispatch` | Typed dispatch hook |
126
+ | `useSelector` | Typed selector hook |
243
127
 
244
- ## 📚 Components
128
+ ## Critical Setup Requirements
245
129
 
246
- ### Core Components
130
+ For all features to work correctly, ensure:
247
131
 
248
- - **`<Canvas />`** - Main canvas component with drawing, images, videos, and text
249
- - **`<Toolbar />`** - Toolbar with drawing tools, colors, and actions
250
- - **`<SlideNavigation />`** - Multi-slide navigation and management
251
- - **`<ScreenRecorder />`** - Screen recording functionality
252
- - **`<PublishButton />`** - Customizable publish button with progress tracking
132
+ 1. **Layout Container**: Components MUST be wrapped in a div with:
133
+ - `width: '100vw'` and `height: '100vh'`
134
+ - `display: 'flex'` and `flexDirection: 'column'`
135
+ - Canvas wrapper needs `flex: 1` and `position: 'relative'`
253
136
 
254
- ### Redux Setup
137
+ 2. **stageRef Required for Recording**: You MUST:
138
+ - Create a `stageRef` with `useRef<Konva.Stage | null>(null)`
139
+ - Pass it to both `<Toolbar stageRef={stageRef} />` and `<Canvas onStageReady={...} />`
255
140
 
256
- - **`ReduxProvider`** - Redux provider (from react-redux)
257
- - **`store`** - Pre-configured Redux store
141
+ 3. **CSS Import Required**: Import the package's CSS in your root layout
258
142
 
259
- ## 🎥 Using the Recording Feature
143
+ ## Recording Feature
260
144
 
261
- The Toolbar component includes a built-in recording button. To enable it, you need to pass the stage reference from the Canvas component to the Toolbar:
145
+ The Toolbar includes a built-in recording button. To enable it:
262
146
 
263
147
  ```tsx
264
148
  'use client';
265
149
 
266
- import { useState, useRef } from 'react';
267
- import {
268
- Canvas,
269
- Toolbar,
270
- SlideNavigation,
271
- ReduxProvider,
272
- store,
273
- type CanvasProps,
274
- type ToolbarProps
275
- } from '@turnix-co/konva-editor';
276
- import Konva from 'konva';
150
+ import { useRef } from 'react';
151
+ import { Canvas, Toolbar, SlideNavigation, ReduxProvider, store } from '@turnix-co/konva-editor';
152
+ import type Konva from 'konva';
277
153
 
278
154
  export default function EditorPage() {
279
155
  const stageRef = useRef<Konva.Stage | null>(null);
@@ -281,18 +157,10 @@ export default function EditorPage() {
281
157
  return (
282
158
  <ReduxProvider store={store}>
283
159
  <div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
284
- {/* Pass stageRef to Toolbar to enable recording */}
285
160
  <Toolbar stageRef={stageRef} />
286
-
287
161
  <div style={{ flex: 1, position: 'relative' }}>
288
- {/* Canvas provides the stageRef via onStageReady callback */}
289
- <Canvas
290
- onStageReady={(ref) => {
291
- stageRef.current = ref.current;
292
- }}
293
- />
162
+ <Canvas onStageReady={(ref) => { stageRef.current = ref.current; }} />
294
163
  </div>
295
-
296
164
  <SlideNavigation />
297
165
  </div>
298
166
  </ReduxProvider>
@@ -300,259 +168,181 @@ export default function EditorPage() {
300
168
  }
301
169
  ```
302
170
 
303
- **Key points:**
304
- 1. Create a `stageRef` using `useRef<Konva.Stage | null>(null)`
305
- 2. Pass the `stageRef` to the `<Toolbar>` component
306
- 3. Use the `onStageReady` callback on `<Canvas>` to populate the stageRef
307
- 4. **IMPORTANT**: Wrap Canvas in a container with `flex: 1` and `position: 'relative'`
308
- 5. **IMPORTANT**: The parent container MUST have `width: '100vw'` and `height: '100vh'` for recorded videos to display in full screen
309
- 6. The recording button in the Toolbar will now work correctly
310
-
311
- Alternatively, you can handle recording externally:
312
-
313
- ```tsx
314
- 'use client';
315
-
316
- import { useState, useRef } from 'react';
317
- import {
318
- Canvas,
319
- Toolbar,
320
- ScreenRecorder,
321
- ReduxProvider,
322
- store
323
- } from '@turnix-co/konva-editor';
324
- import Konva from 'konva';
325
-
326
- export default function EditorPage() {
327
- const stageRef = useRef<Konva.Stage | null>(null);
328
- const [showRecorder, setShowRecorder] = useState(false);
329
-
330
- const handleRecordingComplete = (videoBlob: Blob, thumbnailDataUrl: string) => {
331
- // Handle the recorded video
332
- console.log('Recording completed', videoBlob);
333
- };
334
-
335
- return (
336
- <ReduxProvider store={store}>
337
- <div style={{ width: '100vw', height: '100vh' }}>
338
- {/* Toolbar with custom recording handler */}
339
- <Toolbar
340
- onScreenRecord={() => setShowRecorder(true)}
341
- />
342
-
343
- <Canvas
344
- onStageReady={(ref) => {
345
- stageRef.current = ref.current;
346
- }}
347
- />
348
-
349
- {/* External ScreenRecorder component */}
350
- {showRecorder && (
351
- <ScreenRecorder
352
- onClose={() => setShowRecorder(false)}
353
- stageRef={stageRef}
354
- onRecordingComplete={handleRecordingComplete}
355
- />
356
- )}
357
- </div>
358
- </ReduxProvider>
359
- );
360
- }
361
- ```
362
-
363
- ## 🎨 Features
364
-
365
- - ✏️ **Drawing tools** - Pen and eraser with customizable colors and sizes
366
- - 🖼️ **Image support** - Drag & drop, resize, rotate with context menu
367
- - 🎥 **Video support** - Upload and playback with thumbnail previews
368
- - 📝 **Text elements** - Add and edit text on canvas
369
- - 🎙️ **Audio recording** - Record voice notes for individual objects
370
- - 📹 **Screen recording** - Record entire canvas with audio
371
- - 📊 **Multi-slide presentations** - Create up to 20 slides
372
- - ↩️ **Undo/Redo** - Full history management
373
- - 💾 **Auto-save** - Automatic persistence with IndexedDB + Redux
374
- - 📤 **Export** - Export slides as images
375
- - 🚀 **Publishing** - Customizable publish button with progress tracking
171
+ ## Publishing
376
172
 
377
- ## 🔧 Advanced Usage
173
+ ### Auto-save (Built-in)
378
174
 
379
- ### Custom Actions
175
+ The package includes automatic data persistence via IndexedDB + Redux:
176
+ - Slides are automatically saved to browser storage on every change
177
+ - Slides are automatically loaded when the page refreshes
178
+ - Works completely offline - no server required
380
179
 
381
- ```tsx
382
- import { useDispatch, addImage, setTool } from '@turnix/konva-editor';
383
-
384
- function CustomControls() {
385
- const dispatch = useDispatch();
386
-
387
- const handleAddImage = () => {
388
- dispatch(addImage({
389
- id: 'custom-id',
390
- src: 'https://example.com/image.jpg',
391
- x: 100,
392
- y: 100,
393
- width: 200,
394
- height: 200,
395
- }));
396
- };
180
+ ### Custom Publishing
397
181
 
398
- return <button onClick={handleAddImage}>Add Image</button>;
399
- }
400
- ```
401
-
402
- ### TypeScript Support
403
-
404
- Full TypeScript support with exported types:
182
+ Add a publish button to save to your backend:
405
183
 
406
184
  ```tsx
407
- import type { RootState, ImageElement, CanvasState } from '@turnix/konva-editor';
408
- ```
409
-
410
- ## 📖 API Reference
411
-
412
- ### PublishButton Props
413
-
414
- ```tsx
415
- interface PublishButtonProps {
416
- // Custom publish function (required)
417
- onPublish?: (
418
- slides: Slide[],
419
- onProgress?: (progress: PublishProgress) => void
420
- ) => Promise<PublishResponse>;
421
-
422
- // Custom button label (optional, default: "Publish Slides")
423
- label?: string;
424
-
425
- // Custom className for positioning/styling (optional)
426
- className?: string;
427
- }
428
-
429
- interface PublishProgress {
430
- current: number; // Current progress (e.g., 5)
431
- total: number; // Total items (e.g., 10)
432
- status: string; // Status message (e.g., "Uploading...")
433
- }
185
+ import {
186
+ PublishButton,
187
+ type PublishProgress,
188
+ type PublishResponse,
189
+ type Slide
190
+ } from '@turnix-co/konva-editor';
434
191
 
435
- interface PublishResponse {
436
- success: boolean; // Whether publish succeeded
437
- message: string; // Success/error message
438
- projectId?: string; // Optional: ID from your backend
439
- url?: string; // Optional: URL to published project
440
- }
441
- ```
192
+ const handlePublish = async (
193
+ slides: Slide[],
194
+ onProgress?: (progress: PublishProgress) => void
195
+ ): Promise<PublishResponse> => {
196
+ onProgress?.({ current: 0, total: slides.length, status: 'Preparing...' });
442
197
 
443
- **Example API Endpoint** (`app/api/publish/route.ts`):
444
- ```tsx
445
- import { NextRequest, NextResponse } from 'next/server';
198
+ const response = await fetch('/api/publish', {
199
+ method: 'POST',
200
+ headers: { 'Content-Type': 'application/json' },
201
+ body: JSON.stringify({ slides })
202
+ });
446
203
 
447
- export async function POST(request: NextRequest) {
448
- const { slides } = await request.json();
204
+ const data = await response.json();
449
205
 
450
- // Save to your database
451
- const project = await db.project.create({
452
- data: {
453
- slides: JSON.stringify(slides),
454
- createdAt: new Date(),
455
- }
456
- });
206
+ return {
207
+ success: true,
208
+ message: 'Published successfully!',
209
+ projectId: data.id,
210
+ url: data.url
211
+ };
212
+ };
457
213
 
458
- return NextResponse.json({
459
- id: project.id,
460
- url: `/projects/${project.id}`,
461
- });
462
- }
214
+ // In your component:
215
+ <PublishButton onPublish={handlePublish} label="Save to Cloud" />
463
216
  ```
464
217
 
465
- ### Redux Actions
218
+ ## Redux Actions
466
219
 
467
- **Canvas Actions:**
468
- - `addImage(payload)` - Add image to canvas
469
- - `addVideo(payload)` - Add video to canvas
470
- - `addText(payload)` - Add text to canvas
471
- - `clearCanvas()` - Clear current slide
472
- - `undo()` - Undo last action
473
- - `redo()` - Redo undone action
474
- - `deleteElement(id)` - Delete element by ID
475
-
476
- **Slide Actions:**
220
+ ### Slide Management
477
221
  - `addSlide()` - Create new slide
478
222
  - `deleteSlide(id)` - Delete slide
479
223
  - `setCurrentSlide(id)` - Switch to slide
480
224
  - `duplicateSlide(id)` - Duplicate slide
225
+ - `reorderSlides(payload)` - Reorder slides
226
+ - `setBackgroundColor(color)` - Set slide background
227
+ - `loadSlides(slides)` - Load slides from data
228
+
229
+ ### Elements
230
+ - `addText`, `updateText`, `deleteText`, `duplicateText`
231
+ - `addShape`, `updateShape`, `deleteShape`, `duplicateShape`
232
+ - `addImage`, `updateImage`, `deleteImage`, `duplicateImage`
233
+ - `addVideo`, `updateVideo`, `deleteVideo`, `duplicateVideo`
234
+ - `addFlashcard`, `updateFlashcard`, `deleteFlashcard`
235
+ - `addPhotoFrame`, `updatePhotoFrame`, `deletePhotoFrame`
236
+ - `addMultipleChoice`, `addTrueFalse`, `addShortAnswer`, `addLongAnswer`, `addFillInTheBlanks`
237
+
238
+ ### Drawing
239
+ - `addLine`, `removeLine`, `updateLastLine`
240
+ - `setLines`, `deleteLineById`, `duplicateLine`
241
+
242
+ ### Canvas Operations
243
+ - `clearCanvas()` - Clear current slide
244
+ - `undo()` - Undo last action
245
+ - `redo()` - Redo undone action
246
+ - `bringToFront(id)`, `sendToBack(id)` - Layer ordering
481
247
 
482
- **Toolbar Actions:**
248
+ ### Toolbar Actions
483
249
  - `setTool(tool)` - Set active tool ('pen' | 'eraser' | 'text')
484
250
  - `setPenColor(color)` - Set pen color
485
251
  - `setStrokeWidth(width)` - Set stroke width
486
252
 
487
- ### Utilities
253
+ ### Selectors
254
+ - `selectCurrentSlide` - Get current slide
255
+ - `selectAllSlides` - Get all slides
256
+ - `selectCurrentSlideId` - Get current slide ID
257
+ - `selectCanAddSlide` - Check if can add more slides
258
+ - `selectSlideById(id)` - Get slide by ID
488
259
 
489
- - `exportSlideAsImage(slideId)` - Export slide as PNG
490
- - `exportSlideAsPDF(slideId)` - Export slide as PDF
260
+ ## Utilities
491
261
 
492
- ## 🏗️ Architecture
262
+ ### Export Slides
493
263
 
494
- The package uses:
495
- - **React 19** for UI
496
- - **Konva** for canvas rendering
497
- - **Redux Toolkit** for state management
498
- - **IndexedDB** for persistence
499
- - **TypeScript** for type safety
264
+ ```tsx
265
+ import { exportSlideAsImage, exportSlideAsBlob, getSlideDataURL } from '@turnix-co/konva-editor';
500
266
 
501
- ## 🔐 Security
267
+ // Export as downloadable image
268
+ await exportSlideAsImage(stageRef, { pixelRatio: 2 });
502
269
 
503
- ⚠️ **This is a private package.** Do not:
504
- - Share authentication credentials
505
- - Publish package code publicly
506
- - Include in public repositories
270
+ // Get as Blob for upload
271
+ const blob = await exportSlideAsBlob(stageRef, { format: 'png' });
507
272
 
508
- ## 📝 License
273
+ // Get as data URL
274
+ const dataUrl = await getSlideDataURL(stageRef);
275
+ ```
509
276
 
510
- UNLICENSED - Private and proprietary software for Turnix team use only.
277
+ ### Line Simplification
511
278
 
512
- ## 🆘 Support
279
+ Reduce payload size by simplifying freehand lines:
513
280
 
514
- For issues or questions, contact the Turnix development team.
281
+ ```tsx
282
+ import { simplifyLines, getCompressionStats } from '@turnix-co/konva-editor';
515
283
 
516
- ## 🐛 Troubleshooting
284
+ // Simplify all lines with tolerance (higher = more compression)
285
+ const simplified = simplifyLines(lines, 3.0);
517
286
 
518
- ### Recorded Video Not Displaying Full Screen
287
+ // Get compression statistics
288
+ const stats = getCompressionStats(originalPoints, simplifiedPoints);
289
+ console.log(`Reduced by ${stats.reduction}`);
290
+ ```
519
291
 
520
- If your recorded video doesn't display in full screen when played:
292
+ ## TypeScript Support
521
293
 
522
- 1. **Check Container Styling**: Ensure the Canvas is wrapped in a container that fills the viewport:
523
- ```tsx
524
- <div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
525
- <Toolbar stageRef={stageRef} />
526
- <div style={{ flex: 1, position: 'relative' }}>
527
- <Canvas onStageReady={(ref) => stageRef.current = ref.current} />
528
- </div>
529
- </div>
530
- ```
294
+ Full TypeScript support with exported types:
531
295
 
532
- 2. **Verify stageRef is Passed**: Make sure you're passing the `stageRef` to the Toolbar component:
533
- ```tsx
534
- <Toolbar stageRef={stageRef} />
535
- ```
296
+ ```tsx
297
+ import type {
298
+ Slide,
299
+ Line,
300
+ TextElement,
301
+ Shape,
302
+ ImageElement,
303
+ VideoElement,
304
+ FlashcardElement,
305
+ PhotoFrameElement,
306
+ MultipleChoice,
307
+ TrueFalse,
308
+ ShortAnswer,
309
+ LongAnswer,
310
+ FillInTheBlanks,
311
+ CanvasProps,
312
+ ToolbarProps,
313
+ EditorRootProps,
314
+ ExportOptions,
315
+ PublishProgress,
316
+ PublishResponse,
317
+ RootState,
318
+ AppDispatch,
319
+ } from '@turnix-co/konva-editor';
320
+ ```
536
321
 
537
- 3. **Check onStageReady Callback**: Ensure the Canvas component's `onStageReady` callback is properly setting the stageRef:
538
- ```tsx
539
- <Canvas onStageReady={(ref) => { stageRef.current = ref.current; }} />
540
- ```
322
+ ## Troubleshooting
541
323
 
542
- 4. **No Fixed Dimensions**: Avoid setting fixed width/height on the Canvas container. Use `flex: 1` instead to allow it to fill available space.
324
+ ### Recorded Video Not Displaying Full Screen
543
325
 
544
- ### Download and Re-record Buttons Not Visible
326
+ 1. **Check Container Styling**: Ensure Canvas is wrapped in a container with `width: '100vw'` and `height: '100vh'`
327
+ 2. **Verify stageRef**: Make sure `stageRef` is passed to both Toolbar and Canvas
328
+ 3. **Use flex: 1**: Canvas container should use `flex: 1` instead of fixed dimensions
545
329
 
546
- After recording stops, you should see a preview dialog with three buttons:
547
- - **Add to Canvas** - Adds the video to the canvas (clears existing content)
548
- - **Download** - Downloads the video file locally
549
- - **Re-record** - Discards the recording and starts over
330
+ ### Styles Not Applied
550
331
 
551
- If you don't see these buttons, ensure you're using version `1.3.3` or later:
552
- ```bash
553
- npm install @turnix-co/konva-editor@latest --registry=https://npm.pkg.github.com
554
- ```
332
+ 1. Make sure you imported `@turnix-co/konva-editor/styles.css`
333
+ 2. Wrap components in `EditorRoot` if you have CSS conflicts
334
+
335
+ ### SSR Errors
336
+
337
+ If you see SSR errors with Konva:
338
+ 1. Make sure your component has `'use client'` directive
339
+ 2. Install Konva peer dependencies separately: `npm install konva react-konva react-konva-utils`
340
+
341
+ ## License
342
+
343
+ UNLICENSED - Proprietary software by Turnix
555
344
 
556
- ---
345
+ ## Support
557
346
 
558
- **Built with ❤️ by the Turnix team**
347
+ For issues and feature requests, please visit:
348
+ https://github.com/turnix-co/schoopla-konva-editor/issues