@remotion/shapes 4.0.476 → 4.0.477

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 CHANGED
@@ -1,5 +1,6 @@
1
1
  export type { Instruction } from '@remotion/paths';
2
2
  export { Arrow, ArrowProps } from './components/arrow';
3
+ export { Callout, CalloutProps } from './components/callout';
3
4
  export { Circle, CircleProps } from './components/circle';
4
5
  export { Ellipse, EllipseProps } from './components/ellipse';
5
6
  export { Heart, HeartProps } from './components/heart';
@@ -9,6 +10,7 @@ export { Rect, RectProps } from './components/rect';
9
10
  export { Star, StarProps } from './components/star';
10
11
  export { Triangle, TriangleProps } from './components/triangle';
11
12
  export { MakeArrowProps, makeArrow } from './utils/make-arrow';
13
+ export { MakeCalloutProps, makeCallout } from './utils/make-callout';
12
14
  export { MakeCircleProps, makeCircle } from './utils/make-circle';
13
15
  export { MakeEllipseOptions, makeEllipse } from './utils/make-ellipse';
14
16
  export { MakeHeartProps, makeHeart } from './utils/make-heart';
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeTriangle = exports.makeStar = exports.makeRect = exports.makePolygon = exports.makePie = exports.makeHeart = exports.makeEllipse = exports.makeCircle = exports.makeArrow = exports.Triangle = exports.Star = exports.Rect = exports.Polygon = exports.Pie = exports.Heart = exports.Ellipse = exports.Circle = exports.Arrow = void 0;
3
+ exports.makeTriangle = exports.makeStar = exports.makeRect = exports.makePolygon = exports.makePie = exports.makeHeart = exports.makeEllipse = exports.makeCircle = exports.makeCallout = exports.makeArrow = exports.Triangle = exports.Star = exports.Rect = exports.Polygon = exports.Pie = exports.Heart = exports.Ellipse = exports.Circle = exports.Callout = exports.Arrow = void 0;
4
4
  const arrow_1 = require("./components/arrow");
5
5
  Object.defineProperty(exports, "Arrow", { enumerable: true, get: function () { return arrow_1.Arrow; } });
6
+ const callout_1 = require("./components/callout");
7
+ Object.defineProperty(exports, "Callout", { enumerable: true, get: function () { return callout_1.Callout; } });
6
8
  const circle_1 = require("./components/circle");
7
9
  Object.defineProperty(exports, "Circle", { enumerable: true, get: function () { return circle_1.Circle; } });
8
10
  const ellipse_1 = require("./components/ellipse");
@@ -21,6 +23,8 @@ const triangle_1 = require("./components/triangle");
21
23
  Object.defineProperty(exports, "Triangle", { enumerable: true, get: function () { return triangle_1.Triangle; } });
22
24
  const make_arrow_1 = require("./utils/make-arrow");
23
25
  Object.defineProperty(exports, "makeArrow", { enumerable: true, get: function () { return make_arrow_1.makeArrow; } });
26
+ const make_callout_1 = require("./utils/make-callout");
27
+ Object.defineProperty(exports, "makeCallout", { enumerable: true, get: function () { return make_callout_1.makeCallout; } });
24
28
  const make_circle_1 = require("./utils/make-circle");
25
29
  Object.defineProperty(exports, "makeCircle", { enumerable: true, get: function () { return make_circle_1.makeCircle; } });
26
30
  const make_ellipse_1 = require("./utils/make-ellipse");
@@ -0,0 +1,26 @@
1
+ import type { ShapeInfo } from './shape-info';
2
+ type PointerDirection = 'up' | 'down' | 'left' | 'right';
3
+ export type MakeCalloutProps = {
4
+ width?: number;
5
+ height?: number;
6
+ pointerLength?: number;
7
+ pointerBaseWidth?: number;
8
+ pointerPosition?: number;
9
+ pointerDirection?: PointerDirection;
10
+ edgeRoundness?: number | null;
11
+ cornerRadius?: number;
12
+ };
13
+ /**
14
+ * @description Generates an SVG path for a callout shape.
15
+ * @param {Number} width The width of the callout body. Default 500.
16
+ * @param {Number} height The height of the callout body. Default 200.
17
+ * @param {Number} pointerLength The length of the pointer. Default 40.
18
+ * @param {Number} pointerBaseWidth The width of the pointer where it meets the body. Default 60.
19
+ * @param {Number} pointerPosition Position of the pointer along its side, from 0 to 1. Default 0.5.
20
+ * @param {string} pointerDirection The direction the pointer points. Default 'down'.
21
+ * @param {null|Number} edgeRoundness Allows to modify the shape by rounding the edges using bezier curves. Default null.
22
+ * @param {Number} cornerRadius Rounds the corner using an arc. Similar to CSS's border-radius. Cannot be used together with edgeRoundness.
23
+ * @see [Documentation](https://www.remotion.dev/docs/shapes/make-callout)
24
+ */
25
+ export declare const makeCallout: ({ width, height, pointerLength, pointerBaseWidth, pointerPosition, pointerDirection, edgeRoundness, cornerRadius, }: MakeCalloutProps) => ShapeInfo;
26
+ export {};
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeCallout = void 0;
4
+ const paths_1 = require("@remotion/paths");
5
+ const join_points_1 = require("./join-points");
6
+ const ensurePositive = (name, value) => {
7
+ if (typeof value !== 'number' || value <= 0) {
8
+ throw new Error(`"${name}" must be a positive number, got ${value}`);
9
+ }
10
+ };
11
+ const pointerInterval = ({ availableLength, pointerBaseWidth, pointerPosition, }) => {
12
+ const center = availableLength * pointerPosition;
13
+ const half = pointerBaseWidth / 2;
14
+ return {
15
+ center,
16
+ start: Math.max(0, center - half),
17
+ end: Math.min(availableLength, center + half),
18
+ };
19
+ };
20
+ const areSamePoint = (a, b) => {
21
+ return a[0] === b[0] && a[1] === b[1];
22
+ };
23
+ const normalizeClosedPoints = (points) => {
24
+ const deduplicated = points.reduce((acc, entry) => {
25
+ const previous = acc[acc.length - 1];
26
+ if (previous && areSamePoint(previous.point, entry.point)) {
27
+ acc[acc.length - 1] = {
28
+ point: previous.point,
29
+ round: previous.round && entry.round,
30
+ };
31
+ return acc;
32
+ }
33
+ return [...acc, entry];
34
+ }, []);
35
+ if (deduplicated.length === 0) {
36
+ return deduplicated;
37
+ }
38
+ const first = deduplicated[0];
39
+ const last = deduplicated[deduplicated.length - 1];
40
+ if (areSamePoint(first.point, last.point)) {
41
+ const [firstEntry, ...rest] = deduplicated;
42
+ const withoutLast = rest.slice(0, -1);
43
+ const mergedFirst = {
44
+ point: firstEntry.point,
45
+ round: firstEntry.round && last.round,
46
+ };
47
+ return [mergedFirst, ...withoutLast, mergedFirst];
48
+ }
49
+ return [...deduplicated, first];
50
+ };
51
+ const unitDir = (from, to) => {
52
+ const dx = to[0] - from[0];
53
+ const dy = to[1] - from[1];
54
+ const len = Math.sqrt(dx * dx + dy * dy);
55
+ if (len === 0) {
56
+ return [0, 0];
57
+ }
58
+ return [dx / len, dy / len];
59
+ };
60
+ const makeInstructions = ({ points, edgeRoundness, cornerRadius, }) => {
61
+ const rawPoints = points.map((p) => p.point);
62
+ if (edgeRoundness !== null || cornerRadius === 0) {
63
+ return [
64
+ ...(0, join_points_1.joinPoints)(rawPoints, {
65
+ edgeRoundness,
66
+ cornerRadius,
67
+ roundCornerStrategy: 'arc',
68
+ }),
69
+ {
70
+ type: 'Z',
71
+ },
72
+ ];
73
+ }
74
+ const uniquePoints = areSamePoint(points[0].point, points[points.length - 1].point)
75
+ ? points.slice(0, -1)
76
+ : points;
77
+ const firstPoint = uniquePoints[0];
78
+ const startDir = firstPoint.round
79
+ ? unitDir(uniquePoints[0].point, uniquePoints[1].point)
80
+ : null;
81
+ const startPoint = startDir
82
+ ? [
83
+ firstPoint.point[0] + startDir[0] * cornerRadius,
84
+ firstPoint.point[1] + startDir[1] * cornerRadius,
85
+ ]
86
+ : firstPoint.point;
87
+ const instructions = [
88
+ { type: 'M', x: startPoint[0], y: startPoint[1] },
89
+ ];
90
+ for (let i = 1; i < uniquePoints.length; i++) {
91
+ const current = uniquePoints[i];
92
+ if (!current.round) {
93
+ instructions.push({
94
+ type: 'L',
95
+ x: current.point[0],
96
+ y: current.point[1],
97
+ });
98
+ continue;
99
+ }
100
+ const previous = uniquePoints[i - 1].point;
101
+ const next = uniquePoints[(i + 1) % uniquePoints.length].point;
102
+ const incoming = unitDir(previous, current.point);
103
+ const outgoing = unitDir(current.point, next);
104
+ const arcStart = [
105
+ current.point[0] - incoming[0] * cornerRadius,
106
+ current.point[1] - incoming[1] * cornerRadius,
107
+ ];
108
+ instructions.push({
109
+ type: 'L',
110
+ x: arcStart[0],
111
+ y: arcStart[1],
112
+ }, {
113
+ type: 'a',
114
+ rx: cornerRadius,
115
+ ry: cornerRadius,
116
+ xAxisRotation: 0,
117
+ dx: incoming[0] * cornerRadius + outgoing[0] * cornerRadius,
118
+ dy: incoming[1] * cornerRadius + outgoing[1] * cornerRadius,
119
+ largeArcFlag: false,
120
+ sweepFlag: true,
121
+ });
122
+ }
123
+ if (firstPoint.round) {
124
+ const previous = uniquePoints[uniquePoints.length - 1].point;
125
+ const incoming = unitDir(previous, firstPoint.point);
126
+ instructions.push({
127
+ type: 'L',
128
+ x: firstPoint.point[0] - incoming[0] * cornerRadius,
129
+ y: firstPoint.point[1] - incoming[1] * cornerRadius,
130
+ }, {
131
+ type: 'a',
132
+ rx: cornerRadius,
133
+ ry: cornerRadius,
134
+ xAxisRotation: 0,
135
+ dx: incoming[0] * cornerRadius + startDir[0] * cornerRadius,
136
+ dy: incoming[1] * cornerRadius + startDir[1] * cornerRadius,
137
+ largeArcFlag: false,
138
+ sweepFlag: true,
139
+ });
140
+ }
141
+ instructions.push({ type: 'Z' });
142
+ return instructions;
143
+ };
144
+ /**
145
+ * @description Generates an SVG path for a callout shape.
146
+ * @param {Number} width The width of the callout body. Default 500.
147
+ * @param {Number} height The height of the callout body. Default 200.
148
+ * @param {Number} pointerLength The length of the pointer. Default 40.
149
+ * @param {Number} pointerBaseWidth The width of the pointer where it meets the body. Default 60.
150
+ * @param {Number} pointerPosition Position of the pointer along its side, from 0 to 1. Default 0.5.
151
+ * @param {string} pointerDirection The direction the pointer points. Default 'down'.
152
+ * @param {null|Number} edgeRoundness Allows to modify the shape by rounding the edges using bezier curves. Default null.
153
+ * @param {Number} cornerRadius Rounds the corner using an arc. Similar to CSS's border-radius. Cannot be used together with edgeRoundness.
154
+ * @see [Documentation](https://www.remotion.dev/docs/shapes/make-callout)
155
+ */
156
+ const makeCallout = ({ width = 500, height = 200, pointerLength = 40, pointerBaseWidth = 60, pointerPosition = 0.5, pointerDirection = 'down', edgeRoundness = null, cornerRadius = 0, }) => {
157
+ ensurePositive('width', width);
158
+ ensurePositive('height', height);
159
+ ensurePositive('pointerLength', pointerLength);
160
+ ensurePositive('pointerBaseWidth', pointerBaseWidth);
161
+ if (typeof pointerPosition !== 'number' ||
162
+ pointerPosition < 0 ||
163
+ pointerPosition > 1) {
164
+ throw new Error(`"pointerPosition" must be a number between 0 and 1, got ${pointerPosition}`);
165
+ }
166
+ const horizontalInterval = pointerInterval({
167
+ availableLength: width,
168
+ pointerBaseWidth,
169
+ pointerPosition,
170
+ });
171
+ const verticalInterval = pointerInterval({
172
+ availableLength: height,
173
+ pointerBaseWidth,
174
+ pointerPosition,
175
+ });
176
+ const pointsByDirection = {
177
+ up: [
178
+ { point: [0, pointerLength], round: true },
179
+ { point: [horizontalInterval.start, pointerLength], round: false },
180
+ { point: [horizontalInterval.center, 0], round: false },
181
+ { point: [horizontalInterval.end, pointerLength], round: false },
182
+ { point: [width, pointerLength], round: true },
183
+ { point: [width, height + pointerLength], round: true },
184
+ { point: [0, height + pointerLength], round: true },
185
+ { point: [0, pointerLength], round: true },
186
+ ],
187
+ down: [
188
+ { point: [0, 0], round: true },
189
+ { point: [width, 0], round: true },
190
+ { point: [width, height], round: true },
191
+ { point: [horizontalInterval.end, height], round: false },
192
+ {
193
+ point: [horizontalInterval.center, height + pointerLength],
194
+ round: false,
195
+ },
196
+ { point: [horizontalInterval.start, height], round: false },
197
+ { point: [0, height], round: true },
198
+ { point: [0, 0], round: true },
199
+ ],
200
+ left: [
201
+ { point: [pointerLength, 0], round: true },
202
+ { point: [width + pointerLength, 0], round: true },
203
+ { point: [width + pointerLength, height], round: true },
204
+ { point: [pointerLength, height], round: true },
205
+ { point: [pointerLength, verticalInterval.end], round: false },
206
+ { point: [0, verticalInterval.center], round: false },
207
+ { point: [pointerLength, verticalInterval.start], round: false },
208
+ { point: [pointerLength, 0], round: true },
209
+ ],
210
+ right: [
211
+ { point: [0, 0], round: true },
212
+ { point: [width, 0], round: true },
213
+ { point: [width, verticalInterval.start], round: false },
214
+ { point: [width + pointerLength, verticalInterval.center], round: false },
215
+ { point: [width, verticalInterval.end], round: false },
216
+ { point: [width, height], round: true },
217
+ { point: [0, height], round: true },
218
+ { point: [0, 0], round: true },
219
+ ],
220
+ };
221
+ const points = normalizeClosedPoints(pointsByDirection[pointerDirection]);
222
+ const instructions = makeInstructions({ points, edgeRoundness, cornerRadius });
223
+ const path = (0, paths_1.serializeInstructions)(instructions);
224
+ const shapeWidth = pointerDirection === 'left' || pointerDirection === 'right'
225
+ ? width + pointerLength
226
+ : width;
227
+ const shapeHeight = pointerDirection === 'up' || pointerDirection === 'down'
228
+ ? height + pointerLength
229
+ : height;
230
+ const bodyX = pointerDirection === 'left' ? pointerLength : 0;
231
+ const bodyY = pointerDirection === 'up' ? pointerLength : 0;
232
+ return {
233
+ width: shapeWidth,
234
+ height: shapeHeight,
235
+ instructions,
236
+ path,
237
+ transformOrigin: `${bodyX + width / 2} ${bodyY + height / 2}`,
238
+ };
239
+ };
240
+ exports.makeCallout = makeCallout;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/shapes"
4
4
  },
5
5
  "name": "@remotion/shapes",
6
- "version": "4.0.476",
6
+ "version": "4.0.477",
7
7
  "description": "Generate SVG shapes",
8
8
  "main": "dist/index.js",
9
9
  "scripts": {
@@ -34,7 +34,7 @@
34
34
  "react": "19.2.3",
35
35
  "react-dom": "19.2.3",
36
36
  "@happy-dom/global-registrator": "14.5.1",
37
- "@remotion/eslint-config-internal": "4.0.476",
37
+ "@remotion/eslint-config-internal": "4.0.477",
38
38
  "eslint": "9.19.0",
39
39
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
40
40
  },
@@ -51,8 +51,8 @@
51
51
  "react-dom": ">=16.8.0"
52
52
  },
53
53
  "dependencies": {
54
- "@remotion/paths": "4.0.476",
55
- "remotion": "4.0.476"
54
+ "@remotion/paths": "4.0.477",
55
+ "remotion": "4.0.477"
56
56
  },
57
57
  "homepage": "https://www.remotion.dev/docs/shapes"
58
58
  }