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