@bendyline/squisq-editor-react 2.4.7 → 2.5.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.
@@ -647,6 +647,8 @@ function EditorProvider({
647
647
  useEffect(() => sceneTextChannel.subscribe(setActiveSceneText), [sceneTextChannel]);
648
648
  const articleIdRef = useRef(articleId);
649
649
  articleIdRef.current = articleId;
650
+ const fileNameRef = useRef(fileName);
651
+ fileNameRef.current = fileName;
650
652
  useEffect(() => {
651
653
  setColorScheme(initialColorScheme);
652
654
  }, [initialColorScheme]);
@@ -660,7 +662,8 @@ function EditorProvider({
660
662
  setParseError(null);
661
663
  try {
662
664
  const generatedDoc = markdownToDoc(parsed, {
663
- articleId: articleIdRef.current
665
+ articleId: articleIdRef.current,
666
+ fileName: fileNameRef.current
664
667
  });
665
668
  setDoc(generatedDoc);
666
669
  } catch (docErr) {
@@ -811,7 +814,8 @@ function EditorProvider({
811
814
  setParseError(null);
812
815
  try {
813
816
  const generatedDoc = markdownToDoc(newDoc, {
814
- articleId: articleIdRef.current
817
+ articleId: articleIdRef.current,
818
+ fileName: fileNameRef.current
815
819
  });
816
820
  setDoc(generatedDoc);
817
821
  } catch (docErr) {
@@ -3259,6 +3263,7 @@ import {
3259
3263
  useRef as useRef7
3260
3264
  } from "react";
3261
3265
  import { createPortal as createPortal2 } from "react-dom";
3266
+ import { BlockRenderer, MediaContext } from "@bendyline/squisq-react";
3262
3267
  import {
3263
3268
  VIEWPORT_PRESETS,
3264
3269
  getThemeSummaries as getThemeSummaries2,
@@ -3277,8 +3282,13 @@ import {
3277
3282
  writeCustomThemesToFrontmatter as writeCustomThemesToFrontmatter2,
3278
3283
  writeCustomTemplatesToFrontmatter,
3279
3284
  FRONTMATTER_CUSTOM_THEMES_KEY as FRONTMATTER_CUSTOM_THEMES_KEY2,
3280
- FRONTMATTER_CUSTOM_TEMPLATES_KEY
3285
+ FRONTMATTER_CUSTOM_TEMPLATES_KEY,
3286
+ COVER_SLIDE_TEMPLATE_OPTIONS,
3287
+ createTemplateContext,
3288
+ expandCoverBlock,
3289
+ resolveCoverSlideSettings
3281
3290
  } from "@bendyline/squisq/doc";
3291
+ import { CoverImageExportModal } from "@bendyline/squisq-video-react/cover-image";
3282
3292
 
3283
3293
  // src/transformStyleId.ts
3284
3294
  import { getTransformStyleSummaries } from "@bendyline/squisq/transform";
@@ -3291,11 +3301,15 @@ function resolvePersistedTransformStyleId(value) {
3291
3301
  }
3292
3302
 
3293
3303
  // src/frontmatterSettings.ts
3304
+ import { COVER_SLIDE_FRONTMATTER_KEYS, DEFAULT_COVER_SLIDE_SETTINGS } from "@bendyline/squisq/doc";
3294
3305
  var FRONTMATTER_SETTING_KEYS = {
3295
3306
  theme: { canonical: "squisq-theme", legacy: ["themeId", "theme"] },
3296
3307
  transform: { canonical: "squisq-transform", legacy: "transform-style" },
3297
3308
  captions: { canonical: "squisq-captions", legacy: "caption-style" },
3298
- coverSlide: { canonical: "squisq-cover-slide", legacy: "cover-slide" },
3309
+ coverSlide: COVER_SLIDE_FRONTMATTER_KEYS.enabled,
3310
+ coverTemplate: COVER_SLIDE_FRONTMATTER_KEYS.template,
3311
+ coverDuration: COVER_SLIDE_FRONTMATTER_KEYS.duration,
3312
+ coverPlayback: COVER_SLIDE_FRONTMATTER_KEYS.playback,
3299
3313
  videoLoop: { canonical: "squisq-video-loop", legacy: "video-loop" },
3300
3314
  videoPresentation: {
3301
3315
  canonical: "squisq-video-presentation",
@@ -3309,7 +3323,10 @@ var FRONTMATTER_SETTING_DEFAULTS = {
3309
3323
  theme: "standard",
3310
3324
  transform: "",
3311
3325
  captions: "standard",
3312
- coverSlide: true,
3326
+ coverSlide: DEFAULT_COVER_SLIDE_SETTINGS.enabled,
3327
+ coverTemplate: DEFAULT_COVER_SLIDE_SETTINGS.template,
3328
+ coverDuration: DEFAULT_COVER_SLIDE_SETTINGS.duration,
3329
+ coverPlayback: DEFAULT_COVER_SLIDE_SETTINGS.playback,
3313
3330
  videoLoop: false,
3314
3331
  videoPresentation: "background",
3315
3332
  pipSize: "small",
@@ -3777,19 +3794,14 @@ function PreviewSettingsProvider({
3777
3794
  },
3778
3795
  [persistFrontmatter]
3779
3796
  );
3780
- const fmCoverSlide = useMemo8(
3781
- () => resolveFrontmatterBoolean(
3782
- readFrontmatterKey(
3783
- frontmatter,
3784
- FRONTMATTER_SETTING_KEYS.coverSlide.canonical,
3785
- FRONTMATTER_SETTING_KEYS.coverSlide.legacy
3786
- )
3787
- ),
3797
+ const resolvedCoverSettings = useMemo8(
3798
+ () => resolveCoverSlideSettings(frontmatter),
3788
3799
  [frontmatter]
3789
3800
  );
3801
+ const fmCoverSlide = resolvedCoverSettings.enabled;
3790
3802
  const [selectedCoverSlide, setSelectedCoverSlide] = useState9(null);
3791
3803
  useEffect8(() => setSelectedCoverSlide(null), [fmCoverSlide]);
3792
- const activeCoverSlide = selectedCoverSlide ?? fmCoverSlide ?? FRONTMATTER_SETTING_DEFAULTS.coverSlide;
3804
+ const activeCoverSlide = selectedCoverSlide ?? fmCoverSlide;
3793
3805
  const handleSetCoverSlideEnabled = useCallback9(
3794
3806
  (enabled) => {
3795
3807
  setSelectedCoverSlide(enabled);
@@ -3806,6 +3818,55 @@ function PreviewSettingsProvider({
3806
3818
  },
3807
3819
  [persistFrontmatter]
3808
3820
  );
3821
+ const [selectedCoverSlideTemplate, setSelectedCoverSlideTemplate] = useState9(null);
3822
+ useEffect8(() => setSelectedCoverSlideTemplate(null), [resolvedCoverSettings.template]);
3823
+ const activeCoverSlideTemplate = selectedCoverSlideTemplate ?? resolvedCoverSettings.template;
3824
+ const handleSetCoverSlideTemplate = useCallback9(
3825
+ (template) => {
3826
+ setSelectedCoverSlideTemplate(template);
3827
+ persistFrontmatter({
3828
+ [FRONTMATTER_SETTING_KEYS.coverTemplate.canonical]: omitFrontmatterDefault(
3829
+ template,
3830
+ FRONTMATTER_SETTING_DEFAULTS.coverTemplate
3831
+ ),
3832
+ [FRONTMATTER_SETTING_KEYS.coverTemplate.legacy]: null
3833
+ });
3834
+ },
3835
+ [persistFrontmatter]
3836
+ );
3837
+ const [selectedCoverSlideDuration, setSelectedCoverSlideDuration] = useState9(null);
3838
+ useEffect8(() => setSelectedCoverSlideDuration(null), [resolvedCoverSettings.duration]);
3839
+ const activeCoverSlideDuration = selectedCoverSlideDuration ?? resolvedCoverSettings.duration;
3840
+ const handleSetCoverSlideDuration = useCallback9(
3841
+ (duration) => {
3842
+ if (!Number.isFinite(duration) || duration < 0 || duration > 60) return;
3843
+ setSelectedCoverSlideDuration(duration);
3844
+ persistFrontmatter({
3845
+ [FRONTMATTER_SETTING_KEYS.coverDuration.canonical]: omitFrontmatterDefault(
3846
+ duration,
3847
+ FRONTMATTER_SETTING_DEFAULTS.coverDuration
3848
+ ),
3849
+ [FRONTMATTER_SETTING_KEYS.coverDuration.legacy]: null
3850
+ });
3851
+ },
3852
+ [persistFrontmatter]
3853
+ );
3854
+ const [selectedCoverSlidePlayback, setSelectedCoverSlidePlayback] = useState9(null);
3855
+ useEffect8(() => setSelectedCoverSlidePlayback(null), [resolvedCoverSettings.playback]);
3856
+ const activeCoverSlidePlayback = selectedCoverSlidePlayback ?? resolvedCoverSettings.playback;
3857
+ const handleSetCoverSlidePlayback = useCallback9(
3858
+ (playback) => {
3859
+ setSelectedCoverSlidePlayback(playback);
3860
+ persistFrontmatter({
3861
+ [FRONTMATTER_SETTING_KEYS.coverPlayback.canonical]: omitFrontmatterDefault(
3862
+ playback,
3863
+ FRONTMATTER_SETTING_DEFAULTS.coverPlayback
3864
+ ),
3865
+ [FRONTMATTER_SETTING_KEYS.coverPlayback.legacy]: null
3866
+ });
3867
+ },
3868
+ [persistFrontmatter]
3869
+ );
3809
3870
  const themeDesigner = useMemo8(
3810
3871
  () => designer.open ? {
3811
3872
  value: designer.editing,
@@ -3843,6 +3904,12 @@ function PreviewSettingsProvider({
3843
3904
  setVideoLoopEnabled: handleSetVideoLoopEnabled,
3844
3905
  activeCoverSlide,
3845
3906
  setCoverSlideEnabled: handleSetCoverSlideEnabled,
3907
+ activeCoverSlideTemplate,
3908
+ setCoverSlideTemplate: handleSetCoverSlideTemplate,
3909
+ activeCoverSlideDuration,
3910
+ setCoverSlideDuration: handleSetCoverSlideDuration,
3911
+ activeCoverSlidePlayback,
3912
+ setCoverSlidePlayback: handleSetCoverSlidePlayback,
3846
3913
  customThemes,
3847
3914
  openThemeDesigner,
3848
3915
  deleteCustomTheme,
@@ -3865,6 +3932,9 @@ function PreviewSettingsProvider({
3865
3932
  activePipPosition,
3866
3933
  activeVideoLoop,
3867
3934
  activeCoverSlide,
3935
+ activeCoverSlideTemplate,
3936
+ activeCoverSlideDuration,
3937
+ activeCoverSlidePlayback,
3868
3938
  handleSetThemeId,
3869
3939
  handleSetTransformStyle,
3870
3940
  handleSetCaptionMode,
@@ -3874,6 +3944,9 @@ function PreviewSettingsProvider({
3874
3944
  handlePipPosition,
3875
3945
  handleSetVideoLoopEnabled,
3876
3946
  handleSetCoverSlideEnabled,
3947
+ handleSetCoverSlideTemplate,
3948
+ handleSetCoverSlideDuration,
3949
+ handleSetCoverSlidePlayback,
3877
3950
  customThemes,
3878
3951
  openThemeDesigner,
3879
3952
  deleteCustomTheme,
@@ -4018,6 +4091,282 @@ var selectStyle = {
4018
4091
  fontSize: "12px",
4019
4092
  cursor: "pointer"
4020
4093
  };
4094
+ var COVER_MENU_WIDTH = 336;
4095
+ var COVER_MENU_GAP = 4;
4096
+ var COVER_MENU_MARGIN = 8;
4097
+ function CoverSlideMenuControl({ compact }) {
4098
+ const settings = usePreviewSettings();
4099
+ const { colorScheme, doc, fileName, mediaProvider } = useEditorContext();
4100
+ const triggerRef = useRef7(null);
4101
+ const menuRef = useRef7(null);
4102
+ const [open, setOpen] = useState9(false);
4103
+ const [anchor, setAnchor] = useState9(null);
4104
+ const [exportOpen, setExportOpen] = useState9(false);
4105
+ const updatePosition = useCallback9(() => {
4106
+ const trigger = triggerRef.current;
4107
+ if (!trigger) return;
4108
+ const rect = trigger.getBoundingClientRect();
4109
+ const width = Math.min(COVER_MENU_WIDTH, window.innerWidth - COVER_MENU_MARGIN * 2);
4110
+ setAnchor({
4111
+ top: rect.bottom + COVER_MENU_GAP,
4112
+ left: clampPreviewPopoverLeft(rect, width, window.innerWidth)
4113
+ });
4114
+ }, []);
4115
+ const closeMenu = useCallback9(() => {
4116
+ setOpen(false);
4117
+ setAnchor(null);
4118
+ }, []);
4119
+ useEffect8(() => {
4120
+ if (!open) return;
4121
+ const handlePointerDown = (event) => {
4122
+ const target = event.target;
4123
+ if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return;
4124
+ closeMenu();
4125
+ };
4126
+ const handleKeyDown = (event) => {
4127
+ if (event.key !== "Escape") return;
4128
+ event.preventDefault();
4129
+ closeMenu();
4130
+ triggerRef.current?.focus();
4131
+ };
4132
+ document.addEventListener("mousedown", handlePointerDown);
4133
+ document.addEventListener("keydown", handleKeyDown);
4134
+ window.addEventListener("resize", updatePosition);
4135
+ window.addEventListener("scroll", updatePosition, true);
4136
+ return () => {
4137
+ document.removeEventListener("mousedown", handlePointerDown);
4138
+ document.removeEventListener("keydown", handleKeyDown);
4139
+ window.removeEventListener("resize", updatePosition);
4140
+ window.removeEventListener("scroll", updatePosition, true);
4141
+ };
4142
+ }, [closeMenu, open, updatePosition]);
4143
+ const coverExists = !!doc?.startBlock;
4144
+ const coverPreviewBlock = useMemo8(() => {
4145
+ if (!open || !doc?.startBlock) return null;
4146
+ const context = createTemplateContext(settings.activeTheme, 0, 1, settings.activeViewport);
4147
+ return {
4148
+ id: "cover-slide-menu-preview",
4149
+ startTime: -1,
4150
+ duration: 0,
4151
+ audioSegment: -1,
4152
+ layers: expandCoverBlock(doc.startBlock, context, settings.activeCoverSlideTemplate)
4153
+ };
4154
+ }, [
4155
+ open,
4156
+ doc?.startBlock,
4157
+ settings.activeTheme,
4158
+ settings.activeViewport,
4159
+ settings.activeCoverSlideTemplate
4160
+ ]);
4161
+ return /* @__PURE__ */ jsxs6(
4162
+ "div",
4163
+ {
4164
+ className: `squisq-preview-control squisq-cover-slide-control${compact ? " squisq-preview-control--compact" : ""}`,
4165
+ children: [
4166
+ /* @__PURE__ */ jsxs6(
4167
+ "button",
4168
+ {
4169
+ ref: triggerRef,
4170
+ type: "button",
4171
+ className: `squisq-cover-slide-trigger${open ? " squisq-cover-slide-trigger--open" : ""}`,
4172
+ "aria-label": "Cover slide settings",
4173
+ "aria-haspopup": "dialog",
4174
+ "aria-expanded": open,
4175
+ onClick: () => {
4176
+ if (open) {
4177
+ closeMenu();
4178
+ } else {
4179
+ updatePosition();
4180
+ setOpen(true);
4181
+ }
4182
+ },
4183
+ children: [
4184
+ /* @__PURE__ */ jsx8(
4185
+ "span",
4186
+ {
4187
+ className: `squisq-cover-slide-status${settings.activeCoverSlide ? " squisq-cover-slide-status--enabled" : ""}`,
4188
+ "aria-hidden": "true",
4189
+ children: /* @__PURE__ */ jsx8(Icon, { icon: settings.activeCoverSlide ? "fa-solid fa-check" : "fa-solid fa-minus" })
4190
+ }
4191
+ ),
4192
+ /* @__PURE__ */ jsx8("span", { children: "Cover slide" }),
4193
+ /* @__PURE__ */ jsx8("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M2 3.5 5 6.5 8 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4" }) })
4194
+ ]
4195
+ }
4196
+ ),
4197
+ open && anchor && createPortal2(
4198
+ /* @__PURE__ */ jsxs6(
4199
+ "div",
4200
+ {
4201
+ ref: menuRef,
4202
+ className: "squisq-cover-slide-menu",
4203
+ "data-theme": colorScheme,
4204
+ role: "dialog",
4205
+ "aria-label": "Cover slide settings",
4206
+ style: { top: anchor.top, left: anchor.left },
4207
+ children: [
4208
+ /* @__PURE__ */ jsxs6("div", { className: "squisq-cover-slide-menu-heading", children: [
4209
+ /* @__PURE__ */ jsx8("span", { children: "Cover slide" }),
4210
+ /* @__PURE__ */ jsxs6("label", { className: "squisq-cover-slide-switch", children: [
4211
+ /* @__PURE__ */ jsx8(
4212
+ "input",
4213
+ {
4214
+ type: "checkbox",
4215
+ "aria-label": "Cover slide",
4216
+ checked: settings.activeCoverSlide,
4217
+ onChange: (event) => settings.setCoverSlideEnabled(event.target.checked)
4218
+ }
4219
+ ),
4220
+ /* @__PURE__ */ jsx8("span", { children: settings.activeCoverSlide ? "Shown" : "Hidden" })
4221
+ ] })
4222
+ ] }),
4223
+ /* @__PURE__ */ jsx8(
4224
+ "div",
4225
+ {
4226
+ className: `squisq-cover-slide-preview${settings.activeCoverSlide ? "" : " squisq-cover-slide-preview--disabled"}`,
4227
+ style: {
4228
+ aspectRatio: `${settings.activeViewport.width} / ${settings.activeViewport.height}`
4229
+ },
4230
+ children: coverPreviewBlock ? /* @__PURE__ */ jsx8(MediaContext.Provider, { value: mediaProvider ?? null, children: /* @__PURE__ */ jsx8("div", { className: "squisq-cover-slide-preview-frame", "aria-hidden": "true", children: /* @__PURE__ */ jsx8(
4231
+ BlockRenderer,
4232
+ {
4233
+ block: coverPreviewBlock,
4234
+ blockTime: 0,
4235
+ basePath: ".",
4236
+ viewport: settings.activeViewport,
4237
+ animationsEnabled: false,
4238
+ muted: true,
4239
+ theme: settings.activeTheme
4240
+ }
4241
+ ) }) }) : /* @__PURE__ */ jsxs6("p", { className: "squisq-cover-slide-preview-empty", children: [
4242
+ "No cover to preview yet \u2014 start the document with a level-1 heading (",
4243
+ /* @__PURE__ */ jsx8("code", { children: "#\xA0Title" }),
4244
+ ") to generate one."
4245
+ ] })
4246
+ }
4247
+ ),
4248
+ /* @__PURE__ */ jsxs6("label", { className: "squisq-cover-slide-field", children: [
4249
+ /* @__PURE__ */ jsx8("span", { children: "Appearance" }),
4250
+ /* @__PURE__ */ jsx8(
4251
+ "select",
4252
+ {
4253
+ "aria-label": "Cover slide appearance",
4254
+ value: settings.activeCoverSlideTemplate,
4255
+ onChange: (event) => settings.setCoverSlideTemplate(event.target.value),
4256
+ children: COVER_SLIDE_TEMPLATE_OPTIONS.map((option) => /* @__PURE__ */ jsx8(
4257
+ "option",
4258
+ {
4259
+ value: option.id,
4260
+ disabled: option.requiresHeroImage && !doc?.startBlock?.heroSrc,
4261
+ children: option.label
4262
+ },
4263
+ option.id
4264
+ ))
4265
+ }
4266
+ )
4267
+ ] }),
4268
+ /* @__PURE__ */ jsx8("p", { className: "squisq-cover-slide-help", children: COVER_SLIDE_TEMPLATE_OPTIONS.find(
4269
+ (option) => option.id === settings.activeCoverSlideTemplate
4270
+ )?.description }),
4271
+ /* @__PURE__ */ jsxs6("label", { className: "squisq-cover-slide-field", children: [
4272
+ /* @__PURE__ */ jsxs6("span", { children: [
4273
+ "Duration",
4274
+ /* @__PURE__ */ jsxs6("output", { children: [
4275
+ settings.activeCoverSlideDuration.toFixed(1),
4276
+ "s"
4277
+ ] })
4278
+ ] }),
4279
+ /* @__PURE__ */ jsx8(
4280
+ "input",
4281
+ {
4282
+ "aria-label": "Cover slide duration",
4283
+ type: "range",
4284
+ min: 0,
4285
+ max: 10,
4286
+ step: 0.5,
4287
+ value: settings.activeCoverSlideDuration,
4288
+ onChange: (event) => settings.setCoverSlideDuration(Number(event.target.value))
4289
+ }
4290
+ )
4291
+ ] }),
4292
+ /* @__PURE__ */ jsxs6("fieldset", { className: "squisq-cover-slide-timing", children: [
4293
+ /* @__PURE__ */ jsx8("legend", { children: "Exported video timing" }),
4294
+ /* @__PURE__ */ jsxs6("label", { children: [
4295
+ /* @__PURE__ */ jsx8(
4296
+ "input",
4297
+ {
4298
+ type: "radio",
4299
+ name: "squisq-cover-playback",
4300
+ value: "preroll",
4301
+ checked: settings.activeCoverSlidePlayback === "preroll",
4302
+ onChange: () => settings.setCoverSlidePlayback("preroll")
4303
+ }
4304
+ ),
4305
+ /* @__PURE__ */ jsxs6("span", { children: [
4306
+ "Delay video",
4307
+ /* @__PURE__ */ jsx8("small", { children: "Start the story after the cover." })
4308
+ ] })
4309
+ ] }),
4310
+ /* @__PURE__ */ jsxs6("label", { children: [
4311
+ /* @__PURE__ */ jsx8(
4312
+ "input",
4313
+ {
4314
+ type: "radio",
4315
+ name: "squisq-cover-playback",
4316
+ value: "overlay",
4317
+ checked: settings.activeCoverSlidePlayback === "overlay",
4318
+ onChange: () => settings.setCoverSlidePlayback("overlay")
4319
+ }
4320
+ ),
4321
+ /* @__PURE__ */ jsxs6("span", { children: [
4322
+ "Play underneath",
4323
+ /* @__PURE__ */ jsx8("small", { children: "Let the story advance behind the cover." })
4324
+ ] })
4325
+ ] })
4326
+ ] }),
4327
+ /* @__PURE__ */ jsxs6(
4328
+ "button",
4329
+ {
4330
+ type: "button",
4331
+ className: "squisq-cover-slide-export",
4332
+ disabled: !coverExists,
4333
+ title: coverExists ? void 0 : "No cover slide to export \u2014 start the document with a level-1 heading (# Title) to generate one.",
4334
+ onClick: () => {
4335
+ closeMenu();
4336
+ setExportOpen(true);
4337
+ },
4338
+ children: [
4339
+ /* @__PURE__ */ jsx8(Icon, { icon: "fa-solid fa-image" }),
4340
+ "Export cover as image\u2026"
4341
+ ]
4342
+ }
4343
+ )
4344
+ ]
4345
+ }
4346
+ ),
4347
+ document.body
4348
+ ),
4349
+ exportOpen && doc && createPortal2(
4350
+ /* @__PURE__ */ jsx8(
4351
+ CoverImageExportModal,
4352
+ {
4353
+ doc,
4354
+ mediaProvider,
4355
+ theme: settings.activeTheme,
4356
+ coverSlideTemplate: settings.activeCoverSlideTemplate,
4357
+ defaultWidth: settings.activeViewport.width,
4358
+ defaultHeight: settings.activeViewport.height,
4359
+ defaultFileName: fileName,
4360
+ colorScheme,
4361
+ onClose: () => setExportOpen(false)
4362
+ }
4363
+ ),
4364
+ document.body
4365
+ )
4366
+ ]
4367
+ }
4368
+ );
4369
+ }
4021
4370
  function PreviewToolbarControls({ displayMode } = {}) {
4022
4371
  const s = usePreviewSettings();
4023
4372
  const controlKeys = controlKeysForMode(displayMode ?? s.activeDisplayMode, s.hasVideoMedia);
@@ -4310,24 +4659,7 @@ function PreviewToolbarControls({ displayMode } = {}) {
4310
4659
  "loop"
4311
4660
  );
4312
4661
  case "cover":
4313
- return /* @__PURE__ */ jsx8(
4314
- "div",
4315
- {
4316
- className: `squisq-preview-control${compact ? " squisq-preview-control--compact" : ""}`,
4317
- children: /* @__PURE__ */ jsxs6("label", { className: "squisq-preview-checkbox", children: [
4318
- /* @__PURE__ */ jsx8(
4319
- "input",
4320
- {
4321
- type: "checkbox",
4322
- checked: s.activeCoverSlide,
4323
- onChange: (e2) => s.setCoverSlideEnabled(e2.target.checked)
4324
- }
4325
- ),
4326
- /* @__PURE__ */ jsx8("span", { children: "Cover slide" })
4327
- ] })
4328
- },
4329
- "cover"
4330
- );
4662
+ return /* @__PURE__ */ jsx8(CoverSlideMenuControl, { compact }, "cover");
4331
4663
  }
4332
4664
  };
4333
4665
  const hasOverflow = visibleCount < controlKeys.length;
@@ -4440,8 +4772,10 @@ function PreviewModeMenu({ openRequest = 0 }) {
4440
4772
  useEffect8(() => {
4441
4773
  if (!open) return;
4442
4774
  const handlePointerDown = (event) => {
4443
- const target = event.target;
4444
- if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return;
4775
+ const eventPath = event.composedPath();
4776
+ if (triggerRef.current && eventPath.includes(triggerRef.current) || menuRef.current && eventPath.includes(menuRef.current)) {
4777
+ return;
4778
+ }
4445
4779
  closeMenu();
4446
4780
  };
4447
4781
  const handleKeyDown = (event) => {
@@ -5198,7 +5532,7 @@ function TemplateThumbnail({ def, width = W2, height = H2 }) {
5198
5532
 
5199
5533
  // src/TemplateContentPreview.tsx
5200
5534
  import { useMemo as useMemo11 } from "react";
5201
- import { BlockRenderer, MediaContext } from "@bendyline/squisq-react";
5535
+ import { BlockRenderer as BlockRenderer2, MediaContext as MediaContext2 } from "@bendyline/squisq-react";
5202
5536
 
5203
5537
  // src/templateContentPreviewResolver.ts
5204
5538
  import {
@@ -5502,8 +5836,8 @@ function TemplateContentPreview({
5502
5836
  className: "squisq-template-gallery-content-preview",
5503
5837
  style: { aspectRatio: `${source.viewport.width} / ${source.viewport.height}` },
5504
5838
  "aria-hidden": "true",
5505
- children: /* @__PURE__ */ jsx14(MediaContext.Provider, { value: source.mediaProvider ?? null, children: /* @__PURE__ */ jsx14(
5506
- BlockRenderer,
5839
+ children: /* @__PURE__ */ jsx14(MediaContext2.Provider, { value: source.mediaProvider ?? null, children: /* @__PURE__ */ jsx14(
5840
+ BlockRenderer2,
5507
5841
  {
5508
5842
  block: preview.visual,
5509
5843
  blockTime: 0,
@@ -5587,6 +5921,17 @@ var TEMPLATE_ENTRIES = [
5587
5921
  /* @__PURE__ */ jsx15("rect", { x: 11, y: 24, width: 20, height: 2.5, rx: 1, fill: F1, opacity: 0.7 })
5588
5922
  ] })
5589
5923
  },
5924
+ {
5925
+ name: "bigText",
5926
+ label: "Big Text",
5927
+ description: "Gigantic uppercase display text \u2014 thumbnail-style \u2014 on a theme surface or over an image with a contrast bloom.",
5928
+ icon: /* @__PURE__ */ jsxs11(TemplateIcon, { children: [
5929
+ /* @__PURE__ */ jsx15("rect", { x: 4, y: 4, width: 48, height: 32, rx: 2, fill: F1, opacity: 0.25 }),
5930
+ /* @__PURE__ */ jsx15("ellipse", { cx: 28, cy: 20, rx: 22, ry: 13, fill: F1, opacity: 0.35 }),
5931
+ /* @__PURE__ */ jsx15("rect", { x: 8, y: 12, width: 40, height: 10, rx: 2, fill: FA }),
5932
+ /* @__PURE__ */ jsx15("rect", { x: 16, y: 26, width: 24, height: 4, rx: 1, fill: F2 })
5933
+ ] })
5934
+ },
5590
5935
  {
5591
5936
  name: "content",
5592
5937
  label: "Content",
@@ -10332,7 +10677,7 @@ import { createPortal as createPortal7 } from "react-dom";
10332
10677
  // src/customTemplates/TemplateDesigner.tsx
10333
10678
  import { useCallback as useCallback26, useId as useId9, useMemo as useMemo23, useRef as useRef25, useState as useState28 } from "react";
10334
10679
  import { createPortal as createPortal6 } from "react-dom";
10335
- import { MediaContext as MediaContext2 } from "@bendyline/squisq-react";
10680
+ import { MediaContext as MediaContext3 } from "@bendyline/squisq-react";
10336
10681
 
10337
10682
  // src/scene/Scene.tsx
10338
10683
  import {
@@ -15126,7 +15471,7 @@ function TemplateDesigner({
15126
15471
  /* @__PURE__ */ jsx36(LayerToolbar, { layer: selectedLayer, onAttr: handleLayerAttr })
15127
15472
  ] })
15128
15473
  ] }),
15129
- /* @__PURE__ */ jsx36("div", { className: "squisq-template-designer-scene", children: /* @__PURE__ */ jsx36(MediaContext2.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx36(
15474
+ /* @__PURE__ */ jsx36("div", { className: "squisq-template-designer-scene", children: /* @__PURE__ */ jsx36(MediaContext3.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx36(
15130
15475
  Scene,
15131
15476
  {
15132
15477
  viewport: currentViewport,
@@ -28806,7 +29151,7 @@ import {
28806
29151
  deriveTemplateInputs as deriveTemplateInputs2
28807
29152
  } from "@bendyline/squisq/doc";
28808
29153
  import { extractPlainText as extractPlainText3, getChildren } from "@bendyline/squisq/markdown";
28809
- import { BlockRenderer as BlockRenderer2, MediaContext as MediaContext3 } from "@bendyline/squisq-react";
29154
+ import { BlockRenderer as BlockRenderer3, MediaContext as MediaContext4 } from "@bendyline/squisq-react";
28810
29155
 
28811
29156
  // src/useHeadingLayout.ts
28812
29157
  import { useCallback as useCallback39, useEffect as useEffect40, useMemo as useMemo36, useState as useState50 } from "react";
@@ -29368,7 +29713,7 @@ function InlinePreviewGutter({
29368
29713
  })
29369
29714
  }
29370
29715
  ),
29371
- /* @__PURE__ */ jsx57(MediaContext3.Provider, { value: mediaProvider ?? null, children: items.map((item) => {
29716
+ /* @__PURE__ */ jsx57(MediaContext4.Provider, { value: mediaProvider ?? null, children: items.map((item) => {
29372
29717
  const top = positions.get(item.id);
29373
29718
  const hidden = top == null;
29374
29719
  return /* @__PURE__ */ jsxs45(
@@ -29400,7 +29745,7 @@ function InlinePreviewGutter({
29400
29745
  aspectRatio: `${viewport.width} / ${viewport.height}`
29401
29746
  },
29402
29747
  children: /* @__PURE__ */ jsx57(
29403
- BlockRenderer2,
29748
+ BlockRenderer3,
29404
29749
  {
29405
29750
  block: item.block,
29406
29751
  blockTime: 0,
@@ -30908,7 +31253,7 @@ import {
30908
31253
  VIEWPORT_PRESETS as VIEWPORT_PRESETS6
30909
31254
  } from "@bendyline/squisq/schemas";
30910
31255
  import { flattenBlocks as flattenBlocks6, DEFAULT_THEME as DEFAULT_THEME6, getPinnedBlockMeta } from "@bendyline/squisq/doc";
30911
- import { MediaClipLayer, MediaContext as MediaContext5 } from "@bendyline/squisq-react";
31256
+ import { MediaClipLayer, MediaContext as MediaContext6 } from "@bendyline/squisq-react";
30912
31257
 
30913
31258
  // src/embeddedMedia.ts
30914
31259
  import { parseTimeSeconds as parseTimeSeconds2 } from "@bendyline/squisq/markdown";
@@ -31028,7 +31373,7 @@ function collectTimelinePlaybackSchedule(doc, scheduled) {
31028
31373
  // src/TimelineBlockPreview.tsx
31029
31374
  import { memo } from "react";
31030
31375
  import { VIEWPORT_PRESETS as VIEWPORT_PRESETS5 } from "@bendyline/squisq/schemas";
31031
- import { BlockRenderer as BlockRenderer3, MediaContext as MediaContext4 } from "@bendyline/squisq-react";
31376
+ import { BlockRenderer as BlockRenderer4, MediaContext as MediaContext5 } from "@bendyline/squisq-react";
31032
31377
  import { jsx as jsx62 } from "react/jsx-runtime";
31033
31378
  var BlockThumbnail = memo(function BlockThumbnail2({
31034
31379
  visual,
@@ -31036,7 +31381,7 @@ var BlockThumbnail = memo(function BlockThumbnail2({
31036
31381
  basePath = "/",
31037
31382
  mediaProvider = null
31038
31383
  }) {
31039
- return /* @__PURE__ */ jsx62(MediaContext4.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx62(BlockRenderer3, { block: visual, blockTime: 0, basePath, viewport }) });
31384
+ return /* @__PURE__ */ jsx62(MediaContext5.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx62(BlockRenderer4, { block: visual, blockTime: 0, basePath, viewport }) });
31040
31385
  });
31041
31386
 
31042
31387
  // src/resolveBlockVisual.ts
@@ -32245,7 +32590,7 @@ function TimelineTrack({
32245
32590
  }
32246
32591
  )
32247
32592
  ] }) }),
32248
- /* @__PURE__ */ jsx64("div", { ref: activeClock.registerMediaHost, className: "squisq-timeline-media-host", "aria-hidden": true, children: /* @__PURE__ */ jsx64(MediaContext5.Provider, { value: mediaProvider ?? null, children: /* @__PURE__ */ jsx64(
32593
+ /* @__PURE__ */ jsx64("div", { ref: activeClock.registerMediaHost, className: "squisq-timeline-media-host", "aria-hidden": true, children: /* @__PURE__ */ jsx64(MediaContext6.Provider, { value: mediaProvider ?? null, children: /* @__PURE__ */ jsx64(
32249
32594
  MediaClipLayer,
32250
32595
  {
32251
32596
  schedule: playbackClips,
@@ -32422,13 +32767,7 @@ function usePreviewProjection(doc, transformStyle, workspaceContainer, documentT
32422
32767
  if (!cancelled) commit(immediate);
32423
32768
  }
32424
32769
  );
32425
- setProjection((previous) => {
32426
- if (!previous) return immediate;
32427
- return {
32428
- ...immediate,
32429
- playerDoc: { ...immediate.playerDoc, audio: previous.playerDoc.audio }
32430
- };
32431
- });
32770
+ setProjection((previous) => previous ?? immediate);
32432
32771
  return () => {
32433
32772
  cancelled = true;
32434
32773
  };
@@ -32457,7 +32796,10 @@ function TimelineCompositionPanel({
32457
32796
  activePipSize,
32458
32797
  activePipShape,
32459
32798
  activePipPosition,
32460
- activeCoverSlide
32799
+ activeCoverSlide,
32800
+ activeCoverSlideTemplate,
32801
+ activeCoverSlideDuration,
32802
+ activeCoverSlidePlayback
32461
32803
  } = usePreviewSettings();
32462
32804
  const { fileName } = useEditorContext();
32463
32805
  const projection = usePreviewProjection(
@@ -32543,6 +32885,9 @@ function TimelineCompositionPanel({
32543
32885
  captionStyle: activeCaptionStyle,
32544
32886
  captionsEnabled: activeCaptionsEnabled,
32545
32887
  showCoverSlide: activeCoverSlide,
32888
+ coverSlideTemplate: activeCoverSlideTemplate,
32889
+ coverSlideDuration: activeCoverSlideDuration,
32890
+ coverSlidePlayback: activeCoverSlidePlayback,
32546
32891
  enableSwipe: false,
32547
32892
  globalKeyboardShortcuts: false
32548
32893
  }
@@ -33762,15 +34107,15 @@ function PrintPreviewToolbar() {
33762
34107
  // src/print/PrintPreview.tsx
33763
34108
  import { useCallback as useCallback48, useEffect as useEffect51, useMemo as useMemo47, useRef as useRef51 } from "react";
33764
34109
  import {
33765
- BlockRenderer as BlockRenderer4,
34110
+ BlockRenderer as BlockRenderer5,
33766
34111
  LinearDocView,
33767
34112
  useDocPlayback,
33768
34113
  useMediaProvider
33769
34114
  } from "@bendyline/squisq-react";
33770
34115
  import {
33771
- createTemplateContext
34116
+ createTemplateContext as createTemplateContext2
33772
34117
  } from "@bendyline/squisq/schemas";
33773
- import { expandCoverBlock } from "@bendyline/squisq/doc";
34118
+ import { expandCoverBlock as expandCoverBlock2 } from "@bendyline/squisq/doc";
33774
34119
  import { resolveTransformStyle } from "@bendyline/squisq/transform";
33775
34120
  import { jsx as jsx71, jsxs as jsxs56 } from "react/jsx-runtime";
33776
34121
  function chunk(values, size) {
@@ -33801,13 +34146,13 @@ function PrintPreview({
33801
34146
  const { blocks } = useDocPlayback(previewDoc, 0, { viewport, theme });
33802
34147
  const coverBlock = useMemo47(() => {
33803
34148
  if (!showCover || !previewDoc?.startBlock) return null;
33804
- const context = createTemplateContext(theme, 0, 1, viewport);
34149
+ const context = createTemplateContext2(theme, 0, 1, viewport);
33805
34150
  return {
33806
34151
  id: "cover-block",
33807
34152
  startTime: -1,
33808
34153
  duration: 0,
33809
34154
  audioSegment: -1,
33810
- layers: expandCoverBlock(previewDoc.startBlock, context)
34155
+ layers: expandCoverBlock2(previewDoc.startBlock, context)
33811
34156
  };
33812
34157
  }, [previewDoc?.startBlock, showCover, theme, viewport]);
33813
34158
  const isTextDocument = displayMode === "page" || displayMode === "narrate";
@@ -33874,7 +34219,7 @@ function PrintPreview({
33874
34219
  "data-slides-per-page": density,
33875
34220
  "aria-label": `Print page ${pageIndex + 1}`,
33876
34221
  children: sheet.map((block) => /* @__PURE__ */ jsx71("div", { className: "squisq-print-slide-cell", children: /* @__PURE__ */ jsx71("div", { className: "squisq-print-slide-frame", children: /* @__PURE__ */ jsx71(
33877
- BlockRenderer4,
34222
+ BlockRenderer5,
33878
34223
  {
33879
34224
  block,
33880
34225
  blockTime: Math.max(0, block.duration),
@@ -33928,7 +34273,10 @@ function PreviewPanel({
33928
34273
  activePipShape,
33929
34274
  activePipPosition,
33930
34275
  activeVideoLoop,
33931
- activeCoverSlide
34276
+ activeCoverSlide,
34277
+ activeCoverSlideTemplate,
34278
+ activeCoverSlideDuration,
34279
+ activeCoverSlidePlayback
33932
34280
  } = usePreviewSettings();
33933
34281
  const mainSurfaceRef = useRef52(null);
33934
34282
  const popupSurfaceRef = useRef52(null);
@@ -34139,6 +34487,9 @@ function PreviewPanel({
34139
34487
  captionStyle: audienceCaptionMode === "social" ? "social" : activeCaptionStyle,
34140
34488
  captionsEnabled: audience && audienceCaptionMode ? audienceCaptionMode !== "off" : activeCaptionsEnabled,
34141
34489
  showCoverSlide: activeCoverSlide,
34490
+ coverSlideTemplate: activeCoverSlideTemplate,
34491
+ coverSlideDuration: activeCoverSlideDuration,
34492
+ coverSlidePlayback: activeCoverSlidePlayback,
34142
34493
  coverVisible: audience ? playbackState?.isCoverVisible : void 0,
34143
34494
  audioController: audience ? followerAudioController : void 0,
34144
34495
  enableSwipe: !audience,
@@ -35153,7 +35504,7 @@ import {
35153
35504
  scopeContainer,
35154
35505
  createMediaProviderFromContainer
35155
35506
  } from "@bendyline/squisq/storage";
35156
- import { MediaContext as MediaContext6, useMediaClipDurations } from "@bendyline/squisq-react";
35507
+ import { MediaContext as MediaContext7, useMediaClipDurations } from "@bendyline/squisq-react";
35157
35508
  import { Fragment as Fragment22, jsx as jsx77, jsxs as jsxs60 } from "react/jsx-runtime";
35158
35509
  function EditorShell({
35159
35510
  initialMarkdown = "",
@@ -35230,7 +35581,7 @@ function EditorShell({
35230
35581
  }, [mediaProvider, effectiveContainer]);
35231
35582
  const filesToggleEnabled = showFilesToggle ?? effectiveMediaProvider !== void 0;
35232
35583
  const effectiveInitialView = hostMode === "chat" || !showPlayTab && initialView === "preview" ? "wysiwyg" : initialView;
35233
- return /* @__PURE__ */ jsx77(MediaContext6.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx77(
35584
+ return /* @__PURE__ */ jsx77(MediaContext7.Provider, { value: effectiveMediaProvider ?? null, children: /* @__PURE__ */ jsx77(
35234
35585
  EditorProvider,
35235
35586
  {
35236
35587
  initialMarkdown,
package/dist/index.d.ts CHANGED
@@ -8,11 +8,11 @@ import { ContentContainer } from '@bendyline/squisq/storage';
8
8
  export { CanvasRect, ImageEditor, ImageEditorAction, ImageEditorProps, ImageEditorState, ImageEditorTool, ImageViewer, ImageViewerProps, UseImageEditorOptions, UseImageEditorReturn, imageEditorReducer, initialImageEditorState, useImageEditor } from './image-editor/index.js';
9
9
  import { IconFamily } from '@bendyline/squisq/icons';
10
10
  import { DisplayMode, CaptionStyle, VideoPresentation, PipSize, PipShape, PipPosition } from '@bendyline/squisq-react';
11
+ import { CoverSlideTemplate, CoverSlidePlayback, ConnectorRouting, AsciiDiagram, Tree, AsciiTimeline, AsciiTimelineSide, AsciiTimelineMarker } from '@bendyline/squisq/doc';
11
12
  import { MarkdownWrapState } from '@bendyline/squisq/markdown';
12
13
  import * as monaco_editor from 'monaco-editor';
13
14
  import { M as MonacoLanguageRequest, a as MonacoLanguageLoadOptions } from './monacoLanguageDetection-DEyUW-BS.js';
14
15
  export { MonacoWorkerConstructor, MonacoWorkerConstructors, configureMonacoWorkers } from './monaco-workers/index.js';
15
- import { ConnectorRouting, AsciiDiagram, Tree, AsciiTimeline, AsciiTimelineSide, AsciiTimelineMarker } from '@bendyline/squisq/doc';
16
16
  import * as _tiptap_core from '@tiptap/core';
17
17
  import { Extension } from '@tiptap/core';
18
18
  import * as _tiptap_extension_heading from '@tiptap/extension-heading';
@@ -826,6 +826,12 @@ interface PreviewSettings {
826
826
  activeCoverSlide: boolean;
827
827
  /** Enable/disable the managed cover slide. */
828
828
  setCoverSlideEnabled: (enabled: boolean) => void;
829
+ activeCoverSlideTemplate: CoverSlideTemplate;
830
+ setCoverSlideTemplate: (template: CoverSlideTemplate) => void;
831
+ activeCoverSlideDuration: number;
832
+ setCoverSlideDuration: (duration: number) => void;
833
+ activeCoverSlidePlayback: CoverSlidePlayback;
834
+ setCoverSlidePlayback: (playback: CoverSlidePlayback) => void;
829
835
  /** Whether Video mode restarts automatically when playback ends. */
830
836
  activeVideoLoop: boolean;
831
837
  /** Enable/disable automatic Video-mode playback restart. */
@@ -873,18 +879,6 @@ interface PreviewSettingsProviderProps {
873
879
  themeOverride?: Theme | null;
874
880
  }
875
881
  declare function PreviewSettingsProvider({ doc, children, defaultViewportPreset, themeOverride, }: PreviewSettingsProviderProps): react_jsx_runtime.JSX.Element;
876
- /**
877
- * Inline preview controls rendered in the main toolbar row.
878
- *
879
- * Collapse is *progressive* (a priority-plus pattern): rather than switch the
880
- * whole row in and out at a fixed window-width breakpoint, the controls
881
- * measure how many of them actually fit in the width the toolbar gives them
882
- * and keep that many inline, folding the rest — from the low-priority end of
883
- * {@link CONTROL_KEYS} — into a single ellipsis button's popover. As
884
- * the toolbar widens or narrows, controls migrate one at a time between the
885
- * inline row and the menu, so the available space is always well used and the
886
- * row never wraps onto a second line.
887
- */
888
882
  interface PreviewToolbarControlsProps {
889
883
  /**
890
884
  * Display mode whose applicable control set should be rendered. Defaults to
package/dist/index.js CHANGED
@@ -194,7 +194,7 @@ import {
194
194
  usePreviewSettings,
195
195
  useTimelineData,
196
196
  useTreeViewData
197
- } from "./chunk-55DQFHK5.js";
197
+ } from "./chunk-DCMJXDQY.js";
198
198
  import "./chunk-V4NBQF5C.js";
199
199
  import {
200
200
  JsonEditor
@@ -5,7 +5,7 @@ import {
5
5
  RawEditor,
6
6
  WysiwygEditor,
7
7
  useEditorContext
8
- } from "../chunk-55DQFHK5.js";
8
+ } from "../chunk-DCMJXDQY.js";
9
9
  import "../chunk-V4NBQF5C.js";
10
10
  import "../chunk-K2WJYVS4.js";
11
11
  import "../chunk-V44VP242.js";
@@ -7269,6 +7269,219 @@
7269
7269
  .squisq-use-mode-menu[data-theme=dark] .squisq-use-mode-menu-check {
7270
7270
  color: #93c5fd;
7271
7271
  }
7272
+ .squisq-cover-slide-trigger {
7273
+ display: inline-flex;
7274
+ align-items: center;
7275
+ gap: 6px;
7276
+ min-height: 28px;
7277
+ padding: 3px 8px;
7278
+ border: 1px solid var(--squisq-border, #d1d5db);
7279
+ border-radius: 5px;
7280
+ background: var(--squisq-input-bg, #fff);
7281
+ color: var(--squisq-text, #1f2937);
7282
+ font: inherit;
7283
+ font-size: 12px;
7284
+ font-weight: 500;
7285
+ white-space: nowrap;
7286
+ cursor: pointer;
7287
+ }
7288
+ .squisq-cover-slide-trigger:hover,
7289
+ .squisq-cover-slide-trigger--open {
7290
+ border-color: var(--squisq-accent, #2563eb);
7291
+ background: var(--squisq-hover-bg, var(--squisq-bg, #f3f4f6));
7292
+ }
7293
+ .squisq-cover-slide-status {
7294
+ display: inline-flex;
7295
+ align-items: center;
7296
+ justify-content: center;
7297
+ width: 15px;
7298
+ height: 15px;
7299
+ border-radius: 50%;
7300
+ background: var(--squisq-border, #d1d5db);
7301
+ color: var(--squisq-text-muted, #6b7280);
7302
+ font-size: 8px;
7303
+ }
7304
+ .squisq-cover-slide-status--enabled {
7305
+ background: var(--squisq-accent, #2563eb);
7306
+ color: var(--squisq-text-on-accent, #fff);
7307
+ }
7308
+ .squisq-cover-slide-menu {
7309
+ --cover-bg: #fff;
7310
+ --cover-control: #fff;
7311
+ --cover-border: #d1d5db;
7312
+ --cover-text: #1f2937;
7313
+ --cover-muted: #6b7280;
7314
+ position: fixed;
7315
+ z-index: 120;
7316
+ box-sizing: border-box;
7317
+ width: min(336px, calc(100vw - 16px));
7318
+ padding: 14px;
7319
+ border: 1px solid var(--cover-border);
7320
+ border-radius: 8px;
7321
+ background: var(--cover-bg);
7322
+ color: var(--cover-text);
7323
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
7324
+ font-family:
7325
+ system-ui,
7326
+ -apple-system,
7327
+ sans-serif;
7328
+ color-scheme: light;
7329
+ }
7330
+ .squisq-cover-slide-menu[data-theme=dark] {
7331
+ --cover-bg: #111827;
7332
+ --cover-control: #0f172a;
7333
+ --cover-border: #475569;
7334
+ --cover-text: #f8fafc;
7335
+ --cover-muted: #94a3b8;
7336
+ color-scheme: dark;
7337
+ }
7338
+ .squisq-cover-slide-menu-heading,
7339
+ .squisq-cover-slide-field > span {
7340
+ display: flex;
7341
+ align-items: center;
7342
+ justify-content: space-between;
7343
+ gap: 12px;
7344
+ }
7345
+ .squisq-cover-slide-menu-heading {
7346
+ margin-bottom: 14px;
7347
+ font-size: 14px;
7348
+ font-weight: 700;
7349
+ }
7350
+ .squisq-cover-slide-switch {
7351
+ display: inline-flex;
7352
+ align-items: center;
7353
+ gap: 6px;
7354
+ font-size: 12px;
7355
+ font-weight: 500;
7356
+ cursor: pointer;
7357
+ }
7358
+ .squisq-cover-slide-switch input,
7359
+ .squisq-cover-slide-timing input {
7360
+ accent-color: var(--squisq-accent, #2563eb);
7361
+ }
7362
+ .squisq-cover-slide-preview {
7363
+ display: flex;
7364
+ align-items: center;
7365
+ justify-content: center;
7366
+ box-sizing: border-box;
7367
+ margin: 0 0 12px;
7368
+ overflow: hidden;
7369
+ border: 1px solid var(--cover-border);
7370
+ border-radius: 6px;
7371
+ background: var(--cover-control);
7372
+ }
7373
+ .squisq-cover-slide-preview--disabled {
7374
+ opacity: 0.45;
7375
+ }
7376
+ .squisq-cover-slide-preview-frame {
7377
+ display: flex;
7378
+ width: 100%;
7379
+ height: 100%;
7380
+ }
7381
+ .squisq-cover-slide-preview-frame .block-svg {
7382
+ display: block;
7383
+ width: 100%;
7384
+ height: 100%;
7385
+ }
7386
+ .squisq-cover-slide-preview-empty {
7387
+ margin: 0;
7388
+ padding: 10px 14px;
7389
+ color: var(--cover-muted);
7390
+ font-size: 11px;
7391
+ line-height: 1.4;
7392
+ text-align: center;
7393
+ }
7394
+ .squisq-cover-slide-field {
7395
+ display: grid;
7396
+ gap: 6px;
7397
+ margin-bottom: 10px;
7398
+ color: var(--cover-text);
7399
+ font-size: 12px;
7400
+ font-weight: 600;
7401
+ }
7402
+ .squisq-cover-slide-field select {
7403
+ box-sizing: border-box;
7404
+ width: 100%;
7405
+ min-height: 34px;
7406
+ padding: 5px 8px;
7407
+ border: 1px solid var(--cover-border);
7408
+ border-radius: 4px;
7409
+ background: var(--cover-control);
7410
+ color: var(--cover-text);
7411
+ font: inherit;
7412
+ }
7413
+ .squisq-cover-slide-field output {
7414
+ color: var(--cover-muted);
7415
+ font-variant-numeric: tabular-nums;
7416
+ font-weight: 500;
7417
+ }
7418
+ .squisq-cover-slide-field input[type=range] {
7419
+ width: 100%;
7420
+ margin: 3px 0;
7421
+ accent-color: var(--squisq-accent, #2563eb);
7422
+ }
7423
+ .squisq-cover-slide-help {
7424
+ min-height: 30px;
7425
+ margin: -4px 0 12px;
7426
+ color: var(--cover-muted);
7427
+ font-size: 11px;
7428
+ line-height: 1.35;
7429
+ }
7430
+ .squisq-cover-slide-timing {
7431
+ display: grid;
7432
+ gap: 7px;
7433
+ margin: 0 0 14px;
7434
+ padding: 10px;
7435
+ border: 1px solid var(--cover-border);
7436
+ border-radius: 5px;
7437
+ }
7438
+ .squisq-cover-slide-timing legend {
7439
+ padding: 0 4px;
7440
+ color: var(--cover-muted);
7441
+ font-size: 11px;
7442
+ font-weight: 700;
7443
+ }
7444
+ .squisq-cover-slide-timing label {
7445
+ display: grid;
7446
+ grid-template-columns: auto 1fr;
7447
+ align-items: start;
7448
+ gap: 8px;
7449
+ font-size: 12px;
7450
+ cursor: pointer;
7451
+ }
7452
+ .squisq-cover-slide-timing label > span {
7453
+ display: grid;
7454
+ gap: 2px;
7455
+ font-weight: 600;
7456
+ }
7457
+ .squisq-cover-slide-timing small {
7458
+ color: var(--cover-muted);
7459
+ font-size: 11px;
7460
+ font-weight: 400;
7461
+ }
7462
+ .squisq-cover-slide-export {
7463
+ display: inline-flex;
7464
+ align-items: center;
7465
+ justify-content: center;
7466
+ gap: 7px;
7467
+ width: 100%;
7468
+ min-height: 34px;
7469
+ border: 1px solid var(--cover-border);
7470
+ border-radius: 5px;
7471
+ background: var(--cover-control);
7472
+ color: var(--cover-text);
7473
+ font: inherit;
7474
+ font-size: 12px;
7475
+ font-weight: 600;
7476
+ cursor: pointer;
7477
+ }
7478
+ .squisq-cover-slide-export:hover:not(:disabled) {
7479
+ border-color: var(--squisq-accent, #2563eb);
7480
+ }
7481
+ .squisq-cover-slide-export:disabled {
7482
+ opacity: 0.55;
7483
+ cursor: not-allowed;
7484
+ }
7272
7485
  .squisq-editor-shell[data-outline-visible=true] .squisq-toolbar-view-tabs {
7273
7486
  flex-shrink: 0;
7274
7487
  min-width: var(--squisq-outline-width, 240px);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-editor-react",
3
- "version": "2.4.7",
3
+ "version": "2.5.0",
4
4
  "description": "React editor shell with raw/WYSIWYG/preview modes for Squisq documents",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -84,9 +84,10 @@
84
84
  "react-dom": "^18.0.0 || ^19.0.0"
85
85
  },
86
86
  "dependencies": {
87
- "@bendyline/squisq": "2.4.4",
88
- "@bendyline/squisq-formats": "2.3.9",
89
- "@bendyline/squisq-react": "2.4.7",
87
+ "@bendyline/squisq": "2.5.0",
88
+ "@bendyline/squisq-formats": "2.3.10",
89
+ "@bendyline/squisq-react": "2.5.0",
90
+ "@bendyline/squisq-video-react": "2.3.0",
90
91
  "@fortawesome/fontawesome-free": "7.2.0",
91
92
  "@tiptap/core": "2.27.2",
92
93
  "@tiptap/extension-heading": "2.27.2",