@vishu1301/script-writing 0.5.1 → 0.5.3
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 +96 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +96 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -283,7 +283,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
283
283
|
{
|
|
284
284
|
ref: fileInputRef,
|
|
285
285
|
type: "file",
|
|
286
|
-
accept: ".pdf
|
|
286
|
+
accept: ".pdf,application/pdf",
|
|
287
287
|
onChange: handleFileChange,
|
|
288
288
|
disabled: isProcessing,
|
|
289
289
|
className: "hidden",
|
|
@@ -337,7 +337,7 @@ function ScreenplayEditorView({
|
|
|
337
337
|
const link = document.createElement("link");
|
|
338
338
|
link.id = fontId;
|
|
339
339
|
link.rel = "stylesheet";
|
|
340
|
-
link.href = "https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap";
|
|
340
|
+
link.href = "https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&display=swap";
|
|
341
341
|
document.head.appendChild(link);
|
|
342
342
|
}
|
|
343
343
|
}, []);
|
|
@@ -385,7 +385,7 @@ function ScreenplayEditorView({
|
|
|
385
385
|
{
|
|
386
386
|
className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 border border-zinc-100 rounded-sm md:rounded-md pl-[1.5in] py-[1in] pr-[1in] flex flex-col w-[210mm] min-h-[297mm] shrink-0",
|
|
387
387
|
style: {
|
|
388
|
-
fontFamily: "'Courier Prime', 'Courier New', Courier, monospace",
|
|
388
|
+
fontFamily: "var(--font-courier-prime, 'Courier Prime', 'Courier New', Courier, monospace) !important",
|
|
389
389
|
paddingLeft: "1.5in",
|
|
390
390
|
paddingRight: "1in",
|
|
391
391
|
paddingTop: "1in",
|
|
@@ -451,6 +451,9 @@ function ScreenplayEditorView({
|
|
|
451
451
|
"aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
|
|
452
452
|
spellCheck: false,
|
|
453
453
|
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
454
|
+
style: {
|
|
455
|
+
minWidth: "3rem"
|
|
456
|
+
},
|
|
454
457
|
onInput: (e) => handleBlockTextChange(
|
|
455
458
|
block.id,
|
|
456
459
|
e.target.innerText
|
|
@@ -949,7 +952,7 @@ function setCaretPosition(element, offset) {
|
|
|
949
952
|
sel.removeAllRanges();
|
|
950
953
|
sel.addRange(range);
|
|
951
954
|
}
|
|
952
|
-
function useScreenplayEditor() {
|
|
955
|
+
function useScreenplayEditor(options) {
|
|
953
956
|
const [blocks, setBlocks] = react.useState(initialBlocks);
|
|
954
957
|
const refs = react.useRef({});
|
|
955
958
|
const [focusedBlockId, setFocusedBlockId] = react.useState(
|
|
@@ -959,6 +962,7 @@ function useScreenplayEditor() {
|
|
|
959
962
|
const [showSuggestions, setShowSuggestions] = react.useState(false);
|
|
960
963
|
const [showExtensionSuggestions, setShowExtensionSuggestions] = react.useState(false);
|
|
961
964
|
const blurTimeout = react.useRef(null);
|
|
965
|
+
const loadedUrlRef = react.useRef(null);
|
|
962
966
|
const characterExtensions = react.useMemo(
|
|
963
967
|
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
964
968
|
[]
|
|
@@ -1388,6 +1392,92 @@ function useScreenplayEditor() {
|
|
|
1388
1392
|
setShowExtensionSuggestions(false);
|
|
1389
1393
|
}, 200);
|
|
1390
1394
|
}, []);
|
|
1395
|
+
const loadFromUrl = react.useCallback(
|
|
1396
|
+
async (url, fetchOptions = {}) => {
|
|
1397
|
+
var _a;
|
|
1398
|
+
try {
|
|
1399
|
+
const response = await fetch(url, fetchOptions);
|
|
1400
|
+
if (!response.ok) {
|
|
1401
|
+
throw new Error(
|
|
1402
|
+
`[useScreenplayEditor] Failed to fetch script. HTTP Status: ${response.status}`
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
let text = await response.text();
|
|
1406
|
+
let preParsedBlocks = void 0;
|
|
1407
|
+
let scriptContent = text;
|
|
1408
|
+
if (text.includes('class="divtype') || url.toLowerCase().includes(".sbx")) {
|
|
1409
|
+
if (text.includes("<div")) {
|
|
1410
|
+
const textarea = document.createElement("textarea");
|
|
1411
|
+
textarea.innerHTML = text;
|
|
1412
|
+
text = textarea.value;
|
|
1413
|
+
}
|
|
1414
|
+
const parser = new DOMParser();
|
|
1415
|
+
const doc = parser.parseFromString(text, "text/html");
|
|
1416
|
+
const divs = Array.from(doc.querySelectorAll("div"));
|
|
1417
|
+
const parsed = [];
|
|
1418
|
+
const typeMap = {
|
|
1419
|
+
divtype0: "SCENE_HEADING",
|
|
1420
|
+
divtype2: "ACTION",
|
|
1421
|
+
divtype3: "CHARACTER",
|
|
1422
|
+
divtype4: "PARENTHETICAL",
|
|
1423
|
+
divtype5: "DIALOGUE",
|
|
1424
|
+
divtype6: "TRANSITION"
|
|
1425
|
+
};
|
|
1426
|
+
divs.forEach((div) => {
|
|
1427
|
+
var _a2;
|
|
1428
|
+
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
1429
|
+
if (!divText) return;
|
|
1430
|
+
let type = "ACTION";
|
|
1431
|
+
for (const className of Array.from(div.classList)) {
|
|
1432
|
+
if (typeMap[className]) {
|
|
1433
|
+
type = typeMap[className];
|
|
1434
|
+
break;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const block = { type, text: divText };
|
|
1438
|
+
if (type === "SCENE_HEADING") {
|
|
1439
|
+
const sceneNum = div.getAttribute("data-scene");
|
|
1440
|
+
if (sceneNum) block.sceneNumber = sceneNum;
|
|
1441
|
+
let parsedText = divText;
|
|
1442
|
+
const typeMatch = parsedText.match(/^(INT\/EXT|INT|EXT)\.?\s+/i);
|
|
1443
|
+
if (typeMatch) {
|
|
1444
|
+
let sType = typeMatch[1].toUpperCase();
|
|
1445
|
+
if (!sType.endsWith(".")) sType += ".";
|
|
1446
|
+
block.sceneType = sType;
|
|
1447
|
+
parsedText = parsedText.substring(typeMatch[0].length).trim();
|
|
1448
|
+
}
|
|
1449
|
+
const timeMatch = parsedText.match(/\s+-\s+([^-]+)$/);
|
|
1450
|
+
if (timeMatch) {
|
|
1451
|
+
block.timeOfDay = timeMatch[1].trim().toUpperCase();
|
|
1452
|
+
parsedText = parsedText.substring(0, timeMatch.index).trim();
|
|
1453
|
+
}
|
|
1454
|
+
block.text = parsedText;
|
|
1455
|
+
}
|
|
1456
|
+
parsed.push(block);
|
|
1457
|
+
});
|
|
1458
|
+
if (parsed.length > 0) {
|
|
1459
|
+
preParsedBlocks = parsed;
|
|
1460
|
+
scriptContent = "";
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
const filename = ((_a = url.split("/").pop()) == null ? void 0 : _a.replace(/\.sbx$/i, "")) || "Imported from URL";
|
|
1464
|
+
handleScriptImport(filename, scriptContent, preParsedBlocks);
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
console.error(
|
|
1467
|
+
"[useScreenplayEditor] Error loading script from URL:",
|
|
1468
|
+
error
|
|
1469
|
+
);
|
|
1470
|
+
throw error;
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
[handleScriptImport]
|
|
1474
|
+
);
|
|
1475
|
+
react.useEffect(() => {
|
|
1476
|
+
if ((options == null ? void 0 : options.initialUrl) && options.initialUrl !== loadedUrlRef.current) {
|
|
1477
|
+
loadedUrlRef.current = options.initialUrl;
|
|
1478
|
+
loadFromUrl(options.initialUrl, options.fetchOptions);
|
|
1479
|
+
}
|
|
1480
|
+
}, [options == null ? void 0 : options.initialUrl, options == null ? void 0 : options.fetchOptions, loadFromUrl]);
|
|
1391
1481
|
return {
|
|
1392
1482
|
blocks,
|
|
1393
1483
|
refs,
|
|
@@ -1407,7 +1497,8 @@ function useScreenplayEditor() {
|
|
|
1407
1497
|
handleScriptImport,
|
|
1408
1498
|
handleSceneNumberChange,
|
|
1409
1499
|
handleFocus,
|
|
1410
|
-
handleBlur
|
|
1500
|
+
handleBlur,
|
|
1501
|
+
loadFromUrl
|
|
1411
1502
|
};
|
|
1412
1503
|
}
|
|
1413
1504
|
var handleSaveAsPdf = (blocks, sceneNumbers) => {
|