@lingjingai/script-editor 0.2.1 → 0.3.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.d.ts +58 -3
- package/dist/index.js +114 -28
- package/dist/index.js.map +1 -1
- package/dist/style.css +60 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ interface ScriptItem {
|
|
|
37
37
|
emotion?: string;
|
|
38
38
|
state_changes?: StateChange[];
|
|
39
39
|
transition_prompt?: TransitionPrompt;
|
|
40
|
+
/** v3 free-form namespace; `extend.timestamp` is the in-episode "M:SS.mmm". */
|
|
41
|
+
extend?: {
|
|
42
|
+
timestamp?: string;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
};
|
|
40
45
|
}
|
|
41
46
|
interface AssetState {
|
|
42
47
|
state_id?: string;
|
|
@@ -500,7 +505,9 @@ interface ScriptEditorAdapters {
|
|
|
500
505
|
|
|
501
506
|
interface ScriptEditorProps extends ScriptEditorAdapters {
|
|
502
507
|
value: ScriptProject;
|
|
503
|
-
|
|
508
|
+
/** the (prev)=>next patch sink. Optional — omit for a pure read-only view
|
|
509
|
+
* (pair with `disabled`); edits become no-ops. */
|
|
510
|
+
onEdit?: (patch: (prev: ScriptProject) => ScriptProject) => void;
|
|
504
511
|
selection?: StudioSelection;
|
|
505
512
|
onSelectionChange?: (next: StudioSelection) => void;
|
|
506
513
|
format?: ScriptFormat;
|
|
@@ -537,8 +544,56 @@ interface ScriptEditorProps extends ScriptEditorAdapters {
|
|
|
537
544
|
/** stable per-scope key (e.g. projectGroupNo) — remembers & restores the
|
|
538
545
|
* scroll position across editor unmount/remount (tab switch / project nav). */
|
|
539
546
|
scrollScopeKey?: string;
|
|
547
|
+
/** render the asset-card groups (角色/场景/道具) below the script. Default true. */
|
|
548
|
+
showAssets?: boolean;
|
|
549
|
+
/** render the top bar's script title. Default true. */
|
|
550
|
+
showTitle?: boolean;
|
|
551
|
+
/** render the 标准/亚洲 format toggle button. Default true (format stays controlled). */
|
|
552
|
+
showFormatToggle?: boolean;
|
|
553
|
+
/** parchment paper surface. Default true; false → flat plain segments. */
|
|
554
|
+
paper?: boolean;
|
|
555
|
+
/** render a MM:SS gutter from each action's extend.timestamp. Default false. */
|
|
556
|
+
showTimestamp?: boolean;
|
|
557
|
+
/** host range highlights (per action), rendered on top of the row. */
|
|
558
|
+
highlights?: ScriptHighlight[];
|
|
559
|
+
/** content column width (script segments + asset cards). Number → px; string
|
|
560
|
+
* passes through as-is (e.g. "100%" to fill, "60rem"). Default 820px. Sets
|
|
561
|
+
* the --lj-se-content-width CSS var; hosts can also override that var in CSS. */
|
|
562
|
+
contentWidth?: number | string;
|
|
563
|
+
/** the floating bottom-center capsule (save status + AI-diff + 返回 breadcrumb).
|
|
564
|
+
* Default true. Set false for a pure display surface with no floating chrome. */
|
|
565
|
+
showSaveCapsule?: boolean;
|
|
566
|
+
}
|
|
567
|
+
/** A host range highlight targeting one action (same coords as DiffActionMark). */
|
|
568
|
+
interface ScriptHighlight {
|
|
569
|
+
target: {
|
|
570
|
+
episodeIdx: number;
|
|
571
|
+
sceneId: string;
|
|
572
|
+
actionIndex: number;
|
|
573
|
+
};
|
|
574
|
+
className?: string;
|
|
575
|
+
style?: React.CSSProperties;
|
|
540
576
|
}
|
|
541
|
-
declare function ScriptEditor({ value, onEdit, selection: controlledSelection, onSelectionChange, format: controlledFormat, onFormatChange, disabled, className, dark, toc, onTitleChange, topBarActions, saveStatus, canUndo, canRedo, onUndo, onRedo, onEditingChange, referenceFocusRequest, scrollScopeKey, diff, asset, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
577
|
+
declare function ScriptEditor({ value, onEdit: onEditProp, selection: controlledSelection, onSelectionChange, format: controlledFormat, onFormatChange, disabled, className, dark, toc, onTitleChange, topBarActions, saveStatus, canUndo, canRedo, onUndo, onRedo, onEditingChange, referenceFocusRequest, scrollScopeKey, showAssets, showTitle, showFormatToggle, paper, showTimestamp, highlights, contentWidth, showSaveCapsule, diff, asset, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Action timestamps live at `action.extend.timestamp` as an in-episode
|
|
581
|
+
* "M:SS.mmm" string (e.g. "00:03.333", "01:12.000"). The editor shows the
|
|
582
|
+
* "MM:SS" part prominently and the ".mmm" fraction de-emphasized.
|
|
583
|
+
*
|
|
584
|
+
* Parsing is lenient: anything that isn't a well-formed timestamp returns null
|
|
585
|
+
* so the caller simply renders no time gutter for that row (never a placeholder).
|
|
586
|
+
*/
|
|
587
|
+
interface ParsedTimestamp {
|
|
588
|
+
/** minutes:seconds, zero-padded — the prominent part, e.g. "01:07". */
|
|
589
|
+
mmss: string;
|
|
590
|
+
/** the fractional ".mmm" suffix incl. the dot, or "" when there is none. */
|
|
591
|
+
ms: string;
|
|
592
|
+
/** full normalized "MM:SS.mmm" (or "MM:SS" when no fraction) for title/hover. */
|
|
593
|
+
full: string;
|
|
594
|
+
}
|
|
595
|
+
/** Parse "M:SS.mmm" → { mmss, ms, full }, or null when malformed / empty. */
|
|
596
|
+
declare function formatTimestamp(raw: unknown): ParsedTimestamp | null;
|
|
542
597
|
|
|
543
598
|
/**
|
|
544
599
|
* Headless navigation model — surfaces the script's TOC tree (the same
|
|
@@ -830,4 +885,4 @@ declare function DeleteConfirmButton({ onConfirm, disabled, targetScope, title,
|
|
|
830
885
|
description?: string;
|
|
831
886
|
}): react.JSX.Element;
|
|
832
887
|
|
|
833
|
-
export { type AssetAdapter, type AssetDeleteRequest, type AssetState, type ChangeSet, type ChatReference, DeleteConfirmButton, type DiffActionMark, type DiffAdapter, type DiffSceneMark, EMPTY_SELECTION, EditableText, type EpisodeWorkspaceView, type FieldChange, type Importance, Popover, type SaveStatus, type Scene, type SceneActionDiff, type SceneChangeKind, type SceneContext, type SceneEnvironment, type ScriptActor, ScriptContentType, type ScriptData, ScriptEditor, type ScriptEditorAdapters, type ScriptEditorProps, type ScriptEpisode, type ScriptFormat, type ScriptItem, type ScriptLocation, type ScriptNav, type ScriptNavEntity, type ScriptNavEpisode, type ScriptNavScene, type ScriptProject, type ScriptProp, type ScriptReferenceFocusRequest, type ScriptReferenceLocator, type ScriptSpeaker, type ScriptTargetKind, SelectField, type StateChange, type StudioSelection, type StudioSelectionFrom, type StudioSelectionOrigin, type TransitionPrompt, type V3Speaker, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, index as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
888
|
+
export { type AssetAdapter, type AssetDeleteRequest, type AssetState, type ChangeSet, type ChatReference, DeleteConfirmButton, type DiffActionMark, type DiffAdapter, type DiffSceneMark, EMPTY_SELECTION, EditableText, type EpisodeWorkspaceView, type FieldChange, type Importance, type ParsedTimestamp, Popover, type SaveStatus, type Scene, type SceneActionDiff, type SceneChangeKind, type SceneContext, type SceneEnvironment, type ScriptActor, ScriptContentType, type ScriptData, ScriptEditor, type ScriptEditorAdapters, type ScriptEditorProps, type ScriptEpisode, type ScriptFormat, type ScriptHighlight, type ScriptItem, type ScriptLocation, type ScriptNav, type ScriptNavEntity, type ScriptNavEpisode, type ScriptNavScene, type ScriptProject, type ScriptProp, type ScriptReferenceFocusRequest, type ScriptReferenceLocator, type ScriptSpeaker, type ScriptTargetKind, SelectField, type StateChange, type StudioSelection, type StudioSelectionFrom, type StudioSelectionOrigin, type TransitionPrompt, type V3Speaker, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, index as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
package/dist/index.js
CHANGED
|
@@ -633,11 +633,11 @@ function EntityGroup({
|
|
|
633
633
|
const valid = items.filter((i) => i.id);
|
|
634
634
|
const featured = valid.filter((i) => i.importance !== "background").sort(byCount);
|
|
635
635
|
const background = valid.filter((i) => i.importance === "background").sort(byCount);
|
|
636
|
-
const row = (i) => /* @__PURE__ */ jsxs(
|
|
636
|
+
const row = (i, bg = false) => /* @__PURE__ */ jsxs(
|
|
637
637
|
"button",
|
|
638
638
|
{
|
|
639
639
|
type: "button",
|
|
640
|
-
className: cn("lj-se-tocitem lj-se-toc-l1", isActive(i.id) && "is-active"),
|
|
640
|
+
className: cn("lj-se-tocitem", bg ? "lj-se-toc-bg" : "lj-se-toc-l1", isActive(i.id) && "is-active"),
|
|
641
641
|
onClick: () => onPick(i.id),
|
|
642
642
|
children: [
|
|
643
643
|
/* @__PURE__ */ jsx(Icon, { className: "lj-se-tocitem-icon lj-se-ic-3", strokeWidth: 1.5 }),
|
|
@@ -648,9 +648,9 @@ function EntityGroup({
|
|
|
648
648
|
i.id
|
|
649
649
|
);
|
|
650
650
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
651
|
-
/* @__PURE__ */ jsx(GroupHeader, { icon: Icon, label, count:
|
|
651
|
+
/* @__PURE__ */ jsx(GroupHeader, { icon: Icon, label, count: featured.length, open, highlighted, onToggle: () => setOpen((v) => !v) }),
|
|
652
652
|
open ? valid.length === 0 ? /* @__PURE__ */ jsx("div", { className: "lj-se-toc-empty", children: emptyText }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
653
|
-
featured.map(row),
|
|
653
|
+
featured.map((i) => row(i)),
|
|
654
654
|
background.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
655
655
|
/* @__PURE__ */ jsxs("button", { type: "button", className: cn("lj-se-toc-fold", bgOpen && "is-open"), onClick: () => setBgOpen((v) => !v), children: [
|
|
656
656
|
/* @__PURE__ */ jsx(ChevronRight, { className: "lj-se-toc-fold-chev lj-se-ic-3", strokeWidth: 2 }),
|
|
@@ -661,7 +661,7 @@ function EntityGroup({
|
|
|
661
661
|
background.length
|
|
662
662
|
] })
|
|
663
663
|
] }),
|
|
664
|
-
bgOpen ? background.map(row) : null
|
|
664
|
+
bgOpen ? background.map((i) => row(i, true)) : null
|
|
665
665
|
] }) : null
|
|
666
666
|
] }) : null
|
|
667
667
|
] });
|
|
@@ -887,6 +887,7 @@ function CanvasTopBar({
|
|
|
887
887
|
contextLabel,
|
|
888
888
|
format,
|
|
889
889
|
onFormatChange,
|
|
890
|
+
showFormatToggle = true,
|
|
890
891
|
canUndo,
|
|
891
892
|
canRedo,
|
|
892
893
|
onUndo,
|
|
@@ -912,7 +913,7 @@ function CanvasTopBar({
|
|
|
912
913
|
] }) : null
|
|
913
914
|
] }),
|
|
914
915
|
/* @__PURE__ */ jsxs("div", { className: "lj-se-topbar-right", children: [
|
|
915
|
-
/* @__PURE__ */ jsx(FormatToggle, { value: format, onChange: onFormatChange }),
|
|
916
|
+
showFormatToggle ? /* @__PURE__ */ jsx(FormatToggle, { value: format, onChange: onFormatChange }) : null,
|
|
916
917
|
onUndo || onRedo ? /* @__PURE__ */ jsxs("div", { className: "lj-se-topbar-undo", children: [
|
|
917
918
|
/* @__PURE__ */ jsx("button", { type: "button", className: "lj-se-rowbtn", disabled: !canUndo, title: "\u64A4\u9500", onClick: onUndo, children: /* @__PURE__ */ jsx(Undo2, { className: "lj-se-ic-4", strokeWidth: 1.75 }) }),
|
|
918
919
|
/* @__PURE__ */ jsx("button", { type: "button", className: "lj-se-rowbtn", disabled: !canRedo, title: "\u91CD\u505A", onClick: onRedo, children: /* @__PURE__ */ jsx(Redo2, { className: "lj-se-ic-4", strokeWidth: 1.75 }) })
|
|
@@ -933,7 +934,17 @@ function SaveCapsule({
|
|
|
933
934
|
returnLabel,
|
|
934
935
|
onReturn
|
|
935
936
|
}) {
|
|
936
|
-
const
|
|
937
|
+
const [savedExpired, setSavedExpired] = useState(false);
|
|
938
|
+
useEffect(() => {
|
|
939
|
+
if (saveStatus !== "saved") {
|
|
940
|
+
setSavedExpired(false);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
setSavedExpired(false);
|
|
944
|
+
const t = setTimeout(() => setSavedExpired(true), 1600);
|
|
945
|
+
return () => clearTimeout(t);
|
|
946
|
+
}, [saveStatus]);
|
|
947
|
+
const showSave = saveStatus !== "idle" && !(saveStatus === "saved" && savedExpired);
|
|
937
948
|
const hasDiff = diffCount > 0;
|
|
938
949
|
const hasReturn = !!(returnLabel && onReturn);
|
|
939
950
|
if (!showSave && !hasDiff && !hasReturn) return null;
|
|
@@ -1861,6 +1872,21 @@ function useDragReorder() {
|
|
|
1861
1872
|
return useContext(DragReorderContext);
|
|
1862
1873
|
}
|
|
1863
1874
|
|
|
1875
|
+
// src/timestamp.ts
|
|
1876
|
+
var TS_RE = /^\s*(\d+):([0-5]?\d)(?:\.(\d{1,3}))?\s*$/;
|
|
1877
|
+
function formatTimestamp(raw) {
|
|
1878
|
+
if (typeof raw !== "string") return null;
|
|
1879
|
+
const m = TS_RE.exec(raw);
|
|
1880
|
+
if (!m) return null;
|
|
1881
|
+
const min = Number(m[1]);
|
|
1882
|
+
const sec = Number(m[2]);
|
|
1883
|
+
if (!Number.isFinite(min) || !Number.isFinite(sec)) return null;
|
|
1884
|
+
const mmss = `${String(min).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
|
|
1885
|
+
const frac = m[3] ? m[3].padEnd(3, "0") : "";
|
|
1886
|
+
const ms = frac ? `.${frac}` : "";
|
|
1887
|
+
return { mmss, ms, full: `${mmss}${ms}` };
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1864
1890
|
// src/mutations/item-mutations.ts
|
|
1865
1891
|
function withSceneUpdated2(data, episodeIndex, sceneIndex, updater) {
|
|
1866
1892
|
const episodes = [...data.episodes || []];
|
|
@@ -2622,6 +2648,8 @@ function SceneEditorImpl({
|
|
|
2622
2648
|
disabled,
|
|
2623
2649
|
focused = false,
|
|
2624
2650
|
actionDiff,
|
|
2651
|
+
showTimestamp = false,
|
|
2652
|
+
highlights,
|
|
2625
2653
|
onEdit,
|
|
2626
2654
|
onNavigateAsset,
|
|
2627
2655
|
onRequestAssetDelete
|
|
@@ -2720,9 +2748,11 @@ function SceneEditorImpl({
|
|
|
2720
2748
|
onNavigateAsset
|
|
2721
2749
|
}
|
|
2722
2750
|
),
|
|
2723
|
-
/* @__PURE__ */ jsxs("div", { className: "lj-se-actions", children: [
|
|
2751
|
+
/* @__PURE__ */ jsxs("div", { className: cn("lj-se-actions", showTimestamp && "has-ts"), children: [
|
|
2724
2752
|
actions.map((item, idx) => {
|
|
2725
2753
|
const mark = actionDiff?.byIndex.get(idx);
|
|
2754
|
+
const hl = highlights?.get(idx);
|
|
2755
|
+
const ts = showTimestamp ? formatTimestamp(item.extend?.timestamp) : null;
|
|
2726
2756
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2727
2757
|
renderGhosts(idx),
|
|
2728
2758
|
/* @__PURE__ */ jsxs(
|
|
@@ -2732,11 +2762,15 @@ function SceneEditorImpl({
|
|
|
2732
2762
|
"lj-se-action-slot",
|
|
2733
2763
|
dragIndex === idx && "is-dragging",
|
|
2734
2764
|
dropSlot === idx && "drop-before",
|
|
2735
|
-
mark && (mark.kind === "added" ? "is-diff-added" : "is-diff-modified")
|
|
2765
|
+
mark && (mark.kind === "added" ? "is-diff-added" : "is-diff-modified"),
|
|
2766
|
+
hl && "lj-se-hl",
|
|
2767
|
+
hl?.className
|
|
2736
2768
|
),
|
|
2769
|
+
style: hl?.style,
|
|
2737
2770
|
onDragOver: (e) => onSlotDragOver(e, idx),
|
|
2738
2771
|
onDrop: onSlotDrop,
|
|
2739
2772
|
children: [
|
|
2773
|
+
ts ? /* @__PURE__ */ jsx("span", { className: "lj-se-ts", title: ts.full, children: ts.mmss }) : null,
|
|
2740
2774
|
mark ? /* @__PURE__ */ jsx(
|
|
2741
2775
|
DiffActionControls,
|
|
2742
2776
|
{
|
|
@@ -2817,7 +2851,8 @@ function safeId(raw, fallback) {
|
|
|
2817
2851
|
}
|
|
2818
2852
|
var GROUP_LABEL = { actors: "\u89D2\u8272", locations: "\u573A\u666F", props: "\u9053\u5177" };
|
|
2819
2853
|
var assetGroupLabel = (g) => GROUP_LABEL[g];
|
|
2820
|
-
function buildFlatStream(data) {
|
|
2854
|
+
function buildFlatStream(data, opts = {}) {
|
|
2855
|
+
const includeAssets = opts.includeAssets ?? true;
|
|
2821
2856
|
const items = [];
|
|
2822
2857
|
const indexByKey = /* @__PURE__ */ new Map();
|
|
2823
2858
|
const sceneIndexLookup = /* @__PURE__ */ new Map();
|
|
@@ -2865,14 +2900,16 @@ function buildFlatStream(data) {
|
|
|
2865
2900
|
}
|
|
2866
2901
|
});
|
|
2867
2902
|
push({ key: "add-episode", kind: "add-episode" });
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2903
|
+
if (includeAssets) {
|
|
2904
|
+
const specs = [
|
|
2905
|
+
{ group: "actors", ids: (data.actors ?? []).map((a, i) => safeId(a.actor_id, `__idx:${i}`)) },
|
|
2906
|
+
{ group: "locations", ids: (data.locations ?? []).map((l, i) => safeId(l.location_id, `__idx:${i}`)) },
|
|
2907
|
+
{ group: "props", ids: (data.props ?? []).map((p, i) => safeId(p.prop_id, `__idx:${i}`)) }
|
|
2908
|
+
];
|
|
2909
|
+
for (const { group, ids } of specs) {
|
|
2910
|
+
push({ key: `asset-group:${group}`, kind: "asset-group-header", group });
|
|
2911
|
+
ids.forEach((assetId) => push({ key: `asset:${group}:${assetId}`, kind: "asset-card", group, assetId }));
|
|
2912
|
+
}
|
|
2876
2913
|
}
|
|
2877
2914
|
return { items, indexByKey, sceneIndexLookup, sceneIdLookup, assetIndexLookup, paperStartKey, paperEndKey };
|
|
2878
2915
|
}
|
|
@@ -3553,6 +3590,7 @@ function AssetCardImpl({
|
|
|
3553
3590
|
onSave: (v) => onEdit((p) => updateEntityStateField(p, kind, assetId, sid, "state_name", v))
|
|
3554
3591
|
}
|
|
3555
3592
|
),
|
|
3593
|
+
(state.state_id ?? "").trim() ? /* @__PURE__ */ jsx("span", { className: "lj-se-assetcard-state-id", title: "\u72B6\u6001 id", children: (state.state_id ?? "").trim() }) : null,
|
|
3556
3594
|
!disabled && (state.state_id ?? "").trim() ? /* @__PURE__ */ jsx(
|
|
3557
3595
|
StateDeleteButton,
|
|
3558
3596
|
{
|
|
@@ -3614,11 +3652,28 @@ function ScriptStream({
|
|
|
3614
3652
|
onAcceptAction,
|
|
3615
3653
|
onRejectAction,
|
|
3616
3654
|
scrollScopeKey,
|
|
3655
|
+
includeAssets = true,
|
|
3656
|
+
paper = true,
|
|
3657
|
+
showTimestamp = false,
|
|
3658
|
+
highlights,
|
|
3617
3659
|
onEdit,
|
|
3618
3660
|
onSelectionChange,
|
|
3619
3661
|
onRequestAssetDelete
|
|
3620
3662
|
}) {
|
|
3621
|
-
const stream = useMemo(() => buildFlatStream(value), [value]);
|
|
3663
|
+
const stream = useMemo(() => buildFlatStream(value, { includeAssets }), [value, includeAssets]);
|
|
3664
|
+
const highlightsByScene = useMemo(() => {
|
|
3665
|
+
const m = /* @__PURE__ */ new Map();
|
|
3666
|
+
for (const h of highlights ?? []) {
|
|
3667
|
+
const key = `${h.episodeIdx}:${h.sceneId}`;
|
|
3668
|
+
let inner = m.get(key);
|
|
3669
|
+
if (!inner) {
|
|
3670
|
+
inner = /* @__PURE__ */ new Map();
|
|
3671
|
+
m.set(key, inner);
|
|
3672
|
+
}
|
|
3673
|
+
inner.set(h.actionIndex, { className: h.className, style: h.style });
|
|
3674
|
+
}
|
|
3675
|
+
return m;
|
|
3676
|
+
}, [highlights]);
|
|
3622
3677
|
const maps = useMemo(
|
|
3623
3678
|
() => ({
|
|
3624
3679
|
actorMap: getActorMap(value.actors ?? []),
|
|
@@ -3686,6 +3741,7 @@ function ScriptStream({
|
|
|
3686
3741
|
const end = key === stream.paperEndKey;
|
|
3687
3742
|
return start && end ? "is-sole" : start ? "is-start" : end ? "is-end" : "is-mid";
|
|
3688
3743
|
};
|
|
3744
|
+
const segClass = (key, extra) => cn(paper ? "lj-se-paper-seg" : "lj-se-plain-seg", paperEdge(key), extra);
|
|
3689
3745
|
useEffect(() => {
|
|
3690
3746
|
const key = selectionTargetKey(selection);
|
|
3691
3747
|
if (selection.origin === "scroll") {
|
|
@@ -3723,7 +3779,7 @@ function ScriptStream({
|
|
|
3723
3779
|
case "episode-header": {
|
|
3724
3780
|
const episode = value.episodes?.[item.episodeIdx];
|
|
3725
3781
|
if (!episode) return null;
|
|
3726
|
-
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", children: /* @__PURE__ */ jsx("div", { className:
|
|
3782
|
+
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", children: /* @__PURE__ */ jsx("div", { className: segClass(item.key, "lj-se-ep-seg"), children: /* @__PURE__ */ jsxs("div", { className: "lj-se-epbanner-wrap", children: [
|
|
3727
3783
|
!disabled ? /* @__PURE__ */ jsx(EpisodeMenu, { episodeIdx: item.episodeIdx, onEdit }) : null,
|
|
3728
3784
|
/* @__PURE__ */ jsx(
|
|
3729
3785
|
EpisodeBanner,
|
|
@@ -3739,7 +3795,7 @@ function ScriptStream({
|
|
|
3739
3795
|
}
|
|
3740
3796
|
case "episode-empty":
|
|
3741
3797
|
if (disabled) return null;
|
|
3742
|
-
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", children: /* @__PURE__ */ jsx("div", { className:
|
|
3798
|
+
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", children: /* @__PURE__ */ jsx("div", { className: segClass(item.key), children: /* @__PURE__ */ jsxs(
|
|
3743
3799
|
"button",
|
|
3744
3800
|
{
|
|
3745
3801
|
type: "button",
|
|
@@ -3765,7 +3821,7 @@ function ScriptStream({
|
|
|
3765
3821
|
onAccept: onAcceptAction,
|
|
3766
3822
|
onReject: onRejectAction
|
|
3767
3823
|
} : void 0;
|
|
3768
|
-
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", "data-quote-source": true, children: /* @__PURE__ */ jsxs("div", { className:
|
|
3824
|
+
return /* @__PURE__ */ jsx("div", { className: "lj-se-stream-row", "data-quote-source": true, children: /* @__PURE__ */ jsxs("div", { className: segClass(item.key, wholeKind ? "is-changed" : void 0), children: [
|
|
3769
3825
|
sceneDiff && inDiff ? /* @__PURE__ */ jsxs("div", { className: "lj-se-scenediff", children: [
|
|
3770
3826
|
/* @__PURE__ */ jsx("span", { className: cn("lj-se-scenediff-tag", wholeKind === "added" && "is-added"), children: wholeKind === "added" ? "AI \u65B0\u589E" : "AI \u6539\u52A8" }),
|
|
3771
3827
|
/* @__PURE__ */ jsx("span", { className: "lj-se-scenediff-spacer" }),
|
|
@@ -3799,6 +3855,8 @@ function ScriptStream({
|
|
|
3799
3855
|
format,
|
|
3800
3856
|
disabled,
|
|
3801
3857
|
focused,
|
|
3858
|
+
showTimestamp,
|
|
3859
|
+
highlights: highlightsByScene.get(diffKey),
|
|
3802
3860
|
onEdit,
|
|
3803
3861
|
onNavigateAsset: select,
|
|
3804
3862
|
onRequestAssetDelete
|
|
@@ -4539,9 +4597,11 @@ function ScriptSearchLayer({
|
|
|
4539
4597
|
/* @__PURE__ */ jsx(HighlightContext.Provider, { value: open ? query : "", children })
|
|
4540
4598
|
] });
|
|
4541
4599
|
}
|
|
4600
|
+
var NOOP_EDIT = (patch) => {
|
|
4601
|
+
};
|
|
4542
4602
|
function ScriptEditor({
|
|
4543
4603
|
value,
|
|
4544
|
-
onEdit,
|
|
4604
|
+
onEdit: onEditProp,
|
|
4545
4605
|
selection: controlledSelection,
|
|
4546
4606
|
onSelectionChange,
|
|
4547
4607
|
format: controlledFormat,
|
|
@@ -4560,11 +4620,20 @@ function ScriptEditor({
|
|
|
4560
4620
|
onEditingChange,
|
|
4561
4621
|
referenceFocusRequest,
|
|
4562
4622
|
scrollScopeKey,
|
|
4623
|
+
showAssets = true,
|
|
4624
|
+
showTitle = true,
|
|
4625
|
+
showFormatToggle = true,
|
|
4626
|
+
paper = true,
|
|
4627
|
+
showTimestamp = false,
|
|
4628
|
+
highlights,
|
|
4629
|
+
contentWidth,
|
|
4630
|
+
showSaveCapsule = true,
|
|
4563
4631
|
diff,
|
|
4564
4632
|
asset,
|
|
4565
4633
|
onAddChatReferences,
|
|
4566
4634
|
onRequestAssetDelete
|
|
4567
4635
|
}) {
|
|
4636
|
+
const onEdit = onEditProp ?? NOOP_EDIT;
|
|
4568
4637
|
const editingCount = useRef(0);
|
|
4569
4638
|
const onEditingChangeRef = useRef(onEditingChange);
|
|
4570
4639
|
onEditingChangeRef.current = onEditingChange;
|
|
@@ -4695,6 +4764,17 @@ function ScriptEditor({
|
|
|
4695
4764
|
const contextLabel = buildContextLabel(value, selection);
|
|
4696
4765
|
const returnTarget = resolveReturnTarget(value, selection);
|
|
4697
4766
|
const rootClass = ["lj-se-root", dark ? "dark" : "", className].filter(Boolean).join(" ");
|
|
4767
|
+
const rootStyle = contentWidth != null ? { "--lj-se-content-width": typeof contentWidth === "number" ? `${contentWidth}px` : contentWidth } : void 0;
|
|
4768
|
+
const streamHighlights = useMemo(
|
|
4769
|
+
() => highlights?.map((h) => ({
|
|
4770
|
+
episodeIdx: h.target.episodeIdx,
|
|
4771
|
+
sceneId: h.target.sceneId,
|
|
4772
|
+
actionIndex: h.target.actionIndex,
|
|
4773
|
+
className: h.className,
|
|
4774
|
+
style: h.style
|
|
4775
|
+
})),
|
|
4776
|
+
[highlights]
|
|
4777
|
+
);
|
|
4698
4778
|
const center = /* @__PURE__ */ jsx(
|
|
4699
4779
|
ScriptStream,
|
|
4700
4780
|
{
|
|
@@ -4708,6 +4788,10 @@ function ScriptEditor({
|
|
|
4708
4788
|
onAcceptAction: diff?.onAcceptAction,
|
|
4709
4789
|
onRejectAction: diff?.onRejectAction,
|
|
4710
4790
|
scrollScopeKey,
|
|
4791
|
+
includeAssets: showAssets,
|
|
4792
|
+
paper,
|
|
4793
|
+
showTimestamp,
|
|
4794
|
+
highlights: streamHighlights,
|
|
4711
4795
|
onEdit,
|
|
4712
4796
|
onSelectionChange: setSelection,
|
|
4713
4797
|
onRequestAssetDelete
|
|
@@ -4717,6 +4801,7 @@ function ScriptEditor({
|
|
|
4717
4801
|
"div",
|
|
4718
4802
|
{
|
|
4719
4803
|
className: rootClass,
|
|
4804
|
+
style: rootStyle,
|
|
4720
4805
|
ref: rootRef,
|
|
4721
4806
|
children: [
|
|
4722
4807
|
toc === "sidebar" ? /* @__PURE__ */ jsx(
|
|
@@ -4732,12 +4817,13 @@ function ScriptEditor({
|
|
|
4732
4817
|
/* @__PURE__ */ jsx(
|
|
4733
4818
|
CanvasTopBar,
|
|
4734
4819
|
{
|
|
4735
|
-
title: value.title,
|
|
4736
|
-
onTitleChange: disabled ? void 0 : onTitleChange,
|
|
4820
|
+
title: showTitle ? value.title : void 0,
|
|
4821
|
+
onTitleChange: disabled || !showTitle ? void 0 : onTitleChange,
|
|
4737
4822
|
titleDisabled: disabled,
|
|
4738
4823
|
contextLabel,
|
|
4739
4824
|
format,
|
|
4740
4825
|
onFormatChange: setFormat,
|
|
4826
|
+
showFormatToggle,
|
|
4741
4827
|
canUndo,
|
|
4742
4828
|
canRedo,
|
|
4743
4829
|
onUndo,
|
|
@@ -4758,7 +4844,7 @@ function ScriptEditor({
|
|
|
4758
4844
|
}
|
|
4759
4845
|
),
|
|
4760
4846
|
onAddChatReferences ? /* @__PURE__ */ jsx(QuoteLayer, { containerRef: canvasRef, onAddChatReferences }) : null,
|
|
4761
|
-
/* @__PURE__ */ jsx(
|
|
4847
|
+
showSaveCapsule ? /* @__PURE__ */ jsx(
|
|
4762
4848
|
SaveCapsule,
|
|
4763
4849
|
{
|
|
4764
4850
|
saveStatus,
|
|
@@ -4772,7 +4858,7 @@ function ScriptEditor({
|
|
|
4772
4858
|
returnLabel: returnTarget?.label,
|
|
4773
4859
|
onReturn: returnTarget ? () => setSelection(returnTarget.selection) : void 0
|
|
4774
4860
|
}
|
|
4775
|
-
)
|
|
4861
|
+
) : null
|
|
4776
4862
|
] })
|
|
4777
4863
|
] })
|
|
4778
4864
|
]
|
|
@@ -4977,6 +5063,6 @@ function DeleteConfirmButton({
|
|
|
4977
5063
|
);
|
|
4978
5064
|
}
|
|
4979
5065
|
|
|
4980
|
-
export { DeleteConfirmButton, EMPTY_SELECTION, EditableText, Popover, ScriptContentType, ScriptEditor, SelectField, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, mutations_exports as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
5066
|
+
export { DeleteConfirmButton, EMPTY_SELECTION, EditableText, Popover, ScriptContentType, ScriptEditor, SelectField, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, findBaselineScene, formatTimestamp, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, mutations_exports as mutations, rejectActionToBaseline, rejectSceneToBaseline, sceneChangeKey, selectionFromScriptReference, selectionTargetKey, withOrigin };
|
|
4981
5067
|
//# sourceMappingURL=index.js.map
|
|
4982
5068
|
//# sourceMappingURL=index.js.map
|