Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7158f9b
Simplify Element install confirmation dialog
samohovets Sep 2, 2026
0bcbdc2
Polish Element install dialog controls
samohovets Sep 2, 2026
392e088
Merge pull request #11040 from remotion-dev/elements-install-dialog-l…
samohovets Sep 2, 2026
197f82b
Elements: Replace drag action with compact handle
samohovets Sep 2, 2026
3446214
Elements: Explain local network permission during discovery
samohovets Sep 2, 2026
f5f57de
Elements: Add unavailable Studio guidance
samohovets Sep 2, 2026
784e9b0
Wait for local network permission during Studio discovery
samohovets Sep 2, 2026
17f06f4
Remove legacy Studio discovery probe
samohovets Sep 2, 2026
a6a7485
Merge pull request #11046 from remotion-dev/elements-remove-legacy-st…
samohovets Sep 2, 2026
c65ff84
Merge remote-tracking branch 'origin/main' into element-install-permi…
samohovets Sep 2, 2026
8b66aea
Fix Studio discovery fetch invocation
samohovets Sep 2, 2026
0ea100a
Elements: Integrate drag handle into install button
samohovets Sep 2, 2026
591c5b5
Handle denied Studio loopback permission
samohovets Sep 2, 2026
2844ee7
Elements: Tighten details spacing
samohovets Sep 2, 2026
a480172
Merge pull request #11044 from remotion-dev/element-install-permission
samohovets Sep 2, 2026
bd1913b
Merge remote-tracking branch 'origin/main' into elements-sidebar-actions
samohovets Sep 2, 2026
5b213fe
Ignore non-Studio discovery responses
samohovets Sep 2, 2026
bf825f3
Elements: Improve unavailable Studio guidance
samohovets Sep 2, 2026
183f961
Merge pull request #11047 from remotion-dev/element-denied-permission
samohovets Sep 2, 2026
c5101d6
Merge pull request #11041 from remotion-dev/elements-sidebar-actions
samohovets Sep 2, 2026
9e67a48
Merge remote-tracking branch 'origin/main' into elements-getting-started
samohovets Sep 2, 2026
2b3d0e1
Merge remote-tracking branch 'origin/main' into fix-studio-discovery-…
samohovets Sep 2, 2026
2fcb86a
Merge pull request #11045 from remotion-dev/elements-getting-started
samohovets Sep 2, 2026
a341918
Merge pull request #11048 from remotion-dev/fix-studio-discovery-non-…
samohovets Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions packages/browser-studio/e2e/browser-studio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1017,16 +1017,17 @@ export const BrowserElement = () => <Rect width={320} height={180} fill="red" />
await canvas.dispatchEvent('drop', coordinates);

await expect(
studio.getByText('Install Element', {exact: true}),
studio.getByText('Install Browser Element', {exact: true}),
).toBeVisible();
await expect(
studio.getByText('Unverified drag-and-drop payload'),
).toBeVisible();
await expect(
studio.getByText(
'Dependencies are resolved in the browser; package lifecycle scripts do not run.',
),
).toHaveCount(0);
studio.getByText('Packages to install', {exact: true}),
).toBeVisible();
await expect(
studio.getByText('@remotion/shapes', {exact: true}),
).toBeVisible();
await studio.getByRole('button', {name: /^Install/}).click();

await expect
Expand Down Expand Up @@ -1099,7 +1100,7 @@ export const LinkedElement = () => <Rect width={320} height={180} fill="red" />;
await expect(studio.getByTitle('/project').getByText('MyComp')).toBeVisible();

await expect(
studio.getByText('Install Element', {exact: true}),
studio.getByText('Install Linked Element', {exact: true}),
).toBeVisible();
await expect(page).toHaveTitle(
'📦 Install Linked Element - Remotion Studio',
Expand Down
18 changes: 15 additions & 3 deletions packages/docs/components/layout/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,26 @@ type PrestyledProps = DetailedHTMLProps<
MandatoryProps;

export const Button: React.FC<Props> = (props) => {
const {children, loading, hoverColor, fullWidth, color, size, ...other} =
props;
const {
children,
loading,
hoverColor,
fullWidth,
color,
size,
className,
...other
} = props;
const actualDisabled = other.disabled || loading;

return (
<button
type="button"
className={styles.buttoncontainer}
className={
className
? `${styles.buttoncontainer} ${className}`
: styles.buttoncontainer
}
disabled={actualDisabled}
{...other}
style={{
Expand Down
3 changes: 1 addition & 2 deletions packages/docs/docs/studio-protocol/install-in-studio.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ On failure, one of:

- `unsupported-origin`
- `no-compatible-studio`
- `loopback-network-permission-denied` <AvailableFrom v="4.0.521" inline />
- `studio-upgrade-required`
- `no-installable-target`
- `unsupported-protocol`
Expand All @@ -90,8 +91,6 @@ A human-readable failure message. Use `code` for application logic.

When called outside Studio, ports 3000 through 3009 are probed in parallel. The most recently focused compatible target is selected. Discovery returns a short-lived, single-use token bound to that Studio tab and contextual composition.

Studios older than 4.0.502 are detected and return `studio-upgrade-required`. The Element is not sent through the legacy endpoint.

## Supported origins

The function supports any HTTPS website. HTTP is supported only on `localhost` and `127.0.0.1` for local development.
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/docs/studio-protocol/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Studio reflects only the requesting allowed origin in CORS. It does not use wild

Elements delivered using [`setStudioDragData()`](/docs/studio-protocol/set-studio-drag-data) or [`installInStudio()`](/docs/studio-protocol/install-in-studio) require confirmation in Studio. A successful `installInStudio()` result only means the request reached Studio and is awaiting confirmation.

Before confirming, Studio shows the target composition and destination file, source code, and every declared dependency with its installation status. For an installation request, Studio also shows the requesting website. Drag-and-drop data has no reliable website provenance and is labeled as unverified. Source code and package lifecycle scripts run with the project's file and network access.
Before confirming, Studio shows the requesting source, destination choice, source code, packages that will be installed, and whether an existing Element source file will be replaced. Drag-and-drop data has no reliable website provenance and is labeled as unverified. Installed source code runs with the project's file and network access. Package lifecycle scripts may also run when packages are installed.

Declining the confirmation does not write source files or install packages.

Expand Down
115 changes: 68 additions & 47 deletions packages/docs/src/components/Elements/ElementPage.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,71 +97,103 @@

.actionRow {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-direction: column;
gap: 10px;
}

.studioAction {
display: flex;
align-items: stretch;
width: 100%;
border-radius: 8px;
background: var(--blue-underlay);
}

.studioAction .installButtonWithDragHandle {
border-top-right-radius: 0;
border-right-width: 0;
border-bottom-right-radius: 0;
}

.dragHandle {
position: relative;
display: flex;
align-items: center;
margin-top: 8px;
padding: 8px 40px;
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: 8px;
background: var(--ifm-background-surface-color);
color: var(--ifm-color-emphasis-800);
justify-content: center;
width: 46px;
min-height: 46px;
flex: none;
border: 2px solid black;
border-bottom-width: 4px;
border-left: 1px solid rgb(0 0 0 / 30%);
border-radius: 0 8px 8px 0;
background: transparent;
color: white;
cursor: grab;
font-size: 0.8125rem;
user-select: none;
}

.dragHandle:hover {
background: var(--ifm-color-emphasis-100);
background: rgb(0 0 0 / 8%);
}

.dragHandle:active {
cursor: grabbing;
}

[data-theme='dark'] .dragHandle {
border-color: var(--ifm-color-emphasis-200);
color: var(--ifm-color-emphasis-700);
}

.dragHandleIcon {
position: absolute;
left: 12px;
top: 50%;
font-size: 1.5rem;
line-height: 1;
transform: translateY(-50%);
}

[data-theme='dark'] .dragHandleIcon {
color: var(--ifm-color-emphasis-500);
.studioGuidance {
margin-top: 12px;
padding: 12px;
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: 8px;
background: var(--ifm-color-emphasis-100);
font-size: 0.875rem;
}

.studioGuidanceTitle {
margin: 0;
font-weight: 600;
}

.dragHandleText {
.studioGuidanceSteps {
display: flex;
flex: 1;
flex-direction: column;
line-height: 1.3;
text-align: center;
white-space: nowrap;
gap: 8px;
margin: 10px 0 0;
padding: 0;
list-style: none;
}

.dragHandleText strong {
font-weight: 600;
.studioGuidanceSteps li {
display: flex;
align-items: flex-start;
gap: 8px;
line-height: 1.5;
}

.studioGuidanceSteps li > div {
flex: none;
}

.studioGuidanceSteps li > span {
min-width: 0;
}

.installingStatus,
.successStatus,
.errorStatus {
margin: 12px 0 0;
font-size: 0.875rem;
}

.installingStatus {
color: var(--ifm-color-emphasis-700);
}

.successStatus {
color: var(--ifm-color-success-dark);
}
Expand All @@ -171,9 +203,7 @@
}

.details {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--ifm-color-emphasis-200);
margin-top: 20px;
}

.description {
Expand All @@ -184,7 +214,7 @@
}

.metadata {
margin: 14px 0 0;
margin: 16px 0 0;
font-size: 0.8125rem;
}

Expand All @@ -202,8 +232,8 @@

.metadata dd {
margin: 0;
color: var(--ifm-color-emphasis-800);
font-variant-numeric: tabular-nums;
font-weight: 600;
}

.metadata > .dependenciesMetadata {
Expand All @@ -225,11 +255,6 @@
overflow-wrap: anywhere;
}

.dependencyList li::marker {
color: var(--ifm-color-primary);
font-size: 0.85em;
}

.dependencyList li + li {
margin-top: 4px;
}
Expand All @@ -242,9 +267,7 @@
}

.contributors:not(:first-child) {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--ifm-color-emphasis-200);
margin-top: 24px;
}

.contributorsLabel {
Expand All @@ -257,7 +280,7 @@
.contributorList {
display: flex;
flex-wrap: wrap;
gap: 12px;
gap: 8px;
min-width: 0;
}

Expand Down Expand Up @@ -301,7 +324,6 @@
}

@container actions-column (max-width: 400px) {
.actionsColumn .actionRow,
.actionsColumn .contributors,
.actionsColumn .contributorList {
align-items: stretch;
Expand All @@ -314,9 +336,8 @@
height: 160px;
}

.actionRow {
align-items: stretch;
flex-direction: column;
.studioGuidance {
font-size: 1rem;
}

.contributors {
Expand Down
Loading
Loading