@vishu1301/script-writing 0.4.4 → 0.4.5

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.cjs CHANGED
@@ -242,9 +242,6 @@ function PdfImporter({ onScriptImported, children }) {
242
242
  }
243
243
  function ScreenplayEditorView({
244
244
  blocks,
245
- pages,
246
- isPageSplitEnabled,
247
- togglePageSplit,
248
245
  refs,
249
246
  focusedBlockId,
250
247
  showSuggestions,
@@ -307,131 +304,56 @@ function ScreenplayEditorView({
307
304
  type
308
305
  );
309
306
  }) }),
310
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-12 w-full items-center pb-24", children: pages.map((pageBlocks, pageIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
307
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-12 w-full items-center pb-24", children: /* @__PURE__ */ jsxRuntime.jsx(
311
308
  "div",
312
309
  {
313
310
  className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 ring-1 ring-zinc-200/50 rounded-sm md:rounded-md pl-[1.5in] py-[1in] pr-[1in] flex flex-col w-[210mm] min-h-[297mm] shrink-0",
314
311
  style: {
315
312
  fontFamily: "var(--font-courier-prime, 'Courier New', Courier, monospace)"
316
313
  },
317
- children: [
318
- pageBlocks.map((block) => {
319
- var _a, _b;
320
- return /* @__PURE__ */ jsxRuntime.jsx(
321
- "div",
322
- {
323
- "data-block-id": block.id,
324
- className: `relative rounded-sm transition-all duration-200 outline-none ${focusedBlockId === block.id ? "bg-zinc-100/50" : "bg-transparent"}`,
325
- children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
326
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
327
- /* @__PURE__ */ jsxRuntime.jsx(
328
- "input",
329
- {
330
- className: "absolute -left-16 top-2 w-12 text-right text-zinc-400 font-semibold select-none bg-transparent outline-none focus:ring-1 focus:ring-blue-400 rounded-sm",
331
- spellCheck: false,
332
- value: block.sceneNumber || "",
333
- onChange: (e) => handleSceneNumberChange(
334
- block.id,
335
- e.target.value.toUpperCase()
336
- ),
337
- onFocus: () => handleFocus(block.id),
338
- onBlur: () => handleBlur(block.id),
339
- onKeyDown: (e) => {
340
- if (e.key === "Enter" || e.key === "Backspace") {
341
- e.stopPropagation();
342
- }
343
- },
344
- "aria-label": "Scene Number"
345
- }
346
- ),
347
- /* @__PURE__ */ jsxRuntime.jsxs(
348
- "select",
349
- {
350
- className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
351
- "aria-label": "Scene Type",
352
- value: (_a = block.sceneType) != null ? _a : "INT.",
353
- onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
354
- children: [
355
- /* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT." }),
356
- /* @__PURE__ */ jsxRuntime.jsx("option", { children: "EXT." }),
357
- /* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT/EXT." })
358
- ]
359
- }
360
- ),
361
- /* @__PURE__ */ jsxRuntime.jsx(
362
- "div",
363
- {
364
- ref: (el) => {
365
- if (!el) return;
366
- refs.current[block.id] = el;
367
- },
368
- contentEditable: true,
369
- suppressContentEditableWarning: true,
370
- "aria-label": `Scene Heading: ${block.text}`,
371
- "aria-haspopup": "listbox",
372
- "aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
373
- spellCheck: false,
374
- className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
375
- onInput: (e) => handleBlockTextChange(
376
- block.id,
377
- e.target.innerText
378
- ),
379
- onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
380
- onFocus: () => handleFocus(block.id),
381
- onBlur: () => handleBlur(block.id)
382
- }
383
- ),
384
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
385
- /* @__PURE__ */ jsxRuntime.jsx(
386
- "select",
387
- {
388
- className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
389
- "aria-label": "Time of Day",
390
- value: (_b = block.timeOfDay) != null ? _b : "DAY",
391
- onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
392
- children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: t }, t))
393
- }
394
- )
395
- ] }),
396
- focusedBlockId === block.id && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
397
- "div",
314
+ children: blocks.map((block) => {
315
+ var _a, _b;
316
+ return /* @__PURE__ */ jsxRuntime.jsx(
317
+ "div",
318
+ {
319
+ "data-block-id": block.id,
320
+ className: `relative rounded-sm transition-all duration-200 outline-none ${focusedBlockId === block.id ? "bg-zinc-100/50" : "bg-transparent"}`,
321
+ children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
322
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
323
+ /* @__PURE__ */ jsxRuntime.jsx(
324
+ "input",
398
325
  {
399
- role: "listbox",
400
- id: `suggestions-${block.id}`,
401
- className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
402
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
403
- (loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
404
- ).map((loc) => /* @__PURE__ */ jsxRuntime.jsxs(
405
- "div",
406
- {
407
- role: "option",
408
- className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
409
- onMouseDown: (e) => {
410
- e.preventDefault();
411
- const element = refs.current[block.id];
412
- if (element) {
413
- element.innerText = loc;
414
- handleBlockTextChange(block.id, loc);
415
- element.focus();
416
- const range = document.createRange();
417
- const sel = window.getSelection();
418
- range.selectNodeContents(element);
419
- range.collapse(false);
420
- sel == null ? void 0 : sel.removeAllRanges();
421
- sel == null ? void 0 : sel.addRange(range);
422
- }
423
- handleBlur(block.id);
424
- },
425
- children: [
426
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
427
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
428
- ]
429
- },
430
- loc
431
- )) })
326
+ className: "absolute -left-16 top-2 w-12 text-right text-zinc-400 font-semibold select-none bg-transparent outline-none focus:ring-1 focus:ring-blue-400 rounded-sm",
327
+ spellCheck: false,
328
+ value: block.sceneNumber || "",
329
+ onChange: (e) => handleSceneNumberChange(
330
+ block.id,
331
+ e.target.value.toUpperCase()
332
+ ),
333
+ onFocus: () => handleFocus(block.id),
334
+ onBlur: () => handleBlur(block.id),
335
+ onKeyDown: (e) => {
336
+ if (e.key === "Enter" || e.key === "Backspace") {
337
+ e.stopPropagation();
338
+ }
339
+ },
340
+ "aria-label": "Scene Number"
432
341
  }
433
- )
434
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
342
+ ),
343
+ /* @__PURE__ */ jsxRuntime.jsxs(
344
+ "select",
345
+ {
346
+ className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
347
+ "aria-label": "Scene Type",
348
+ value: (_a = block.sceneType) != null ? _a : "INT.",
349
+ onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
350
+ children: [
351
+ /* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT." }),
352
+ /* @__PURE__ */ jsxRuntime.jsx("option", { children: "EXT." }),
353
+ /* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT/EXT." })
354
+ ]
355
+ }
356
+ ),
435
357
  /* @__PURE__ */ jsxRuntime.jsx(
436
358
  "div",
437
359
  {
@@ -441,100 +363,168 @@ function ScreenplayEditorView({
441
363
  },
442
364
  contentEditable: true,
443
365
  suppressContentEditableWarning: true,
444
- "aria-label": `${blockStyles[block.type].label} text`,
445
- "aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
366
+ "aria-label": `Scene Heading: ${block.text}`,
367
+ "aria-haspopup": "listbox",
368
+ "aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
446
369
  spellCheck: false,
447
- className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
370
+ className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
448
371
  onInput: (e) => handleBlockTextChange(
449
372
  block.id,
450
373
  e.target.innerText
451
374
  ),
452
375
  onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
453
376
  onFocus: () => handleFocus(block.id),
454
- onBlur: () => handleBlur(block.id),
455
- style: blockStyles[block.type].inputStyle
377
+ onBlur: () => handleBlur(block.id)
456
378
  }
457
379
  ),
458
- focusedBlockId === block.id && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
459
- "div",
460
- {
461
- role: "listbox",
462
- id: `suggestions-${block.id}`,
463
- className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
464
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
465
- (char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
466
- ).map((char) => /* @__PURE__ */ jsxRuntime.jsxs(
467
- "div",
468
- {
469
- role: "option",
470
- className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
471
- onMouseDown: (e) => {
472
- e.preventDefault();
473
- const element = refs.current[block.id];
474
- if (element) {
475
- element.innerText = char;
476
- handleBlockTextChange(block.id, char);
477
- element.focus();
478
- const range = document.createRange();
479
- const sel = window.getSelection();
480
- range.selectNodeContents(element);
481
- range.collapse(false);
482
- sel == null ? void 0 : sel.removeAllRanges();
483
- sel == null ? void 0 : sel.addRange(range);
484
- }
485
- handleBlur(block.id);
486
- },
487
- children: [
488
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-sky-500 transition-colors mr-3" }),
489
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
490
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
491
- ]
492
- },
493
- char
494
- )) })
495
- }
496
- ),
497
- focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsxRuntime.jsx(
498
- "div",
380
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
381
+ /* @__PURE__ */ jsxRuntime.jsx(
382
+ "select",
499
383
  {
500
- role: "listbox",
501
- id: `extension-suggestions-${block.id}`,
502
- className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
503
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
504
- const openParenIndex = block.text.lastIndexOf("(");
505
- const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
506
- return ext.toUpperCase().includes(query);
507
- }).map((ext) => /* @__PURE__ */ jsxRuntime.jsxs(
508
- "div",
509
- {
510
- role: "option",
511
- className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
512
- onMouseDown: (e) => {
513
- e.preventDefault();
514
- handleSelectCharacterExtension(ext);
515
- },
516
- children: [
517
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
518
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
519
- ]
520
- },
521
- ext
522
- )) })
384
+ className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
385
+ "aria-label": "Time of Day",
386
+ value: (_b = block.timeOfDay) != null ? _b : "DAY",
387
+ onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
388
+ children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: t }, t))
523
389
  }
524
390
  )
525
- ] })
526
- },
527
- block.id + "-" + block.type
528
- );
529
- }),
530
- isPageSplitEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-10 right-16 md:right-20 text-zinc-400 font-semibold text-sm select-none pointer-events-none", children: [
531
- pageIndex + 1,
532
- "."
533
- ] })
534
- ]
535
- },
536
- pageIndex
537
- )) }),
391
+ ] }),
392
+ focusedBlockId === block.id && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
393
+ "div",
394
+ {
395
+ role: "listbox",
396
+ id: `suggestions-${block.id}`,
397
+ className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
398
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
399
+ (loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
400
+ ).map((loc) => /* @__PURE__ */ jsxRuntime.jsxs(
401
+ "div",
402
+ {
403
+ role: "option",
404
+ className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
405
+ onMouseDown: (e) => {
406
+ e.preventDefault();
407
+ const element = refs.current[block.id];
408
+ if (element) {
409
+ element.innerText = loc;
410
+ handleBlockTextChange(block.id, loc);
411
+ element.focus();
412
+ const range = document.createRange();
413
+ const sel = window.getSelection();
414
+ range.selectNodeContents(element);
415
+ range.collapse(false);
416
+ sel == null ? void 0 : sel.removeAllRanges();
417
+ sel == null ? void 0 : sel.addRange(range);
418
+ }
419
+ handleBlur(block.id);
420
+ },
421
+ children: [
422
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
423
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
424
+ ]
425
+ },
426
+ loc
427
+ )) })
428
+ }
429
+ )
430
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx(
432
+ "div",
433
+ {
434
+ ref: (el) => {
435
+ if (!el) return;
436
+ refs.current[block.id] = el;
437
+ },
438
+ contentEditable: true,
439
+ suppressContentEditableWarning: true,
440
+ "aria-label": `${blockStyles[block.type].label} text`,
441
+ "aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
442
+ spellCheck: false,
443
+ className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
444
+ onInput: (e) => handleBlockTextChange(
445
+ block.id,
446
+ e.target.innerText
447
+ ),
448
+ onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
449
+ onFocus: () => handleFocus(block.id),
450
+ onBlur: () => handleBlur(block.id),
451
+ style: blockStyles[block.type].inputStyle
452
+ }
453
+ ),
454
+ focusedBlockId === block.id && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
455
+ "div",
456
+ {
457
+ role: "listbox",
458
+ id: `suggestions-${block.id}`,
459
+ className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
460
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
461
+ (char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
462
+ ).map((char) => /* @__PURE__ */ jsxRuntime.jsxs(
463
+ "div",
464
+ {
465
+ role: "option",
466
+ className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
467
+ onMouseDown: (e) => {
468
+ e.preventDefault();
469
+ const element = refs.current[block.id];
470
+ if (element) {
471
+ element.innerText = char;
472
+ handleBlockTextChange(block.id, char);
473
+ element.focus();
474
+ const range = document.createRange();
475
+ const sel = window.getSelection();
476
+ range.selectNodeContents(element);
477
+ range.collapse(false);
478
+ sel == null ? void 0 : sel.removeAllRanges();
479
+ sel == null ? void 0 : sel.addRange(range);
480
+ }
481
+ handleBlur(block.id);
482
+ },
483
+ children: [
484
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-sky-500 transition-colors mr-3" }),
485
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
486
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
487
+ ]
488
+ },
489
+ char
490
+ )) })
491
+ }
492
+ ),
493
+ focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsxRuntime.jsx(
494
+ "div",
495
+ {
496
+ role: "listbox",
497
+ id: `extension-suggestions-${block.id}`,
498
+ className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
499
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
500
+ const openParenIndex = block.text.lastIndexOf("(");
501
+ const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
502
+ return ext.toUpperCase().includes(query);
503
+ }).map((ext) => /* @__PURE__ */ jsxRuntime.jsxs(
504
+ "div",
505
+ {
506
+ role: "option",
507
+ className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
508
+ onMouseDown: (e) => {
509
+ e.preventDefault();
510
+ handleSelectCharacterExtension(ext);
511
+ },
512
+ children: [
513
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
514
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
515
+ ]
516
+ },
517
+ ext
518
+ )) })
519
+ }
520
+ )
521
+ ] })
522
+ },
523
+ block.id + "-" + block.type
524
+ );
525
+ })
526
+ }
527
+ ) }),
538
528
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-6 right-6 flex flex-col items-end gap-4 z-50", children: [
539
529
  /* @__PURE__ */ jsxRuntime.jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
540
530
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-5 h-5" }),
@@ -566,46 +556,24 @@ function ScreenplayEditorView({
566
556
  ),
567
557
  isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/80 backdrop-blur-md rounded-xl shadow-lg border border-zinc-200/50 p-4 text-xs text-zinc-700 select-none font-sans overflow-hidden transition-all duration-300 w-64 origin-bottom-right animate-in fade-in zoom-in-95", children: [
568
558
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-bold text-zinc-800 mb-3 text-sm", children: "Settings & Shortcuts" }),
569
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
570
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-6", children: [
571
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-zinc-800", children: "A4 Page Split" }),
572
- /* @__PURE__ */ jsxRuntime.jsx(
573
- "button",
574
- {
575
- type: "button",
576
- role: "switch",
577
- "aria-checked": isPageSplitEnabled,
578
- onClick: togglePageSplit,
579
- className: `${isPageSplitEnabled ? "bg-zinc-900" : "bg-zinc-300"} relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none`,
580
- children: /* @__PURE__ */ jsxRuntime.jsx(
581
- "span",
582
- {
583
- "aria-hidden": "true",
584
- className: `${isPageSplitEnabled ? "translate-x-4" : "translate-x-0"} pointer-events-none inline-block h-4 w-4 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out`
585
- }
586
- )
587
- }
588
- )
559
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-1.5", children: [
560
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
561
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "New Block" }),
562
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Enter" })
589
563
  ] }),
590
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5 pt-3 border-t border-zinc-200/50", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-1.5", children: [
591
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
592
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "New Block" }),
593
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Enter" })
594
- ] }),
595
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
596
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delete Block" }),
597
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Backspace" })
598
- ] }),
599
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
600
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Change Type" }),
601
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
602
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Ctrl" }),
603
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+" }),
604
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "\u2191/\u2193" })
605
- ] })
564
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
565
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delete Block" }),
566
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Backspace" })
567
+ ] }),
568
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
569
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Change Type" }),
570
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
571
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Ctrl" }),
572
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+" }),
573
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "\u2191/\u2193" })
606
574
  ] })
607
- ] }) })
608
- ] })
575
+ ] })
576
+ ] }) }) })
609
577
  ] }),
610
578
  /* @__PURE__ */ jsxRuntime.jsx(
611
579
  "button",
@@ -893,19 +861,6 @@ function useScreenplayEditor() {
893
861
  const [showSuggestions, setShowSuggestions] = react.useState(false);
894
862
  const [showExtensionSuggestions, setShowExtensionSuggestions] = react.useState(false);
895
863
  const blurTimeout = react.useRef(null);
896
- const [isPageSplitEnabled, setIsPageSplitEnabled] = react.useState(false);
897
- const [pageBreaks, setPageBreaks] = react.useState([]);
898
- const focusStateRef = react.useRef(null);
899
- const togglePageSplit = react.useCallback(() => {
900
- if (focusedBlockId && document.activeElement && document.activeElement.hasAttribute("contenteditable")) {
901
- const el = refs.current[focusedBlockId];
902
- if (el) {
903
- const offset = getCaretCharacterOffsetWithin(el);
904
- focusStateRef.current = { id: focusedBlockId, offset };
905
- }
906
- }
907
- setIsPageSplitEnabled((prev) => !prev);
908
- }, [focusedBlockId]);
909
864
  const characterExtensions = react.useMemo(
910
865
  () => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
911
866
  []
@@ -1007,98 +962,6 @@ function useScreenplayEditor() {
1007
962
  document.removeEventListener("mousedown", handleClickOutside);
1008
963
  };
1009
964
  }, []);
1010
- react.useEffect(() => {
1011
- if (!isPageSplitEnabled) {
1012
- setPageBreaks([]);
1013
- return;
1014
- }
1015
- const saveFocus = () => {
1016
- if (focusedBlockId && document.activeElement && document.activeElement.hasAttribute("contenteditable")) {
1017
- const el = refs.current[focusedBlockId];
1018
- if (el) {
1019
- const offset = getCaretCharacterOffsetWithin(el);
1020
- focusStateRef.current = { id: focusedBlockId, offset };
1021
- }
1022
- } else {
1023
- focusStateRef.current = null;
1024
- }
1025
- };
1026
- const timeoutId = setTimeout(() => {
1027
- let currentHeight = 0;
1028
- let hasSceneOnCurrentPage = false;
1029
- const A4_HEIGHT = 960;
1030
- const newPageBreaks = [];
1031
- blocks.forEach((block) => {
1032
- const el = refs.current[block.id];
1033
- if (el) {
1034
- const measureEl = document.querySelector(`[data-block-id="${block.id}"]`) || el;
1035
- const style = window.getComputedStyle(measureEl);
1036
- const marginTop = parseFloat(style.marginTop) || 0;
1037
- const marginBottom = parseFloat(style.marginBottom) || 0;
1038
- const height = measureEl.getBoundingClientRect().height + marginTop + marginBottom;
1039
- let breakPage = false;
1040
- if (currentHeight + height > A4_HEIGHT) {
1041
- breakPage = true;
1042
- } else if (block.type === "SCENE_HEADING") {
1043
- if (hasSceneOnCurrentPage) {
1044
- breakPage = true;
1045
- } else if (currentHeight > A4_HEIGHT - 120) {
1046
- breakPage = true;
1047
- }
1048
- }
1049
- if (breakPage && currentHeight > 0) {
1050
- newPageBreaks.push(block.id);
1051
- currentHeight = height;
1052
- hasSceneOnCurrentPage = block.type === "SCENE_HEADING";
1053
- } else {
1054
- currentHeight += height;
1055
- if (block.type === "SCENE_HEADING") {
1056
- hasSceneOnCurrentPage = true;
1057
- }
1058
- }
1059
- }
1060
- });
1061
- setPageBreaks((prev) => {
1062
- if (prev.length !== newPageBreaks.length) {
1063
- saveFocus();
1064
- return newPageBreaks;
1065
- }
1066
- for (let i = 0; i < prev.length; i++) {
1067
- if (prev[i] !== newPageBreaks[i]) {
1068
- saveFocus();
1069
- return newPageBreaks;
1070
- }
1071
- }
1072
- return prev;
1073
- });
1074
- }, 300);
1075
- return () => clearTimeout(timeoutId);
1076
- }, [blocks, isPageSplitEnabled, focusedBlockId]);
1077
- const pages = react.useMemo(() => {
1078
- if (!isPageSplitEnabled || pageBreaks.length === 0) return [blocks];
1079
- const result = [];
1080
- let currentPage = [];
1081
- for (const block of blocks) {
1082
- if (pageBreaks.includes(block.id) && currentPage.length > 0) {
1083
- result.push(currentPage);
1084
- currentPage = [];
1085
- }
1086
- currentPage.push(block);
1087
- }
1088
- if (currentPage.length > 0) result.push(currentPage);
1089
- return result;
1090
- }, [blocks, isPageSplitEnabled, pageBreaks]);
1091
- react.useEffect(() => {
1092
- if (focusStateRef.current) {
1093
- const { id, offset } = focusStateRef.current;
1094
- const el = refs.current[id];
1095
- if (el && document.activeElement !== el) {
1096
- el.focus();
1097
- setCaretPosition(el, offset);
1098
- }
1099
- focusStateRef.current = null;
1100
- }
1101
- }, [pages]);
1102
965
  const handleBlockTextChange = react.useCallback(
1103
966
  (id, text) => {
1104
967
  const block = blocks.find((b) => b.id === id);
@@ -1428,9 +1291,6 @@ function useScreenplayEditor() {
1428
1291
  }, []);
1429
1292
  return {
1430
1293
  blocks,
1431
- pages,
1432
- isPageSplitEnabled,
1433
- togglePageSplit,
1434
1294
  refs,
1435
1295
  focusedBlockId,
1436
1296
  showSuggestions,