@withwiz/block-editor 0.1.0
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 +219 -0
- package/dist/blocks/built-in.d.ts +6 -0
- package/dist/blocks/built-in.js +11 -0
- package/dist/chunk-3R3HAGQL.js +102 -0
- package/dist/chunk-62BAOSP6.js +100 -0
- package/dist/chunk-CJGZUEQO.js +270 -0
- package/dist/chunk-CLC3FEL2.js +313 -0
- package/dist/chunk-CYMYM7LP.js +25 -0
- package/dist/chunk-EERQYNER.js +123 -0
- package/dist/chunk-G6J2DCC5.js +77 -0
- package/dist/chunk-N3ETBM74.js +24 -0
- package/dist/chunk-PPVXNJWI.js +28 -0
- package/dist/chunk-QR225IXX.js +148 -0
- package/dist/chunk-VIJV6FLT.js +250 -0
- package/dist/components/ArtistEditor.d.ts +12 -0
- package/dist/components/ArtistEditor.js +11 -0
- package/dist/components/BlockEditor.d.ts +24 -0
- package/dist/components/BlockEditor.js +16 -0
- package/dist/components/BlockRenderer.d.ts +10 -0
- package/dist/components/BlockRenderer.js +12 -0
- package/dist/components/ImageUploadField.d.ts +11 -0
- package/dist/components/ImageUploadField.js +11 -0
- package/dist/context/BlockEditorProvider.d.ts +21 -0
- package/dist/context/BlockEditorProvider.js +10 -0
- package/dist/core/html-renderer.d.ts +13 -0
- package/dist/core/html-renderer.js +11 -0
- package/dist/core/image-resize.d.ts +17 -0
- package/dist/core/image-resize.js +11 -0
- package/dist/core/serializer.d.ts +9 -0
- package/dist/core/serializer.js +7 -0
- package/dist/hooks/useImageDropZone.d.ts +23 -0
- package/dist/hooks/useImageDropZone.js +10 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +57 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.js +0 -0
- package/package.json +43 -0
- package/styles/artist.css +332 -0
- package/styles/editor.css +394 -0
- package/styles/preview.css +203 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BlockData, BlockEditorConfig } from "../types";
|
|
2
|
+
interface SerializedMode {
|
|
3
|
+
/** Serialized HTML+marker string from DB */
|
|
4
|
+
content: string;
|
|
5
|
+
/** Called with HTML+marker string */
|
|
6
|
+
onChange: (html: string) => void;
|
|
7
|
+
}
|
|
8
|
+
interface RawMode {
|
|
9
|
+
/** Block array (for parent-managed serialization) */
|
|
10
|
+
blocks: BlockData[];
|
|
11
|
+
/** Called with updated block array */
|
|
12
|
+
onBlocksChange: (blocks: BlockData[]) => void;
|
|
13
|
+
}
|
|
14
|
+
type BlockEditorProps = (SerializedMode | RawMode) & {
|
|
15
|
+
config: BlockEditorConfig;
|
|
16
|
+
/** Current category (when enableCategoryFilter is true) */
|
|
17
|
+
category?: string;
|
|
18
|
+
/** Track uploaded image keys for orphan cleanup */
|
|
19
|
+
onImageUploaded?: (key: string) => void;
|
|
20
|
+
/** Template/sample load notification */
|
|
21
|
+
onModeChange?: (mode: "template" | "sample") => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function BlockEditor(props: BlockEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
BlockEditor
|
|
4
|
+
} from "../chunk-CLC3FEL2.js";
|
|
5
|
+
import "../chunk-EERQYNER.js";
|
|
6
|
+
import "../chunk-62BAOSP6.js";
|
|
7
|
+
import "../chunk-PPVXNJWI.js";
|
|
8
|
+
import "../chunk-CJGZUEQO.js";
|
|
9
|
+
import "../chunk-G6J2DCC5.js";
|
|
10
|
+
import "../chunk-QR225IXX.js";
|
|
11
|
+
import "../chunk-3R3HAGQL.js";
|
|
12
|
+
import "../chunk-CYMYM7LP.js";
|
|
13
|
+
import "../chunk-N3ETBM74.js";
|
|
14
|
+
export {
|
|
15
|
+
BlockEditor
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BlockData } from "../types";
|
|
2
|
+
interface BlockRendererProps {
|
|
3
|
+
block: BlockData;
|
|
4
|
+
updateBlock: (id: number, field: string, value: string) => void;
|
|
5
|
+
addSubItem: (id: number, type: string) => void;
|
|
6
|
+
removeSubItem: (id: number, idx: number) => void;
|
|
7
|
+
onImageUploaded?: (key: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function BlockRenderer({ block, updateBlock, addSubItem, removeSubItem, onImageUploaded }: BlockRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
BlockRenderer
|
|
4
|
+
} from "../chunk-CJGZUEQO.js";
|
|
5
|
+
import "../chunk-G6J2DCC5.js";
|
|
6
|
+
import "../chunk-QR225IXX.js";
|
|
7
|
+
import "../chunk-3R3HAGQL.js";
|
|
8
|
+
import "../chunk-CYMYM7LP.js";
|
|
9
|
+
import "../chunk-N3ETBM74.js";
|
|
10
|
+
export {
|
|
11
|
+
BlockRenderer
|
|
12
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface ImageUploadFieldProps {
|
|
2
|
+
blockId: number;
|
|
3
|
+
field: string;
|
|
4
|
+
src: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
onUploadComplete: (blockId: number, field: string, url: string) => void;
|
|
7
|
+
onKeyTracked?: (key: string) => void;
|
|
8
|
+
onClear: (blockId: number, field: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function ImageUploadField({ blockId, field, src, className, onUploadComplete, onKeyTracked, onClear, }: ImageUploadFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { UploadFn, ErrorFn } from "../types";
|
|
2
|
+
interface BlockEditorContextValue {
|
|
3
|
+
uploadImage: UploadFn;
|
|
4
|
+
onError: ErrorFn;
|
|
5
|
+
autoResize: boolean;
|
|
6
|
+
maxSizeMB: number;
|
|
7
|
+
}
|
|
8
|
+
interface BlockEditorProviderProps {
|
|
9
|
+
/** Upload function — project-specific (e.g. adminFetch → /api/upload) */
|
|
10
|
+
uploadImage: UploadFn;
|
|
11
|
+
/** Error handler — project-specific (e.g. toast.error) */
|
|
12
|
+
onError?: ErrorFn;
|
|
13
|
+
/** Auto-resize images over maxSizeMB (default: true) */
|
|
14
|
+
autoResize?: boolean;
|
|
15
|
+
/** Max image size in MB before auto-resize (default: 10) */
|
|
16
|
+
maxSizeMB?: number;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export declare function BlockEditorProvider({ uploadImage, onError, autoResize, maxSizeMB, children, }: BlockEditorProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function useBlockEditorContext(): BlockEditorContextValue;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BlockData } from "../types";
|
|
2
|
+
export declare function h(s: string): string;
|
|
3
|
+
export declare function nl2br(s: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Creates an HTML renderer with the given CSS class prefix.
|
|
6
|
+
* @param prefix - CSS class prefix (e.g. "nbe-pvb", "rm-bk")
|
|
7
|
+
* @param catClass - optional category CSS class for themed blocks (e.g. "onstage")
|
|
8
|
+
*/
|
|
9
|
+
export declare function createHtmlRenderer(prefix: string, catClass?: string): {
|
|
10
|
+
renderBlock: (b: BlockData) => string;
|
|
11
|
+
renderBlocks: (blocks: BlockData[]) => string;
|
|
12
|
+
renderBlocksWrapped: (blocks: BlockData[]) => string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side image resizing utility using Canvas API.
|
|
3
|
+
* Automatically resizes images over the threshold while preserving aspect ratio.
|
|
4
|
+
*/
|
|
5
|
+
import type { ResizeResult } from "../types";
|
|
6
|
+
export declare const ALLOWED_IMAGE_TYPES: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Resizes images over 10MB using Canvas API.
|
|
9
|
+
* Preserves aspect ratio with a two-stage strategy:
|
|
10
|
+
* - Stage 1: Quality adjustment only
|
|
11
|
+
* - Stage 2: Dimension reduction + quality
|
|
12
|
+
*
|
|
13
|
+
* GIF images are returned as-is (animation loss prevention).
|
|
14
|
+
*/
|
|
15
|
+
export declare function resizeImageIfNeeded(file: File): Promise<ResizeResult>;
|
|
16
|
+
/** Validate image file type and size */
|
|
17
|
+
export declare function validateImageFile(file: File): string | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic serializer factory.
|
|
3
|
+
* Creates serialize/deserialize functions for a given marker string.
|
|
4
|
+
* Data is stored as base64-encoded JSON inside HTML comments: <!-- {marker}{base64} -->
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSerializer<T = unknown>(marker: string): {
|
|
7
|
+
serialize: (data: T) => string;
|
|
8
|
+
deserialize: (html: string) => T | null;
|
|
9
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type DragEvent } from "react";
|
|
2
|
+
import type { UploadResult } from "../types";
|
|
3
|
+
interface UseImageDropZoneOptions {
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
maxFiles?: number;
|
|
6
|
+
onUpload: (result: UploadResult) => void;
|
|
7
|
+
onKeyTracked?: (key: string) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function useImageDropZone(options: UseImageDropZoneOptions): {
|
|
11
|
+
isDragOver: boolean;
|
|
12
|
+
isUploading: boolean;
|
|
13
|
+
isResizing: boolean;
|
|
14
|
+
error: string | null;
|
|
15
|
+
dragHandlers: {
|
|
16
|
+
onDragEnter: (e: DragEvent) => void;
|
|
17
|
+
onDragOver: (e: DragEvent) => void;
|
|
18
|
+
onDragLeave: (e: DragEvent) => void;
|
|
19
|
+
onDrop: (e: DragEvent) => void;
|
|
20
|
+
};
|
|
21
|
+
handleFileInput: (fileList: FileList | null) => Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { BlockData, BlockDef, BlockEditorConfig, UploadResult, UploadFn, ErrorFn, ResizeResult, ArtistBioData, } from "./types";
|
|
2
|
+
export { createSerializer } from "./core/serializer";
|
|
3
|
+
export { createHtmlRenderer, h, nl2br } from "./core/html-renderer";
|
|
4
|
+
export { resizeImageIfNeeded, validateImageFile, ALLOWED_IMAGE_TYPES } from "./core/image-resize";
|
|
5
|
+
export { BUILT_IN_BLOCKS, createEmptyBlock, getBlockDef } from "./blocks/built-in";
|
|
6
|
+
export { BlockEditorProvider, useBlockEditorContext } from "./context/BlockEditorProvider";
|
|
7
|
+
export { BlockEditor } from "./components/BlockEditor";
|
|
8
|
+
export { BlockRenderer } from "./components/BlockRenderer";
|
|
9
|
+
export { ImageUploadField } from "./components/ImageUploadField";
|
|
10
|
+
export { ArtistEditor } from "./components/ArtistEditor";
|
|
11
|
+
export { useImageDropZone } from "./hooks/useImageDropZone";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArtistEditor
|
|
3
|
+
} from "./chunk-VIJV6FLT.js";
|
|
4
|
+
import {
|
|
5
|
+
BlockEditor
|
|
6
|
+
} from "./chunk-CLC3FEL2.js";
|
|
7
|
+
import {
|
|
8
|
+
BUILT_IN_BLOCKS,
|
|
9
|
+
createEmptyBlock,
|
|
10
|
+
getBlockDef
|
|
11
|
+
} from "./chunk-EERQYNER.js";
|
|
12
|
+
import {
|
|
13
|
+
createHtmlRenderer,
|
|
14
|
+
h,
|
|
15
|
+
nl2br
|
|
16
|
+
} from "./chunk-62BAOSP6.js";
|
|
17
|
+
import {
|
|
18
|
+
createSerializer
|
|
19
|
+
} from "./chunk-PPVXNJWI.js";
|
|
20
|
+
import {
|
|
21
|
+
BlockRenderer
|
|
22
|
+
} from "./chunk-CJGZUEQO.js";
|
|
23
|
+
import {
|
|
24
|
+
ImageUploadField
|
|
25
|
+
} from "./chunk-G6J2DCC5.js";
|
|
26
|
+
import {
|
|
27
|
+
useImageDropZone
|
|
28
|
+
} from "./chunk-QR225IXX.js";
|
|
29
|
+
import {
|
|
30
|
+
ALLOWED_IMAGE_TYPES,
|
|
31
|
+
resizeImageIfNeeded,
|
|
32
|
+
validateImageFile
|
|
33
|
+
} from "./chunk-3R3HAGQL.js";
|
|
34
|
+
import {
|
|
35
|
+
BlockEditorProvider,
|
|
36
|
+
useBlockEditorContext
|
|
37
|
+
} from "./chunk-CYMYM7LP.js";
|
|
38
|
+
import "./chunk-N3ETBM74.js";
|
|
39
|
+
export {
|
|
40
|
+
ALLOWED_IMAGE_TYPES,
|
|
41
|
+
ArtistEditor,
|
|
42
|
+
BUILT_IN_BLOCKS,
|
|
43
|
+
BlockEditor,
|
|
44
|
+
BlockEditorProvider,
|
|
45
|
+
BlockRenderer,
|
|
46
|
+
ImageUploadField,
|
|
47
|
+
createEmptyBlock,
|
|
48
|
+
createHtmlRenderer,
|
|
49
|
+
createSerializer,
|
|
50
|
+
getBlockDef,
|
|
51
|
+
h,
|
|
52
|
+
nl2br,
|
|
53
|
+
resizeImageIfNeeded,
|
|
54
|
+
useBlockEditorContext,
|
|
55
|
+
useImageDropZone,
|
|
56
|
+
validateImageFile
|
|
57
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface BlockData {
|
|
2
|
+
id: number;
|
|
3
|
+
type: string;
|
|
4
|
+
text?: string;
|
|
5
|
+
en?: string;
|
|
6
|
+
src?: string;
|
|
7
|
+
src1?: string;
|
|
8
|
+
src2?: string;
|
|
9
|
+
src3?: string;
|
|
10
|
+
cap?: string;
|
|
11
|
+
attr?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
role?: string;
|
|
14
|
+
bio?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
url?: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
q?: string;
|
|
19
|
+
a?: string;
|
|
20
|
+
size?: string;
|
|
21
|
+
items?: Record<string, string>[];
|
|
22
|
+
}
|
|
23
|
+
export interface BlockDef {
|
|
24
|
+
type: string;
|
|
25
|
+
label: string;
|
|
26
|
+
icon: string;
|
|
27
|
+
desc?: string;
|
|
28
|
+
cats?: string[];
|
|
29
|
+
createEmpty: (id: number) => BlockData;
|
|
30
|
+
}
|
|
31
|
+
export interface UploadResult {
|
|
32
|
+
url: string;
|
|
33
|
+
key?: string;
|
|
34
|
+
}
|
|
35
|
+
export type UploadFn = (file: File) => Promise<UploadResult>;
|
|
36
|
+
export type ErrorFn = (message: string) => void;
|
|
37
|
+
export interface ResizeResult {
|
|
38
|
+
file: File;
|
|
39
|
+
wasResized: boolean;
|
|
40
|
+
originalSize: number;
|
|
41
|
+
newSize: number;
|
|
42
|
+
}
|
|
43
|
+
export interface BlockEditorConfig {
|
|
44
|
+
/** Available block definitions */
|
|
45
|
+
blocks: BlockDef[];
|
|
46
|
+
/** Serialization marker name (e.g. "nbe-blocks:") */
|
|
47
|
+
marker: string;
|
|
48
|
+
/** CSS class prefix for rendered HTML (e.g. "nbe-pvb") */
|
|
49
|
+
cssPrefix: string;
|
|
50
|
+
/** Enable drag-and-drop reordering (default: true) */
|
|
51
|
+
enableDragDrop?: boolean;
|
|
52
|
+
/** Enable category-based block filtering (default: false) */
|
|
53
|
+
enableCategoryFilter?: boolean;
|
|
54
|
+
/** Category list (required when enableCategoryFilter is true) */
|
|
55
|
+
categories?: string[];
|
|
56
|
+
/** Category → CSS class mapping for themed blocks */
|
|
57
|
+
catClasses?: Record<string, string>;
|
|
58
|
+
/** Category-keyed empty templates */
|
|
59
|
+
templates?: Record<string, Omit<BlockData, "id">[]>;
|
|
60
|
+
/** Category-keyed sample content */
|
|
61
|
+
samples?: Record<string, Omit<BlockData, "id">[]>;
|
|
62
|
+
}
|
|
63
|
+
export interface ArtistBioData {
|
|
64
|
+
text: string;
|
|
65
|
+
mainImage: string;
|
|
66
|
+
gallery: string[];
|
|
67
|
+
}
|
package/dist/types.js
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@withwiz/block-editor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Block-based content editor for web publishing",
|
|
5
|
+
"private": false,
|
|
6
|
+
"files": ["dist", "styles"],
|
|
7
|
+
"typesVersions": {
|
|
8
|
+
"*": {
|
|
9
|
+
"*": ["./dist/*"]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./types": "./dist/types.js",
|
|
15
|
+
"./blocks/built-in": "./dist/blocks/built-in.js",
|
|
16
|
+
"./components/BlockEditor": "./dist/components/BlockEditor.js",
|
|
17
|
+
"./components/BlockRenderer": "./dist/components/BlockRenderer.js",
|
|
18
|
+
"./components/ImageUploadField": "./dist/components/ImageUploadField.js",
|
|
19
|
+
"./components/ArtistEditor": "./dist/components/ArtistEditor.js",
|
|
20
|
+
"./context/BlockEditorProvider": "./dist/context/BlockEditorProvider.js",
|
|
21
|
+
"./core/serializer": "./dist/core/serializer.js",
|
|
22
|
+
"./core/html-renderer": "./dist/core/html-renderer.js",
|
|
23
|
+
"./core/image-resize": "./dist/core/image-resize.js",
|
|
24
|
+
"./hooks/useImageDropZone": "./dist/hooks/useImageDropZone.js",
|
|
25
|
+
"./styles/editor.css": "./styles/editor.css",
|
|
26
|
+
"./styles/preview.css": "./styles/preview.css",
|
|
27
|
+
"./styles/artist.css": "./styles/artist.css"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup && tsc --emitDeclarationOnly --skipLibCheck",
|
|
31
|
+
"build:js": "tsup",
|
|
32
|
+
"build:types": "tsc --emitDeclarationOnly --skipLibCheck"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "19.2.7",
|
|
39
|
+
"@types/react-dom": "19.2.3",
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5"
|
|
42
|
+
}
|
|
43
|
+
}
|