@vishu1301/script-writing 0.3.8 → 0.4.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.
- package/dist/index.cjs +228 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +228 -37
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ var blockStyles = {
|
|
|
46
46
|
inputStyle: {
|
|
47
47
|
textTransform: "uppercase",
|
|
48
48
|
fontWeight: 700,
|
|
49
|
+
maxWidth: "6.0in",
|
|
49
50
|
outline: "none",
|
|
50
51
|
whiteSpace: "pre-wrap",
|
|
51
52
|
overflowWrap: "break-word",
|
|
@@ -54,21 +55,24 @@ var blockStyles = {
|
|
|
54
55
|
},
|
|
55
56
|
ACTION: {
|
|
56
57
|
label: "Action",
|
|
57
|
-
className: "text-zinc-800
|
|
58
|
+
className: "text-zinc-800",
|
|
58
59
|
inputStyle: {
|
|
60
|
+
maxWidth: "6.0in",
|
|
59
61
|
outline: "none",
|
|
60
62
|
whiteSpace: "pre-wrap",
|
|
61
63
|
overflowWrap: "break-word",
|
|
62
64
|
wordBreak: "break-word",
|
|
63
|
-
lineHeight:
|
|
65
|
+
lineHeight: "12pt"
|
|
64
66
|
}
|
|
65
67
|
},
|
|
66
68
|
CHARACTER: {
|
|
67
69
|
label: "Character",
|
|
68
|
-
className: "uppercase font-bold text-
|
|
70
|
+
className: "uppercase font-bold text-zinc-900 tracking-widest",
|
|
69
71
|
inputStyle: {
|
|
70
72
|
textTransform: "uppercase",
|
|
71
|
-
textAlign: "
|
|
73
|
+
textAlign: "left",
|
|
74
|
+
marginLeft: "2.0in",
|
|
75
|
+
maxWidth: "4.0in",
|
|
72
76
|
fontWeight: 700,
|
|
73
77
|
letterSpacing: "0.1em",
|
|
74
78
|
outline: "none",
|
|
@@ -79,31 +83,32 @@ var blockStyles = {
|
|
|
79
83
|
},
|
|
80
84
|
PARENTHETICAL: {
|
|
81
85
|
label: "Parenthetical",
|
|
82
|
-
className: "text-
|
|
86
|
+
className: "text-zinc-600",
|
|
83
87
|
inputStyle: {
|
|
84
88
|
fontStyle: "normal",
|
|
85
|
-
maxWidth: "
|
|
86
|
-
|
|
89
|
+
maxWidth: "3.0in",
|
|
90
|
+
marginLeft: "1.5in",
|
|
91
|
+
textTransform: "lowercase",
|
|
87
92
|
outline: "none",
|
|
88
93
|
whiteSpace: "pre-wrap",
|
|
89
94
|
overflowWrap: "break-word",
|
|
90
95
|
wordBreak: "break-word",
|
|
91
|
-
textAlign: "
|
|
96
|
+
textAlign: "left"
|
|
92
97
|
}
|
|
93
98
|
},
|
|
94
99
|
DIALOGUE: {
|
|
95
100
|
label: "Dialogue",
|
|
96
|
-
className: "text-zinc-900
|
|
101
|
+
className: "text-zinc-900",
|
|
97
102
|
inputStyle: {
|
|
98
|
-
marginLeft: "
|
|
99
|
-
|
|
103
|
+
marginLeft: "1.0in",
|
|
104
|
+
maxWidth: "3.5in",
|
|
100
105
|
outline: "none",
|
|
101
106
|
whiteSpace: "pre-wrap",
|
|
102
107
|
overflowWrap: "break-word",
|
|
103
108
|
wordBreak: "break-word",
|
|
104
109
|
fontSize: "1.05rem",
|
|
105
110
|
textAlign: "left",
|
|
106
|
-
lineHeight:
|
|
111
|
+
lineHeight: "12pt"
|
|
107
112
|
}
|
|
108
113
|
},
|
|
109
114
|
TRANSITION: {
|
|
@@ -128,6 +133,8 @@ function ScreenplayEditorView({
|
|
|
128
133
|
refs,
|
|
129
134
|
focusedBlockId,
|
|
130
135
|
showSuggestions,
|
|
136
|
+
showExtensionSuggestions,
|
|
137
|
+
characterExtensions,
|
|
131
138
|
locations,
|
|
132
139
|
characters,
|
|
133
140
|
sceneNumbers,
|
|
@@ -135,6 +142,7 @@ function ScreenplayEditorView({
|
|
|
135
142
|
handleSceneTypeChange,
|
|
136
143
|
handleTimeOfDayChange,
|
|
137
144
|
handleBlockTypeChange,
|
|
145
|
+
handleSelectCharacterExtension,
|
|
138
146
|
handleKeyDown,
|
|
139
147
|
handleFocus,
|
|
140
148
|
handleBlur,
|
|
@@ -185,7 +193,7 @@ function ScreenplayEditorView({
|
|
|
185
193
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-12 w-full items-center pb-24", children: pages.map((pageBlocks, pageIndex) => /* @__PURE__ */ jsxs(
|
|
186
194
|
"div",
|
|
187
195
|
{
|
|
188
|
-
className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 ring-1 ring-zinc-200/50 rounded-sm md:rounded-md
|
|
196
|
+
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",
|
|
189
197
|
style: {
|
|
190
198
|
fontFamily: "var(--font-courier-prime, 'Courier New', Courier, monospace)"
|
|
191
199
|
},
|
|
@@ -227,7 +235,7 @@ function ScreenplayEditorView({
|
|
|
227
235
|
"aria-haspopup": "listbox",
|
|
228
236
|
"aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
|
|
229
237
|
spellCheck: false,
|
|
230
|
-
className: "min-w-[
|
|
238
|
+
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
231
239
|
onInput: (e) => handleBlockTextChange(
|
|
232
240
|
block.id,
|
|
233
241
|
e.target.innerText
|
|
@@ -349,6 +357,34 @@ function ScreenplayEditorView({
|
|
|
349
357
|
char
|
|
350
358
|
)) })
|
|
351
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
|
+
}
|
|
352
388
|
)
|
|
353
389
|
] })
|
|
354
390
|
},
|
|
@@ -466,6 +502,8 @@ function createNewBlock(type) {
|
|
|
466
502
|
if (type === "SCENE_HEADING") {
|
|
467
503
|
newBlock.sceneType = "INT.";
|
|
468
504
|
newBlock.timeOfDay = "DAY";
|
|
505
|
+
} else if (type === "PARENTHETICAL") {
|
|
506
|
+
newBlock.text = "()";
|
|
469
507
|
}
|
|
470
508
|
return newBlock;
|
|
471
509
|
}
|
|
@@ -571,6 +609,7 @@ function useScreenplayEditor() {
|
|
|
571
609
|
);
|
|
572
610
|
const [newBlockId, setNewBlockId] = useState(null);
|
|
573
611
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
612
|
+
const [showExtensionSuggestions, setShowExtensionSuggestions] = useState(false);
|
|
574
613
|
const blurTimeout = useRef(null);
|
|
575
614
|
const [isPageSplitEnabled, setIsPageSplitEnabled] = useState(false);
|
|
576
615
|
const [pageBreaks, setPageBreaks] = useState([]);
|
|
@@ -585,12 +624,23 @@ function useScreenplayEditor() {
|
|
|
585
624
|
}
|
|
586
625
|
setIsPageSplitEnabled((prev) => !prev);
|
|
587
626
|
}, [focusedBlockId]);
|
|
627
|
+
const characterExtensions = useMemo(
|
|
628
|
+
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
629
|
+
[]
|
|
630
|
+
);
|
|
588
631
|
const locations = useMemo(() => {
|
|
589
632
|
const locs = blocks.filter((b) => b.type === "SCENE_HEADING" && b.text.trim() !== "").map((b) => b.text.trim().toUpperCase());
|
|
590
633
|
return [...new Set(locs)];
|
|
591
634
|
}, [blocks]);
|
|
592
635
|
const characters = useMemo(() => {
|
|
593
|
-
const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) =>
|
|
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);
|
|
594
644
|
return [...new Set(chars)];
|
|
595
645
|
}, [blocks]);
|
|
596
646
|
const sceneNumbers = useMemo(() => {
|
|
@@ -605,13 +655,22 @@ function useScreenplayEditor() {
|
|
|
605
655
|
return map;
|
|
606
656
|
}, [blocks]);
|
|
607
657
|
useEffect(() => {
|
|
608
|
-
var _a;
|
|
609
658
|
if (newBlockId && refs.current[newBlockId]) {
|
|
610
|
-
|
|
659
|
+
const block = blocks.find((b) => b.id === newBlockId);
|
|
660
|
+
const el = refs.current[newBlockId];
|
|
661
|
+
if (el && block) {
|
|
662
|
+
el.focus();
|
|
663
|
+
el.innerText = block.text;
|
|
664
|
+
if (block.type === "PARENTHETICAL") {
|
|
665
|
+
setTimeout(() => setCaretPosition(el, 1), 0);
|
|
666
|
+
} else {
|
|
667
|
+
setTimeout(() => setCaretPosition(el, block.text.length), 0);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
611
670
|
setFocusedBlockId(newBlockId);
|
|
612
671
|
setNewBlockId(null);
|
|
613
672
|
}
|
|
614
|
-
}, [newBlockId]);
|
|
673
|
+
}, [newBlockId, blocks]);
|
|
615
674
|
useEffect(() => {
|
|
616
675
|
blocks.forEach((block) => {
|
|
617
676
|
const element = refs.current[block.id];
|
|
@@ -620,6 +679,23 @@ function useScreenplayEditor() {
|
|
|
620
679
|
}
|
|
621
680
|
});
|
|
622
681
|
}, [blocks, isPageSplitEnabled, pageBreaks]);
|
|
682
|
+
useEffect(() => {
|
|
683
|
+
const handleClickOutside = (e) => {
|
|
684
|
+
const target = e.target;
|
|
685
|
+
const isInsideBlock = target.closest("[data-block-id]");
|
|
686
|
+
const isInsideToolbar = target.closest(".sticky");
|
|
687
|
+
const isInsideSuggestions = target.closest('[role="listbox"]');
|
|
688
|
+
if (!isInsideBlock && !isInsideToolbar && !isInsideSuggestions) {
|
|
689
|
+
setFocusedBlockId("");
|
|
690
|
+
setShowSuggestions(false);
|
|
691
|
+
setShowExtensionSuggestions(false);
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
695
|
+
return () => {
|
|
696
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
697
|
+
};
|
|
698
|
+
}, []);
|
|
623
699
|
useEffect(() => {
|
|
624
700
|
if (!isPageSplitEnabled) {
|
|
625
701
|
setPageBreaks([]);
|
|
@@ -712,9 +788,45 @@ function useScreenplayEditor() {
|
|
|
712
788
|
focusStateRef.current = null;
|
|
713
789
|
}
|
|
714
790
|
}, [pages]);
|
|
715
|
-
const handleBlockTextChange = useCallback(
|
|
716
|
-
|
|
717
|
-
|
|
791
|
+
const handleBlockTextChange = useCallback(
|
|
792
|
+
(id, text) => {
|
|
793
|
+
const block = blocks.find((b) => b.id === id);
|
|
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
|
+
}
|
|
809
|
+
let processedText = text;
|
|
810
|
+
if (block.type === "PARENTHETICAL") {
|
|
811
|
+
const clean = text.replace(/[()]/g, "");
|
|
812
|
+
processedText = `(${clean})`;
|
|
813
|
+
}
|
|
814
|
+
setBlocks(
|
|
815
|
+
(bs) => updateBlock(bs, id, "text", processedText)
|
|
816
|
+
);
|
|
817
|
+
if (text !== processedText) {
|
|
818
|
+
const el = refs.current[id];
|
|
819
|
+
if (el) {
|
|
820
|
+
const offset = getCaretCharacterOffsetWithin(el);
|
|
821
|
+
const charsBeforeCaret = text.substring(0, offset).replace(/[()]/g, "").length;
|
|
822
|
+
const newOffset = 1 + charsBeforeCaret;
|
|
823
|
+
el.innerText = processedText;
|
|
824
|
+
setCaretPosition(el, newOffset);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
[blocks, showExtensionSuggestions]
|
|
829
|
+
);
|
|
718
830
|
const handleSceneTypeChange = useCallback(
|
|
719
831
|
(id, sceneType) => {
|
|
720
832
|
setBlocks(
|
|
@@ -745,13 +857,48 @@ function useScreenplayEditor() {
|
|
|
745
857
|
setTimeout(() => {
|
|
746
858
|
const el = refs.current[focusedBlockId];
|
|
747
859
|
if (el) {
|
|
748
|
-
el.innerText = "";
|
|
749
860
|
el.focus();
|
|
861
|
+
const newBlock = createNewBlock(newType);
|
|
862
|
+
el.innerText = newBlock.text;
|
|
863
|
+
if (newType === "PARENTHETICAL") {
|
|
864
|
+
setCaretPosition(el, 1);
|
|
865
|
+
} else {
|
|
866
|
+
setCaretPosition(el, newBlock.text.length);
|
|
867
|
+
}
|
|
750
868
|
}
|
|
751
869
|
}, 0);
|
|
752
870
|
},
|
|
753
871
|
[focusedBlockId]
|
|
754
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
|
+
);
|
|
755
902
|
const focusBlock = (id, position = "start") => {
|
|
756
903
|
const el = refs.current[id];
|
|
757
904
|
if (!el) return;
|
|
@@ -765,19 +912,44 @@ function useScreenplayEditor() {
|
|
|
765
912
|
sel.addRange(range);
|
|
766
913
|
};
|
|
767
914
|
const cycleBlockType = (id, direction) => {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
915
|
+
const block = blocks.find((b) => b.id === id);
|
|
916
|
+
if (!block) return;
|
|
917
|
+
const idx = blockTypes.indexOf(block.type);
|
|
918
|
+
let newIdx = direction === "up" ? idx - 1 : idx + 1;
|
|
919
|
+
if (newIdx < 0) newIdx = blockTypes.length - 1;
|
|
920
|
+
if (newIdx >= blockTypes.length) newIdx = 0;
|
|
921
|
+
const newType = blockTypes[newIdx];
|
|
922
|
+
setBlocks((bs) => changeBlockType(bs, id, newType));
|
|
923
|
+
setTimeout(() => {
|
|
924
|
+
const el = refs.current[id];
|
|
925
|
+
if (el) {
|
|
926
|
+
el.focus();
|
|
927
|
+
const newBlock = createNewBlock(newType);
|
|
928
|
+
el.innerText = newBlock.text;
|
|
929
|
+
if (newType === "PARENTHETICAL") {
|
|
930
|
+
setCaretPosition(el, 1);
|
|
931
|
+
} else {
|
|
932
|
+
setCaretPosition(el, el.innerText.length);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}, 10);
|
|
777
936
|
};
|
|
778
937
|
const handleKeyDown = useCallback(
|
|
779
938
|
(e, id, text) => {
|
|
780
939
|
var _a;
|
|
940
|
+
const block = blocks.find((b) => b.id === id);
|
|
941
|
+
if ((block == null ? void 0 : block.type) === "PARENTHETICAL") {
|
|
942
|
+
const offset = getCaretCharacterOffsetWithin(e.currentTarget);
|
|
943
|
+
if (e.key === "Backspace" && (offset <= 1 || text === "()")) {
|
|
944
|
+
e.preventDefault();
|
|
945
|
+
cycleBlockType(id, "up");
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (e.key === "Delete" && (offset >= text.length - 1 || text === "()")) {
|
|
949
|
+
e.preventDefault();
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
781
953
|
if ((e.key === "Backspace" || e.key === "Delete") && text.length <= 1) {
|
|
782
954
|
e.preventDefault();
|
|
783
955
|
const { newBlocks, nextFocusedId } = deleteBlock(
|
|
@@ -803,11 +975,9 @@ function useScreenplayEditor() {
|
|
|
803
975
|
} else if (e.key === "ArrowUp" && e.ctrlKey) {
|
|
804
976
|
e.preventDefault();
|
|
805
977
|
cycleBlockType(id, "up");
|
|
806
|
-
requestAnimationFrame(() => focusBlock(id));
|
|
807
978
|
} else if (e.key === "ArrowDown" && e.ctrlKey) {
|
|
808
979
|
e.preventDefault();
|
|
809
980
|
cycleBlockType(id, "down");
|
|
810
|
-
requestAnimationFrame(() => focusBlock(id));
|
|
811
981
|
} else if (e.key === "ArrowUp" && !e.ctrlKey) {
|
|
812
982
|
const selection = window.getSelection();
|
|
813
983
|
if (!selection || !selection.isCollapsed || selection.rangeCount === 0) {
|
|
@@ -884,18 +1054,36 @@ function useScreenplayEditor() {
|
|
|
884
1054
|
}
|
|
885
1055
|
}
|
|
886
1056
|
},
|
|
887
|
-
[blocks]
|
|
1057
|
+
[blocks, handleBlockTextChange]
|
|
888
1058
|
);
|
|
889
1059
|
const handleFocus = useCallback((id) => {
|
|
890
1060
|
if (blurTimeout.current) {
|
|
891
1061
|
clearTimeout(blurTimeout.current);
|
|
892
1062
|
}
|
|
893
1063
|
setFocusedBlockId(id);
|
|
894
|
-
|
|
895
|
-
|
|
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]);
|
|
896
1081
|
const handleBlur = useCallback((id) => {
|
|
897
1082
|
if (document.activeElement === refs.current[id]) return;
|
|
898
|
-
blurTimeout.current = setTimeout(() =>
|
|
1083
|
+
blurTimeout.current = setTimeout(() => {
|
|
1084
|
+
setShowSuggestions(false);
|
|
1085
|
+
setShowExtensionSuggestions(false);
|
|
1086
|
+
}, 200);
|
|
899
1087
|
}, []);
|
|
900
1088
|
return {
|
|
901
1089
|
blocks,
|
|
@@ -905,6 +1093,8 @@ function useScreenplayEditor() {
|
|
|
905
1093
|
refs,
|
|
906
1094
|
focusedBlockId,
|
|
907
1095
|
showSuggestions,
|
|
1096
|
+
showExtensionSuggestions,
|
|
1097
|
+
characterExtensions,
|
|
908
1098
|
locations,
|
|
909
1099
|
characters,
|
|
910
1100
|
sceneNumbers,
|
|
@@ -912,6 +1102,7 @@ function useScreenplayEditor() {
|
|
|
912
1102
|
handleSceneTypeChange,
|
|
913
1103
|
handleTimeOfDayChange,
|
|
914
1104
|
handleBlockTypeChange,
|
|
1105
|
+
handleSelectCharacterExtension,
|
|
915
1106
|
handleKeyDown,
|
|
916
1107
|
handleFocus,
|
|
917
1108
|
handleBlur
|