@vishu1301/script-writing 1.1.0 → 1.1.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.
package/dist/index.cjs CHANGED
@@ -315,6 +315,9 @@ function ScreenplayEditorView({
315
315
  characterExtensions,
316
316
  locations,
317
317
  characters,
318
+ showPdfImport = false,
319
+ showSaveButton = false,
320
+ showSyncButton = false,
318
321
  handleBlockTextChange,
319
322
  handleSceneTypeChange,
320
323
  handleTimeOfDayChange,
@@ -331,7 +334,21 @@ function ScreenplayEditorView({
331
334
  handleSceneNumberChange
332
335
  }) {
333
336
  const [isRulesOpen, setIsRulesOpen] = react.useState(false);
337
+ const rulesRef = react.useRef(null);
334
338
  const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
339
+ react.useEffect(() => {
340
+ const handleClickOutside = (event) => {
341
+ if (rulesRef.current && !rulesRef.current.contains(event.target)) {
342
+ setIsRulesOpen(false);
343
+ }
344
+ };
345
+ if (isRulesOpen) {
346
+ document.addEventListener("mousedown", handleClickOutside);
347
+ }
348
+ return () => {
349
+ document.removeEventListener("mousedown", handleClickOutside);
350
+ };
351
+ }, [isRulesOpen]);
335
352
  react.useEffect(() => {
336
353
  const fontId = "google-font-courier-prime";
337
354
  const styleId = "screenplay-editor-force-v4";
@@ -413,8 +430,8 @@ function ScreenplayEditorView({
413
430
  }) }),
414
431
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0 relative px-1", children: [
415
432
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[1px] h-6 bg-zinc-200/80 mx-2 hidden sm:block rounded-full" }),
416
- /* @__PURE__ */ jsxRuntime.jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsxRuntime.jsx("div", { title: "Import Script", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-[18px] h-[18px]" }) }) }),
417
- onSave && /* @__PURE__ */ jsxRuntime.jsx(
433
+ showPdfImport && /* @__PURE__ */ jsxRuntime.jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsxRuntime.jsx("div", { title: "Import Script", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-[18px] h-[18px]" }) }) }),
434
+ onSave && showSaveButton && /* @__PURE__ */ jsxRuntime.jsx(
418
435
  "button",
419
436
  {
420
437
  onClick: onSave,
@@ -424,7 +441,7 @@ function ScreenplayEditorView({
424
441
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "w-[18px] h-[18px]" })
425
442
  }
426
443
  ),
427
- onSaveAsPdf && /* @__PURE__ */ jsxRuntime.jsx(
444
+ onSaveAsPdf && showSaveButton && /* @__PURE__ */ jsxRuntime.jsx(
428
445
  "button",
429
446
  {
430
447
  onClick: onSaveAsPdf,
@@ -434,49 +451,51 @@ function ScreenplayEditorView({
434
451
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "w-[18px] h-[18px]" })
435
452
  }
436
453
  ),
437
- onSaveAsSbx && /* @__PURE__ */ jsxRuntime.jsx(
454
+ onSyncWithCloud && showSyncButton && /* @__PURE__ */ jsxRuntime.jsx(
438
455
  "button",
439
456
  {
440
- onClick: onSaveAsSbx,
457
+ onClick: onSyncWithCloud,
441
458
  className: "flex items-center justify-center w-10 h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all duration-200 active:scale-95",
442
- title: "Sync with Cloud (SBX)",
443
- "aria-label": "Save Script as SBX",
459
+ title: "Sync with Cloud",
460
+ "aria-label": "Sync with Cloud",
444
461
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcw, { className: "w-[18px] h-[18px]" })
445
462
  }
446
463
  ),
447
- /* @__PURE__ */ jsxRuntime.jsx(
448
- "button",
449
- {
450
- onClick: () => setIsRulesOpen(!isRulesOpen),
451
- className: `flex items-center justify-center w-10 h-10 rounded-full transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-zinc-900 text-white shadow-md shadow-zinc-900/20" : "text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
452
- title: "Settings & Shortcuts",
453
- "aria-label": "Toggle Settings",
454
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-[18px] h-[18px]" })
455
- }
456
- ),
457
- isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-[calc(100%+1rem)] right-0 bg-white/95 backdrop-blur-3xl rounded-[1.5rem] shadow-[0_20px_60px_-15px_rgba(0,0,0,0.1)] ring-1 ring-zinc-900/5 p-5 text-sm text-zinc-700 select-none font-sans overflow-hidden transition-all duration-300 w-72 origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
458
- /* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "font-bold text-zinc-900 mb-4 text-sm flex items-center gap-2", children: [
459
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-4 h-4 text-zinc-400" }),
460
- "Settings & Shortcuts"
461
- ] }),
462
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-2.5", children: [
463
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
464
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "New Block" }),
465
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Enter" })
464
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rulesRef, className: "relative flex items-center", children: [
465
+ /* @__PURE__ */ jsxRuntime.jsx(
466
+ "button",
467
+ {
468
+ onClick: () => setIsRulesOpen(!isRulesOpen),
469
+ className: `flex items-center justify-center w-10 h-10 rounded-full transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-zinc-900 text-white shadow-md shadow-zinc-900/20" : "text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
470
+ title: "Settings & Shortcuts",
471
+ "aria-label": "Toggle Settings",
472
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-[18px] h-[18px]" })
473
+ }
474
+ ),
475
+ isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-full mt-2 right-0 bg-white/95 backdrop-blur-3xl rounded-[1.5rem] shadow-[0_20px_60px_-15px_rgba(0,0,0,0.1)] ring-1 ring-zinc-900/5 p-5 text-sm text-zinc-700 select-none font-sans overflow-hidden transition-all duration-300 w-72 origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
476
+ /* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "font-bold text-zinc-900 mb-4 text-sm flex items-center gap-2", children: [
477
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-4 h-4 text-zinc-400" }),
478
+ "Settings & Shortcuts"
466
479
  ] }),
467
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
468
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Delete Block" }),
469
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Backspace" })
470
- ] }),
471
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
472
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Change Type" }),
473
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
474
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Ctrl" }),
475
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 font-medium", children: "+" }),
476
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "\u2191/\u2193" })
480
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-2.5", children: [
481
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
482
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "New Block" }),
483
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Enter" })
484
+ ] }),
485
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
486
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Delete Block" }),
487
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Backspace" })
488
+ ] }),
489
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
490
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Change Type" }),
491
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
492
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Ctrl" }),
493
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 font-medium", children: "+" }),
494
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "\u2191/\u2193" })
495
+ ] })
477
496
  ] })
478
- ] })
479
- ] }) })
497
+ ] }) })
498
+ ] })
480
499
  ] })
481
500
  ] })
482
501
  ]
@@ -995,6 +1014,11 @@ function useScreenplayEditor(options) {
995
1014
  const [showExtensionSuggestions, setShowExtensionSuggestions] = react.useState(false);
996
1015
  const blurTimeout = react.useRef(null);
997
1016
  const loadedUrlRef = react.useRef(null);
1017
+ const lastSavedContent = react.useRef(null);
1018
+ const onSaveRef = react.useRef(options == null ? void 0 : options.onSave);
1019
+ react.useEffect(() => {
1020
+ onSaveRef.current = options == null ? void 0 : options.onSave;
1021
+ }, [options == null ? void 0 : options.onSave]);
998
1022
  const characterExtensions = react.useMemo(
999
1023
  () => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
1000
1024
  []
@@ -1351,11 +1375,10 @@ function useScreenplayEditor(options) {
1351
1375
  );
1352
1376
  const handleScriptImport = react.useCallback(
1353
1377
  (title, content, preParsedBlocks) => {
1354
- var _a;
1355
1378
  let parsedBlocks = [];
1356
1379
  if (preParsedBlocks && preParsedBlocks.length > 0) {
1357
1380
  parsedBlocks = preParsedBlocks.map((b) => ({
1358
- id: uuid(),
1381
+ id: b.id || uuid(),
1359
1382
  type: b.type || "ACTION",
1360
1383
  text: b.text || "",
1361
1384
  sceneNumber: b.sceneNumber,
@@ -1381,7 +1404,7 @@ function useScreenplayEditor(options) {
1381
1404
  return block;
1382
1405
  });
1383
1406
  setBlocks(finalizedBlocks);
1384
- if (options == null ? void 0 : options.onSave) {
1407
+ if (onSaveRef.current) {
1385
1408
  const typeToDivClass = {
1386
1409
  SCENE_HEADING: "divtype0",
1387
1410
  ACTION: "divtype2",
@@ -1405,15 +1428,18 @@ function useScreenplayEditor(options) {
1405
1428
  }
1406
1429
  return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
1407
1430
  }).join("");
1408
- const blob = new Blob([sbxData], { type: "text/plain" });
1409
- (_a = options == null ? void 0 : options.onSave) == null ? void 0 : _a.call(options, blob);
1431
+ if (sbxData !== lastSavedContent.current) {
1432
+ lastSavedContent.current = sbxData;
1433
+ const blob = new Blob([sbxData], { type: "text/plain" });
1434
+ onSaveRef.current(blob);
1435
+ }
1410
1436
  }
1411
1437
  setTimeout(() => {
1412
- var _a2;
1438
+ var _a;
1413
1439
  const firstId = parsedBlocks[0].id;
1414
1440
  if (firstId && refs.current[firstId]) {
1415
1441
  setFocusedBlockId(firstId);
1416
- (_a2 = refs.current[firstId]) == null ? void 0 : _a2.focus();
1442
+ (_a = refs.current[firstId]) == null ? void 0 : _a.focus();
1417
1443
  }
1418
1444
  }, 100);
1419
1445
  }
@@ -1495,6 +1521,10 @@ function useScreenplayEditor(options) {
1495
1521
  }
1496
1522
  }
1497
1523
  const block = { type, text: divText };
1524
+ const idAttr = div.getAttribute("id");
1525
+ if (idAttr && idAttr.startsWith("par")) {
1526
+ block.id = idAttr.substring(3);
1527
+ }
1498
1528
  if (type === "SCENE_HEADING") {
1499
1529
  const sceneNum = div.getAttribute("data-scene");
1500
1530
  if (sceneNum) block.sceneNumber = sceneNum;
@@ -1678,7 +1708,7 @@ var convertBlocksToSbx = (blocks, sceneNumbers) => {
1678
1708
  return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
1679
1709
  }).join("");
1680
1710
  };
1681
- var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx, project_name) => {
1711
+ var handleSyncWithCloud = (blocks, sceneNumbers, onSaveAsSbx, project_name) => {
1682
1712
  const sbxData = convertBlocksToSbx(blocks, sceneNumbers);
1683
1713
  const blob = new Blob([sbxData], { type: "text/plain" });
1684
1714
  if (onSaveAsSbx) {
@@ -1695,12 +1725,6 @@ var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx, project_name) => {
1695
1725
  }
1696
1726
  }
1697
1727
  };
1698
- var handleSyncWithCloud = (blocks, sceneNumbers, onSyncWithCloud) => {
1699
- if (onSyncWithCloud) {
1700
- const sbxData = convertBlocksToSbx(blocks, sceneNumbers);
1701
- onSyncWithCloud(sbxData);
1702
- }
1703
- };
1704
1728
 
1705
1729
  // app/types/script-breakdown.types.tsx
1706
1730
  var CATEGORIES = [
@@ -2384,7 +2408,6 @@ exports.blockStyles = blockStyles;
2384
2408
  exports.blockTypes = blockTypes;
2385
2409
  exports.convertBlocksToSbx = convertBlocksToSbx;
2386
2410
  exports.handleSaveAsPdf = handleSaveAsPdf;
2387
- exports.handleSaveAsSbx = handleSaveAsSbx;
2388
2411
  exports.handleSyncWithCloud = handleSyncWithCloud;
2389
2412
  exports.icons = icons;
2390
2413
  exports.timeOfDayOptions = timeOfDayOptions;