@vishu1301/script-writing 0.5.1 → 0.5.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 +92 -4
- 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 +92 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -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)",
|
|
389
389
|
paddingLeft: "1.5in",
|
|
390
390
|
paddingRight: "1in",
|
|
391
391
|
paddingTop: "1in",
|
|
@@ -949,7 +949,7 @@ function setCaretPosition(element, offset) {
|
|
|
949
949
|
sel.removeAllRanges();
|
|
950
950
|
sel.addRange(range);
|
|
951
951
|
}
|
|
952
|
-
function useScreenplayEditor() {
|
|
952
|
+
function useScreenplayEditor(options) {
|
|
953
953
|
const [blocks, setBlocks] = react.useState(initialBlocks);
|
|
954
954
|
const refs = react.useRef({});
|
|
955
955
|
const [focusedBlockId, setFocusedBlockId] = react.useState(
|
|
@@ -959,6 +959,7 @@ function useScreenplayEditor() {
|
|
|
959
959
|
const [showSuggestions, setShowSuggestions] = react.useState(false);
|
|
960
960
|
const [showExtensionSuggestions, setShowExtensionSuggestions] = react.useState(false);
|
|
961
961
|
const blurTimeout = react.useRef(null);
|
|
962
|
+
const loadedUrlRef = react.useRef(null);
|
|
962
963
|
const characterExtensions = react.useMemo(
|
|
963
964
|
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
964
965
|
[]
|
|
@@ -1388,6 +1389,92 @@ function useScreenplayEditor() {
|
|
|
1388
1389
|
setShowExtensionSuggestions(false);
|
|
1389
1390
|
}, 200);
|
|
1390
1391
|
}, []);
|
|
1392
|
+
const loadFromUrl = react.useCallback(
|
|
1393
|
+
async (url, fetchOptions = {}) => {
|
|
1394
|
+
var _a;
|
|
1395
|
+
try {
|
|
1396
|
+
const response = await fetch(url, fetchOptions);
|
|
1397
|
+
if (!response.ok) {
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`[useScreenplayEditor] Failed to fetch script. HTTP Status: ${response.status}`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
let text = await response.text();
|
|
1403
|
+
let preParsedBlocks = void 0;
|
|
1404
|
+
let scriptContent = text;
|
|
1405
|
+
if (text.includes('class="divtype') || url.toLowerCase().includes(".sbx")) {
|
|
1406
|
+
if (text.includes("<div")) {
|
|
1407
|
+
const textarea = document.createElement("textarea");
|
|
1408
|
+
textarea.innerHTML = text;
|
|
1409
|
+
text = textarea.value;
|
|
1410
|
+
}
|
|
1411
|
+
const parser = new DOMParser();
|
|
1412
|
+
const doc = parser.parseFromString(text, "text/html");
|
|
1413
|
+
const divs = Array.from(doc.querySelectorAll("div"));
|
|
1414
|
+
const parsed = [];
|
|
1415
|
+
const typeMap = {
|
|
1416
|
+
divtype0: "SCENE_HEADING",
|
|
1417
|
+
divtype2: "ACTION",
|
|
1418
|
+
divtype3: "CHARACTER",
|
|
1419
|
+
divtype4: "PARENTHETICAL",
|
|
1420
|
+
divtype5: "DIALOGUE",
|
|
1421
|
+
divtype6: "TRANSITION"
|
|
1422
|
+
};
|
|
1423
|
+
divs.forEach((div) => {
|
|
1424
|
+
var _a2;
|
|
1425
|
+
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
1426
|
+
if (!divText) return;
|
|
1427
|
+
let type = "ACTION";
|
|
1428
|
+
for (const className of Array.from(div.classList)) {
|
|
1429
|
+
if (typeMap[className]) {
|
|
1430
|
+
type = typeMap[className];
|
|
1431
|
+
break;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
const block = { type, text: divText };
|
|
1435
|
+
if (type === "SCENE_HEADING") {
|
|
1436
|
+
const sceneNum = div.getAttribute("data-scene");
|
|
1437
|
+
if (sceneNum) block.sceneNumber = sceneNum;
|
|
1438
|
+
let parsedText = divText;
|
|
1439
|
+
const typeMatch = parsedText.match(/^(INT\/EXT|INT|EXT)\.?\s+/i);
|
|
1440
|
+
if (typeMatch) {
|
|
1441
|
+
let sType = typeMatch[1].toUpperCase();
|
|
1442
|
+
if (!sType.endsWith(".")) sType += ".";
|
|
1443
|
+
block.sceneType = sType;
|
|
1444
|
+
parsedText = parsedText.substring(typeMatch[0].length).trim();
|
|
1445
|
+
}
|
|
1446
|
+
const timeMatch = parsedText.match(/\s+-\s+([^-]+)$/);
|
|
1447
|
+
if (timeMatch) {
|
|
1448
|
+
block.timeOfDay = timeMatch[1].trim().toUpperCase();
|
|
1449
|
+
parsedText = parsedText.substring(0, timeMatch.index).trim();
|
|
1450
|
+
}
|
|
1451
|
+
block.text = parsedText;
|
|
1452
|
+
}
|
|
1453
|
+
parsed.push(block);
|
|
1454
|
+
});
|
|
1455
|
+
if (parsed.length > 0) {
|
|
1456
|
+
preParsedBlocks = parsed;
|
|
1457
|
+
scriptContent = "";
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
const filename = ((_a = url.split("/").pop()) == null ? void 0 : _a.replace(/\.sbx$/i, "")) || "Imported from URL";
|
|
1461
|
+
handleScriptImport(filename, scriptContent, preParsedBlocks);
|
|
1462
|
+
} catch (error) {
|
|
1463
|
+
console.error(
|
|
1464
|
+
"[useScreenplayEditor] Error loading script from URL:",
|
|
1465
|
+
error
|
|
1466
|
+
);
|
|
1467
|
+
throw error;
|
|
1468
|
+
}
|
|
1469
|
+
},
|
|
1470
|
+
[handleScriptImport]
|
|
1471
|
+
);
|
|
1472
|
+
react.useEffect(() => {
|
|
1473
|
+
if ((options == null ? void 0 : options.initialUrl) && options.initialUrl !== loadedUrlRef.current) {
|
|
1474
|
+
loadedUrlRef.current = options.initialUrl;
|
|
1475
|
+
loadFromUrl(options.initialUrl, options.fetchOptions);
|
|
1476
|
+
}
|
|
1477
|
+
}, [options == null ? void 0 : options.initialUrl, options == null ? void 0 : options.fetchOptions, loadFromUrl]);
|
|
1391
1478
|
return {
|
|
1392
1479
|
blocks,
|
|
1393
1480
|
refs,
|
|
@@ -1407,7 +1494,8 @@ function useScreenplayEditor() {
|
|
|
1407
1494
|
handleScriptImport,
|
|
1408
1495
|
handleSceneNumberChange,
|
|
1409
1496
|
handleFocus,
|
|
1410
|
-
handleBlur
|
|
1497
|
+
handleBlur,
|
|
1498
|
+
loadFromUrl
|
|
1411
1499
|
};
|
|
1412
1500
|
}
|
|
1413
1501
|
var handleSaveAsPdf = (blocks, sceneNumbers) => {
|