@vishu1301/script-writing 0.3.9 → 0.4.1

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.js CHANGED
@@ -67,7 +67,7 @@ var blockStyles = {
67
67
  },
68
68
  CHARACTER: {
69
69
  label: "Character",
70
- className: "uppercase font-bold text-zinc-900 tracking-widest",
70
+ className: "uppercase text-zinc-900 tracking-widest",
71
71
  inputStyle: {
72
72
  textTransform: "uppercase",
73
73
  textAlign: "left",
@@ -115,7 +115,6 @@ var blockStyles = {
115
115
  label: "Transition",
116
116
  className: "uppercase font-bold text-right text-zinc-900",
117
117
  inputStyle: {
118
- marginLeft: "4.0in",
119
118
  textTransform: "uppercase",
120
119
  fontWeight: 600,
121
120
  textAlign: "right",
@@ -134,6 +133,8 @@ function ScreenplayEditorView({
134
133
  refs,
135
134
  focusedBlockId,
136
135
  showSuggestions,
136
+ showExtensionSuggestions,
137
+ characterExtensions,
137
138
  locations,
138
139
  characters,
139
140
  sceneNumbers,
@@ -141,6 +142,7 @@ function ScreenplayEditorView({
141
142
  handleSceneTypeChange,
142
143
  handleTimeOfDayChange,
143
144
  handleBlockTypeChange,
145
+ handleSelectCharacterExtension,
144
146
  handleKeyDown,
145
147
  handleFocus,
146
148
  handleBlur,
@@ -355,6 +357,34 @@ function ScreenplayEditorView({
355
357
  char
356
358
  )) })
357
359
  }
360
+ ),
361
+ focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsx(
362
+ "div",
363
+ {
364
+ role: "listbox",
365
+ id: `extension-suggestions-${block.id}`,
366
+ 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",
367
+ children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
368
+ const openParenIndex = block.text.lastIndexOf("(");
369
+ const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
370
+ return ext.toUpperCase().includes(query);
371
+ }).map((ext) => /* @__PURE__ */ jsxs(
372
+ "div",
373
+ {
374
+ role: "option",
375
+ className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
376
+ onMouseDown: (e) => {
377
+ e.preventDefault();
378
+ handleSelectCharacterExtension(ext);
379
+ },
380
+ children: [
381
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
382
+ /* @__PURE__ */ jsx(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" })
383
+ ]
384
+ },
385
+ ext
386
+ )) })
387
+ }
358
388
  )
359
389
  ] })
360
390
  },
@@ -579,6 +609,7 @@ function useScreenplayEditor() {
579
609
  );
580
610
  const [newBlockId, setNewBlockId] = useState(null);
581
611
  const [showSuggestions, setShowSuggestions] = useState(false);
612
+ const [showExtensionSuggestions, setShowExtensionSuggestions] = useState(false);
582
613
  const blurTimeout = useRef(null);
583
614
  const [isPageSplitEnabled, setIsPageSplitEnabled] = useState(false);
584
615
  const [pageBreaks, setPageBreaks] = useState([]);
@@ -593,12 +624,23 @@ function useScreenplayEditor() {
593
624
  }
594
625
  setIsPageSplitEnabled((prev) => !prev);
595
626
  }, [focusedBlockId]);
627
+ const characterExtensions = useMemo(
628
+ () => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
629
+ []
630
+ );
596
631
  const locations = useMemo(() => {
597
632
  const locs = blocks.filter((b) => b.type === "SCENE_HEADING" && b.text.trim() !== "").map((b) => b.text.trim().toUpperCase());
598
633
  return [...new Set(locs)];
599
634
  }, [blocks]);
600
635
  const characters = useMemo(() => {
601
- const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) => b.text.trim().toUpperCase());
636
+ const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) => {
637
+ const text = b.text.trim().toUpperCase();
638
+ const parenIndex = text.indexOf("(");
639
+ if (parenIndex > -1) {
640
+ return text.substring(0, parenIndex).trim();
641
+ }
642
+ return text;
643
+ }).filter(Boolean);
602
644
  return [...new Set(chars)];
603
645
  }, [blocks]);
604
646
  const sceneNumbers = useMemo(() => {
@@ -646,6 +688,7 @@ function useScreenplayEditor() {
646
688
  if (!isInsideBlock && !isInsideToolbar && !isInsideSuggestions) {
647
689
  setFocusedBlockId("");
648
690
  setShowSuggestions(false);
691
+ setShowExtensionSuggestions(false);
649
692
  }
650
693
  };
651
694
  document.addEventListener("mousedown", handleClickOutside);
@@ -749,6 +792,20 @@ function useScreenplayEditor() {
749
792
  (id, text) => {
750
793
  const block = blocks.find((b) => b.id === id);
751
794
  if (!block) return;
795
+ if (block.type === "CHARACTER") {
796
+ const trimmedText = text.trim();
797
+ const openParenIndex = trimmedText.lastIndexOf("(");
798
+ const closeParenIndex = trimmedText.lastIndexOf(")");
799
+ if (openParenIndex !== -1 && openParenIndex > closeParenIndex) {
800
+ setShowExtensionSuggestions(true);
801
+ setShowSuggestions(false);
802
+ } else {
803
+ setShowExtensionSuggestions(false);
804
+ setShowSuggestions(openParenIndex === -1);
805
+ }
806
+ } else if (showExtensionSuggestions) {
807
+ setShowExtensionSuggestions(false);
808
+ }
752
809
  let processedText = text;
753
810
  if (block.type === "PARENTHETICAL") {
754
811
  const clean = text.replace(/[()]/g, "");
@@ -768,7 +825,7 @@ function useScreenplayEditor() {
768
825
  }
769
826
  }
770
827
  },
771
- [blocks]
828
+ [blocks, showExtensionSuggestions]
772
829
  );
773
830
  const handleSceneTypeChange = useCallback(
774
831
  (id, sceneType) => {
@@ -813,6 +870,35 @@ function useScreenplayEditor() {
813
870
  },
814
871
  [focusedBlockId]
815
872
  );
873
+ const handleSelectCharacterExtension = useCallback(
874
+ (extension) => {
875
+ if (!focusedBlockId) return;
876
+ setBlocks((currentBlocks) => {
877
+ const block = currentBlocks.find((b) => b.id === focusedBlockId);
878
+ if (!block || block.type !== "CHARACTER") return currentBlocks;
879
+ const parenIndex = block.text.indexOf("(");
880
+ const baseText = (parenIndex > -1 ? block.text.substring(0, parenIndex) : block.text).trim();
881
+ const newText = `${baseText} ${extension}`;
882
+ const newBlocks = updateBlock(
883
+ currentBlocks,
884
+ focusedBlockId,
885
+ "text",
886
+ newText
887
+ );
888
+ setTimeout(() => {
889
+ const el = refs.current[focusedBlockId];
890
+ if (el) {
891
+ el.innerText = newText;
892
+ el.focus();
893
+ setCaretPosition(el, newText.length);
894
+ }
895
+ }, 0);
896
+ return newBlocks;
897
+ });
898
+ setShowExtensionSuggestions(false);
899
+ },
900
+ [focusedBlockId]
901
+ );
816
902
  const focusBlock = (id, position = "start") => {
817
903
  const el = refs.current[id];
818
904
  if (!el) return;
@@ -975,11 +1061,29 @@ function useScreenplayEditor() {
975
1061
  clearTimeout(blurTimeout.current);
976
1062
  }
977
1063
  setFocusedBlockId(id);
978
- setShowSuggestions(true);
979
- }, []);
1064
+ const block = blocks.find((b) => b.id === id);
1065
+ if ((block == null ? void 0 : block.type) === "CHARACTER") {
1066
+ const trimmedText = block.text.trim();
1067
+ const openParenIndex = trimmedText.lastIndexOf("(");
1068
+ const closeParenIndex = trimmedText.lastIndexOf(")");
1069
+ if (openParenIndex !== -1 && openParenIndex > closeParenIndex) {
1070
+ setShowExtensionSuggestions(true);
1071
+ setShowSuggestions(false);
1072
+ } else {
1073
+ setShowExtensionSuggestions(false);
1074
+ setShowSuggestions(openParenIndex === -1);
1075
+ }
1076
+ } else {
1077
+ setShowSuggestions(true);
1078
+ setShowExtensionSuggestions(false);
1079
+ }
1080
+ }, [blocks]);
980
1081
  const handleBlur = useCallback((id) => {
981
1082
  if (document.activeElement === refs.current[id]) return;
982
- blurTimeout.current = setTimeout(() => setShowSuggestions(false), 200);
1083
+ blurTimeout.current = setTimeout(() => {
1084
+ setShowSuggestions(false);
1085
+ setShowExtensionSuggestions(false);
1086
+ }, 200);
983
1087
  }, []);
984
1088
  return {
985
1089
  blocks,
@@ -989,6 +1093,8 @@ function useScreenplayEditor() {
989
1093
  refs,
990
1094
  focusedBlockId,
991
1095
  showSuggestions,
1096
+ showExtensionSuggestions,
1097
+ characterExtensions,
992
1098
  locations,
993
1099
  characters,
994
1100
  sceneNumbers,
@@ -996,6 +1102,7 @@ function useScreenplayEditor() {
996
1102
  handleSceneTypeChange,
997
1103
  handleTimeOfDayChange,
998
1104
  handleBlockTypeChange,
1105
+ handleSelectCharacterExtension,
999
1106
  handleKeyDown,
1000
1107
  handleFocus,
1001
1108
  handleBlur