@remotion/studio 4.0.526 → 4.0.527
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/components/Canvas.js +88 -26
- package/dist/components/CanvasCaptureDropHandler.js +63 -0
- package/dist/components/CanvasOrLoading.js +10 -2
- package/dist/components/CompositionSelectorItem.js +1 -0
- package/dist/components/CurrentAsset.js +2 -1
- package/dist/components/InitialCompositionLoader.js +1 -1
- package/dist/components/InlineDropdown.js +26 -2
- package/dist/components/InlineEditableTitle.js +1 -0
- package/dist/components/InspectorPanel/CollapsibleInspectorSectionHeader.js +1 -0
- package/dist/components/InspectorPanel/CompositionInspector.js +3 -3
- package/dist/components/InspectorPanel/CompositionMetadata.js +4 -0
- package/dist/components/InspectorPanel/ElementLibraryButton.js +1 -0
- package/dist/components/InspectorPanel/MultiSequenceInspector.js +32 -1
- package/dist/components/InspectorPanel/SequenceSelectionInspector.js +41 -1
- package/dist/components/InspectorPanel/common.js +1 -0
- package/dist/components/InspectorPanel/styles.js +2 -0
- package/dist/components/InspectorPanel/use-composition-actions.js +1 -0
- package/dist/components/InspectorSourceLocation.js +3 -0
- package/dist/components/MenuBuildIndicator.js +1 -0
- package/dist/components/NewComposition/CancelButton.js +1 -1
- package/dist/components/Preview.js +3 -0
- package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +1 -0
- package/dist/components/QuickSwitcher/QuickSwitcherContent.js +1 -0
- package/dist/components/RadioButton.js +1 -0
- package/dist/components/RenderModal/DataEditor.js +4 -1
- package/dist/components/RenderQueue/CaptionQueueItem.js +5 -2
- package/dist/components/RenderQueue/CaptionQueueProcessor.js +35 -8
- package/dist/components/RenderQueue/VideoMattingQueueItem.js +1 -0
- package/dist/components/RenderQueue/caption-job-types.d.ts +6 -0
- package/dist/components/RenderQueue/index.js +1 -0
- package/dist/components/RendersTab.js +2 -0
- package/dist/components/SelectedOutlineSnapIndicators.d.ts +6 -0
- package/dist/components/SelectedOutlineSnapIndicators.js +16 -12
- package/dist/components/SequencePropsSubscriptionProvider.d.ts +3 -0
- package/dist/components/SequencePropsSubscriptionProvider.js +8 -6
- package/dist/components/Timeline/TimelineDeleteKeybindings.js +6 -9
- package/dist/components/Timeline/TimelineEffectItem.js +1 -0
- package/dist/components/Timeline/TimelineExpandArrowButton.js +1 -0
- package/dist/components/Timeline/TimelineExpandedRow.js +1 -0
- package/dist/components/Timeline/TimelineFieldLabel.js +1 -0
- package/dist/components/Timeline/TimelineKeyframeControls.js +1 -0
- package/dist/components/Timeline/TimelineSequence.js +26 -0
- package/dist/components/Timeline/TimelineSequenceFrame.js +1 -0
- package/dist/components/Timeline/TimelineSequenceItem.js +28 -0
- package/dist/components/Timeline/TimelineViewport.d.ts +1 -0
- package/dist/components/Timeline/TimelineViewport.js +10 -1
- package/dist/components/Timeline/delete-selected-timeline-item.js +2 -2
- package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +3 -1
- package/dist/components/Timeline/get-sequence-context-menu-items.js +13 -1
- package/dist/components/Timeline/split-selected-timeline-item.d.ts +13 -10
- package/dist/components/Timeline/split-selected-timeline-item.js +58 -35
- package/dist/components/TimelineCombobox.js +1 -0
- package/dist/components/Transcription/TranscriptionModal.js +16 -11
- package/dist/components/Transcription/TranscriptionModalWithOptionalWhisper.js +1 -1
- package/dist/components/WebMcp.js +1 -0
- package/dist/components/composition-drop-preview.d.ts +9 -2
- package/dist/components/composition-drop-preview.js +7 -4
- package/dist/components/composition-menu-items.js +4 -4
- package/dist/components/delete-jsx-nodes-api.d.ts +2 -0
- package/dist/components/{delete-jsx-node-api.js → delete-jsx-nodes-api.js} +5 -5
- package/dist/components/get-open-in-menu-items.js +7 -7
- package/dist/components/keyboard-shortcuts.d.ts +4 -4
- package/dist/components/keyboard-shortcuts.js +3 -1
- package/dist/components/public-output-name.d.ts +1 -0
- package/dist/components/public-output-name.js +7 -3
- package/dist/esm/{CaptionQueueProcessor-k0yrm3dj.mjs → CaptionQueueProcessor-npa6szn1.mjs} +39 -8
- package/dist/esm/{LazyModels-nk7py0zt.mjs → LazyModels-nh3c8h9p.mjs} +4 -3
- package/dist/esm/{LazyModels-mtggyjye.mjs → LazyModels-rr5v8h5y.mjs} +4 -3
- package/dist/esm/{TranscriptionModal-ymnx1c7m.mjs → TranscriptionModal-79m5wgcj.mjs} +25 -17
- package/dist/esm/{VideoMattingModal-05vpczks.mjs → VideoMattingModal-31pew0xj.mjs} +9 -6
- package/dist/esm/index-21hxsfaa.mjs +239 -0
- package/dist/esm/{index-0gewwxse.mjs → index-4zen9prq.mjs} +2293 -2203
- package/dist/esm/index-5t2dwxsk.mjs +530 -0
- package/dist/esm/{index-5gd8k9yv.mjs → index-614tdz2q.mjs} +1 -1
- package/dist/esm/{index-cdy8v54v.mjs → index-9xxg6218.mjs} +20 -541
- package/dist/esm/{index-5bfxbpca.mjs → index-ac5550e7.mjs} +1 -1
- package/dist/esm/{index-eb5txqp6.mjs → index-e855w59j.mjs} +8 -86
- package/dist/esm/{index-4dsz9035.mjs → index-n5gmcvhz.mjs} +1 -1
- package/dist/esm/{index-bs39wngg.mjs → index-ppspzgn9.mjs} +3134 -2994
- package/dist/esm/{index-g7k2dvar.mjs → index-r0ejh5sy.mjs} +1 -1
- package/dist/esm/index-r1gr3j3a.mjs +80 -0
- package/dist/esm/{index-x40wwfmt.mjs → index-s7qa3xbw.mjs} +6 -4
- package/dist/esm/{index-f97r9e2g.mjs → index-vxwg66ar.mjs} +5 -3
- package/dist/esm/index.mjs +3 -2
- package/dist/esm/internals.mjs +10 -7
- package/dist/esm/previewEntry.mjs +10 -7
- package/dist/esm/{resolve-composition-component-location-bt2d6qxq.mjs → resolve-composition-component-location-qrp05g62.mjs} +1 -1
- package/dist/helpers/copy-text.js +1 -16
- package/dist/helpers/hoverable.js +2 -1
- package/dist/helpers/open-in-editor.js +1 -1
- package/dist/helpers/studio-runtime-config.d.ts +1 -1
- package/dist/helpers/use-keybinding.d.ts +1 -1
- package/dist/helpers/use-keyboard-shortcut-label.d.ts +2 -2
- package/dist/helpers/use-menu-structure.js +15 -9
- package/dist/state/modals.d.ts +5 -0
- package/dist/state/timeline-zoom.js +4 -0
- package/package.json +19 -19
- package/dist/components/delete-jsx-node-api.d.ts +0 -2
|
@@ -6,15 +6,19 @@ const react_1 = require("react");
|
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
7
7
|
const client_id_1 = require("../../helpers/client-id");
|
|
8
8
|
const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
|
|
9
|
+
const use_media_metadata_1 = require("../../helpers/use-media-metadata");
|
|
9
10
|
const audio_1 = require("../../icons/audio");
|
|
10
11
|
const duplicate_1 = require("../../icons/duplicate");
|
|
11
12
|
const scissors_1 = require("../../icons/scissors");
|
|
12
13
|
const snowflake_1 = require("../../icons/snowflake");
|
|
14
|
+
const transcription_1 = require("../../icons/transcription");
|
|
13
15
|
const trash_1 = require("../../icons/trash");
|
|
16
|
+
const modals_1 = require("../../state/modals");
|
|
14
17
|
const ConfirmationDialog_1 = require("../ConfirmationDialog");
|
|
15
18
|
const InspectorSequenceSection_1 = require("../InspectorSequenceSection");
|
|
16
19
|
const is_menu_item_1 = require("../Menu/is-menu-item");
|
|
17
20
|
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
21
|
+
const public_output_name_1 = require("../public-output-name");
|
|
18
22
|
const split_video_from_audio_api_1 = require("../split-video-from-audio-api");
|
|
19
23
|
const duplicate_selected_timeline_item_1 = require("../Timeline/duplicate-selected-timeline-item");
|
|
20
24
|
const split_selected_timeline_item_1 = require("../Timeline/split-selected-timeline-item");
|
|
@@ -70,8 +74,10 @@ const SplitSequenceQuickAction = ({ selection, track }) => {
|
|
|
70
74
|
return (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: !canSplit, onClick: onSplit, title: disabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(scissors_1.ScissorsIcon, { style: actionIconStyle, color: color })), children: "Split clip" }));
|
|
71
75
|
};
|
|
72
76
|
const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
|
|
77
|
+
var _a;
|
|
73
78
|
const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
|
|
74
79
|
const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
80
|
+
const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
|
|
75
81
|
const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
|
|
76
82
|
const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
|
|
77
83
|
const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
|
|
@@ -90,6 +96,40 @@ const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
|
|
|
90
96
|
validatedSource,
|
|
91
97
|
});
|
|
92
98
|
const sourceActionsDisabled = previewServerState.type !== 'connected' || !(0, interactivity_enabled_1.isStudioInteractivityEnabled)();
|
|
99
|
+
const mediaSequence = track.sequence.type === 'video' || track.sequence.type === 'audio'
|
|
100
|
+
? track.sequence
|
|
101
|
+
: null;
|
|
102
|
+
const mediaMetadata = (0, use_media_metadata_1.useMediaMetadata)((_a = mediaSequence === null || mediaSequence === void 0 ? void 0 : mediaSequence.src) !== null && _a !== void 0 ? _a : null);
|
|
103
|
+
const transcriptionDisabledReason = sourceActionsDisabled
|
|
104
|
+
? 'Studio is read-only'
|
|
105
|
+
: selection.nodePathInfo.numberOfSequencesWithThisNodePath > 1
|
|
106
|
+
? 'Programmatically duplicated media cannot be transcribed from source'
|
|
107
|
+
: undefined;
|
|
108
|
+
const onGenerateCaptions = (0, react_1.useCallback)(() => {
|
|
109
|
+
if (transcriptionDisabledReason !== undefined || mediaSequence === null) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const nodePath = selection.nodePathInfo.sequenceSubscriptionKey;
|
|
113
|
+
setSelectedModal({
|
|
114
|
+
type: 'transcribe',
|
|
115
|
+
src: mediaSequence.src,
|
|
116
|
+
displayName: (0, public_output_name_1.getMediaFileName)(mediaSequence.src, mediaSequence.displayName),
|
|
117
|
+
audioStreamIndex: null,
|
|
118
|
+
requestInit: null,
|
|
119
|
+
target: {
|
|
120
|
+
fileName: nodePath.absolutePath,
|
|
121
|
+
nodePath,
|
|
122
|
+
durationInFrames: Number.isFinite(mediaSequence.duration)
|
|
123
|
+
? mediaSequence.duration
|
|
124
|
+
: null,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}, [
|
|
128
|
+
selection.nodePathInfo,
|
|
129
|
+
setSelectedModal,
|
|
130
|
+
mediaSequence,
|
|
131
|
+
transcriptionDisabledReason,
|
|
132
|
+
]);
|
|
93
133
|
const onDuplicate = (0, react_1.useCallback)(() => {
|
|
94
134
|
if (sourceActionsDisabled) {
|
|
95
135
|
return;
|
|
@@ -125,7 +165,7 @@ const SequenceSourceQuickActions = ({ selection, track, validatedSource }) => {
|
|
|
125
165
|
(0, NotificationCenter_1.showNotification)(err.message, 4000);
|
|
126
166
|
});
|
|
127
167
|
}, [selection.nodePathInfo, splitVideoFromAudioDisabledReason]);
|
|
128
|
-
return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [(freezeFrameMenuItem === null || freezeFrameMenuItem === void 0 ? void 0 : freezeFrameMenuItem.type) === 'item' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: Boolean(freezeFrameMenuItem.disabled), onClick: () => freezeFrameMenuItem.onClick(freezeFrameMenuItem.id, null), renderIcon: (color) => (jsx_runtime_1.jsx(snowflake_1.SnowflakeIcon, { style: largeActionIconStyle, color: color })), children: freezeFrameMenuItem.label })) : null, track.sequence.type === 'video' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: splitVideoFromAudioDisabledReason !== undefined, onClick: onSplitVideoFromAudio, title: splitVideoFromAudioDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(audio_1.AudioIcon, { style: actionIconStyle, color: color })), children: "Split video from audio" })) : null, jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDuplicate, renderIcon: (color) => (jsx_runtime_1.jsx(duplicate_1.DuplicateIcon, { style: largeActionIconStyle, color: color })), children: "Duplicate" }), jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDelete, renderIcon: (color) => (jsx_runtime_1.jsx(trash_1.TrashIcon, { style: actionIconStyle, color: color })), children: "Delete" })] }));
|
|
168
|
+
return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [(freezeFrameMenuItem === null || freezeFrameMenuItem === void 0 ? void 0 : freezeFrameMenuItem.type) === 'item' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: Boolean(freezeFrameMenuItem.disabled), onClick: () => freezeFrameMenuItem.onClick(freezeFrameMenuItem.id, null), renderIcon: (color) => (jsx_runtime_1.jsx(snowflake_1.SnowflakeIcon, { style: largeActionIconStyle, color: color })), children: freezeFrameMenuItem.label })) : null, track.sequence.type === 'video' ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: splitVideoFromAudioDisabledReason !== undefined, onClick: onSplitVideoFromAudio, title: splitVideoFromAudioDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(audio_1.AudioIcon, { style: actionIconStyle, color: color })), children: "Split video from audio" })) : null, mediaSequence !== null && (mediaMetadata === null || mediaMetadata === void 0 ? void 0 : mediaMetadata.hasAudioTrack) !== false ? (jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: transcriptionDisabledReason !== undefined, onClick: onGenerateCaptions, title: transcriptionDisabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(transcription_1.TranscriptionIcon, { style: actionIconStyle, color: color })), children: "Generate captions" })) : null, jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDuplicate, renderIcon: (color) => (jsx_runtime_1.jsx(duplicate_1.DuplicateIcon, { style: largeActionIconStyle, color: color })), children: "Duplicate" }), jsx_runtime_1.jsx(common_1.InspectorQuickAction, { disabled: sourceActionsDisabled, onClick: onDelete, renderIcon: (color) => (jsx_runtime_1.jsx(trash_1.TrashIcon, { style: actionIconStyle, color: color })), children: "Delete" })] }));
|
|
129
169
|
};
|
|
130
170
|
const SequenceExpandedInspector = ({ track, readOnlyStudio }) => {
|
|
131
171
|
const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
@@ -40,6 +40,7 @@ exports.sectionHeader = {
|
|
|
40
40
|
lineHeight: '24px',
|
|
41
41
|
padding: `4px 0 4px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
|
|
42
42
|
userSelect: 'none',
|
|
43
|
+
WebkitUserSelect: 'none',
|
|
43
44
|
};
|
|
44
45
|
exports.inspectorSectionBody = {
|
|
45
46
|
display: 'flex',
|
|
@@ -144,6 +145,7 @@ exports.detailLabel = {
|
|
|
144
145
|
overflow: 'hidden',
|
|
145
146
|
textOverflow: 'ellipsis',
|
|
146
147
|
userSelect: 'none',
|
|
148
|
+
WebkitUserSelect: 'none',
|
|
147
149
|
whiteSpace: 'nowrap',
|
|
148
150
|
};
|
|
149
151
|
exports.detailValue = {
|
|
@@ -59,6 +59,7 @@ const useCompositionActions = () => {
|
|
|
59
59
|
const canInsertComposition = canShowInsertComposition && !isAddingComposition;
|
|
60
60
|
const canShowGenerateWithAgent = previewInteractive &&
|
|
61
61
|
!window.remotion_isReadOnlyStudio &&
|
|
62
|
+
browserStudioOperations === null &&
|
|
62
63
|
currentCompositionId !== null;
|
|
63
64
|
const insertSolid = (0, react_1.useCallback)(async () => {
|
|
64
65
|
if (!canInsertSolid ||
|
|
@@ -28,11 +28,13 @@ const sourceLocationStyle = {
|
|
|
28
28
|
textDecoration: 'none',
|
|
29
29
|
textOverflow: 'ellipsis',
|
|
30
30
|
userSelect: 'none',
|
|
31
|
+
WebkitUserSelect: 'none',
|
|
31
32
|
whiteSpace: 'nowrap',
|
|
32
33
|
width: 'fit-content',
|
|
33
34
|
};
|
|
34
35
|
const quickActionStyle = {
|
|
35
36
|
userSelect: 'none',
|
|
37
|
+
WebkitUserSelect: 'none',
|
|
36
38
|
};
|
|
37
39
|
const sourceLocationLabelStyle = {
|
|
38
40
|
color: 'inherit',
|
|
@@ -44,6 +46,7 @@ const sourceLocationLabelStyle = {
|
|
|
44
46
|
overflow: 'hidden',
|
|
45
47
|
textOverflow: 'ellipsis',
|
|
46
48
|
userSelect: 'none',
|
|
49
|
+
WebkitUserSelect: 'none',
|
|
47
50
|
whiteSpace: 'nowrap',
|
|
48
51
|
};
|
|
49
52
|
const InspectorSourceLocation = ({ location, canOpen, onOpen, renderIcon, size = 'default' }) => {
|
|
@@ -15,7 +15,7 @@ const style = {
|
|
|
15
15
|
alignItems: 'center',
|
|
16
16
|
};
|
|
17
17
|
const CancelIcon = (props) => {
|
|
18
|
-
return (jsx_runtime_1.jsx("svg", { viewBox: "0 0
|
|
18
|
+
return (jsx_runtime_1.jsx("svg", { viewBox: "0 0 640 640", ...props, children: jsx_runtime_1.jsx("path", { fill: colors_1.CURRENT_COLOR, d: "M507.3 155.3C513.5 149.1 513.5 138.9 507.3 132.7C501.1 126.5 490.9 126.5 484.7 132.7L320 297.4L155.3 132.7C149.1 126.5 138.9 126.5 132.7 132.7C126.5 138.9 126.5 149.1 132.7 155.3L297.4 320L132.7 484.7C126.5 490.9 126.5 501.1 132.7 507.3C138.9 513.5 149.1 513.5 155.3 507.3L320 342.6L484.7 507.3C490.9 513.5 501.1 513.5 507.3 507.3C513.5 501.1 513.5 490.9 507.3 484.7L342.6 320L507.3 155.3z" }) }));
|
|
19
19
|
};
|
|
20
20
|
exports.CancelIcon = CancelIcon;
|
|
21
21
|
const CancelButton = ({ onPress, ...props }) => {
|
|
@@ -47,6 +47,9 @@ const PIXEL_GRID_MIN_SCALE = 4;
|
|
|
47
47
|
const containerStyle = (options) => {
|
|
48
48
|
return {
|
|
49
49
|
transform: `scale(${options.scale})`,
|
|
50
|
+
// Keep the scaled composition on its own layer so the checkerboard does
|
|
51
|
+
// not bleed through its edges at fractional preview scales.
|
|
52
|
+
willChange: 'transform',
|
|
50
53
|
marginLeft: options.xCorrection,
|
|
51
54
|
marginTop: options.yCorrection,
|
|
52
55
|
width: options.width,
|
|
@@ -274,6 +274,9 @@ const DataEditor = ({ unresolvedComposition, defaultProps, setDefaultProps, prop
|
|
|
274
274
|
if (!unresolvedComposition.defaultProps) {
|
|
275
275
|
return jsx_runtime_1.jsx(SchemaErrorMessages_1.NoDefaultProps, { mode: schemaErrorMode });
|
|
276
276
|
}
|
|
277
|
+
// <Composition> normalizes omitted defaultProps to an empty object.
|
|
278
|
+
// Avoid rendering field editors with undefined values in that case.
|
|
279
|
+
const emptyDefaultPropsAreInvalid = Object.keys(defaultProps).length === 0 && !zodValidationResult.success;
|
|
277
280
|
const shouldRenderControlRow = !hideModeControls || (!hideWarningButton && warnings.length > 0);
|
|
278
281
|
const shouldRenderWarningMessages = showWarning && warnings.length > 0;
|
|
279
282
|
const compactLayout = layout === 'inspector';
|
|
@@ -284,6 +287,6 @@ const DataEditor = ({ unresolvedComposition, defaultProps, setDefaultProps, prop
|
|
|
284
287
|
jsx_runtime_1.jsx(layout_1.Spacing, { y: 1 }), jsx_runtime_1.jsx(ValidationMessage_1.ValidationMessage, { message: warning.message, align: "flex-start", type: "warning", size: compactLayout ? 'compact' : 'default', action: warning.resolveLink ? (jsx_runtime_1.jsx("a", { href: warning.resolveLink, target: "_blank", rel: "noopener noreferrer", style: compactLayout
|
|
285
288
|
? compactResolveLinkStyle
|
|
286
289
|
: resolveLinkStyle, children: "Resolve" })) : null })] }, warning.id)))
|
|
287
|
-
: null] })) : null, mode === 'schema' ? (jsx_runtime_1.jsx(SchemaEditor_1.SchemaEditor, { value: defaultProps, setValue: setDefaultProps, schema: schema, scrollableContainer: !compactLayout, contentInset: compactLayout ? InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING : undefined, errorMode: schemaErrorMode })) : (jsx_runtime_1.jsx(RenderModalJSONPropsEditor_1.RenderModalJSONPropsEditor, { value: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}, setValue: jsonEditorSetValue, onSave: onSave, serializedJSON: serializedJSON, defaultProps: unresolvedComposition.defaultProps, schema: schema, compositionId: unresolvedComposition.id, layout: layout }))] }));
|
|
290
|
+
: null] })) : null, mode === 'schema' ? (emptyDefaultPropsAreInvalid ? (jsx_runtime_1.jsx(SchemaErrorMessages_1.InvalidDefaultProps, { zodValidationResult: zodValidationResult })) : (jsx_runtime_1.jsx(SchemaEditor_1.SchemaEditor, { value: defaultProps, setValue: setDefaultProps, schema: schema, scrollableContainer: !compactLayout, contentInset: compactLayout ? InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING : undefined, errorMode: schemaErrorMode }))) : (jsx_runtime_1.jsx(RenderModalJSONPropsEditor_1.RenderModalJSONPropsEditor, { value: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}, setValue: jsonEditorSetValue, onSave: onSave, serializedJSON: serializedJSON, defaultProps: unresolvedComposition.defaultProps, schema: schema, compositionId: unresolvedComposition.id, layout: layout }))] }));
|
|
288
291
|
};
|
|
289
292
|
exports.DataEditor = DataEditor;
|
|
@@ -68,7 +68,7 @@ const CaptionQueueItem = ({ job, selected }) => {
|
|
|
68
68
|
const [hovered, setHovered] = (0, react_1.useState)(false);
|
|
69
69
|
const { removeCaptionJob } = (0, react_1.useContext)(context_1.RenderQueueContext);
|
|
70
70
|
const selectAsset = (0, use_select_asset_1.useSelectAsset)();
|
|
71
|
-
const isHoverable = job.status === 'done';
|
|
71
|
+
const isHoverable = job.status === 'done' && job.target === null;
|
|
72
72
|
const containerStyle = (0, react_1.useMemo)(() => {
|
|
73
73
|
return {
|
|
74
74
|
...container,
|
|
@@ -95,6 +95,9 @@ const CaptionQueueItem = ({ job, selected }) => {
|
|
|
95
95
|
if (job.status !== 'done') {
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
|
+
if (job.target !== null) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
98
101
|
selectAsset(job.outName);
|
|
99
102
|
(0, url_state_1.pushUrl)(`/assets/${job.outName}`);
|
|
100
103
|
}, [job, selectAsset]);
|
|
@@ -120,7 +123,7 @@ const CaptionQueueItem = ({ job, selected }) => {
|
|
|
120
123
|
if (job.status === 'failed') {
|
|
121
124
|
return job.error.message;
|
|
122
125
|
}
|
|
123
|
-
return job.outName;
|
|
126
|
+
return job.target === null ? job.outName : 'Captions added to composition';
|
|
124
127
|
}, [job]);
|
|
125
128
|
return (jsx_runtime_1.jsxs(layout_1.Row, { "data-render-queue-item": job.id, style: containerStyle, align: "center", onClick: onClick, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, className: selected ? item_style_1.RENDER_QUEUE_ITEM_SELECTED_CLASSNAME : undefined, children: [
|
|
126
129
|
jsx_runtime_1.jsx(CaptionJobStatus, { job: job }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsxs("div", { style: right, children: [
|
|
@@ -4,6 +4,9 @@ exports.CaptionQueueProcessor = void 0;
|
|
|
4
4
|
const whisper_webgpu_1 = require("@remotion/whisper-webgpu");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const write_static_file_1 = require("../../api/write-static-file");
|
|
7
|
+
const browser_studio_operations_1 = require("../../helpers/browser-studio-operations");
|
|
8
|
+
const install_required_package_1 = require("../../helpers/install-required-package");
|
|
9
|
+
const call_api_1 = require("../call-api");
|
|
7
10
|
const resample_media_to_16_khz_1 = require("../Transcription/resample-media-to-16-khz");
|
|
8
11
|
const context_1 = require("./context");
|
|
9
12
|
const load_model_for_job_1 = require("./load-model-for-job");
|
|
@@ -73,14 +76,38 @@ const CaptionQueueProcessor = () => {
|
|
|
73
76
|
const { captions } = (0, whisper_webgpu_1.toCaptions)({
|
|
74
77
|
whisperWebGpuOutput: transcription,
|
|
75
78
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
if (job.target === null) {
|
|
80
|
+
updateCaptionJobProgress(job.id, {
|
|
81
|
+
message: `Saving ${job.outName}...`,
|
|
82
|
+
value: 0.95,
|
|
83
|
+
});
|
|
84
|
+
await (0, write_static_file_1.writeStaticFile)({
|
|
85
|
+
contents: JSON.stringify(captions, null, 2),
|
|
86
|
+
filePath: job.outName,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
updateCaptionJobProgress(job.id, {
|
|
91
|
+
message: 'Adding Basic captions...',
|
|
92
|
+
value: 0.95,
|
|
93
|
+
});
|
|
94
|
+
await (0, install_required_package_1.installRequiredPackages)([
|
|
95
|
+
{ name: '@remotion/captions', version: null },
|
|
96
|
+
]);
|
|
97
|
+
const request = {
|
|
98
|
+
fileName: job.target.fileName,
|
|
99
|
+
nodePath: job.target.nodePath.nodePath,
|
|
100
|
+
durationInFrames: job.target.durationInFrames,
|
|
101
|
+
captions,
|
|
102
|
+
};
|
|
103
|
+
const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
|
|
104
|
+
const response = browserStudioOperations
|
|
105
|
+
? await browserStudioOperations.insertBasicCaptions(request)
|
|
106
|
+
: await (0, call_api_1.callApi)('/api/insert-basic-captions', request);
|
|
107
|
+
if (!response.success) {
|
|
108
|
+
throw new Error(response.reason);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
84
111
|
captionCount = captions.length;
|
|
85
112
|
}
|
|
86
113
|
catch (error) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { WhisperWebGpuModel, WhisperWebGpuTask } from '@remotion/whisper-webgpu';
|
|
2
|
+
import type { SequencePropsSubscriptionKey } from 'remotion';
|
|
2
3
|
export type CaptionJobProgress = {
|
|
3
4
|
message: string;
|
|
4
5
|
value: number;
|
|
@@ -24,6 +25,11 @@ export type AddCaptionJobParams = {
|
|
|
24
25
|
audioStreamIndex: number | null;
|
|
25
26
|
requestInit: Omit<RequestInit, 'signal'> | null;
|
|
26
27
|
outName: string;
|
|
28
|
+
target: {
|
|
29
|
+
fileName: string;
|
|
30
|
+
nodePath: SequencePropsSubscriptionKey;
|
|
31
|
+
durationInFrames: number | null;
|
|
32
|
+
} | null;
|
|
27
33
|
model: WhisperWebGpuModel;
|
|
28
34
|
language: string | null;
|
|
29
35
|
task: WhisperWebGpuTask;
|
|
@@ -108,6 +108,7 @@ const RenderQueue = () => {
|
|
|
108
108
|
for (let i = 0; i < allJobs.length; i++) {
|
|
109
109
|
const job = allJobs[i];
|
|
110
110
|
if ((0, caption_job_types_1.isCaptionJob)(job) &&
|
|
111
|
+
job.target === null &&
|
|
111
112
|
job.status === 'done' &&
|
|
112
113
|
canvasContent.asset === job.outName) {
|
|
113
114
|
return i;
|
|
@@ -15,6 +15,7 @@ const row = {
|
|
|
15
15
|
alignItems: 'center',
|
|
16
16
|
flex: 1,
|
|
17
17
|
userSelect: 'none',
|
|
18
|
+
WebkitUserSelect: 'none',
|
|
18
19
|
};
|
|
19
20
|
const badge = {
|
|
20
21
|
height: 16,
|
|
@@ -25,6 +26,7 @@ const badge = {
|
|
|
25
26
|
justifyContent: 'center',
|
|
26
27
|
alignItems: 'center',
|
|
27
28
|
userSelect: 'none',
|
|
29
|
+
WebkitUserSelect: 'none',
|
|
28
30
|
};
|
|
29
31
|
const RendersTab = ({ selected, onClick }) => {
|
|
30
32
|
const { jobs, captionJobs } = (0, react_1.useContext)(context_1.RenderQueueContext);
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type SelectedOutlineSnapPoint } from './selected-outline-snap';
|
|
3
3
|
export type UpdateSelectedOutlineSnapPoints = (snapPoints: readonly SelectedOutlineSnapPoint[]) => void;
|
|
4
|
+
export declare const SelectedOutlineSnapLines: React.FC<{
|
|
5
|
+
readonly compositionHeight: number;
|
|
6
|
+
readonly compositionWidth: number;
|
|
7
|
+
readonly scale: number;
|
|
8
|
+
readonly snapPoints: readonly SelectedOutlineSnapPoint[];
|
|
9
|
+
}>;
|
|
4
10
|
export declare const SelectedOutlineSnapIndicators: React.FC<{
|
|
5
11
|
readonly compositionHeight: number;
|
|
6
12
|
readonly compositionWidth: number;
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SelectedOutlineSnapIndicators = void 0;
|
|
3
|
+
exports.SelectedOutlineSnapIndicators = exports.SelectedOutlineSnapLines = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const selected_outline_snap_1 = require("./selected-outline-snap");
|
|
7
|
+
const SelectedOutlineSnapLines = ({ compositionHeight, compositionWidth, scale, snapPoints }) => {
|
|
8
|
+
if (snapPoints.length === 0) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return (jsx_runtime_1.jsx("g", { pointerEvents: "none", children: snapPoints.map((snapPoint) => {
|
|
12
|
+
if (snapPoint.target.axis === 'x') {
|
|
13
|
+
const x = snapPoint.target.position * scale;
|
|
14
|
+
return (jsx_runtime_1.jsx("line", { x1: x, x2: x, y1: 0, y2: compositionHeight * scale, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
|
|
15
|
+
}
|
|
16
|
+
const y = snapPoint.target.position * scale;
|
|
17
|
+
return (jsx_runtime_1.jsx("line", { x1: 0, x2: compositionWidth * scale, y1: y, y2: y, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
|
|
18
|
+
}) }));
|
|
19
|
+
};
|
|
20
|
+
exports.SelectedOutlineSnapLines = SelectedOutlineSnapLines;
|
|
7
21
|
const SelectedOutlineSnapIndicators = ({ compositionHeight, compositionWidth, scale, updateSnapPointsRef }) => {
|
|
8
22
|
const [activeSnapPoints, setActiveSnapPoints] = (0, react_1.useState)([]);
|
|
9
23
|
(0, react_1.useLayoutEffect)(() => {
|
|
@@ -14,16 +28,6 @@ const SelectedOutlineSnapIndicators = ({ compositionHeight, compositionWidth, sc
|
|
|
14
28
|
}
|
|
15
29
|
};
|
|
16
30
|
}, [updateSnapPointsRef]);
|
|
17
|
-
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
return (jsx_runtime_1.jsx("g", { pointerEvents: "none", children: activeSnapPoints.map((snapPoint) => {
|
|
21
|
-
if (snapPoint.target.axis === 'x') {
|
|
22
|
-
const x = snapPoint.target.position * scale;
|
|
23
|
-
return (jsx_runtime_1.jsx("line", { x1: x, x2: x, y1: 0, y2: compositionHeight * scale, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
|
|
24
|
-
}
|
|
25
|
-
const y = snapPoint.target.position * scale;
|
|
26
|
-
return (jsx_runtime_1.jsx("line", { x1: 0, x2: compositionWidth * scale, y1: y, y2: y, stroke: selected_outline_snap_1.selectedOutlineSnapIndicatorColor, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, `${snapPoint.target.axis}-${snapPoint.target.type}-${snapPoint.target.position}-${snapPoint.edge}`));
|
|
27
|
-
}) }));
|
|
31
|
+
return (jsx_runtime_1.jsx(exports.SelectedOutlineSnapLines, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, scale: scale, snapPoints: activeSnapPoints }));
|
|
28
32
|
};
|
|
29
33
|
exports.SelectedOutlineSnapIndicators = SelectedOutlineSnapIndicators;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { OverrideIdToNodePaths, TSequence } from 'remotion';
|
|
2
|
+
export declare const OverrideIdToNodePathMappingsRefContext: import("react").Context<{
|
|
3
|
+
readonly current: OverrideIdToNodePaths;
|
|
4
|
+
}>;
|
|
2
5
|
export declare const getReadOnlyOverrideIdToNodePathMappings: (sequences: readonly TSequence[]) => OverrideIdToNodePaths;
|
|
3
6
|
export declare const SequencePropsSubscriptionProvider: React.FC<{
|
|
4
7
|
readonly children: React.ReactNode;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SequencePropsSubscriptionProvider = exports.getReadOnlyOverrideIdToNodePathMappings = void 0;
|
|
3
|
+
exports.SequencePropsSubscriptionProvider = exports.getReadOnlyOverrideIdToNodePathMappings = exports.OverrideIdToNodePathMappingsRefContext = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
7
|
+
exports.OverrideIdToNodePathMappingsRefContext = (0, react_1.createContext)({ current: {} });
|
|
7
8
|
const getReadOnlyOverrideIdToNodePathMappings = (sequences) => {
|
|
8
9
|
return Object.fromEntries(sequences.flatMap((sequence) => {
|
|
9
10
|
var _a;
|
|
@@ -32,6 +33,9 @@ const SequencePropsSubscriptionProvider = ({ children }) => {
|
|
|
32
33
|
const readOnlyOverrideToNodePathMap = (0, react_1.useMemo)(() => window.remotion_isReadOnlyStudio
|
|
33
34
|
? (0, exports.getReadOnlyOverrideIdToNodePathMappings)(sequences)
|
|
34
35
|
: null, [sequences]);
|
|
36
|
+
const overrideIdToNodePathMappings = readOnlyOverrideToNodePathMap !== null && readOnlyOverrideToNodePathMap !== void 0 ? readOnlyOverrideToNodePathMap : overrideToNodePathMap;
|
|
37
|
+
const overrideIdToNodePathMappingsRef = (0, react_1.useRef)(overrideIdToNodePathMappings);
|
|
38
|
+
overrideIdToNodePathMappingsRef.current = overrideIdToNodePathMappings;
|
|
35
39
|
const setOverrideIdToNodePath = (0, react_1.useCallback)((overrideId, state) => {
|
|
36
40
|
setOverrideIdToNodePathMap((prev) => {
|
|
37
41
|
const existing = prev[overrideId];
|
|
@@ -50,13 +54,11 @@ const SequencePropsSubscriptionProvider = ({ children }) => {
|
|
|
50
54
|
});
|
|
51
55
|
}, []);
|
|
52
56
|
const getters = (0, react_1.useMemo)(() => {
|
|
53
|
-
return {
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
}, [overrideToNodePathMap, readOnlyOverrideToNodePathMap]);
|
|
57
|
+
return { overrideIdToNodePathMappings };
|
|
58
|
+
}, [overrideIdToNodePathMappings]);
|
|
57
59
|
const setters = (0, react_1.useMemo)(() => {
|
|
58
60
|
return { setOverrideIdToNodePath };
|
|
59
61
|
}, [setOverrideIdToNodePath]);
|
|
60
|
-
return (jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsGettersContext.Provider, { value: getters, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsSettersContext.Provider, { value: setters, children: children }) }));
|
|
62
|
+
return (jsx_runtime_1.jsx(exports.OverrideIdToNodePathMappingsRefContext.Provider, { value: overrideIdToNodePathMappingsRef, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsGettersContext.Provider, { value: getters, children: jsx_runtime_1.jsx(remotion_1.Internals.OverrideIdsToNodePathsSettersContext.Provider, { value: setters, children: children }) }) }));
|
|
61
63
|
};
|
|
62
64
|
exports.SequencePropsSubscriptionProvider = SequencePropsSubscriptionProvider;
|
|
@@ -6,6 +6,7 @@ const remotion_1 = require("remotion");
|
|
|
6
6
|
const client_id_1 = require("../../helpers/client-id");
|
|
7
7
|
const use_keybinding_1 = require("../../helpers/use-keybinding");
|
|
8
8
|
const ConfirmationDialog_1 = require("../ConfirmationDialog");
|
|
9
|
+
const SequencePropsSubscriptionProvider_1 = require("../SequencePropsSubscriptionProvider");
|
|
9
10
|
const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
|
|
10
11
|
const imperative_state_1 = require("./imperative-state");
|
|
11
12
|
const split_selected_timeline_item_1 = require("./split-selected-timeline-item");
|
|
@@ -15,7 +16,7 @@ const TimelineDeleteKeybindings = () => {
|
|
|
15
16
|
const keybindings = (0, use_keybinding_1.useKeybinding)();
|
|
16
17
|
const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
17
18
|
const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
|
|
18
|
-
const
|
|
19
|
+
const overrideIdToNodePathMappingsRef = (0, react_1.useContext)(SequencePropsSubscriptionProvider_1.OverrideIdToNodePathMappingsRefContext);
|
|
19
20
|
const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
|
|
20
21
|
const { canSelect } = (0, TimelineSelection_1.useTimelineSelection)();
|
|
21
22
|
const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
|
|
@@ -56,11 +57,8 @@ const TimelineDeleteKeybindings = () => {
|
|
|
56
57
|
});
|
|
57
58
|
const split = keybindings.registerKeybinding({
|
|
58
59
|
event: 'keydown',
|
|
59
|
-
|
|
60
|
-
callback: (
|
|
61
|
-
if (!(0, split_selected_timeline_item_1.shouldHandleTimelineSplitShortcut)(event)) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
60
|
+
action: 'splitSequences',
|
|
61
|
+
callback: () => {
|
|
64
62
|
const { selectedItems } = currentSelection.current;
|
|
65
63
|
if (selectedItems.length === 0) {
|
|
66
64
|
return;
|
|
@@ -68,7 +66,7 @@ const TimelineDeleteKeybindings = () => {
|
|
|
68
66
|
const splitPromise = (0, split_selected_timeline_item_1.splitSelectedTimelineItems)({
|
|
69
67
|
selections: selectedItems,
|
|
70
68
|
sequences: sequencesRef.current,
|
|
71
|
-
overrideIdsToNodePaths:
|
|
69
|
+
overrideIdsToNodePaths: overrideIdToNodePathMappingsRef.current,
|
|
72
70
|
propStatuses: propStatusesRef.current,
|
|
73
71
|
splitFrame: (0, imperative_state_1.getCurrentFrame)(),
|
|
74
72
|
});
|
|
@@ -77,7 +75,6 @@ const TimelineDeleteKeybindings = () => {
|
|
|
77
75
|
}
|
|
78
76
|
splitPromise.catch(() => undefined);
|
|
79
77
|
},
|
|
80
|
-
commandCtrlKey: true,
|
|
81
78
|
preventDefault: true,
|
|
82
79
|
triggerIfInputFieldFocused: false,
|
|
83
80
|
keepRegisteredWhenNotHighestContext: false,
|
|
@@ -93,7 +90,7 @@ const TimelineDeleteKeybindings = () => {
|
|
|
93
90
|
currentSelection,
|
|
94
91
|
deleteTimelineItems,
|
|
95
92
|
keybindings,
|
|
96
|
-
|
|
93
|
+
overrideIdToNodePathMappingsRef,
|
|
97
94
|
propStatusesRef,
|
|
98
95
|
previewServerState,
|
|
99
96
|
sequencesRef,
|
|
@@ -20,6 +20,7 @@ const rowLabel = {
|
|
|
20
20
|
fontSize: 12,
|
|
21
21
|
color: colors_1.WHITE_ALPHA_80,
|
|
22
22
|
userSelect: 'none',
|
|
23
|
+
WebkitUserSelect: 'none',
|
|
23
24
|
};
|
|
24
25
|
const TimelineExpandedRowInner = ({ node, depth, nestedDepth, rowDepthBase, getIsExpanded, toggleTrack, validatedLocation, nodePath, schema, keyframeDisplayOffset, keyframeControlsMode, }) => {
|
|
25
26
|
const rowDepth = (rowDepthBase !== null && rowDepthBase !== void 0 ? rowDepthBase : (0, timeline_row_layout_1.getExpandedRowDepth)({ nestedDepth, treeDepth: 0 })) + depth;
|
|
@@ -12,6 +12,7 @@ const fieldNameBase = {
|
|
|
12
12
|
lineHeight: `${timeline_field_row_layout_1.TIMELINE_STACKED_FIELD_HEADER_HEIGHT}px`,
|
|
13
13
|
color: colors_1.WHITE_ALPHA_80,
|
|
14
14
|
userSelect: 'none',
|
|
15
|
+
WebkitUserSelect: 'none',
|
|
15
16
|
whiteSpace: 'nowrap',
|
|
16
17
|
overflow: 'hidden',
|
|
17
18
|
textOverflow: 'ellipsis',
|