@twick/2d 0.14.0 → 1.14.3
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/LICENSE +21 -21
- package/editor/editor/tsconfig.build.tsbuildinfo +1 -1
- package/lib/components/Audio.d.ts.map +1 -1
- package/lib/components/Audio.js +33 -3
- package/lib/components/CodeBlock.d.ts +1 -1
- package/lib/components/Img.js +23 -23
- package/lib/components/Line.js +31 -31
- package/lib/components/Media.d.ts +6 -0
- package/lib/components/Media.d.ts.map +1 -1
- package/lib/components/Media.js +277 -61
- package/lib/components/Node.d.ts +1 -1
- package/lib/components/Path.d.ts +1 -1
- package/lib/components/SVG.d.ts +1 -1
- package/lib/components/Shape.d.ts +1 -1
- package/lib/components/Spline.js +25 -25
- package/lib/components/Video.d.ts +0 -1
- package/lib/components/Video.d.ts.map +1 -1
- package/lib/components/Video.js +70 -65
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -5
- package/src/editor/NodeInspectorConfig.tsx +76 -76
- package/src/editor/PreviewOverlayConfig.tsx +67 -67
- package/src/editor/Provider.tsx +93 -93
- package/src/editor/SceneGraphTabConfig.tsx +81 -81
- package/src/editor/icons/CircleIcon.tsx +7 -7
- package/src/editor/icons/CodeBlockIcon.tsx +8 -8
- package/src/editor/icons/CurveIcon.tsx +7 -7
- package/src/editor/icons/GridIcon.tsx +7 -7
- package/src/editor/icons/IconMap.ts +35 -35
- package/src/editor/icons/ImgIcon.tsx +8 -8
- package/src/editor/icons/LayoutIcon.tsx +9 -9
- package/src/editor/icons/LineIcon.tsx +7 -7
- package/src/editor/icons/NodeIcon.tsx +7 -7
- package/src/editor/icons/RayIcon.tsx +7 -7
- package/src/editor/icons/RectIcon.tsx +7 -7
- package/src/editor/icons/ShapeIcon.tsx +7 -7
- package/src/editor/icons/TxtIcon.tsx +8 -8
- package/src/editor/icons/VideoIcon.tsx +7 -7
- package/src/editor/icons/View2DIcon.tsx +10 -10
- package/src/editor/index.ts +17 -17
- package/src/editor/tree/DetachedRoot.tsx +23 -23
- package/src/editor/tree/NodeElement.tsx +74 -74
- package/src/editor/tree/TreeElement.tsx +72 -72
- package/src/editor/tree/TreeRoot.tsx +10 -10
- package/src/editor/tree/ViewRoot.tsx +20 -20
- package/src/editor/tree/index.module.scss +38 -38
- package/src/editor/tree/index.ts +3 -3
- package/src/editor/tsconfig.build.json +5 -5
- package/src/editor/tsconfig.json +12 -12
- package/src/editor/tsdoc.json +4 -4
- package/src/editor/vite-env.d.ts +1 -1
- package/src/lib/code/CodeCursor.ts +445 -445
- package/src/lib/code/CodeDiffer.ts +78 -78
- package/src/lib/code/CodeFragment.ts +97 -97
- package/src/lib/code/CodeHighlighter.ts +75 -75
- package/src/lib/code/CodeMetrics.ts +47 -47
- package/src/lib/code/CodeRange.test.ts +74 -74
- package/src/lib/code/CodeRange.ts +216 -216
- package/src/lib/code/CodeScope.ts +101 -101
- package/src/lib/code/CodeSelection.ts +24 -24
- package/src/lib/code/CodeSignal.ts +327 -327
- package/src/lib/code/CodeTokenizer.ts +54 -54
- package/src/lib/code/DefaultHighlightStyle.ts +98 -98
- package/src/lib/code/LezerHighlighter.ts +113 -113
- package/src/lib/code/diff.test.ts +311 -311
- package/src/lib/code/diff.ts +319 -319
- package/src/lib/code/extractRange.ts +126 -126
- package/src/lib/code/index.ts +13 -13
- package/src/lib/components/Audio.ts +168 -131
- package/src/lib/components/Bezier.ts +105 -105
- package/src/lib/components/Circle.ts +266 -266
- package/src/lib/components/Code.ts +526 -526
- package/src/lib/components/CodeBlock.ts +576 -576
- package/src/lib/components/CubicBezier.ts +112 -112
- package/src/lib/components/Curve.ts +455 -455
- package/src/lib/components/Grid.ts +135 -135
- package/src/lib/components/Icon.ts +96 -96
- package/src/lib/components/Img.ts +319 -319
- package/src/lib/components/Knot.ts +157 -157
- package/src/lib/components/Latex.ts +122 -122
- package/src/lib/components/Layout.ts +1092 -1092
- package/src/lib/components/Line.ts +429 -429
- package/src/lib/components/Media.ts +576 -346
- package/src/lib/components/Node.ts +1940 -1940
- package/src/lib/components/Path.ts +137 -137
- package/src/lib/components/Polygon.ts +171 -171
- package/src/lib/components/QuadBezier.ts +100 -100
- package/src/lib/components/Ray.ts +125 -125
- package/src/lib/components/Rect.ts +187 -187
- package/src/lib/components/Rive.ts +156 -156
- package/src/lib/components/SVG.ts +797 -797
- package/src/lib/components/Shape.ts +143 -143
- package/src/lib/components/Spline.ts +344 -344
- package/src/lib/components/Txt.test.tsx +81 -81
- package/src/lib/components/Txt.ts +203 -203
- package/src/lib/components/TxtLeaf.ts +205 -205
- package/src/lib/components/Video.ts +461 -462
- package/src/lib/components/View2D.ts +98 -98
- package/src/lib/components/__tests__/children.test.tsx +142 -142
- package/src/lib/components/__tests__/clone.test.tsx +126 -126
- package/src/lib/components/__tests__/generatorTest.ts +28 -28
- package/src/lib/components/__tests__/mockScene2D.ts +45 -45
- package/src/lib/components/__tests__/query.test.tsx +122 -122
- package/src/lib/components/__tests__/state.test.tsx +60 -60
- package/src/lib/components/index.ts +28 -28
- package/src/lib/components/types.ts +35 -35
- package/src/lib/curves/ArcSegment.ts +159 -159
- package/src/lib/curves/CircleSegment.ts +77 -77
- package/src/lib/curves/CubicBezierSegment.ts +78 -78
- package/src/lib/curves/CurveDrawingInfo.ts +11 -11
- package/src/lib/curves/CurvePoint.ts +15 -15
- package/src/lib/curves/CurveProfile.ts +7 -7
- package/src/lib/curves/KnotInfo.ts +10 -10
- package/src/lib/curves/LineSegment.ts +62 -62
- package/src/lib/curves/Polynomial.ts +355 -355
- package/src/lib/curves/Polynomial2D.ts +62 -62
- package/src/lib/curves/PolynomialSegment.ts +124 -124
- package/src/lib/curves/QuadBezierSegment.ts +64 -64
- package/src/lib/curves/Segment.ts +17 -17
- package/src/lib/curves/UniformPolynomialCurveSampler.ts +94 -94
- package/src/lib/curves/createCurveProfileLerp.ts +471 -471
- package/src/lib/curves/getBezierSplineProfile.ts +223 -223
- package/src/lib/curves/getCircleProfile.ts +86 -86
- package/src/lib/curves/getPathProfile.ts +178 -178
- package/src/lib/curves/getPointAtDistance.ts +21 -21
- package/src/lib/curves/getPolylineProfile.test.ts +21 -21
- package/src/lib/curves/getPolylineProfile.ts +89 -89
- package/src/lib/curves/getRectProfile.ts +139 -139
- package/src/lib/curves/index.ts +16 -16
- package/src/lib/decorators/canvasStyleSignal.ts +16 -16
- package/src/lib/decorators/colorSignal.ts +9 -9
- package/src/lib/decorators/compound.ts +72 -72
- package/src/lib/decorators/computed.ts +18 -18
- package/src/lib/decorators/defaultStyle.ts +18 -18
- package/src/lib/decorators/filtersSignal.ts +136 -136
- package/src/lib/decorators/index.ts +10 -10
- package/src/lib/decorators/initializers.ts +32 -32
- package/src/lib/decorators/nodeName.ts +13 -13
- package/src/lib/decorators/signal.test.ts +90 -90
- package/src/lib/decorators/signal.ts +345 -345
- package/src/lib/decorators/spacingSignal.ts +15 -15
- package/src/lib/decorators/vector2Signal.ts +30 -30
- package/src/lib/globals.d.ts +2 -2
- package/src/lib/index.ts +8 -8
- package/src/lib/jsx-dev-runtime.ts +2 -2
- package/src/lib/jsx-runtime.ts +46 -46
- package/src/lib/parse-svg-path.d.ts +14 -14
- package/src/lib/partials/Filter.ts +180 -180
- package/src/lib/partials/Gradient.ts +102 -102
- package/src/lib/partials/Pattern.ts +34 -34
- package/src/lib/partials/ShaderConfig.ts +117 -117
- package/src/lib/partials/index.ts +4 -4
- package/src/lib/partials/types.ts +58 -58
- package/src/lib/scenes/Scene2D.ts +242 -242
- package/src/lib/scenes/index.ts +3 -3
- package/src/lib/scenes/makeScene2D.ts +16 -16
- package/src/lib/scenes/useScene2D.ts +6 -6
- package/src/lib/tsconfig.build.json +5 -5
- package/src/lib/tsconfig.json +10 -10
- package/src/lib/tsdoc.json +4 -4
- package/src/lib/utils/CanvasUtils.ts +306 -306
- package/src/lib/utils/diff.test.ts +453 -453
- package/src/lib/utils/diff.ts +148 -148
- package/src/lib/utils/index.ts +2 -2
- package/src/lib/utils/is.ts +11 -11
- package/src/lib/utils/makeSignalExtensions.ts +30 -30
- package/src/lib/utils/video/declarations.d.ts +1 -1
- package/src/lib/utils/video/ffmpeg-client.ts +50 -50
- package/src/lib/utils/video/mp4-parser-manager.ts +72 -72
- package/src/lib/utils/video/parser/index.ts +1 -1
- package/src/lib/utils/video/parser/parser.ts +257 -257
- package/src/lib/utils/video/parser/sampler.ts +72 -72
- package/src/lib/utils/video/parser/segment.ts +302 -302
- package/src/lib/utils/video/parser/sink.ts +29 -29
- package/src/lib/utils/video/parser/utils.ts +31 -31
- package/src/tsconfig.base.json +19 -19
- package/src/tsconfig.build.json +8 -8
- package/src/tsconfig.json +5 -5
- package/tsconfig.project.json +7 -7
- package/lib/components/utils/waitUntil.d.ts +0 -7
- package/lib/components/utils/waitUntil.d.ts.map +0 -1
- package/lib/components/utils/waitUntil.js +0 -15
- package/lib/utils/waitUntil.d.ts +0 -7
- package/lib/utils/waitUntil.d.ts.map +0 -1
- package/lib/utils/waitUntil.js +0 -15
- package/src/lib/utils/waitUntil.ts +0 -18
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
import type {CodeRange} from './CodeRange';
|
|
2
|
-
import type {CodeTag} from './CodeScope';
|
|
3
|
-
import {resolveCodeTag} from './CodeScope';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Transform the fragments to isolate the given range into its own fragment.
|
|
7
|
-
*
|
|
8
|
-
* @remarks
|
|
9
|
-
* This function will try to preserve the original fragments, resolving them
|
|
10
|
-
* only if they overlap with the range.
|
|
11
|
-
*
|
|
12
|
-
* @param range - The range to extract.
|
|
13
|
-
* @param fragments - The fragments to transform.
|
|
14
|
-
*
|
|
15
|
-
* @returns A tuple containing the transformed fragments and the index of the
|
|
16
|
-
* isolated fragment within.
|
|
17
|
-
*/
|
|
18
|
-
export function extractRange(
|
|
19
|
-
range: CodeRange,
|
|
20
|
-
fragments: CodeTag[],
|
|
21
|
-
): [CodeTag[], number] {
|
|
22
|
-
const [from, to] = range;
|
|
23
|
-
let [fromRow, fromColumn] = from;
|
|
24
|
-
let [toRow, toColumn] = to;
|
|
25
|
-
if (fromRow > toRow || (fromRow === toRow && fromColumn > toColumn)) {
|
|
26
|
-
[fromRow, fromColumn] = to;
|
|
27
|
-
[toRow, toColumn] = from;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let currentRow = 0;
|
|
31
|
-
let currentColumn = 0;
|
|
32
|
-
const newFragments: CodeTag[] = [];
|
|
33
|
-
let index = -1;
|
|
34
|
-
let found = false;
|
|
35
|
-
let extracted = '';
|
|
36
|
-
|
|
37
|
-
for (const fragment of fragments) {
|
|
38
|
-
if (found) {
|
|
39
|
-
newFragments.push(fragment);
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const resolved = resolveCodeTag(fragment, false);
|
|
44
|
-
const lines = resolved.split('\n');
|
|
45
|
-
const newRows = lines.length - 1;
|
|
46
|
-
const lastColumn = lines[newRows].length;
|
|
47
|
-
const nextColumn = newRows > 0 ? lastColumn : currentColumn + lastColumn;
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
fromRow > currentRow + newRows ||
|
|
51
|
-
(fromRow === currentRow + newRows && fromColumn > nextColumn)
|
|
52
|
-
) {
|
|
53
|
-
currentRow += newRows;
|
|
54
|
-
currentColumn = nextColumn;
|
|
55
|
-
newFragments.push(fragment);
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < resolved.length; i++) {
|
|
60
|
-
const char = resolved.charAt(i);
|
|
61
|
-
if (fromRow === currentRow && fromColumn >= currentColumn) {
|
|
62
|
-
if (fromColumn === currentColumn) {
|
|
63
|
-
index = newFragments.length + 1;
|
|
64
|
-
newFragments.push(resolved.slice(0, i), '');
|
|
65
|
-
} else if (char === '\n') {
|
|
66
|
-
index = newFragments.length + 1;
|
|
67
|
-
newFragments.push(
|
|
68
|
-
resolved.slice(0, i) + ' '.repeat(fromColumn - currentColumn),
|
|
69
|
-
'',
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (index !== -1 && toRow === currentRow && toColumn >= currentColumn) {
|
|
75
|
-
if (toColumn === currentColumn) {
|
|
76
|
-
newFragments.push(resolved.slice(i));
|
|
77
|
-
found = true;
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (char === '\n') {
|
|
82
|
-
if (currentColumn < toColumn) {
|
|
83
|
-
extracted += '\n';
|
|
84
|
-
if (i + 1 < resolved.length) {
|
|
85
|
-
newFragments.push(resolved.slice(i + 1));
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
newFragments.push(resolved.slice(i));
|
|
89
|
-
}
|
|
90
|
-
found = true;
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (index !== -1) {
|
|
96
|
-
extracted += char;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (char === '\n') {
|
|
100
|
-
currentRow++;
|
|
101
|
-
currentColumn = 0;
|
|
102
|
-
} else {
|
|
103
|
-
currentColumn++;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (index === -1) {
|
|
108
|
-
newFragments.push(fragment);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (index === -1) {
|
|
113
|
-
index = newFragments.length + 1;
|
|
114
|
-
const missingRows = fromRow - currentRow;
|
|
115
|
-
const missingColumns =
|
|
116
|
-
missingRows > 0 ? fromColumn : fromColumn - currentColumn;
|
|
117
|
-
newFragments.push(
|
|
118
|
-
'\n'.repeat(missingRows) + ' '.repeat(missingColumns),
|
|
119
|
-
'',
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
newFragments[index] = extracted;
|
|
124
|
-
|
|
125
|
-
return [newFragments, index];
|
|
126
|
-
}
|
|
1
|
+
import type {CodeRange} from './CodeRange';
|
|
2
|
+
import type {CodeTag} from './CodeScope';
|
|
3
|
+
import {resolveCodeTag} from './CodeScope';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Transform the fragments to isolate the given range into its own fragment.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* This function will try to preserve the original fragments, resolving them
|
|
10
|
+
* only if they overlap with the range.
|
|
11
|
+
*
|
|
12
|
+
* @param range - The range to extract.
|
|
13
|
+
* @param fragments - The fragments to transform.
|
|
14
|
+
*
|
|
15
|
+
* @returns A tuple containing the transformed fragments and the index of the
|
|
16
|
+
* isolated fragment within.
|
|
17
|
+
*/
|
|
18
|
+
export function extractRange(
|
|
19
|
+
range: CodeRange,
|
|
20
|
+
fragments: CodeTag[],
|
|
21
|
+
): [CodeTag[], number] {
|
|
22
|
+
const [from, to] = range;
|
|
23
|
+
let [fromRow, fromColumn] = from;
|
|
24
|
+
let [toRow, toColumn] = to;
|
|
25
|
+
if (fromRow > toRow || (fromRow === toRow && fromColumn > toColumn)) {
|
|
26
|
+
[fromRow, fromColumn] = to;
|
|
27
|
+
[toRow, toColumn] = from;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let currentRow = 0;
|
|
31
|
+
let currentColumn = 0;
|
|
32
|
+
const newFragments: CodeTag[] = [];
|
|
33
|
+
let index = -1;
|
|
34
|
+
let found = false;
|
|
35
|
+
let extracted = '';
|
|
36
|
+
|
|
37
|
+
for (const fragment of fragments) {
|
|
38
|
+
if (found) {
|
|
39
|
+
newFragments.push(fragment);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const resolved = resolveCodeTag(fragment, false);
|
|
44
|
+
const lines = resolved.split('\n');
|
|
45
|
+
const newRows = lines.length - 1;
|
|
46
|
+
const lastColumn = lines[newRows].length;
|
|
47
|
+
const nextColumn = newRows > 0 ? lastColumn : currentColumn + lastColumn;
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
fromRow > currentRow + newRows ||
|
|
51
|
+
(fromRow === currentRow + newRows && fromColumn > nextColumn)
|
|
52
|
+
) {
|
|
53
|
+
currentRow += newRows;
|
|
54
|
+
currentColumn = nextColumn;
|
|
55
|
+
newFragments.push(fragment);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
60
|
+
const char = resolved.charAt(i);
|
|
61
|
+
if (fromRow === currentRow && fromColumn >= currentColumn) {
|
|
62
|
+
if (fromColumn === currentColumn) {
|
|
63
|
+
index = newFragments.length + 1;
|
|
64
|
+
newFragments.push(resolved.slice(0, i), '');
|
|
65
|
+
} else if (char === '\n') {
|
|
66
|
+
index = newFragments.length + 1;
|
|
67
|
+
newFragments.push(
|
|
68
|
+
resolved.slice(0, i) + ' '.repeat(fromColumn - currentColumn),
|
|
69
|
+
'',
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (index !== -1 && toRow === currentRow && toColumn >= currentColumn) {
|
|
75
|
+
if (toColumn === currentColumn) {
|
|
76
|
+
newFragments.push(resolved.slice(i));
|
|
77
|
+
found = true;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (char === '\n') {
|
|
82
|
+
if (currentColumn < toColumn) {
|
|
83
|
+
extracted += '\n';
|
|
84
|
+
if (i + 1 < resolved.length) {
|
|
85
|
+
newFragments.push(resolved.slice(i + 1));
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
newFragments.push(resolved.slice(i));
|
|
89
|
+
}
|
|
90
|
+
found = true;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (index !== -1) {
|
|
96
|
+
extracted += char;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (char === '\n') {
|
|
100
|
+
currentRow++;
|
|
101
|
+
currentColumn = 0;
|
|
102
|
+
} else {
|
|
103
|
+
currentColumn++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (index === -1) {
|
|
108
|
+
newFragments.push(fragment);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (index === -1) {
|
|
113
|
+
index = newFragments.length + 1;
|
|
114
|
+
const missingRows = fromRow - currentRow;
|
|
115
|
+
const missingColumns =
|
|
116
|
+
missingRows > 0 ? fromColumn : fromColumn - currentColumn;
|
|
117
|
+
newFragments.push(
|
|
118
|
+
'\n'.repeat(missingRows) + ' '.repeat(missingColumns),
|
|
119
|
+
'',
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
newFragments[index] = extracted;
|
|
124
|
+
|
|
125
|
+
return [newFragments, index];
|
|
126
|
+
}
|
package/src/lib/code/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export * from './CodeCursor';
|
|
2
|
-
export * from './CodeDiffer';
|
|
3
|
-
export * from './CodeFragment';
|
|
4
|
-
export * from './CodeHighlighter';
|
|
5
|
-
export * from './CodeRange';
|
|
6
|
-
export * from './CodeScope';
|
|
7
|
-
export * from './CodeSelection';
|
|
8
|
-
export * from './CodeSignal';
|
|
9
|
-
export * from './CodeTokenizer';
|
|
10
|
-
export * from './DefaultHighlightStyle';
|
|
11
|
-
export * from './diff';
|
|
12
|
-
export * from './extractRange';
|
|
13
|
-
export * from './LezerHighlighter';
|
|
1
|
+
export * from './CodeCursor';
|
|
2
|
+
export * from './CodeDiffer';
|
|
3
|
+
export * from './CodeFragment';
|
|
4
|
+
export * from './CodeHighlighter';
|
|
5
|
+
export * from './CodeRange';
|
|
6
|
+
export * from './CodeScope';
|
|
7
|
+
export * from './CodeSelection';
|
|
8
|
+
export * from './CodeSignal';
|
|
9
|
+
export * from './CodeTokenizer';
|
|
10
|
+
export * from './DefaultHighlightStyle';
|
|
11
|
+
export * from './diff';
|
|
12
|
+
export * from './extractRange';
|
|
13
|
+
export * from './LezerHighlighter';
|
|
@@ -1,131 +1,168 @@
|
|
|
1
|
-
import {DependencyContext, PlaybackState} from '@twick/core';
|
|
2
|
-
import {computed, nodeName} from '../decorators';
|
|
3
|
-
import type {MediaProps} from './Media';
|
|
4
|
-
import {Media} from './Media';
|
|
5
|
-
|
|
6
|
-
@nodeName('Audio')
|
|
7
|
-
export class Audio extends Media {
|
|
8
|
-
private static readonly pool: Record<string, HTMLAudioElement> = {};
|
|
9
|
-
|
|
10
|
-
public constructor(props: MediaProps) {
|
|
11
|
-
super(props);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
protected mediaElement(): HTMLAudioElement {
|
|
15
|
-
return this.audio();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
protected seekedMedia(): HTMLAudioElement {
|
|
19
|
-
return this.seekedAudio();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
protected fastSeekedMedia(): HTMLAudioElement {
|
|
23
|
-
return this.fastSeekedAudio();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@computed()
|
|
27
|
-
protected audio(): HTMLAudioElement {
|
|
28
|
-
const src = this.src();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (this.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
1
|
+
import {DependencyContext, PlaybackState} from '@twick/core';
|
|
2
|
+
import {computed, nodeName} from '../decorators';
|
|
3
|
+
import type {MediaProps} from './Media';
|
|
4
|
+
import {Media} from './Media';
|
|
5
|
+
|
|
6
|
+
@nodeName('Audio')
|
|
7
|
+
export class Audio extends Media {
|
|
8
|
+
private static readonly pool: Record<string, HTMLAudioElement> = {};
|
|
9
|
+
|
|
10
|
+
public constructor(props: MediaProps) {
|
|
11
|
+
super(props);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
protected mediaElement(): HTMLAudioElement {
|
|
15
|
+
return this.audio();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected seekedMedia(): HTMLAudioElement {
|
|
19
|
+
return this.seekedAudio();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected fastSeekedMedia(): HTMLAudioElement {
|
|
23
|
+
return this.fastSeekedAudio();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@computed()
|
|
27
|
+
protected audio(): HTMLAudioElement {
|
|
28
|
+
const src = this.src();
|
|
29
|
+
|
|
30
|
+
// Use a temporary key for undefined src to avoid conflicts
|
|
31
|
+
const key = `${this.key}/${src || 'pending'}`;
|
|
32
|
+
|
|
33
|
+
let audio = Audio.pool[key];
|
|
34
|
+
if (!audio) {
|
|
35
|
+
audio = document.createElement('audio');
|
|
36
|
+
audio.crossOrigin = 'anonymous';
|
|
37
|
+
|
|
38
|
+
// Only set src if it's valid, otherwise leave it empty
|
|
39
|
+
if (src && src !== 'undefined') {
|
|
40
|
+
audio.src = src;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Audio.pool[key] = audio;
|
|
44
|
+
} else if (src && src !== 'undefined' && audio.src !== src) {
|
|
45
|
+
// Update existing audio element if src has changed and is now valid
|
|
46
|
+
audio.src = src;
|
|
47
|
+
|
|
48
|
+
// Move audio to correct pool key
|
|
49
|
+
delete Audio.pool[key];
|
|
50
|
+
const newKey = `${this.key}/${src}`;
|
|
51
|
+
Audio.pool[newKey] = audio;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// If src is still undefined, wait for it to become available
|
|
55
|
+
if (!src || src === 'undefined') {
|
|
56
|
+
DependencyContext.collectPromise(
|
|
57
|
+
new Promise<void>(resolve => {
|
|
58
|
+
// Check periodically for valid src
|
|
59
|
+
const checkSrc = () => {
|
|
60
|
+
const currentSrc = this.src();
|
|
61
|
+
if (currentSrc && currentSrc !== 'undefined') {
|
|
62
|
+
resolve();
|
|
63
|
+
} else {
|
|
64
|
+
setTimeout(checkSrc, 10);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
checkSrc();
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const weNeedToWait = this.waitForCanPlayNecessary(audio);
|
|
73
|
+
if (!weNeedToWait) {
|
|
74
|
+
return audio;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
DependencyContext.collectPromise(
|
|
78
|
+
new Promise<void>(resolve => {
|
|
79
|
+
this.waitForCanPlay(audio, resolve);
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return audio;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@computed()
|
|
87
|
+
protected seekedAudio(): HTMLAudioElement {
|
|
88
|
+
const audio = this.audio();
|
|
89
|
+
|
|
90
|
+
audio.addEventListener('ended', () => {
|
|
91
|
+
this.pause();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!(this.time() < audio.duration)) {
|
|
95
|
+
this.pause();
|
|
96
|
+
return audio;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const time = this.clampTime(this.time());
|
|
100
|
+
audio.playbackRate = this.playbackRate();
|
|
101
|
+
|
|
102
|
+
if (!audio.paused) {
|
|
103
|
+
audio.pause();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (this.lastTime === time) {
|
|
107
|
+
return audio;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.setCurrentTime(time);
|
|
111
|
+
|
|
112
|
+
return audio;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@computed()
|
|
116
|
+
protected fastSeekedAudio(): HTMLAudioElement {
|
|
117
|
+
const audio = this.audio();
|
|
118
|
+
|
|
119
|
+
if (!(this.time() < audio.duration)) {
|
|
120
|
+
this.pause();
|
|
121
|
+
return audio;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const time = this.clampTime(this.time());
|
|
125
|
+
|
|
126
|
+
audio.playbackRate = this.playbackRate();
|
|
127
|
+
|
|
128
|
+
if (this.lastTime === time) {
|
|
129
|
+
return audio;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const playing =
|
|
133
|
+
this.playing() && time < audio.duration && audio.playbackRate > 0;
|
|
134
|
+
if (playing) {
|
|
135
|
+
if (audio.paused) {
|
|
136
|
+
DependencyContext.collectPromise(audio.play());
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
if (!audio.paused) {
|
|
140
|
+
audio.pause();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (Math.abs(audio.currentTime - time) > 0.3) {
|
|
144
|
+
this.setCurrentTime(time);
|
|
145
|
+
} else if (!playing) {
|
|
146
|
+
audio.currentTime = time;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return audio;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
protected override async draw(context: CanvasRenderingContext2D) {
|
|
153
|
+
// Auto-start playback if Twick is playing but media isn't
|
|
154
|
+
this.autoPlayBasedOnTwick();
|
|
155
|
+
|
|
156
|
+
const playbackState = this.view().playbackState();
|
|
157
|
+
|
|
158
|
+
playbackState === PlaybackState.Playing ||
|
|
159
|
+
playbackState === PlaybackState.Presenting
|
|
160
|
+
? this.fastSeekedAudio()
|
|
161
|
+
: this.seekedAudio();
|
|
162
|
+
|
|
163
|
+
context.save();
|
|
164
|
+
context.restore();
|
|
165
|
+
|
|
166
|
+
await this.drawChildren(context);
|
|
167
|
+
}
|
|
168
|
+
}
|