@lingjingai/script-editor 0.3.0 → 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.d.ts +49 -2
- package/dist/index.js +57 -3
- package/dist/index.js.map +1 -1
- package/dist/style.css +11 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -265,6 +265,15 @@ declare function getSceneContext(scene: Scene): {
|
|
|
265
265
|
state_id?: string | null;
|
|
266
266
|
}[];
|
|
267
267
|
};
|
|
268
|
+
/**
|
|
269
|
+
* Count how many scenes each asset appears in (its scene-cast / location / prop
|
|
270
|
+
* refs), in one pass. Drives the TOC's "出现次数" sort. v3-aware via getSceneContext.
|
|
271
|
+
*/
|
|
272
|
+
declare function countAssetAppearances(data: ScriptProject): {
|
|
273
|
+
actors: Map<string, number>;
|
|
274
|
+
locations: Map<string, number>;
|
|
275
|
+
props: Map<string, number>;
|
|
276
|
+
};
|
|
268
277
|
declare function getEpisodeTitle(episode: ScriptEpisode, index: number): string;
|
|
269
278
|
|
|
270
279
|
interface SelectOption {
|
|
@@ -289,6 +298,27 @@ type ScriptFormat = "standard" | "asian";
|
|
|
289
298
|
|
|
290
299
|
type SaveStatus = "idle" | "saving" | "saved" | "error";
|
|
291
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Flattens a ScriptProject into ONE continuous, stable-keyed item list for the
|
|
303
|
+
* virtualized stream — mirroring agent-frontend's single global scroll:
|
|
304
|
+
* each episode (episode-header → scene → scene → …)
|
|
305
|
+
* → asset groups (角色 / 场景 / 道具: group-header → asset-card × N)
|
|
306
|
+
* Plus selection ↔ flatIndex lookups (two-way) for scroll/scrollspy sync.
|
|
307
|
+
* (世界观 & 风格 is edited in a dialog now, not inline — see ScriptEditor.)
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
type AssetGroup = "actors" | "locations" | "props";
|
|
311
|
+
/** An asset as seen by `assetSort` — enough to reproduce any TOC ordering
|
|
312
|
+
* (by name / importance / appearance count) host-side. */
|
|
313
|
+
interface AssetSortItem {
|
|
314
|
+
group: AssetGroup;
|
|
315
|
+
id: string;
|
|
316
|
+
name: string;
|
|
317
|
+
importance?: string;
|
|
318
|
+
/** appearance count (scenes referencing this asset). */
|
|
319
|
+
count: number;
|
|
320
|
+
}
|
|
321
|
+
|
|
292
322
|
/**
|
|
293
323
|
* Reference focus — the INVERSE of "quote to chat". The host pushes a
|
|
294
324
|
* ScriptReferenceFocusRequest (e.g. when a chat message / comment that quotes
|
|
@@ -563,6 +593,23 @@ interface ScriptEditorProps extends ScriptEditorAdapters {
|
|
|
563
593
|
/** the floating bottom-center capsule (save status + AI-diff + 返回 breadcrumb).
|
|
564
594
|
* Default true. Set false for a pure display surface with no floating chrome. */
|
|
565
595
|
showSaveCapsule?: boolean;
|
|
596
|
+
/** per-action hover (target on enter, null on leave) — pair with `highlights`
|
|
597
|
+
* to build a hover-to-highlight effect entirely host-side. */
|
|
598
|
+
onActionHover?: (target: {
|
|
599
|
+
episodeIdx: number;
|
|
600
|
+
sceneId: string;
|
|
601
|
+
actionIndex: number;
|
|
602
|
+
} | null) => void;
|
|
603
|
+
/** per-action click, with full address. */
|
|
604
|
+
onActionClick?: (target: {
|
|
605
|
+
episodeIdx: number;
|
|
606
|
+
sceneId: string;
|
|
607
|
+
actionIndex: number;
|
|
608
|
+
}) => void;
|
|
609
|
+
/** order assets within each group in the preview (角色/场景/道具). Feed the SAME
|
|
610
|
+
* comparator your TOC uses so the left nav and right preview stay in lockstep.
|
|
611
|
+
* Omit → script.json array order. */
|
|
612
|
+
assetSort?: (a: AssetSortItem, b: AssetSortItem) => number;
|
|
566
613
|
}
|
|
567
614
|
/** A host range highlight targeting one action (same coords as DiffActionMark). */
|
|
568
615
|
interface ScriptHighlight {
|
|
@@ -574,7 +621,7 @@ interface ScriptHighlight {
|
|
|
574
621
|
className?: string;
|
|
575
622
|
style?: React.CSSProperties;
|
|
576
623
|
}
|
|
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;
|
|
624
|
+
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, onActionHover, onActionClick, assetSort, diff, asset, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
578
625
|
|
|
579
626
|
/**
|
|
580
627
|
* Action timestamps live at `action.extend.timestamp` as an in-episode
|
|
@@ -885,4 +932,4 @@ declare function DeleteConfirmButton({ onConfirm, disabled, targetScope, title,
|
|
|
885
932
|
description?: string;
|
|
886
933
|
}): react.JSX.Element;
|
|
887
934
|
|
|
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 };
|
|
935
|
+
export { type AssetAdapter, type AssetDeleteRequest, type AssetSortItem, 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, countAssetAppearances, 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
|
@@ -618,6 +618,29 @@ function StudioToc({
|
|
|
618
618
|
)
|
|
619
619
|
] });
|
|
620
620
|
}
|
|
621
|
+
function TocLabel({ text, className }) {
|
|
622
|
+
const ref = useRef(null);
|
|
623
|
+
const [tip, setTip] = useState(null);
|
|
624
|
+
const onEnter = () => {
|
|
625
|
+
const el = ref.current;
|
|
626
|
+
if (!el || el.scrollWidth <= el.clientWidth) return;
|
|
627
|
+
const r = el.getBoundingClientRect();
|
|
628
|
+
setTip({ x: r.right, y: r.top + r.height / 2 });
|
|
629
|
+
};
|
|
630
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
631
|
+
/* @__PURE__ */ jsx(
|
|
632
|
+
"span",
|
|
633
|
+
{
|
|
634
|
+
ref,
|
|
635
|
+
className,
|
|
636
|
+
onMouseEnter: onEnter,
|
|
637
|
+
onMouseLeave: () => setTip(null),
|
|
638
|
+
children: text
|
|
639
|
+
}
|
|
640
|
+
),
|
|
641
|
+
tip ? /* @__PURE__ */ jsx("span", { className: "lj-se-toc-tip", style: { left: tip.x, top: tip.y }, role: "tooltip", children: text }) : null
|
|
642
|
+
] });
|
|
643
|
+
}
|
|
621
644
|
function EntityGroup({
|
|
622
645
|
icon: Icon,
|
|
623
646
|
label,
|
|
@@ -641,7 +664,7 @@ function EntityGroup({
|
|
|
641
664
|
onClick: () => onPick(i.id),
|
|
642
665
|
children: [
|
|
643
666
|
/* @__PURE__ */ jsx(Icon, { className: "lj-se-tocitem-icon lj-se-ic-3", strokeWidth: 1.5 }),
|
|
644
|
-
/* @__PURE__ */ jsx(
|
|
667
|
+
/* @__PURE__ */ jsx(TocLabel, { className: "lj-se-tocitem-label", text: i.name }),
|
|
645
668
|
i.count > 0 ? /* @__PURE__ */ jsx("span", { className: "lj-se-tocitem-meta", children: i.count }) : null
|
|
646
669
|
]
|
|
647
670
|
},
|
|
@@ -2650,6 +2673,8 @@ function SceneEditorImpl({
|
|
|
2650
2673
|
actionDiff,
|
|
2651
2674
|
showTimestamp = false,
|
|
2652
2675
|
highlights,
|
|
2676
|
+
onActionHover,
|
|
2677
|
+
onActionClick,
|
|
2653
2678
|
onEdit,
|
|
2654
2679
|
onNavigateAsset,
|
|
2655
2680
|
onRequestAssetDelete
|
|
@@ -2657,6 +2682,7 @@ function SceneEditorImpl({
|
|
|
2657
2682
|
const [pendingEdit, setPendingEdit] = useState(null);
|
|
2658
2683
|
const { actorMap, speakerMap, locationMap, propMap } = maps;
|
|
2659
2684
|
const actions = scene.actions ?? [];
|
|
2685
|
+
const sceneId = scene.scene_id ?? "";
|
|
2660
2686
|
const actorOptions = useMemo(() => {
|
|
2661
2687
|
const out = [];
|
|
2662
2688
|
for (const a of actorMap.values()) {
|
|
@@ -2769,6 +2795,9 @@ function SceneEditorImpl({
|
|
|
2769
2795
|
style: hl?.style,
|
|
2770
2796
|
onDragOver: (e) => onSlotDragOver(e, idx),
|
|
2771
2797
|
onDrop: onSlotDrop,
|
|
2798
|
+
onMouseEnter: onActionHover ? () => onActionHover({ episodeIdx: episodeIndex, sceneId, actionIndex: idx }) : void 0,
|
|
2799
|
+
onMouseLeave: onActionHover ? () => onActionHover(null) : void 0,
|
|
2800
|
+
onClick: onActionClick ? () => onActionClick({ episodeIdx: episodeIndex, sceneId, actionIndex: idx }) : void 0,
|
|
2772
2801
|
children: [
|
|
2773
2802
|
ts ? /* @__PURE__ */ jsx("span", { className: "lj-se-ts", title: ts.full, children: ts.mmss }) : null,
|
|
2774
2803
|
mark ? /* @__PURE__ */ jsx(
|
|
@@ -2906,6 +2935,20 @@ function buildFlatStream(data, opts = {}) {
|
|
|
2906
2935
|
{ group: "locations", ids: (data.locations ?? []).map((l, i) => safeId(l.location_id, `__idx:${i}`)) },
|
|
2907
2936
|
{ group: "props", ids: (data.props ?? []).map((p, i) => safeId(p.prop_id, `__idx:${i}`)) }
|
|
2908
2937
|
];
|
|
2938
|
+
if (opts.assetSort) {
|
|
2939
|
+
const counts = countAssetAppearances(data);
|
|
2940
|
+
const actorMap = getActorMap(data.actors ?? []);
|
|
2941
|
+
const locationMap = getLocationMap(data.locations ?? []);
|
|
2942
|
+
const propMap = getPropMap(data.props ?? []);
|
|
2943
|
+
const enrich = (group, id) => {
|
|
2944
|
+
if (group === "actors") return { group, id, name: getActorDisplayName(actorMap.get(id)) || id, importance: actorMap.get(id)?.importance, count: counts.actors.get(id) ?? 0 };
|
|
2945
|
+
if (group === "locations") return { group, id, name: getLocationDisplayName(locationMap.get(id)) || id, importance: locationMap.get(id)?.importance, count: counts.locations.get(id) ?? 0 };
|
|
2946
|
+
return { group, id, name: getPropDisplayName(propMap.get(id)) || id, importance: propMap.get(id)?.importance, count: counts.props.get(id) ?? 0 };
|
|
2947
|
+
};
|
|
2948
|
+
for (const spec of specs) {
|
|
2949
|
+
spec.ids = spec.ids.map((id) => enrich(spec.group, id)).sort(opts.assetSort).map((it) => it.id);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2909
2952
|
for (const { group, ids } of specs) {
|
|
2910
2953
|
push({ key: `asset-group:${group}`, kind: "asset-group-header", group });
|
|
2911
2954
|
ids.forEach((assetId) => push({ key: `asset:${group}:${assetId}`, kind: "asset-card", group, assetId }));
|
|
@@ -3653,14 +3696,17 @@ function ScriptStream({
|
|
|
3653
3696
|
onRejectAction,
|
|
3654
3697
|
scrollScopeKey,
|
|
3655
3698
|
includeAssets = true,
|
|
3699
|
+
assetSort,
|
|
3656
3700
|
paper = true,
|
|
3657
3701
|
showTimestamp = false,
|
|
3658
3702
|
highlights,
|
|
3703
|
+
onActionHover,
|
|
3704
|
+
onActionClick,
|
|
3659
3705
|
onEdit,
|
|
3660
3706
|
onSelectionChange,
|
|
3661
3707
|
onRequestAssetDelete
|
|
3662
3708
|
}) {
|
|
3663
|
-
const stream = useMemo(() => buildFlatStream(value, { includeAssets }), [value, includeAssets]);
|
|
3709
|
+
const stream = useMemo(() => buildFlatStream(value, { includeAssets, assetSort }), [value, includeAssets, assetSort]);
|
|
3664
3710
|
const highlightsByScene = useMemo(() => {
|
|
3665
3711
|
const m = /* @__PURE__ */ new Map();
|
|
3666
3712
|
for (const h of highlights ?? []) {
|
|
@@ -3857,6 +3903,8 @@ function ScriptStream({
|
|
|
3857
3903
|
focused,
|
|
3858
3904
|
showTimestamp,
|
|
3859
3905
|
highlights: highlightsByScene.get(diffKey),
|
|
3906
|
+
onActionHover,
|
|
3907
|
+
onActionClick,
|
|
3860
3908
|
onEdit,
|
|
3861
3909
|
onNavigateAsset: select,
|
|
3862
3910
|
onRequestAssetDelete
|
|
@@ -4628,6 +4676,9 @@ function ScriptEditor({
|
|
|
4628
4676
|
highlights,
|
|
4629
4677
|
contentWidth,
|
|
4630
4678
|
showSaveCapsule = true,
|
|
4679
|
+
onActionHover,
|
|
4680
|
+
onActionClick,
|
|
4681
|
+
assetSort,
|
|
4631
4682
|
diff,
|
|
4632
4683
|
asset,
|
|
4633
4684
|
onAddChatReferences,
|
|
@@ -4789,9 +4840,12 @@ function ScriptEditor({
|
|
|
4789
4840
|
onRejectAction: diff?.onRejectAction,
|
|
4790
4841
|
scrollScopeKey,
|
|
4791
4842
|
includeAssets: showAssets,
|
|
4843
|
+
assetSort,
|
|
4792
4844
|
paper,
|
|
4793
4845
|
showTimestamp,
|
|
4794
4846
|
highlights: streamHighlights,
|
|
4847
|
+
onActionHover,
|
|
4848
|
+
onActionClick,
|
|
4795
4849
|
onEdit,
|
|
4796
4850
|
onSelectionChange: setSelection,
|
|
4797
4851
|
onRequestAssetDelete
|
|
@@ -5063,6 +5117,6 @@ function DeleteConfirmButton({
|
|
|
5063
5117
|
);
|
|
5064
5118
|
}
|
|
5065
5119
|
|
|
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 };
|
|
5120
|
+
export { DeleteConfirmButton, EMPTY_SELECTION, EditableText, Popover, ScriptContentType, ScriptEditor, SelectField, acceptActionIntoBaseline, acceptSceneIntoBaseline, applyActionAccept, applyActionReject, buildActionDiff, buildDiffFromBaseline, buildScriptNav, buildSelectionFrom, changeSetToDiffScenes, computeChangeSet, computeSceneActionDiff, countAssetAppearances, 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 };
|
|
5067
5121
|
//# sourceMappingURL=index.js.map
|
|
5068
5122
|
//# sourceMappingURL=index.js.map
|