@blockslides/react 0.2.0 → 0.3.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/dist/index.d.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import * as react_jsx_runtime_js from 'react/jsx-runtime.js';
2
- import { EditorOptions, Editor, MarkViewRendererOptions, MarkView, MarkViewProps, MarkViewRenderer, NodeViewProps, NodeViewRendererOptions, NodeView, NodeViewRendererProps, NodeViewRenderer } from '@blockslides/core';
2
+ import * as _blockslides_core from '@blockslides/core';
3
+ import { EditorOptions, Editor, MarkViewRendererOptions, MarkView, MarkViewProps, MarkViewRenderer, NodeViewProps, NodeViewRendererOptions, NodeView, NodeViewRendererProps, NodeViewRenderer, JSONContent, AnyExtension } from '@blockslides/core';
3
4
  export * from '@blockslides/core';
4
5
  import * as React from 'react';
5
- import React__default, { DependencyList, ReactNode, HTMLAttributes, HTMLProps, ForwardedRef, ComponentProps, ComponentClass, FunctionComponent, ForwardRefExoticComponent, PropsWithoutRef, RefAttributes, ComponentType as ComponentType$1 } from 'react';
6
+ import React__default, { DependencyList, ReactNode, HTMLAttributes, HTMLProps, ForwardedRef, ComponentProps, ComponentClass, FunctionComponent, ForwardRefExoticComponent, PropsWithoutRef, RefAttributes, ComponentType as ComponentType$1, CSSProperties } from 'react';
6
7
  import { Node } from '@blockslides/pm/model';
7
8
  import { Decoration, DecorationSource } from '@blockslides/pm/view';
9
+ import * as packages_ai_context_src_templates_v1_presetTemplateBuilder_js from 'packages/ai-context/src/templates/v1/presetTemplateBuilder.js';
10
+ import * as _blockslides_extension_kit from '@blockslides/extension-kit';
11
+ import { ExtensionKitOptions } from '@blockslides/extension-kit';
8
12
  import { BubbleMenuPresetOptions } from '@blockslides/extension-bubble-menu-preset';
13
+ import { templatesV1 } from '@blockslides/ai-context';
9
14
 
10
15
  /**
11
16
  * The options for the `useEditor` hook.
@@ -287,6 +292,79 @@ declare class ReactNodeView<T = HTMLElement, Component extends ComponentType$1<R
287
292
  */
288
293
  declare function ReactNodeViewRenderer<T = HTMLElement>(component: ComponentType$1<ReactNodeViewProps<T>>, options?: Partial<ReactNodeViewRendererOptions>): NodeViewRenderer;
289
294
 
295
+ type BubbleMenuPresetProps = Omit<BubbleMenuPresetOptions, 'element' | 'pluginKey'> & React__default.HTMLAttributes<HTMLElement> & {
296
+ editor?: Editor | null;
297
+ };
298
+ declare const BubbleMenuPreset: React__default.ForwardRefExoticComponent<Omit<BubbleMenuPresetOptions, "element" | "pluginKey"> & React__default.HTMLAttributes<HTMLElement> & {
299
+ editor?: Editor | null;
300
+ } & React__default.RefAttributes<HTMLElement>>;
301
+
302
+ type PresetTemplates = ReturnType<typeof templatesV1.listPresetTemplates>;
303
+ type UseSlideEditorProps = {
304
+ /**
305
+ * Initial content for the editor. If omitted, a single preset slide is used.
306
+ */
307
+ content?: UseEditorOptions["content"];
308
+ /**
309
+ * Called on every update with the current JSON document.
310
+ */
311
+ onChange?: (doc: JSONContent, editor: Editor) => void;
312
+ /**
313
+ * Additional extensions to append after the ExtensionKit bundle.
314
+ */
315
+ extensions?: AnyExtension[];
316
+ /**
317
+ * Customize or disable pieces of ExtensionKit (e.g., bubbleMenu: false).
318
+ */
319
+ extensionKitOptions?: ExtensionKitOptions;
320
+ /**
321
+ * Optional preset list to power the add-slide button.
322
+ */
323
+ presetTemplates?: PresetTemplates;
324
+ /**
325
+ * Dependencies array forwarded to useEditor for re-instantiation control.
326
+ * Leave empty to avoid recreating the editor on prop changes.
327
+ */
328
+ deps?: DependencyList;
329
+ /**
330
+ * Called once when an editor instance is ready.
331
+ */
332
+ onEditorReady?: (editor: Editor) => void;
333
+ } & Omit<UseEditorOptions, "extensions" | "content">;
334
+ declare const useSlideEditor: ({ content, onChange, extensions, extensionKitOptions, presetTemplates, deps, onEditorReady, immediatelyRender, shouldRerenderOnTransaction, theme, editorProps, onUpdate, ...editorOptions }?: UseSlideEditorProps) => {
335
+ editor: Editor;
336
+ presets: templatesV1.PresetTemplate[];
337
+ };
338
+
339
+ declare const SlideEditor: React__default.ForwardRefExoticComponent<{
340
+ content?: UseEditorOptions["content"];
341
+ onChange?: (doc: _blockslides_core.JSONContent, editor: _blockslides_core.Editor) => void;
342
+ extensions?: _blockslides_core.AnyExtension[];
343
+ extensionKitOptions?: _blockslides_extension_kit.ExtensionKitOptions;
344
+ presetTemplates?: packages_ai_context_src_templates_v1_presetTemplateBuilder_js.PresetTemplate[];
345
+ deps?: React__default.DependencyList;
346
+ onEditorReady?: (editor: _blockslides_core.Editor) => void;
347
+ } & Omit<UseEditorOptions, "content" | "extensions"> & {
348
+ /**
349
+ * Toggle or customize the built-in BubbleMenuPreset.
350
+ * - true (default): render with defaults
351
+ * - false: disable entirely
352
+ * - object: pass through to BubbleMenuPreset
353
+ */
354
+ bubbleMenuPreset?: boolean | BubbleMenuPresetProps;
355
+ /**
356
+ * Additional props forwarded to EditorContent.
357
+ */
358
+ editorContentProps?: Omit<EditorContentProps, "editor">;
359
+ /**
360
+ * Viewport scale factor applied to the slide viewport.
361
+ * @default 1
362
+ */
363
+ viewportScale?: number;
364
+ className?: string;
365
+ style?: CSSProperties;
366
+ } & React__default.RefAttributes<HTMLDivElement>>;
367
+
290
368
  type EditorStateSnapshot<TEditor extends Editor | null = Editor | null> = {
291
369
  editor: TEditor;
292
370
  transactionNumber: number;
@@ -347,11 +425,4 @@ declare const ReactNodeViewContentProvider: ({ children, content }: {
347
425
  }) => React.FunctionComponentElement<React.ProviderProps<ReactNodeViewContextProps>>;
348
426
  declare const useReactNodeView: () => ReactNodeViewContextProps;
349
427
 
350
- type BubbleMenuPresetProps = Omit<BubbleMenuPresetOptions, 'element'> & React__default.HTMLAttributes<HTMLElement> & {
351
- editor?: Editor | null;
352
- };
353
- declare const BubbleMenuPreset: React__default.ForwardRefExoticComponent<Omit<BubbleMenuPresetOptions, "element"> & React__default.HTMLAttributes<HTMLElement> & {
354
- editor?: Editor | null;
355
- } & React__default.RefAttributes<HTMLElement>>;
356
-
357
- export { BubbleMenuPreset, type BubbleMenuPresetProps, EditorConsumer, EditorContent, type EditorContentProps, EditorContext, type EditorContextValue, EditorProvider, type EditorProviderProps, type EditorStateSnapshot, MarkViewContent, type MarkViewContentProps, type MarkViewContextProps, NodeViewContent, type NodeViewContentProps, NodeViewWrapper, type NodeViewWrapperProps, PureEditorContent, ReactMarkView, ReactMarkViewContext, ReactMarkViewRenderer, type ReactMarkViewRendererOptions, ReactNodeView, ReactNodeViewContentProvider, ReactNodeViewContext, type ReactNodeViewContextProps, type ReactNodeViewProps, ReactNodeViewRenderer, type ReactNodeViewRendererOptions, ReactRenderer, type ReactRendererOptions, type UseEditorOptions, type UseEditorStateOptions, useCurrentEditor, useEditor, useEditorState, useReactNodeView };
428
+ export { BubbleMenuPreset, type BubbleMenuPresetProps, EditorConsumer, EditorContent, type EditorContentProps, EditorContext, type EditorContextValue, EditorProvider, type EditorProviderProps, type EditorStateSnapshot, MarkViewContent, type MarkViewContentProps, type MarkViewContextProps, NodeViewContent, type NodeViewContentProps, NodeViewWrapper, type NodeViewWrapperProps, PureEditorContent, ReactMarkView, ReactMarkViewContext, ReactMarkViewRenderer, type ReactMarkViewRendererOptions, ReactNodeView, ReactNodeViewContentProvider, ReactNodeViewContext, type ReactNodeViewContextProps, type ReactNodeViewProps, ReactNodeViewRenderer, type ReactNodeViewRendererOptions, ReactRenderer, type ReactRendererOptions, SlideEditor as ReactSlideEditor, type UseEditorOptions, type UseEditorStateOptions, type UseSlideEditorProps, useCurrentEditor, useEditor, useEditorState, useReactNodeView, useSlideEditor };
package/dist/index.js CHANGED
@@ -1015,6 +1015,9 @@ function ReactNodeViewRenderer(component, options) {
1015
1015
  };
1016
1016
  }
1017
1017
 
1018
+ // src/SlideEditor.tsx
1019
+ import { forwardRef as forwardRef2, useMemo as useMemo3 } from "react";
1020
+
1018
1021
  // src/menus/BubbleMenuPreset.tsx
1019
1022
  import React5, { useEffect as useEffect3, useRef as useRef2 } from "react";
1020
1023
  import { createPortal } from "react-dom";
@@ -1035,7 +1038,6 @@ import { isTextSelection } from "@blockslides/core";
1035
1038
  import { jsx as jsx8 } from "react/jsx-runtime";
1036
1039
  var BubbleMenuPreset = React5.forwardRef(
1037
1040
  ({
1038
- pluginKey = "bubbleMenuPreset",
1039
1041
  editor,
1040
1042
  updateDelay,
1041
1043
  resizeDelay,
@@ -1051,8 +1053,11 @@ var BubbleMenuPreset = React5.forwardRef(
1051
1053
  fonts,
1052
1054
  fontSizes,
1053
1055
  alignments,
1056
+ onTextAction,
1057
+ onImageReplace,
1054
1058
  ...rest
1055
1059
  }, ref) => {
1060
+ const pluginKey = "bubbleMenuPreset";
1056
1061
  const { editor: currentEditor } = useCurrentEditor();
1057
1062
  const menuEl = useRef2(null);
1058
1063
  useEffect3(() => {
@@ -1068,7 +1073,9 @@ var BubbleMenuPreset = React5.forwardRef(
1068
1073
  highlightColors: highlightColors != null ? highlightColors : DEFAULT_HIGHLIGHT_PALETTE,
1069
1074
  fonts: fonts != null ? fonts : DEFAULT_FONTS,
1070
1075
  fontSizes: fontSizes != null ? fontSizes : DEFAULT_FONT_SIZES,
1071
- alignments: alignments != null ? alignments : DEFAULT_ALIGNMENTS
1076
+ alignments: alignments != null ? alignments : DEFAULT_ALIGNMENTS,
1077
+ onTextAction,
1078
+ onImageReplace
1072
1079
  });
1073
1080
  menuEl.current = element;
1074
1081
  if (typeof ref === "function") {
@@ -1110,7 +1117,6 @@ var BubbleMenuPreset = React5.forwardRef(
1110
1117
  }, [
1111
1118
  editor,
1112
1119
  currentEditor,
1113
- pluginKey,
1114
1120
  updateDelay,
1115
1121
  resizeDelay,
1116
1122
  appendTo,
@@ -1125,6 +1131,8 @@ var BubbleMenuPreset = React5.forwardRef(
1125
1131
  fonts,
1126
1132
  fontSizes,
1127
1133
  alignments,
1134
+ onTextAction,
1135
+ onImageReplace,
1128
1136
  ref
1129
1137
  ]);
1130
1138
  return menuEl.current ? createPortal(/* @__PURE__ */ jsx8("div", { ...rest }), menuEl.current) : null;
@@ -1132,6 +1140,222 @@ var BubbleMenuPreset = React5.forwardRef(
1132
1140
  );
1133
1141
  BubbleMenuPreset.displayName = "BubbleMenuPreset";
1134
1142
 
1143
+ // src/useSlideEditor.ts
1144
+ import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
1145
+ import { templatesV1 } from "@blockslides/ai-context";
1146
+ import {
1147
+ ExtensionKit
1148
+ } from "@blockslides/extension-kit";
1149
+ var defaultSlide = () => ({
1150
+ /**
1151
+ * Placeholder slide if no content is provided.
1152
+ */
1153
+ type: "doc",
1154
+ content: [
1155
+ {
1156
+ type: "slide",
1157
+ attrs: {
1158
+ size: "16x9",
1159
+ className: "",
1160
+ id: "slide-1",
1161
+ backgroundMode: "none",
1162
+ backgroundColor: null,
1163
+ backgroundImage: null,
1164
+ backgroundOverlayColor: null,
1165
+ backgroundOverlayOpacity: null
1166
+ },
1167
+ content: [
1168
+ {
1169
+ type: "column",
1170
+ attrs: {
1171
+ align: "center",
1172
+ padding: "lg",
1173
+ margin: null,
1174
+ gap: "md",
1175
+ backgroundColor: "#ffffff",
1176
+ backgroundImage: null,
1177
+ borderRadius: null,
1178
+ border: null,
1179
+ fill: true,
1180
+ width: null,
1181
+ height: null,
1182
+ justify: "center"
1183
+ },
1184
+ content: [
1185
+ {
1186
+ type: "heading",
1187
+ attrs: {
1188
+ align: null,
1189
+ padding: null,
1190
+ margin: null,
1191
+ gap: null,
1192
+ backgroundColor: null,
1193
+ backgroundImage: null,
1194
+ borderRadius: null,
1195
+ border: null,
1196
+ fill: null,
1197
+ width: null,
1198
+ height: null,
1199
+ justify: null,
1200
+ id: "1fc4664c-333d-4203-a3f1-3ad27a54c535",
1201
+ "data-toc-id": "1fc4664c-333d-4203-a3f1-3ad27a54c535",
1202
+ level: 1
1203
+ },
1204
+ content: [
1205
+ {
1206
+ type: "text",
1207
+ text: "Lorem ipsum dolor sit amet"
1208
+ }
1209
+ ]
1210
+ },
1211
+ {
1212
+ type: "paragraph",
1213
+ attrs: {
1214
+ align: null,
1215
+ padding: null,
1216
+ margin: null,
1217
+ gap: null,
1218
+ backgroundColor: null,
1219
+ backgroundImage: null,
1220
+ borderRadius: null,
1221
+ border: null,
1222
+ fill: null,
1223
+ width: null,
1224
+ height: null,
1225
+ justify: null
1226
+ },
1227
+ content: [
1228
+ {
1229
+ type: "text",
1230
+ text: "Consectetur adipiscing elit. Sed do eiusmod tempor incididunt. "
1231
+ }
1232
+ ]
1233
+ }
1234
+ ]
1235
+ }
1236
+ ]
1237
+ }
1238
+ ]
1239
+ });
1240
+ var defaultAddSlideButton = (presets) => ({
1241
+ showPresets: true,
1242
+ presets,
1243
+ presetBackground: "#0f172a",
1244
+ presetForeground: "#e5e7eb"
1245
+ });
1246
+ var defaultSlideOptions = {
1247
+ renderMode: "dynamic",
1248
+ hoverOutline: { color: "#3b82f6", width: "1.5px", offset: "4px" },
1249
+ hoverOutlineCascade: false
1250
+ };
1251
+ var useSlideEditor = ({
1252
+ content,
1253
+ onChange,
1254
+ extensions,
1255
+ extensionKitOptions,
1256
+ presetTemplates,
1257
+ deps = [],
1258
+ onEditorReady,
1259
+ immediatelyRender = false,
1260
+ shouldRerenderOnTransaction = false,
1261
+ theme = "light",
1262
+ editorProps,
1263
+ onUpdate,
1264
+ ...editorOptions
1265
+ } = {}) => {
1266
+ var _a;
1267
+ const presets = useMemo2(
1268
+ () => presetTemplates != null ? presetTemplates : templatesV1.listPresetTemplates(),
1269
+ [presetTemplates]
1270
+ );
1271
+ const mergedExtensionKitOptions = useMemo2(() => {
1272
+ var _a2, _b;
1273
+ const addSlideButton = (extensionKitOptions == null ? void 0 : extensionKitOptions.addSlideButton) === false ? false : {
1274
+ ...defaultAddSlideButton(presets),
1275
+ ...(_a2 = extensionKitOptions == null ? void 0 : extensionKitOptions.addSlideButton) != null ? _a2 : {}
1276
+ };
1277
+ const slide = (extensionKitOptions == null ? void 0 : extensionKitOptions.slide) === false ? false : {
1278
+ ...defaultSlideOptions,
1279
+ ...(_b = extensionKitOptions == null ? void 0 : extensionKitOptions.slide) != null ? _b : {}
1280
+ };
1281
+ return {
1282
+ ...extensionKitOptions,
1283
+ addSlideButton,
1284
+ slide
1285
+ };
1286
+ }, [extensionKitOptions, presets]);
1287
+ const resolvedExtensions = useMemo2(() => {
1288
+ const kit = ExtensionKit.configure(mergedExtensionKitOptions);
1289
+ return extensions ? [kit, ...extensions] : [kit];
1290
+ }, [extensions, mergedExtensionKitOptions]);
1291
+ const initialContent = content != null ? content : defaultSlide();
1292
+ const editor = useEditor(
1293
+ {
1294
+ content: initialContent,
1295
+ extensions: resolvedExtensions,
1296
+ immediatelyRender,
1297
+ shouldRerenderOnTransaction,
1298
+ theme,
1299
+ editorProps: {
1300
+ attributes: {
1301
+ autocomplete: "off",
1302
+ autocorrect: "off",
1303
+ autocapitalize: "off",
1304
+ class: "min-h-full min-w-full",
1305
+ ...(_a = editorProps == null ? void 0 : editorProps.attributes) != null ? _a : {}
1306
+ },
1307
+ ...editorProps
1308
+ },
1309
+ ...editorOptions,
1310
+ onUpdate: (ctx) => {
1311
+ const json = ctx.editor.getJSON();
1312
+ onChange == null ? void 0 : onChange(json, ctx.editor);
1313
+ onUpdate == null ? void 0 : onUpdate(ctx);
1314
+ }
1315
+ },
1316
+ deps
1317
+ );
1318
+ useEffect4(() => {
1319
+ if (editor && !editor.isDestroyed) {
1320
+ onEditorReady == null ? void 0 : onEditorReady(editor);
1321
+ }
1322
+ }, [editor, onEditorReady]);
1323
+ return { editor, presets };
1324
+ };
1325
+
1326
+ // src/SlideEditor.tsx
1327
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
1328
+ var SlideEditor = forwardRef2(
1329
+ ({
1330
+ bubbleMenuPreset = true,
1331
+ editorContentProps,
1332
+ viewportScale = 1,
1333
+ className,
1334
+ style,
1335
+ ...hookProps
1336
+ }, ref) => {
1337
+ const { editor } = useSlideEditor(hookProps);
1338
+ const bubbleMenuProps = useMemo3(() => {
1339
+ if (bubbleMenuPreset === false) return null;
1340
+ if (bubbleMenuPreset === true) return {};
1341
+ return bubbleMenuPreset;
1342
+ }, [bubbleMenuPreset]);
1343
+ if (!editor) return null;
1344
+ return /* @__PURE__ */ jsx9("div", { ref, className, style, children: /* @__PURE__ */ jsxs3(
1345
+ "div",
1346
+ {
1347
+ className: "bs-viewport",
1348
+ style: { ["--zoom"]: viewportScale },
1349
+ children: [
1350
+ /* @__PURE__ */ jsx9(EditorContent, { editor, ...editorContentProps }),
1351
+ bubbleMenuProps && /* @__PURE__ */ jsx9(BubbleMenuPreset, { editor, ...bubbleMenuProps })
1352
+ ]
1353
+ }
1354
+ ) });
1355
+ }
1356
+ );
1357
+ SlideEditor.displayName = "SlideEditor";
1358
+
1135
1359
  // src/index.ts
1136
1360
  export * from "@blockslides/core";
1137
1361
  export {
@@ -1152,9 +1376,11 @@ export {
1152
1376
  ReactNodeViewContext,
1153
1377
  ReactNodeViewRenderer,
1154
1378
  ReactRenderer,
1379
+ SlideEditor as ReactSlideEditor,
1155
1380
  useCurrentEditor,
1156
1381
  useEditor,
1157
1382
  useEditorState,
1158
- useReactNodeView
1383
+ useReactNodeView,
1384
+ useSlideEditor
1159
1385
  };
1160
1386
  //# sourceMappingURL=index.js.map