remotion
Advanced tools
| import React from 'react'; | ||
| import type { SequenceProps } from './Sequence.js'; | ||
| type InteractiveHtmlTag = 'a' | 'article' | 'aside' | 'button' | 'code' | 'div' | 'em' | 'footer' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'header' | 'label' | 'li' | 'main' | 'nav' | 'ol' | 'p' | 'pre' | 'section' | 'small' | 'span' | 'strong' | 'ul'; | ||
| type InteractiveSvgTag = 'circle' | 'ellipse' | 'g' | 'line' | 'path' | 'rect' | 'svg' | 'text'; | ||
| type InteractiveTag = InteractiveHtmlTag | InteractiveSvgTag; | ||
| type ElementForTag<Tag extends InteractiveTag> = Tag extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[Tag] : Tag extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[Tag] : Element; | ||
| type InteractiveSequenceProps = Pick<SequenceProps, 'durationInFrames' | 'from' | 'hidden' | 'name' | 'showInTimeline'> & { | ||
| /** | ||
| * @deprecated For internal use only | ||
| */ | ||
| readonly stack?: string; | ||
| }; | ||
| type InteractiveElementProps<Tag extends InteractiveTag> = Omit<React.ComponentPropsWithoutRef<Tag>, keyof InteractiveSequenceProps> & InteractiveSequenceProps; | ||
| type InteractiveElementComponent<Tag extends InteractiveTag> = React.ComponentType<InteractiveElementProps<Tag> & React.RefAttributes<ElementForTag<Tag>>>; | ||
| /** | ||
| * @description HTML and SVG elements that are registered in the Remotion Studio timeline and can be visually edited. | ||
| */ | ||
| export declare const Interactive: { | ||
| A: InteractiveElementComponent<"a">; | ||
| Article: InteractiveElementComponent<"article">; | ||
| Aside: InteractiveElementComponent<"aside">; | ||
| Button: InteractiveElementComponent<"button">; | ||
| Circle: InteractiveElementComponent<"circle">; | ||
| Code: InteractiveElementComponent<"code">; | ||
| Div: InteractiveElementComponent<"div">; | ||
| Ellipse: InteractiveElementComponent<"ellipse">; | ||
| Em: InteractiveElementComponent<"em">; | ||
| Footer: InteractiveElementComponent<"footer">; | ||
| G: InteractiveElementComponent<"g">; | ||
| H1: InteractiveElementComponent<"h1">; | ||
| H2: InteractiveElementComponent<"h2">; | ||
| H3: InteractiveElementComponent<"h3">; | ||
| H4: InteractiveElementComponent<"h4">; | ||
| H5: InteractiveElementComponent<"h5">; | ||
| H6: InteractiveElementComponent<"h6">; | ||
| Header: InteractiveElementComponent<"header">; | ||
| Label: InteractiveElementComponent<"label">; | ||
| Li: InteractiveElementComponent<"li">; | ||
| Line: InteractiveElementComponent<"line">; | ||
| Main: InteractiveElementComponent<"main">; | ||
| Nav: InteractiveElementComponent<"nav">; | ||
| Ol: InteractiveElementComponent<"ol">; | ||
| P: InteractiveElementComponent<"p">; | ||
| Path: InteractiveElementComponent<"path">; | ||
| Pre: InteractiveElementComponent<"pre">; | ||
| Rect: InteractiveElementComponent<"rect">; | ||
| Section: InteractiveElementComponent<"section">; | ||
| Small: InteractiveElementComponent<"small">; | ||
| Span: InteractiveElementComponent<"span">; | ||
| Strong: InteractiveElementComponent<"strong">; | ||
| Svg: InteractiveElementComponent<"svg">; | ||
| Text: InteractiveElementComponent<"text">; | ||
| Ul: InteractiveElementComponent<"ul">; | ||
| }; | ||
| export type InteractiveProps<Tag extends InteractiveTag> = InteractiveElementProps<Tag>; | ||
| export {}; |
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Interactive = void 0; | ||
| const jsx_runtime_1 = require("react/jsx-runtime"); | ||
| const react_1 = __importStar(require("react")); | ||
| const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js"); | ||
| const sequence_field_schema_js_1 = require("./sequence-field-schema.js"); | ||
| const Sequence_js_1 = require("./Sequence.js"); | ||
| const wrap_in_schema_js_1 = require("./wrap-in-schema.js"); | ||
| const interactiveElementSchema = { | ||
| durationInFrames: sequence_field_schema_js_1.durationInFramesField, | ||
| from: sequence_field_schema_js_1.fromField, | ||
| ...sequence_field_schema_js_1.sequenceVisualStyleSchema, | ||
| hidden: sequence_field_schema_js_1.hiddenField, | ||
| }; | ||
| const setRef = (ref, value) => { | ||
| if (typeof ref === 'function') { | ||
| ref(value); | ||
| } | ||
| else if (ref) { | ||
| ref.current = value; | ||
| } | ||
| }; | ||
| const makeInteractiveElement = (tag, displayName) => { | ||
| const Inner = (0, react_1.forwardRef)((propsWithControls, ref) => { | ||
| const { durationInFrames, from, hidden, name, showInTimeline, stack, _experimentalControls, ...props } = propsWithControls; | ||
| const refForOutline = (0, react_1.useRef)(null); | ||
| const callbackRef = (0, react_1.useCallback)((element) => { | ||
| refForOutline.current = element; | ||
| setRef(ref, element); | ||
| }, [ref]); | ||
| return (jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, hidden: hidden, name: name !== null && name !== void 0 ? name : displayName, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, _experimentalControls: _experimentalControls, _remotionInternalStack: stack, _remotionInternalRefForOutline: refForOutline, children: react_1.default.createElement(tag, { | ||
| ...props, | ||
| ref: callbackRef, | ||
| }) })); | ||
| }); | ||
| Inner.displayName = displayName; | ||
| const Wrapped = (0, wrap_in_schema_js_1.wrapInSchema)({ | ||
| Component: Inner, | ||
| schema: interactiveElementSchema, | ||
| supportsEffects: false, | ||
| }); | ||
| Wrapped.displayName = displayName; | ||
| (0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(Wrapped); | ||
| return Wrapped; | ||
| }; | ||
| /** | ||
| * @description HTML and SVG elements that are registered in the Remotion Studio timeline and can be visually edited. | ||
| */ | ||
| exports.Interactive = { | ||
| A: makeInteractiveElement('a', '<Interactive.A>'), | ||
| Article: makeInteractiveElement('article', '<Interactive.Article>'), | ||
| Aside: makeInteractiveElement('aside', '<Interactive.Aside>'), | ||
| Button: makeInteractiveElement('button', '<Interactive.Button>'), | ||
| Circle: makeInteractiveElement('circle', '<Interactive.Circle>'), | ||
| Code: makeInteractiveElement('code', '<Interactive.Code>'), | ||
| Div: makeInteractiveElement('div', '<Interactive.Div>'), | ||
| Ellipse: makeInteractiveElement('ellipse', '<Interactive.Ellipse>'), | ||
| Em: makeInteractiveElement('em', '<Interactive.Em>'), | ||
| Footer: makeInteractiveElement('footer', '<Interactive.Footer>'), | ||
| G: makeInteractiveElement('g', '<Interactive.G>'), | ||
| H1: makeInteractiveElement('h1', '<Interactive.H1>'), | ||
| H2: makeInteractiveElement('h2', '<Interactive.H2>'), | ||
| H3: makeInteractiveElement('h3', '<Interactive.H3>'), | ||
| H4: makeInteractiveElement('h4', '<Interactive.H4>'), | ||
| H5: makeInteractiveElement('h5', '<Interactive.H5>'), | ||
| H6: makeInteractiveElement('h6', '<Interactive.H6>'), | ||
| Header: makeInteractiveElement('header', '<Interactive.Header>'), | ||
| Label: makeInteractiveElement('label', '<Interactive.Label>'), | ||
| Li: makeInteractiveElement('li', '<Interactive.Li>'), | ||
| Line: makeInteractiveElement('line', '<Interactive.Line>'), | ||
| Main: makeInteractiveElement('main', '<Interactive.Main>'), | ||
| Nav: makeInteractiveElement('nav', '<Interactive.Nav>'), | ||
| Ol: makeInteractiveElement('ol', '<Interactive.Ol>'), | ||
| P: makeInteractiveElement('p', '<Interactive.P>'), | ||
| Path: makeInteractiveElement('path', '<Interactive.Path>'), | ||
| Pre: makeInteractiveElement('pre', '<Interactive.Pre>'), | ||
| Rect: makeInteractiveElement('rect', '<Interactive.Rect>'), | ||
| Section: makeInteractiveElement('section', '<Interactive.Section>'), | ||
| Small: makeInteractiveElement('small', '<Interactive.Small>'), | ||
| Span: makeInteractiveElement('span', '<Interactive.Span>'), | ||
| Strong: makeInteractiveElement('strong', '<Interactive.Strong>'), | ||
| Svg: makeInteractiveElement('svg', '<Interactive.Svg>'), | ||
| Text: makeInteractiveElement('text', '<Interactive.Text>'), | ||
| Ul: makeInteractiveElement('ul', '<Interactive.Ul>'), | ||
| }; |
@@ -28,3 +28,3 @@ "use strict"; | ||
| default: 1, | ||
| description: 'Playback Rate', | ||
| description: 'Playback rate', | ||
| hiddenFromList: false, | ||
@@ -31,0 +31,0 @@ keyframable: false, |
@@ -5,2 +5,8 @@ import { type RefObject } from 'react'; | ||
| export declare const canvasImageSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -7,0 +13,0 @@ readonly type: "translate"; |
@@ -21,2 +21,8 @@ import React from 'react'; | ||
| export declare const imgSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -23,0 +29,0 @@ readonly type: "translate"; |
@@ -130,2 +130,3 @@ import './_check-rsc.js'; | ||
| export { Img, ImgProps } from './Img.js'; | ||
| export { Interactive, type InteractiveProps } from './Interactive.js'; | ||
| export * from './internals.js'; | ||
@@ -132,0 +133,0 @@ export { interpolateColors, type InterpolateColorsOptions, } from './interpolate-colors.js'; |
@@ -17,3 +17,3 @@ "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Config = exports.Experimental = exports.watchStaticFile = exports.MediaPlaybackError = exports.Video = exports.OffthreadVideo = exports.Html5Video = exports.useRemotionEnvironment = exports.usePixelDensity = exports.useDelayRender = exports.useCurrentScale = exports.useCurrentFrame = exports.useBufferState = exports.staticFile = exports.Series = exports.Sequence = exports.registerRoot = exports.prefetch = exports.random = exports.interpolate = exports.assertValidInterpolatePosterizeOption = exports.assertValidInterpolateEasingOption = exports.Loop = exports.interpolateColors = exports.Img = exports.getStaticFiles = exports.getRemotionEnvironment = exports.delayRender = exports.continueRender = exports.getInputProps = exports.Composition = exports.CanvasImage = exports.isHtmlInCanvasSupported = exports.HtmlInCanvas = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.Solid = exports.cancelRender = exports.Html5Audio = exports.Audio = exports.Artifact = void 0; | ||
| exports.Config = exports.Experimental = exports.watchStaticFile = exports.MediaPlaybackError = exports.Video = exports.OffthreadVideo = exports.Html5Video = exports.useRemotionEnvironment = exports.usePixelDensity = exports.useDelayRender = exports.useCurrentScale = exports.useCurrentFrame = exports.useBufferState = exports.staticFile = exports.Series = exports.Sequence = exports.registerRoot = exports.prefetch = exports.random = exports.interpolate = exports.assertValidInterpolatePosterizeOption = exports.assertValidInterpolateEasingOption = exports.Loop = exports.interpolateColors = exports.Interactive = exports.Img = exports.getStaticFiles = exports.getRemotionEnvironment = exports.delayRender = exports.continueRender = exports.getInputProps = exports.Composition = exports.CanvasImage = exports.isHtmlInCanvasSupported = exports.HtmlInCanvas = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.Solid = exports.cancelRender = exports.Html5Audio = exports.Audio = exports.Artifact = void 0; | ||
| require("./_check-rsc.js"); | ||
@@ -68,2 +68,4 @@ require("./asset-types.js"); | ||
| Object.defineProperty(exports, "Img", { enumerable: true, get: function () { return Img_js_1.Img; } }); | ||
| const Interactive_js_1 = require("./Interactive.js"); | ||
| Object.defineProperty(exports, "Interactive", { enumerable: true, get: function () { return Interactive_js_1.Interactive; } }); | ||
| __exportStar(require("./internals.js"), exports); | ||
@@ -70,0 +72,0 @@ const interpolate_colors_js_1 = require("./interpolate-colors.js"); |
@@ -108,2 +108,8 @@ import type { ScheduleAudioNodeResult } from './audio/shared-audio-tags.js'; | ||
| readonly 'absolute-fill': { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -165,2 +171,8 @@ readonly type: "translate"; | ||
| readonly sequenceStyleSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -217,2 +229,8 @@ readonly type: "translate"; | ||
| readonly sequenceVisualStyleSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -219,0 +237,0 @@ readonly type: "translate"; |
@@ -5,5 +5,4 @@ /** | ||
| */ | ||
| export type InterpolateColorsOptions = { | ||
| posterize: number | undefined; | ||
| }; | ||
| import { type InterpolateOptions } from './interpolate.js'; | ||
| export type InterpolateColorsOptions = Pick<InterpolateOptions, 'easing' | 'posterize'>; | ||
| export declare const colorNames: { | ||
@@ -10,0 +9,0 @@ [key: string]: number; |
@@ -542,2 +542,3 @@ "use strict"; | ||
| const unrounded = (0, interpolate_js_1.interpolate)(value, inputRange, colors.map((c) => f(c)), { | ||
| easing: options === null || options === void 0 ? void 0 : options.easing, | ||
| extrapolateLeft: 'clamp', | ||
@@ -544,0 +545,0 @@ extrapolateRight: 'clamp', |
@@ -31,2 +31,3 @@ "use strict"; | ||
| return (0, interpolate_colors_js_1.interpolateColors)(frame, inputRange, outputs, { | ||
| easing: easing.map(easingToFn), | ||
| posterize: status.posterize, | ||
@@ -33,0 +34,0 @@ }); |
+147
-0
@@ -45,2 +45,28 @@ "use strict"; | ||
| const cssNumberRegex = /^([+-]?(?:\d+\.?\d*|\.\d+))([a-zA-Z%]+)?$/; | ||
| const transformOriginKeywords = new Set([ | ||
| 'left', | ||
| 'center', | ||
| 'right', | ||
| 'top', | ||
| 'bottom', | ||
| ]); | ||
| const transformOriginKeywordOptions = (keyword) => { | ||
| if (keyword === 'left') { | ||
| return [{ axis: 'x', value: { value: 0, unit: '%' } }]; | ||
| } | ||
| if (keyword === 'right') { | ||
| return [{ axis: 'x', value: { value: 100, unit: '%' } }]; | ||
| } | ||
| if (keyword === 'top') { | ||
| return [{ axis: 'y', value: { value: 0, unit: '%' } }]; | ||
| } | ||
| if (keyword === 'bottom') { | ||
| return [{ axis: 'y', value: { value: 100, unit: '%' } }]; | ||
| } | ||
| return [ | ||
| { axis: 'x', value: { value: 50, unit: '%' } }, | ||
| { axis: 'y', value: { value: 50, unit: '%' } }, | ||
| ]; | ||
| }; | ||
| const transformOriginCenter = { value: 50, unit: '%' }; | ||
| const stringifyNumber = (value) => { | ||
@@ -71,2 +97,120 @@ return String((0, normalize_number_js_1.normalizeNumber)(value)); | ||
| }; | ||
| const parseTransformOriginLengthPercentage = ({ component, value, allowPercentage, }) => { | ||
| var _a; | ||
| const match = cssNumberRegex.exec(component); | ||
| if (match === null) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not a supported transform-origin ${allowPercentage ? 'length-percentage' : 'z length'}`); | ||
| } | ||
| const unit = (_a = match[2]) !== null && _a !== void 0 ? _a : null; | ||
| const numberValue = Number(match[1]); | ||
| if (!Number.isFinite(numberValue)) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not finite`); | ||
| } | ||
| if (unit === null || | ||
| !lengthUnits.has(unit) || | ||
| (!allowPercentage && unit === '%')) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not a supported transform-origin ${allowPercentage ? 'length-percentage' : 'z length'}`); | ||
| } | ||
| return { value: numberValue, unit }; | ||
| }; | ||
| const parseTransformOriginToken = (component, value) => { | ||
| const lower = component.toLowerCase(); | ||
| if (transformOriginKeywords.has(lower)) { | ||
| return { type: 'keyword', keyword: lower }; | ||
| } | ||
| return { | ||
| type: 'length-percentage', | ||
| parsed: parseTransformOriginLengthPercentage({ | ||
| component, | ||
| value, | ||
| allowPercentage: true, | ||
| }), | ||
| }; | ||
| }; | ||
| const parseTwoTransformOriginKeywords = (first, second, value) => { | ||
| const candidates = []; | ||
| for (const firstOption of transformOriginKeywordOptions(first)) { | ||
| for (const secondOption of transformOriginKeywordOptions(second)) { | ||
| if (firstOption.axis === secondOption.axis) { | ||
| continue; | ||
| } | ||
| candidates.push(firstOption.axis === 'x' | ||
| ? [firstOption.value, secondOption.value] | ||
| : [secondOption.value, firstOption.value]); | ||
| } | ||
| } | ||
| if (candidates.length === 0) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${first} ${second}" is not a valid transform-origin keyword pair`); | ||
| } | ||
| return candidates[0]; | ||
| }; | ||
| const parseTransformOriginXY = (parts, value) => { | ||
| if (parts.length === 1) { | ||
| const token = parseTransformOriginToken(parts[0], value); | ||
| if (token.type === 'length-percentage') { | ||
| return [token.parsed, transformOriginCenter]; | ||
| } | ||
| if (token.keyword === 'top' || token.keyword === 'bottom') { | ||
| return [ | ||
| transformOriginCenter, | ||
| transformOriginKeywordOptions(token.keyword)[0].value, | ||
| ]; | ||
| } | ||
| return [ | ||
| transformOriginKeywordOptions(token.keyword)[0].value, | ||
| transformOriginCenter, | ||
| ]; | ||
| } | ||
| const first = parseTransformOriginToken(parts[0], value); | ||
| const second = parseTransformOriginToken(parts[1], value); | ||
| if (first.type === 'length-percentage' && | ||
| second.type === 'length-percentage') { | ||
| return [first.parsed, second.parsed]; | ||
| } | ||
| if (first.type === 'keyword' && second.type === 'keyword') { | ||
| return parseTwoTransformOriginKeywords(first.keyword, second.keyword, value); | ||
| } | ||
| const keyword = first.type === 'keyword' | ||
| ? first | ||
| : second.type === 'keyword' | ||
| ? second | ||
| : null; | ||
| const length = first.type === 'length-percentage' | ||
| ? first.parsed | ||
| : second.type === 'length-percentage' | ||
| ? second.parsed | ||
| : null; | ||
| if (keyword === null || length === null) { | ||
| throw new Error('Expected a keyword and a length-percentage value'); | ||
| } | ||
| const keywordIsFirst = first.type === 'keyword'; | ||
| if (keyword.keyword === 'left' || keyword.keyword === 'right') { | ||
| if (!keywordIsFirst) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because horizontal transform-origin keywords must come before a length-percentage value`); | ||
| } | ||
| return [transformOriginKeywordOptions(keyword.keyword)[0].value, length]; | ||
| } | ||
| if (keyword.keyword === 'top' || keyword.keyword === 'bottom') { | ||
| return [length, transformOriginKeywordOptions(keyword.keyword)[0].value]; | ||
| } | ||
| return keywordIsFirst | ||
| ? [transformOriginCenter, length] | ||
| : [length, transformOriginCenter]; | ||
| }; | ||
| const parseTransformOriginValue = (output, parts) => { | ||
| const [x, y] = parseTransformOriginXY(parts.slice(0, 2), output); | ||
| const z = parts[2] === undefined | ||
| ? { value: 0, unit: null } | ||
| : parseTransformOriginLengthPercentage({ | ||
| component: parts[2], | ||
| value: output, | ||
| allowPercentage: false, | ||
| }); | ||
| return { | ||
| kind: 'translate', | ||
| values: [x.value, y.value, z.value], | ||
| units: [x.unit, y.unit, z.unit], | ||
| dimensions: parts[2] === undefined ? 2 : 3, | ||
| }; | ||
| }; | ||
| const parseStringInterpolationValue = (output) => { | ||
@@ -90,2 +234,5 @@ var _a, _b, _c, _d, _e, _f; | ||
| } | ||
| if (parts.some((part) => transformOriginKeywords.has(part.toLowerCase()))) { | ||
| return parseTransformOriginValue(output, parts); | ||
| } | ||
| const parsed = parts.map((part) => parseStringInterpolationComponent(part, output)); | ||
@@ -92,0 +239,0 @@ const [{ kind }] = parsed; |
@@ -85,2 +85,8 @@ export type { ArtifactAsset, AudioOrVideoAsset, InlineAudioAsset, TRenderAsset, } from './CompositionManager'; | ||
| readonly 'absolute-fill': { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -87,0 +93,0 @@ readonly type: "translate"; |
@@ -44,2 +44,9 @@ export type HiddenFieldSchema = { | ||
| }; | ||
| export type TransformOriginFieldSchema = { | ||
| type: 'transform-origin'; | ||
| step?: number; | ||
| default: string | undefined; | ||
| description?: string; | ||
| keyframable?: boolean; | ||
| }; | ||
| export type ScaleFieldSchema = { | ||
@@ -99,3 +106,3 @@ type: 'scale'; | ||
| }; | ||
| export type VisibleFieldSchema = NumberFieldSchema | BooleanFieldSchema | RotationCssFieldSchema | RotationDegreesFieldSchema | TranslateFieldSchema | ScaleFieldSchema | UvCoordinateFieldSchema | ColorFieldSchema | ArrayFieldSchema | EnumFieldSchema; | ||
| export type VisibleFieldSchema = NumberFieldSchema | BooleanFieldSchema | RotationCssFieldSchema | RotationDegreesFieldSchema | TranslateFieldSchema | TransformOriginFieldSchema | ScaleFieldSchema | UvCoordinateFieldSchema | ColorFieldSchema | ArrayFieldSchema | EnumFieldSchema; | ||
| export type SequenceFieldSchema = VisibleFieldSchema | HiddenFieldSchema; | ||
@@ -107,2 +114,8 @@ export type SequenceSchema = { | ||
| export declare const sequenceVisualStyleSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -161,2 +174,8 @@ readonly type: "translate"; | ||
| export declare const sequenceStyleSchema: { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -247,2 +266,8 @@ readonly type: "translate"; | ||
| readonly 'absolute-fill': { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -317,2 +342,8 @@ readonly type: "translate"; | ||
| readonly 'absolute-fill': { | ||
| readonly 'style.transformOrigin': { | ||
| readonly type: "transform-origin"; | ||
| readonly step: 1; | ||
| readonly default: "50% 50%"; | ||
| readonly description: "Transform origin"; | ||
| }; | ||
| readonly 'style.translate': { | ||
@@ -319,0 +350,0 @@ readonly type: "translate"; |
@@ -5,2 +5,8 @@ "use strict"; | ||
| exports.sequenceVisualStyleSchema = { | ||
| 'style.transformOrigin': { | ||
| type: 'transform-origin', | ||
| step: 1, | ||
| default: '50% 50%', | ||
| description: 'Transform origin', | ||
| }, | ||
| 'style.translate': { | ||
@@ -7,0 +13,0 @@ type: 'translate', |
@@ -6,2 +6,2 @@ /** | ||
| */ | ||
| export declare const VERSION = "4.0.474"; | ||
| export declare const VERSION = "4.0.475"; |
@@ -10,2 +10,2 @@ "use strict"; | ||
| */ | ||
| exports.VERSION = '4.0.474'; | ||
| exports.VERSION = '4.0.475'; |
+139
-0
@@ -45,2 +45,28 @@ // src/normalize-number.ts | ||
| var cssNumberRegex = /^([+-]?(?:\d+\.?\d*|\.\d+))([a-zA-Z%]+)?$/; | ||
| var transformOriginKeywords = new Set([ | ||
| "left", | ||
| "center", | ||
| "right", | ||
| "top", | ||
| "bottom" | ||
| ]); | ||
| var transformOriginKeywordOptions = (keyword) => { | ||
| if (keyword === "left") { | ||
| return [{ axis: "x", value: { value: 0, unit: "%" } }]; | ||
| } | ||
| if (keyword === "right") { | ||
| return [{ axis: "x", value: { value: 100, unit: "%" } }]; | ||
| } | ||
| if (keyword === "top") { | ||
| return [{ axis: "y", value: { value: 0, unit: "%" } }]; | ||
| } | ||
| if (keyword === "bottom") { | ||
| return [{ axis: "y", value: { value: 100, unit: "%" } }]; | ||
| } | ||
| return [ | ||
| { axis: "x", value: { value: 50, unit: "%" } }, | ||
| { axis: "y", value: { value: 50, unit: "%" } } | ||
| ]; | ||
| }; | ||
| var transformOriginCenter = { value: 50, unit: "%" }; | ||
| var stringifyNumber = (value) => { | ||
@@ -70,2 +96,106 @@ return String(normalizeNumber(value)); | ||
| }; | ||
| var parseTransformOriginLengthPercentage = ({ | ||
| component, | ||
| value, | ||
| allowPercentage | ||
| }) => { | ||
| const match = cssNumberRegex.exec(component); | ||
| if (match === null) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not a supported transform-origin ${allowPercentage ? "length-percentage" : "z length"}`); | ||
| } | ||
| const unit = match[2] ?? null; | ||
| const numberValue = Number(match[1]); | ||
| if (!Number.isFinite(numberValue)) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not finite`); | ||
| } | ||
| if (unit === null || !lengthUnits.has(unit) || !allowPercentage && unit === "%") { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${component}" is not a supported transform-origin ${allowPercentage ? "length-percentage" : "z length"}`); | ||
| } | ||
| return { value: numberValue, unit }; | ||
| }; | ||
| var parseTransformOriginToken = (component, value) => { | ||
| const lower = component.toLowerCase(); | ||
| if (transformOriginKeywords.has(lower)) { | ||
| return { type: "keyword", keyword: lower }; | ||
| } | ||
| return { | ||
| type: "length-percentage", | ||
| parsed: parseTransformOriginLengthPercentage({ | ||
| component, | ||
| value, | ||
| allowPercentage: true | ||
| }) | ||
| }; | ||
| }; | ||
| var parseTwoTransformOriginKeywords = (first, second, value) => { | ||
| const candidates = []; | ||
| for (const firstOption of transformOriginKeywordOptions(first)) { | ||
| for (const secondOption of transformOriginKeywordOptions(second)) { | ||
| if (firstOption.axis === secondOption.axis) { | ||
| continue; | ||
| } | ||
| candidates.push(firstOption.axis === "x" ? [firstOption.value, secondOption.value] : [secondOption.value, firstOption.value]); | ||
| } | ||
| } | ||
| if (candidates.length === 0) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because "${first} ${second}" is not a valid transform-origin keyword pair`); | ||
| } | ||
| return candidates[0]; | ||
| }; | ||
| var parseTransformOriginXY = (parts, value) => { | ||
| if (parts.length === 1) { | ||
| const token = parseTransformOriginToken(parts[0], value); | ||
| if (token.type === "length-percentage") { | ||
| return [token.parsed, transformOriginCenter]; | ||
| } | ||
| if (token.keyword === "top" || token.keyword === "bottom") { | ||
| return [ | ||
| transformOriginCenter, | ||
| transformOriginKeywordOptions(token.keyword)[0].value | ||
| ]; | ||
| } | ||
| return [ | ||
| transformOriginKeywordOptions(token.keyword)[0].value, | ||
| transformOriginCenter | ||
| ]; | ||
| } | ||
| const first = parseTransformOriginToken(parts[0], value); | ||
| const second = parseTransformOriginToken(parts[1], value); | ||
| if (first.type === "length-percentage" && second.type === "length-percentage") { | ||
| return [first.parsed, second.parsed]; | ||
| } | ||
| if (first.type === "keyword" && second.type === "keyword") { | ||
| return parseTwoTransformOriginKeywords(first.keyword, second.keyword, value); | ||
| } | ||
| const keyword = first.type === "keyword" ? first : second.type === "keyword" ? second : null; | ||
| const length = first.type === "length-percentage" ? first.parsed : second.type === "length-percentage" ? second.parsed : null; | ||
| if (keyword === null || length === null) { | ||
| throw new Error("Expected a keyword and a length-percentage value"); | ||
| } | ||
| const keywordIsFirst = first.type === "keyword"; | ||
| if (keyword.keyword === "left" || keyword.keyword === "right") { | ||
| if (!keywordIsFirst) { | ||
| throw new TypeError(`Cannot interpolate "${value}" because horizontal transform-origin keywords must come before a length-percentage value`); | ||
| } | ||
| return [transformOriginKeywordOptions(keyword.keyword)[0].value, length]; | ||
| } | ||
| if (keyword.keyword === "top" || keyword.keyword === "bottom") { | ||
| return [length, transformOriginKeywordOptions(keyword.keyword)[0].value]; | ||
| } | ||
| return keywordIsFirst ? [transformOriginCenter, length] : [length, transformOriginCenter]; | ||
| }; | ||
| var parseTransformOriginValue = (output, parts) => { | ||
| const [x, y] = parseTransformOriginXY(parts.slice(0, 2), output); | ||
| const z = parts[2] === undefined ? { value: 0, unit: null } : parseTransformOriginLengthPercentage({ | ||
| component: parts[2], | ||
| value: output, | ||
| allowPercentage: false | ||
| }); | ||
| return { | ||
| kind: "translate", | ||
| values: [x.value, y.value, z.value], | ||
| units: [x.unit, y.unit, z.unit], | ||
| dimensions: parts[2] === undefined ? 2 : 3 | ||
| }; | ||
| }; | ||
| var parseStringInterpolationValue = (output) => { | ||
@@ -87,2 +217,5 @@ if (typeof output === "number") { | ||
| } | ||
| if (parts.some((part) => transformOriginKeywords.has(part.toLowerCase()))) { | ||
| return parseTransformOriginValue(output, parts); | ||
| } | ||
| const parsed = parts.map((part) => parseStringInterpolationComponent(part, output)); | ||
@@ -1013,2 +1146,8 @@ const [{ kind }] = parsed; | ||
| var sequenceVisualStyleSchema = { | ||
| "style.transformOrigin": { | ||
| type: "transform-origin", | ||
| step: 1, | ||
| default: "50% 50%", | ||
| description: "Transform origin" | ||
| }, | ||
| "style.translate": { | ||
@@ -1015,0 +1154,0 @@ type: "translate", |
| // src/version.ts | ||
| var VERSION = "4.0.474"; | ||
| var VERSION = "4.0.475"; | ||
| export { | ||
| VERSION | ||
| }; |
+2
-2
@@ -6,3 +6,3 @@ { | ||
| "name": "remotion", | ||
| "version": "4.0.474", | ||
| "version": "4.0.475", | ||
| "description": "Make videos programmatically", | ||
@@ -39,3 +39,3 @@ "main": "dist/cjs/index.js", | ||
| "zod": "4.3.6", | ||
| "@remotion/eslint-config-internal": "4.0.474", | ||
| "@remotion/eslint-config-internal": "4.0.475", | ||
| "eslint": "9.19.0", | ||
@@ -42,0 +42,0 @@ "@typescript/native-preview": "7.0.0-dev.20260217.1" |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1206177
2.77%379
0.53%30900
2.58%