@bendyline/squisq-editor-react 1.6.0 → 1.6.2

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 (68) hide show
  1. package/README.md +57 -10
  2. package/dist/index.d.ts +476 -105
  3. package/dist/index.js +8703 -6741
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles/fa-brands-400-AHOAZHCU.woff2 +0 -0
  6. package/dist/styles/fa-regular-400-VRZYIBIZ.woff2 +0 -0
  7. package/dist/styles/fa-solid-900-MDEYK55F.woff2 +0 -0
  8. package/dist/styles/fa-v4compatibility-ETEVP6IB.woff2 +0 -0
  9. package/dist/styles/index.css +14617 -0
  10. package/package.json +15 -7
  11. package/src/BlockPropertiesPopover.tsx +23 -7
  12. package/src/EditorContext.tsx +22 -16
  13. package/src/EditorShell.tsx +121 -35
  14. package/src/MediaBin.tsx +171 -28
  15. package/src/OutlinePanel.tsx +26 -4
  16. package/src/PreviewControls.tsx +475 -145
  17. package/src/PreviewPanel.tsx +17 -9
  18. package/src/RawEditor.tsx +10 -4
  19. package/src/TemplateAnnotation.ts +22 -7
  20. package/src/TemplateContentPreview.tsx +56 -0
  21. package/src/TemplatePicker.tsx +295 -128
  22. package/src/ThemeCustomizerPanel.tsx +22 -15
  23. package/src/Toolbar.tsx +547 -217
  24. package/src/TransitionPicker.tsx +8 -1
  25. package/src/VersionHistoryPanel.tsx +2 -2
  26. package/src/ViewSwitcher.tsx +4 -4
  27. package/src/WysiwygEditor.tsx +45 -3
  28. package/src/__tests__/buildPreviewDocTransition.test.ts +1 -2
  29. package/src/__tests__/codeContextSectionView.test.tsx +95 -0
  30. package/src/__tests__/codeContextZoneManager.test.ts +127 -0
  31. package/src/__tests__/diffContextSections.test.ts +39 -0
  32. package/src/__tests__/editorShellCodeContext.test.tsx +86 -0
  33. package/src/__tests__/editorShellProps.test.tsx +363 -0
  34. package/src/__tests__/headingTransition.test.ts +59 -9
  35. package/src/__tests__/imageEditorShell.test.tsx +23 -0
  36. package/src/__tests__/mediaReferences.test.ts +82 -0
  37. package/src/__tests__/previewControls.test.tsx +163 -0
  38. package/src/__tests__/templateAnnotationRoundTrip.test.ts +23 -2
  39. package/src/__tests__/templateContentPreview.test.ts +101 -0
  40. package/src/__tests__/tiptapBridge.test.ts +47 -0
  41. package/src/__tests__/useJsonEditorTokens.test.ts +59 -0
  42. package/src/__tests__/useMediaRecorder.test.ts +17 -0
  43. package/src/codeContext/CodeContextSectionView.tsx +124 -0
  44. package/src/codeContext/CodeContextZoneManager.ts +149 -0
  45. package/src/codeContext/CodeContextZones.tsx +121 -0
  46. package/src/codeContext/diffContextSections.ts +38 -0
  47. package/src/codeContext/types.ts +75 -0
  48. package/src/diagram/DiagramWidget.tsx +6 -4
  49. package/src/headingTransition.ts +96 -21
  50. package/src/index.ts +34 -2
  51. package/src/jsonEditor/useJsonEditorTokens.ts +13 -43
  52. package/src/mediaReferences.ts +299 -0
  53. package/src/recorder/hooks/useMediaRecorder.ts +9 -10
  54. package/src/scene/Scene.tsx +53 -7
  55. package/src/scene/SceneBlockWidget.tsx +6 -3
  56. package/src/scene/SceneSelection.tsx +19 -15
  57. package/src/scene/SceneSideToolbar.tsx +89 -0
  58. package/src/scene/layers/DiagramEdges.tsx +4 -3
  59. package/src/scene/layers/edgeGeometry.ts +23 -4
  60. package/src/scene/scene.css +142 -2
  61. package/src/scene/tools/ConnectTool.ts +113 -24
  62. package/src/scene/tools/DrawingConnectTool.ts +86 -16
  63. package/src/scene/tools/SceneTool.ts +2 -0
  64. package/src/styles/code-context.css +155 -0
  65. package/src/styles/editor.css +991 -84
  66. package/src/styles/index.css +1 -0
  67. package/src/templateContentPreviewResolver.ts +353 -0
  68. package/src/tiptapBridge.ts +60 -33
@@ -48,6 +48,8 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
48
48
  activeTheme,
49
49
  activeTransformStyle,
50
50
  activeCaptionStyle,
51
+ activeCaptionsEnabled,
52
+ activeCoverSlide,
51
53
  } = usePreviewSettings();
52
54
 
53
55
  // Build the player-ready Doc whenever the parsed doc changes.
@@ -108,10 +110,15 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
108
110
  );
109
111
  }
110
112
 
111
- // Page mode renders directly from markdown it doesn't depend on the
112
- // parsed Doc tree or the player preview build, so let it fall through
113
- // even when those aren't ready yet.
114
- if (!previewDoc && activeDisplayMode !== 'page') {
113
+ // The public DisplayMode values predate the current labels: raw `page`
114
+ // is the plain Document preview, while raw `linear` is the styled Page view.
115
+ const isDocumentMode = activeDisplayMode === 'page';
116
+ const isPageMode = activeDisplayMode === 'linear';
117
+
118
+ // Document mode renders directly from markdown — it doesn't depend on the
119
+ // parsed Doc tree or the player preview build, so let it fall through even
120
+ // when those aren't ready yet.
121
+ if (!previewDoc && !isDocumentMode) {
115
122
  return (
116
123
  <div className={`squisq-preview-status ${className || ''}`} data-testid="preview-panel">
117
124
  <p>No content to preview. Start typing in the editor.</p>
@@ -119,8 +126,7 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
119
126
  );
120
127
  }
121
128
 
122
- const fillsContainer =
123
- activeDisplayMode === 'linear' || activeDisplayMode === 'page' ? 'stretch' : 'center';
129
+ const fillsContainer = isDocumentMode || isPageMode ? 'stretch' : 'center';
124
130
 
125
131
  return (
126
132
  <div
@@ -147,7 +153,7 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
147
153
  minHeight: 0,
148
154
  }}
149
155
  >
150
- {activeDisplayMode === 'page' ? (
156
+ {isDocumentMode ? (
151
157
  <PlainHtmlPreview
152
158
  markdown={markdownSource}
153
159
  title={(doc?.frontmatter?.title as string | undefined) ?? undefined}
@@ -155,7 +161,7 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
155
161
  mediaRevision={mediaRevision}
156
162
  theme={activeTheme}
157
163
  />
158
- ) : activeDisplayMode === 'linear' ? (
164
+ ) : isPageMode ? (
159
165
  <LinearDocView
160
166
  doc={doc!}
161
167
  basePath={basePath}
@@ -164,7 +170,7 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
164
170
  />
165
171
  ) : (
166
172
  <DocPlayer
167
- script={previewDoc!}
173
+ doc={previewDoc!}
168
174
  basePath={basePath}
169
175
  showControls
170
176
  muted
@@ -172,6 +178,8 @@ export function PreviewPanel({ basePath = '/', className, workspaceContainer }:
172
178
  displayMode={activeDisplayMode}
173
179
  theme={activeTheme}
174
180
  captionStyle={activeCaptionStyle}
181
+ captionsEnabled={activeCaptionsEnabled}
182
+ showCoverSlide={activeCoverSlide}
175
183
  />
176
184
  )}
177
185
  </div>
package/src/RawEditor.tsx CHANGED
@@ -56,8 +56,14 @@ const SQUISQ_THEMES: Record<string, string> = {
56
56
  };
57
57
 
58
58
  export interface RawEditorProps {
59
- /** Monaco editor theme (default: 'vs-dark') */
60
- theme?: string;
59
+ /**
60
+ * Monaco editor theme name (default: `'vs'`). Accepts Monaco's built-in
61
+ * theme ids (`'vs'`, `'vs-dark'`, `'hc-black'`) — which are transparently
62
+ * mapped to the Squisq-tinted variants — or any custom theme registered
63
+ * via `monaco.editor.defineTheme`. This is the *code editor* color
64
+ * theme, distinct from the shell's light/dark `colorScheme`.
65
+ */
66
+ monacoTheme?: string;
61
67
  /** Show minimap (default: false) */
62
68
  minimap?: boolean;
63
69
  /** Font size in pixels (default: 14) */
@@ -80,7 +86,7 @@ export interface RawEditorProps {
80
86
  * Binds to the shared EditorContext for source synchronization.
81
87
  */
82
88
  export function RawEditor({
83
- theme = 'vs',
89
+ monacoTheme = 'vs',
84
90
  minimap = false,
85
91
  fontSize = 14,
86
92
  wordWrap = 'on',
@@ -640,7 +646,7 @@ export function RawEditor({
640
646
  }
641
647
  }, [editorSource, language, monacoNs]);
642
648
 
643
- const effectiveTheme = SQUISQ_THEMES[theme] ?? theme;
649
+ const effectiveTheme = SQUISQ_THEMES[monacoTheme] ?? monacoTheme;
644
650
 
645
651
  // Wait for the lazy monaco namespace + `loader.config()` to settle
646
652
  // before mounting `<Editor>`. Without this gate, the @monaco-editor/
@@ -63,10 +63,10 @@ export const HeadingWithTemplate = Heading.extend({
63
63
  (HTMLAttributes['data-template-params'] as string | undefined) ?? null,
64
64
  );
65
65
 
66
- // Render heading with a trailing badge span. The badge has no text
67
- // content — its label is painted via CSS `content: attr(data-template-label)`
68
- // so the template name never becomes part of the serialized heading
69
- // text (which would leak into markdown on round-trip).
66
+ // Render heading with a trailing badge span. The badge and its inner core
67
+ // have no real text content — labels/braces are painted via CSS so the
68
+ // template name never becomes part of serialized heading text (which
69
+ // would leak into markdown on round-trip).
70
70
  //
71
71
  // When no template is set we still render a subtle "empty" badge so
72
72
  // authors have a visible affordance for opening the template picker
@@ -86,10 +86,17 @@ export const HeadingWithTemplate = Heading.extend({
86
86
  role: 'button',
87
87
  tabindex: '0',
88
88
  'aria-haspopup': 'listbox',
89
- title: 'Change block template',
89
+ title: 'Change block type',
90
90
  'data-template': templateName,
91
- 'data-template-label': templateLabel(templateName),
92
91
  },
92
+ [
93
+ 'span',
94
+ {
95
+ class: 'squisq-template-badge-core',
96
+ 'data-template-label': templateLabel(templateName),
97
+ 'aria-hidden': 'true',
98
+ },
99
+ ],
93
100
  ],
94
101
  propsBadgeSpec(propsSummary),
95
102
  ];
@@ -107,8 +114,16 @@ export const HeadingWithTemplate = Heading.extend({
107
114
  role: 'button',
108
115
  tabindex: '0',
109
116
  'aria-haspopup': 'listbox',
110
- title: 'Choose block template',
117
+ title: 'Choose block type',
111
118
  },
119
+ [
120
+ 'span',
121
+ {
122
+ class: 'squisq-template-badge-core',
123
+ 'data-template-label': 'Block',
124
+ 'aria-hidden': 'true',
125
+ },
126
+ ],
112
127
  ],
113
128
  propsBadgeSpec(propsSummary),
114
129
  ];
@@ -0,0 +1,56 @@
1
+ import { useMemo } from 'react';
2
+ import { BlockRenderer, MediaContext } from '@bendyline/squisq-react';
3
+ import {
4
+ resolveTemplateContentPreviewResult,
5
+ type TemplatePreviewSource,
6
+ } from './templateContentPreviewResolver';
7
+
8
+ export interface TemplateContentPreviewProps {
9
+ templateName: string;
10
+ source?: TemplatePreviewSource;
11
+ fallback: JSX.Element;
12
+ }
13
+
14
+ export function TemplateContentPreview({
15
+ templateName,
16
+ source,
17
+ fallback,
18
+ }: TemplateContentPreviewProps) {
19
+ const preview = useMemo(
20
+ () => (source ? resolveTemplateContentPreviewResult(templateName, source) : null),
21
+ [templateName, source],
22
+ );
23
+
24
+ if (!source) return fallback;
25
+
26
+ if (!preview?.visual) {
27
+ if (!preview?.warning) return fallback;
28
+ return (
29
+ <div
30
+ className="squisq-template-gallery-content-preview squisq-template-gallery-content-preview--fallback"
31
+ style={{ aspectRatio: `${source.viewport.width} / ${source.viewport.height}` }}
32
+ aria-hidden="true"
33
+ >
34
+ <div className="squisq-template-gallery-content-preview-fallback">{fallback}</div>
35
+ <span className="squisq-template-gallery-content-preview-warning">{preview.warning}</span>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ return (
41
+ <div
42
+ className="squisq-template-gallery-content-preview"
43
+ style={{ aspectRatio: `${source.viewport.width} / ${source.viewport.height}` }}
44
+ aria-hidden="true"
45
+ >
46
+ <MediaContext.Provider value={source.mediaProvider ?? null}>
47
+ <BlockRenderer
48
+ block={preview.visual}
49
+ blockTime={0}
50
+ basePath={source.basePath ?? '/'}
51
+ viewport={source.viewport}
52
+ />
53
+ </MediaContext.Provider>
54
+ </div>
55
+ );
56
+ }