@blocklet/editor 1.6.233 → 1.6.236

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.
Files changed (42) hide show
  1. package/lib/config.js +3 -11
  2. package/lib/ext/AIPlugin/index.js +1 -1
  3. package/lib/ext/Aide/context.d.ts +2 -4
  4. package/lib/ext/Aide/context.js +9 -57
  5. package/lib/ext/Alert/AlertNode.js +1 -1
  6. package/lib/ext/ContentLocale.d.ts +7 -0
  7. package/lib/ext/ContentLocale.js +15 -0
  8. package/lib/ext/FilePlugin/FileNode.d.ts +44 -0
  9. package/lib/ext/FilePlugin/FileNode.js +194 -0
  10. package/lib/ext/FilePlugin/FilePlugin.d.ts +7 -0
  11. package/lib/ext/FilePlugin/FilePlugin.js +27 -0
  12. package/lib/ext/FilePlugin/index.d.ts +2 -0
  13. package/lib/ext/FilePlugin/index.js +2 -0
  14. package/lib/ext/PagesKitComponent/PagesKitComponentNode.d.ts +31 -0
  15. package/lib/ext/PagesKitComponent/PagesKitComponentNode.js +96 -0
  16. package/lib/ext/PagesKitComponent/PagesKitComponentPlugin.d.ts +18 -0
  17. package/lib/ext/PagesKitComponent/PagesKitComponentPlugin.js +38 -0
  18. package/lib/ext/PagesKitComponent/PagesKitComponentRenderer.d.ts +9 -0
  19. package/lib/ext/PagesKitComponent/PagesKitComponentRenderer.js +75 -0
  20. package/lib/ext/PagesKitComponent/PropertyField.d.ts +13 -0
  21. package/lib/ext/PagesKitComponent/PropertyField.js +65 -0
  22. package/lib/ext/PagesKitComponent/utils.d.ts +25 -0
  23. package/lib/ext/PagesKitComponent/utils.js +16 -0
  24. package/lib/ext/PdfPlugin/PdfNode.d.ts +7 -7
  25. package/lib/ext/PdfPlugin/PdfNode.js +8 -6
  26. package/lib/ext/SubpageListingPlugin/SubpageListingComponent.js +1 -1
  27. package/lib/ext/VideoPlugin/VideoPlugin.d.ts +1 -1
  28. package/lib/ext/VideoPlugin/VideoPlugin.js +2 -3
  29. package/lib/ext/utils.d.ts +1 -0
  30. package/lib/ext/utils.js +3 -0
  31. package/lib/main/editor.js +3 -1
  32. package/lib/main/nodes/ImageComponent.js +3 -3
  33. package/lib/main/nodes/ImageNode.css +10 -3
  34. package/lib/main/nodes/PlaygroundNodes.js +4 -0
  35. package/lib/main/plugins/ComponentPickerPlugin/index.js +23 -5
  36. package/lib/main/plugins/ImagesPlugin/index.d.ts +1 -0
  37. package/lib/main/plugins/ImagesPlugin/index.js +3 -0
  38. package/lib/main/plugins/ToolbarPlugin/index.js +1 -5
  39. package/lib/main/themes/customTheme.js +1 -1
  40. package/lib/main/themes/defaultTheme.js +7 -5
  41. package/lib/main/ui/ImageResizer.js +2 -2
  42. package/package.json +6 -4
package/lib/config.js CHANGED
@@ -1,20 +1,12 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import memoize from 'lodash/memoize';
3
2
  import { createContext, useContext, useMemo } from 'react';
4
3
  const EditorConfigContext = createContext({});
5
4
  export function EditorConfigProvider({ children, value }) {
5
+ const parentCtx = useContext(EditorConfigContext);
6
6
  const _value = useMemo(() => {
7
- const result = { ...value };
8
- if (result.AI) {
9
- result.AI.fetchTemplateTags = result.AI.fetchTemplateTags ? memoize(result.AI.fetchTemplateTags) : undefined;
10
- // 注意 memoize 默认以首个参数作为 cache key, 两个属性值相同但引用不同的 object 会被认为是不同的 key
11
- result.AI.fetchTemplates = result.AI.fetchTemplates
12
- ? memoize(result.AI.fetchTemplates, (arg) => JSON.stringify(arg))
13
- : undefined;
14
- result.AI.checkAvailable = memoize(result.AI.checkAvailable);
15
- }
7
+ const result = { ...parentCtx, ...value };
16
8
  return result;
17
- }, [value]);
9
+ }, [value, parentCtx]);
18
10
  return _jsx(EditorConfigContext.Provider, { value: _value, children: children });
19
11
  }
20
12
  export const useEditorConfig = () => useContext(EditorConfigContext);
@@ -189,7 +189,7 @@ export default function AidePluginWrapper() {
189
189
  const _copy = (output) => {
190
190
  copy(output);
191
191
  };
192
- return (_jsx(AideProvider, { checkAvailable: AI.checkAvailable, fetchTemplateTags: AI.fetchTemplateTags, fetchTemplates: AI.fetchTemplates, completions: AI.completions, replaceSelection: _replaceSelection, copy: _copy, insertBelow: _insertBelow, children: _jsx(AidePlugin, {}) }));
192
+ return (_jsx(AideProvider, { checkAvailable: AI.checkAvailable, completions: AI.completions, replaceSelection: _replaceSelection, copy: _copy, insertBelow: _insertBelow, children: _jsx(AidePlugin, {}) }));
193
193
  }
194
194
  return null;
195
195
  }
@@ -1,10 +1,8 @@
1
1
  import { ReactNode } from 'react';
2
- import type { Completions, FetchTemplates, FetchTemplatesRequest, FetchTemplateTags, Mode, ParameterizedTemplate, ParameterizedTemplateCompletionsPayload, Status } from './types';
2
+ import type { Completions, FetchTemplatesRequest, Mode, ParameterizedTemplate, ParameterizedTemplateCompletionsPayload, Status } from './types';
3
3
  import { Template } from './types';
4
4
  interface AideProviderProps {
5
5
  children: ReactNode;
6
- fetchTemplateTags?: FetchTemplateTags;
7
- fetchTemplates?: FetchTemplates;
8
6
  completions: Completions;
9
7
  checkAvailable: () => Promise<boolean> | boolean;
10
8
  replaceSelection?: (selection: any, output: string) => void;
@@ -46,5 +44,5 @@ interface AideContextType extends AideContextState, Pick<AideProviderProps, 'rep
46
44
  }
47
45
  export declare const AideContext: import("react").Context<AideContextType>;
48
46
  export declare const useAideContext: () => AideContextType;
49
- export declare function AideProvider({ checkAvailable, fetchTemplateTags, fetchTemplates, completions, replaceSelection, insertBelow, copy, children, }: AideProviderProps): import("react/jsx-runtime").JSX.Element;
47
+ export declare function AideProvider({ checkAvailable, completions, replaceSelection, insertBelow, copy, children, }: AideProviderProps): import("react/jsx-runtime").JSX.Element;
50
48
  export {};
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createContext, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
3
- import { useGetState } from 'ahooks';
2
+ import { createContext, useCallback, useContext, useMemo, useRef } from 'react';
3
+ import { useGetState, useRequest } from 'ahooks';
4
4
  import builtinTemplates from './builtin-templates';
5
5
  import { Template } from './types';
6
6
  export const AideContext = createContext({});
7
7
  export const useAideContext = () => useContext(AideContext);
8
- export function AideProvider({ checkAvailable, fetchTemplateTags, fetchTemplates, completions, replaceSelection, insertBelow, copy, children, }) {
8
+ export function AideProvider({ checkAvailable, completions, replaceSelection, insertBelow, copy, children, }) {
9
9
  const [state, setState, getState] = useGetState({
10
10
  available: false,
11
11
  templates: builtinTemplates,
@@ -39,60 +39,12 @@ export function AideProvider({ checkAvailable, fetchTemplateTags, fetchTemplates
39
39
  ...params,
40
40
  }));
41
41
  };
42
- const loadMoreTemplates = async (params = {}) => {
43
- if (fetchTemplates) {
44
- try {
45
- setState((prev) => ({ ...prev, externalTemplates: { ...prev.externalTemplates, loading: true } }));
46
- const { offset = state.externalTemplates.templates.length, limit = 20, tag } = params;
47
- const result = await fetchTemplates({ offset, limit: limit + 1, tag });
48
- if (result.length > 0) {
49
- const hasMore = result.length === limit + 1;
50
- const templates = hasMore ? result.slice(0, -1) : result;
51
- setState((prev) => ({
52
- ...prev,
53
- externalTemplates: {
54
- ...prev.externalTemplates,
55
- templates: offset === 0 ? templates : [...prev.externalTemplates.templates, ...templates],
56
- hasMore,
57
- tag,
58
- loading: false,
59
- },
60
- }));
61
- }
62
- }
63
- catch (e) {
64
- console.error(e);
65
- }
66
- }
67
- };
68
- useEffect(() => {
69
- const init = async () => {
70
- const available = await checkAvailable();
71
- if (available) {
72
- setState((prev) => ({ ...prev, available }));
73
- // load templates & tags
74
- const loadTemplateTags = async () => {
75
- if (fetchTemplateTags) {
76
- try {
77
- const tags = await fetchTemplateTags();
78
- setState((prev) => ({
79
- ...prev,
80
- externalTemplates: {
81
- ...prev.externalTemplates,
82
- tags,
83
- },
84
- }));
85
- }
86
- catch (e) {
87
- console.error(e);
88
- }
89
- }
90
- };
91
- await Promise.all([loadTemplateTags(), loadMoreTemplates()]);
92
- }
93
- };
94
- init();
95
- }, []);
42
+ // @deprecated
43
+ const loadMoreTemplates = async () => { };
44
+ useRequest(async () => {
45
+ const available = await checkAvailable();
46
+ setState((prev) => ({ ...prev, available }));
47
+ }, { cacheKey: 'editor-aide-available' });
96
48
  const activateAI = useCallback(
97
49
  // eslint-disable-next-line require-await
98
50
  async ({ mode = 'normal', selectionText, selection }) => {
@@ -86,7 +86,7 @@ export class AlertNode extends DecoratorBlockNode {
86
86
  editor.update(() => {
87
87
  this.setText(text);
88
88
  if (selection) {
89
- $setSelection(selection);
89
+ $setSelection(selection.clone());
90
90
  }
91
91
  });
92
92
  };
@@ -0,0 +1,7 @@
1
+ import { PropsWithChildren } from 'react';
2
+ interface ContextType {
3
+ locale: string;
4
+ }
5
+ export declare const useContentLocale: () => string;
6
+ export declare const ContentLocaleProvider: ({ locale, children }: PropsWithChildren & ContextType) => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import { createContext, useContext, useMemo } from 'react';
4
+ const ContentLocaleContext = createContext(null);
5
+ // 该 hook 关注 editor content 的 locale, 区别于 LocaleContext
6
+ // (编辑 post 翻译版本时, 会切换 ContentLocaleContext)
7
+ export const useContentLocale = () => {
8
+ const { locale: contextLocale } = useLocaleContext();
9
+ const ctx = useContext(ContentLocaleContext);
10
+ return ctx?.locale || contextLocale;
11
+ };
12
+ export const ContentLocaleProvider = ({ locale, children }) => {
13
+ const value = useMemo(() => ({ locale }), [locale]);
14
+ return _jsx(ContentLocaleContext.Provider, { value: value, children: children });
15
+ };
@@ -0,0 +1,44 @@
1
+ /// <reference types="react" />
2
+ import type { DOMConversionMap, DOMExportOutput, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread } from 'lexical';
3
+ import { DecoratorNode } from 'lexical';
4
+ export declare const getAbsoluteUrl: ({ fileUrl, name }: {
5
+ fileUrl: string;
6
+ name?: string | undefined;
7
+ }) => string;
8
+ export interface FilePayload {
9
+ key?: NodeKey;
10
+ src: string;
11
+ name?: string;
12
+ mimetype?: string;
13
+ width?: number | string;
14
+ height?: number | string;
15
+ }
16
+ export type SerializedFileNode = Spread<{
17
+ height?: number | string;
18
+ src: string;
19
+ name?: string;
20
+ mimetype?: string;
21
+ width?: number | string;
22
+ }, SerializedLexicalNode>;
23
+ export declare class FileNode extends DecoratorNode<JSX.Element> {
24
+ __src: string;
25
+ __name?: string;
26
+ __mimetype?: string;
27
+ __width: 'inherit' | number | string;
28
+ __height: 'inherit' | number | string;
29
+ static getType(): string;
30
+ static clone(node: FileNode): FileNode;
31
+ static importJSON(serializedNode: SerializedFileNode): FileNode;
32
+ exportDOM(): DOMExportOutput;
33
+ static importDOM(): DOMConversionMap | null;
34
+ constructor(src: string, name?: string, mimetype?: string, width?: 'inherit' | number | string, height?: 'inherit' | number | string, key?: NodeKey);
35
+ exportJSON(): SerializedFileNode;
36
+ setWidthAndHeight(width: 'inherit' | number, height: 'inherit' | number): void;
37
+ createDOM(config: EditorConfig): HTMLElement;
38
+ updateDOM(): false;
39
+ getSrc(): string;
40
+ setSrc(src: string): void;
41
+ decorate(): JSX.Element;
42
+ }
43
+ export declare function $createFileNode({ height, src, name, mimetype, width, key }: FilePayload): FileNode;
44
+ export declare function $isFileNode(node: LexicalNode | null | undefined): node is FileNode;
@@ -0,0 +1,194 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Tooltip } from '@mui/material';
3
+ import { useEffect, Suspense, useState } from 'react';
4
+ import { Link } from 'react-router-dom';
5
+ import joinURL from 'url-join';
6
+ import { Icon } from '@iconify/react';
7
+ import { $applyNodeReplacement, DecoratorNode } from 'lexical';
8
+ import mime from 'mime-types';
9
+ import TablerFileIcon from '@iconify/icons-tabler/file';
10
+ import { withQuery } from 'ufo';
11
+ const iconSize = 80;
12
+ const baseColor = 'primary.main';
13
+ const FileComponent = ({ src, mimetype, name }) => {
14
+ const [ext, setExt] = useState('file');
15
+ useEffect(() => {
16
+ setExt(mime.extension(mimetype || '') || 'file');
17
+ }, [mimetype]);
18
+ return (_jsx(Tooltip, { title: name, placement: "top", children: _jsxs(Box, { component: Link, to: src, target: "_blank", sx: {
19
+ // remove a tag underline and color
20
+ color: baseColor,
21
+ textDecoration: 'none',
22
+ display: 'inline-flex',
23
+ flexDirection: 'column',
24
+ alignItems: 'center',
25
+ gap: 1,
26
+ pt: 1.25,
27
+ mt: 1,
28
+ border: 2,
29
+ borderColor: baseColor,
30
+ borderRadius: 1,
31
+ transition: 'all 0.3s',
32
+ userSelect: 'none',
33
+ ':hover': {
34
+ opacity: 0.75,
35
+ },
36
+ }, children: [_jsxs(Box, { sx: {
37
+ position: 'relative',
38
+ display: 'inline-flex',
39
+ }, children: [_jsx(Icon, { icon: TablerFileIcon, style: { fontSize: iconSize } }), _jsx(Box, { sx: {
40
+ position: 'absolute',
41
+ left: 0,
42
+ right: 0,
43
+ top: '50%',
44
+ textAlign: 'center',
45
+ margin: 'auto',
46
+ fontWeight: 900,
47
+ maxWidth: iconSize * 0.45,
48
+ whiteSpace: 'nowrap',
49
+ overflow: 'hidden',
50
+ textOverflow: 'ellipsis',
51
+ fontSize: 14,
52
+ }, children: ext })] }), _jsx(Box, { sx: {
53
+ bgcolor: baseColor,
54
+ color: 'white',
55
+ px: 1,
56
+ lineHeight: 2,
57
+ fontSize: 13,
58
+ maxWidth: iconSize * 1.5,
59
+ whiteSpace: 'nowrap',
60
+ overflow: 'hidden',
61
+ display: 'inline-block',
62
+ '@keyframes scroll': {
63
+ '0%': {
64
+ ml: 0,
65
+ transform: 'translateX(0)',
66
+ },
67
+ '100%': {
68
+ ml: '100%',
69
+ transform: 'translateX(-100%)',
70
+ },
71
+ },
72
+ }, children: _jsx(Box, { sx: {
73
+ animation: 'scroll linear 5s alternate infinite',
74
+ float: 'left',
75
+ }, children: name }) })] }) }));
76
+ };
77
+ export const getAbsoluteUrl = ({ fileUrl, name }) => {
78
+ if (!fileUrl || typeof fileUrl !== 'string') {
79
+ return '';
80
+ }
81
+ if (/^https?:\/\//.test(fileUrl)) {
82
+ return withQuery(fileUrl, {
83
+ filename: name,
84
+ });
85
+ }
86
+ // @ts-ignore
87
+ const { componentMountPoints = [] } = window.blocklet;
88
+ const mediaKit = componentMountPoints.find((x) => x.did === 'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9');
89
+ const realUrl = mediaKit ? joinURL(window.location.origin, mediaKit.mountPoint || '/', '/uploads', fileUrl) : fileUrl;
90
+ return withQuery(realUrl, {
91
+ filename: name,
92
+ });
93
+ };
94
+ function convertFileElement(domNode) {
95
+ if (domNode instanceof HTMLObjectElement) {
96
+ // @ts-ignore
97
+ const { data, width, height, type, alt } = domNode;
98
+ const node = $createFileNode({ height, width, src: data, mimetype: type, name: alt });
99
+ return { node };
100
+ }
101
+ return null;
102
+ }
103
+ export class FileNode extends DecoratorNode {
104
+ __src;
105
+ __name;
106
+ __mimetype;
107
+ __width;
108
+ __height;
109
+ static getType() {
110
+ return 'file';
111
+ }
112
+ static clone(node) {
113
+ return new FileNode(node.__src, node.__name, node.__mimetype, node.__width, node.__height, node.__key);
114
+ }
115
+ static importJSON(serializedNode) {
116
+ const { height, width, src, mimetype, name } = serializedNode;
117
+ const node = $createFileNode({
118
+ height,
119
+ src,
120
+ width,
121
+ mimetype,
122
+ name,
123
+ });
124
+ return node;
125
+ }
126
+ exportDOM() {
127
+ const element = document.createElement('object');
128
+ element.setAttribute('data', this.__src);
129
+ element.setAttribute('width', this.__width.toString());
130
+ element.setAttribute('height', this.__height.toString());
131
+ element.setAttribute('type', this.__mimetype || 'image/png');
132
+ element.setAttribute('loading', 'lazy');
133
+ element.setAttribute('alt', this.__name || '');
134
+ return { element };
135
+ }
136
+ static importDOM() {
137
+ return {
138
+ object: (node) => ({
139
+ conversion: convertFileElement,
140
+ priority: 0,
141
+ }),
142
+ };
143
+ }
144
+ constructor(src, name, mimetype, width, height, key) {
145
+ super(key);
146
+ this.__src = src;
147
+ this.__name = name;
148
+ this.__mimetype = mimetype;
149
+ this.__width = width || 'inherit';
150
+ this.__height = height || 'inherit';
151
+ }
152
+ exportJSON() {
153
+ return {
154
+ height: this.__height === 'inherit' ? 0 : this.__height,
155
+ src: this.getSrc(),
156
+ type: 'file',
157
+ version: 1,
158
+ width: this.__width === 'inherit' ? 0 : this.__width,
159
+ name: this.__name,
160
+ mimetype: this.__mimetype,
161
+ };
162
+ }
163
+ setWidthAndHeight(width, height) {
164
+ const writable = this.getWritable();
165
+ writable.__width = width;
166
+ writable.__height = height;
167
+ }
168
+ createDOM(config) {
169
+ const span = document.createElement('span');
170
+ return span;
171
+ }
172
+ updateDOM() {
173
+ return false;
174
+ }
175
+ getSrc() {
176
+ return this.__src;
177
+ }
178
+ setSrc(src) {
179
+ const writable = this.getWritable();
180
+ writable.__src = src;
181
+ }
182
+ decorate() {
183
+ return (_jsx(Suspense, { fallback: null, children: _jsx(FileComponent, { src: getAbsoluteUrl({
184
+ fileUrl: this.__src,
185
+ name: this.__name,
186
+ }), mimetype: this.__mimetype, name: this.__name }) }));
187
+ }
188
+ }
189
+ export function $createFileNode({ height, src, name, mimetype, width, key }) {
190
+ return $applyNodeReplacement(new FileNode(src, name, mimetype, width, height, key));
191
+ }
192
+ export function $isFileNode(node) {
193
+ return node instanceof FileNode;
194
+ }
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import { LexicalCommand } from 'lexical';
3
+ import { FilePayload } from './FileNode';
4
+ export type InsertFilePayload = Readonly<FilePayload>;
5
+ export declare const INSERT_FILE_COMMAND: LexicalCommand<InsertFilePayload>;
6
+ export declare function FilePlugin(): JSX.Element | null;
7
+ export declare const isFile: (filename: string) => string | undefined;
@@ -0,0 +1,27 @@
1
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
2
+ import { $wrapNodeInElement, mergeRegister } from '@lexical/utils';
3
+ import { $createParagraphNode, $insertNodes, $isRootOrShadowRoot, COMMAND_PRIORITY_EDITOR, createCommand, } from 'lexical';
4
+ import { useEffect } from 'react';
5
+ import { $createFileNode, FileNode } from './FileNode';
6
+ export const INSERT_FILE_COMMAND = createCommand('INSERT_FILE_COMMAND');
7
+ export function FilePlugin() {
8
+ const [editor] = useLexicalComposerContext();
9
+ useEffect(() => {
10
+ if (!editor.hasNodes([FileNode])) {
11
+ throw new Error('FilePlugin: FileNode not registered on editor');
12
+ }
13
+ return mergeRegister(editor.registerCommand(INSERT_FILE_COMMAND, (payload) => {
14
+ const fileNode = $createFileNode(payload);
15
+ $insertNodes([fileNode]);
16
+ if ($isRootOrShadowRoot(fileNode.getParentOrThrow())) {
17
+ $wrapNodeInElement(fileNode, $createParagraphNode).selectEnd();
18
+ }
19
+ return true;
20
+ }, COMMAND_PRIORITY_EDITOR));
21
+ }, [editor]);
22
+ return null;
23
+ }
24
+ export const isFile = (filename) => {
25
+ const ext = filename.split('.').pop();
26
+ return ext;
27
+ };
@@ -0,0 +1,2 @@
1
+ export * from './FilePlugin';
2
+ export { FileNode } from './FileNode';
@@ -0,0 +1,2 @@
1
+ export * from './FilePlugin';
2
+ export { FileNode } from './FileNode';
@@ -0,0 +1,31 @@
1
+ /// <reference types="react" />
2
+ import type { DOMConversionMap, DOMExportOutput, EditorConfig, ElementFormatType, LexicalEditor, LexicalNode, NodeKey, Spread } from 'lexical';
3
+ import { DecoratorBlockNode, SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
4
+ import type { Properties } from './utils';
5
+ export interface ComponentData {
6
+ id: string;
7
+ name: string;
8
+ properties?: Properties;
9
+ }
10
+ export type SerializedPagesKitComponentNode = Spread<{
11
+ data: ComponentData;
12
+ type: 'pages-kit-component';
13
+ version: 1;
14
+ }, SerializedDecoratorBlockNode>;
15
+ export declare class PagesKitComponentNode extends DecoratorBlockNode {
16
+ __data: ComponentData;
17
+ static getType(): string;
18
+ static clone(node: PagesKitComponentNode): PagesKitComponentNode;
19
+ static importJSON(serializedNode: SerializedPagesKitComponentNode): PagesKitComponentNode;
20
+ exportJSON(): SerializedPagesKitComponentNode;
21
+ constructor(data: ComponentData, format?: ElementFormatType, key?: NodeKey);
22
+ exportDOM(): DOMExportOutput;
23
+ static importDOM(): DOMConversionMap | null;
24
+ updateDOM(): false;
25
+ getId(): string;
26
+ setProperties(properties: any): void;
27
+ decorate(editor: LexicalEditor, config: EditorConfig): JSX.Element;
28
+ isInline(): false;
29
+ }
30
+ export declare function $createPagesKitComponentNode(data: ComponentData): PagesKitComponentNode;
31
+ export declare function $isPagesKitComponentNode(node: PagesKitComponentNode | LexicalNode | null | undefined): node is PagesKitComponentNode;
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { BlockWithAlignableContents } from '@lexical/react/LexicalBlockWithAlignableContents';
3
+ import { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
4
+ import { PagesKitComponentRenderer } from './PagesKitComponentRenderer';
5
+ function PagesKitComponent({ className, format, nodeKey, data, onPropertiesChange }) {
6
+ return (_jsx(BlockWithAlignableContents, { className: className, format: format, nodeKey: nodeKey, children: _jsx(PagesKitComponentRenderer, { id: data.id, name: data.name, properties: data.properties, onPropertiesChange: onPropertiesChange }) }));
7
+ }
8
+ function convertPagesKitComponentElement(domNode) {
9
+ const pagesKitComponentStr = domNode.getAttribute('data-lexical-pages-kit-component');
10
+ try {
11
+ const parsed = JSON.parse(pagesKitComponentStr);
12
+ if (parsed) {
13
+ const node = $createPagesKitComponentNode(parsed);
14
+ return { node };
15
+ }
16
+ }
17
+ catch (e) {
18
+ console.warn(`Failed to parse: ${pagesKitComponentStr}`, e);
19
+ }
20
+ return null;
21
+ }
22
+ export class PagesKitComponentNode extends DecoratorBlockNode {
23
+ __data;
24
+ static getType() {
25
+ return 'pages-kit-component';
26
+ }
27
+ static clone(node) {
28
+ return new PagesKitComponentNode({ ...node.__data }, node.__format, node.__key);
29
+ }
30
+ static importJSON(serializedNode) {
31
+ const node = $createPagesKitComponentNode(serializedNode.data);
32
+ node.setFormat(serializedNode.format);
33
+ return node;
34
+ }
35
+ exportJSON() {
36
+ return {
37
+ ...super.exportJSON(),
38
+ type: 'pages-kit-component',
39
+ version: 1,
40
+ data: this.__data,
41
+ };
42
+ }
43
+ constructor(data, format, key) {
44
+ super(format, key);
45
+ this.__data = data;
46
+ }
47
+ exportDOM() {
48
+ const element = document.createElement('div');
49
+ element.setAttribute('data-lexical-pages-kit-component', JSON.stringify(this.__data));
50
+ return { element };
51
+ }
52
+ static importDOM() {
53
+ return {
54
+ div: (domNode) => {
55
+ if (!domNode.hasAttribute('data-lexical-pages-kit-component')) {
56
+ return null;
57
+ }
58
+ return {
59
+ conversion: convertPagesKitComponentElement,
60
+ priority: 1,
61
+ };
62
+ },
63
+ };
64
+ }
65
+ updateDOM() {
66
+ return false;
67
+ }
68
+ getId() {
69
+ return this.__data.id;
70
+ }
71
+ setProperties(properties) {
72
+ const writable = this.getWritable();
73
+ writable.__data = { ...writable.__data, properties };
74
+ }
75
+ decorate(editor, config) {
76
+ const embedBlockTheme = config.theme.embedBlock || {};
77
+ const className = {
78
+ base: embedBlockTheme.base || '',
79
+ focus: embedBlockTheme.focus || '',
80
+ };
81
+ return (_jsx(PagesKitComponent, { className: className, format: this.__format, nodeKey: this.getKey(), data: this.__data, onPropertiesChange: (props) => {
82
+ editor.update(() => {
83
+ this.setProperties(props);
84
+ });
85
+ } }));
86
+ }
87
+ isInline() {
88
+ return false;
89
+ }
90
+ }
91
+ export function $createPagesKitComponentNode(data) {
92
+ return new PagesKitComponentNode(data);
93
+ }
94
+ export function $isPagesKitComponentNode(node) {
95
+ return node instanceof PagesKitComponentNode;
96
+ }
@@ -0,0 +1,18 @@
1
+ /// <reference types="react" />
2
+ import { LexicalCommand } from 'lexical';
3
+ type CommandPayload = {
4
+ id: string;
5
+ name: string;
6
+ };
7
+ export declare const INSERT_PAGES_KIT_COMPONENT_COMMAND: LexicalCommand<CommandPayload>;
8
+ export declare function PagesKitComponentPlugin(): JSX.Element | null;
9
+ export declare function usePagesKitComponents(): {
10
+ pagesKitComponents: {
11
+ id: string;
12
+ name: string;
13
+ properties?: {
14
+ [key: string]: any;
15
+ } | undefined;
16
+ }[];
17
+ };
18
+ export {};
@@ -0,0 +1,38 @@
1
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
2
+ import { $insertNodeToNearestRoot } from '@lexical/utils';
3
+ import { COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
4
+ import { useEffect } from 'react';
5
+ import { useRequest } from 'ahooks';
6
+ import { joinURL } from 'ufo';
7
+ import { $createPagesKitComponentNode, PagesKitComponentNode } from './PagesKitComponentNode';
8
+ import { getBlockletMountPointInfo, isBlockletRunning } from '../utils';
9
+ import { mode } from './utils';
10
+ export const INSERT_PAGES_KIT_COMPONENT_COMMAND = createCommand('INSERT_PAGES_KIT_COMPONENT_COMMAND');
11
+ export function PagesKitComponentPlugin() {
12
+ const [editor] = useLexicalComposerContext();
13
+ useEffect(() => {
14
+ if (!editor.hasNodes([PagesKitComponentNode])) {
15
+ throw new Error('PagesKitComponentPlugin: PagesKitComponentNode not registered on editor');
16
+ }
17
+ return editor.registerCommand(INSERT_PAGES_KIT_COMPONENT_COMMAND, (payload) => {
18
+ const node = $createPagesKitComponentNode(payload);
19
+ $insertNodeToNearestRoot(node);
20
+ return true;
21
+ }, COMMAND_PRIORITY_EDITOR);
22
+ }, [editor]);
23
+ return null;
24
+ }
25
+ export function usePagesKitComponents() {
26
+ const { data: pagesKitComponents = [] } = useRequest(() => {
27
+ if (!isBlockletRunning('pages-kit')) {
28
+ return Promise.resolve([]);
29
+ }
30
+ return fetch(joinURL(getBlockletMountPointInfo('pages-kit').mountPoint || '/', `/api/components?mode=${mode}`))
31
+ .then((res) => res.json())
32
+ .then((res) => res?.components || [])
33
+ .catch((res) => []);
34
+ }, {
35
+ cacheKey: 'editor-pages-kit-components',
36
+ });
37
+ return { pagesKitComponents };
38
+ }
@@ -0,0 +1,9 @@
1
+ import { type Properties } from './utils';
2
+ type PagesKitComponentProps = {
3
+ id: string;
4
+ name: string;
5
+ properties?: Properties;
6
+ onPropertiesChange: (properties: Properties) => void;
7
+ };
8
+ export declare function PagesKitComponentRenderer({ id, name, properties, onPropertiesChange }: PagesKitComponentProps): import("react/jsx-runtime").JSX.Element | null;
9
+ export {};