mirror of
https://github.com/motion-canvas/motion-canvas.git
synced 2026-01-11 14:57:56 -05:00
feat: function components
This commit is contained in:
14
package-lock.json
generated
14
package-lock.json
generated
@@ -18,7 +18,7 @@
|
||||
"strongly-typed-events": "^3.0.1",
|
||||
"three": "^0.138.3",
|
||||
"ts-loader": "^9.2.6",
|
||||
"typescript": "^4.5.5",
|
||||
"typescript": "^4.6.4",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.68.0",
|
||||
"webpack-dev-server": "^4.7.4"
|
||||
@@ -5533,9 +5533,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -10302,9 +10302,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA=="
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg=="
|
||||
},
|
||||
"unique-filename": {
|
||||
"version": "1.1.1",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"strongly-typed-events": "^3.0.1",
|
||||
"three": "^0.138.3",
|
||||
"ts-loader": "^9.2.6",
|
||||
"typescript": "^4.5.5",
|
||||
"typescript": "^4.6.4",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.68.0",
|
||||
"webpack-dev-server": "^4.7.4"
|
||||
|
||||
@@ -14,6 +14,7 @@ import {SceneTransition} from './transitions';
|
||||
import {decorate, threadable} from './decorators';
|
||||
import {PROJECT, SCENE} from './symbols';
|
||||
import {SimpleEventDispatcher} from 'strongly-typed-events';
|
||||
import {setScene} from './utils';
|
||||
|
||||
export interface SceneRunner {
|
||||
(layer: Scene, project: Project): ThreadGenerator;
|
||||
@@ -130,6 +131,7 @@ export class Scene extends Layer {
|
||||
}
|
||||
|
||||
public async next() {
|
||||
setScene(this);
|
||||
let result = this.runner.next();
|
||||
while (result.value) {
|
||||
if (isPromise(result.value)) {
|
||||
@@ -192,7 +194,7 @@ export class Scene extends Layer {
|
||||
}
|
||||
|
||||
public add(...children: (Shape | Group)[]): this {
|
||||
super.add(...children);
|
||||
super.add(...children.flat());
|
||||
this.debugNode.moveToTop();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@ import {PROJECT, SCENE} from '../symbols';
|
||||
import {ThreadGenerator} from '../threading';
|
||||
|
||||
decorate(waitUntil, threadable());
|
||||
export function waitUntil(
|
||||
time: number,
|
||||
after?: ThreadGenerator,
|
||||
): ThreadGenerator;
|
||||
export function waitUntil(
|
||||
event: string,
|
||||
after?: ThreadGenerator,
|
||||
): ThreadGenerator;
|
||||
export function* waitUntil(
|
||||
targetTime: number | string = 0,
|
||||
after?: ThreadGenerator,
|
||||
@@ -29,7 +37,7 @@ export function* waitFor(
|
||||
seconds = 0,
|
||||
after?: ThreadGenerator,
|
||||
): ThreadGenerator {
|
||||
const project = (yield PROJECT) as Project;
|
||||
const project: Project = yield PROJECT;
|
||||
const frames = project.secondsToFrames(seconds);
|
||||
const startFrame = project.frame;
|
||||
while (project.frame - startFrame < frames) {
|
||||
|
||||
62
src/components/Icon.ts
Normal file
62
src/components/Icon.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import {LayoutShape, LayoutShapeConfig} from './LayoutShape';
|
||||
import {KonvaNode} from '../decorators';
|
||||
import {Context} from 'konva/lib/Context';
|
||||
|
||||
const FILL = [
|
||||
new Path2D(
|
||||
'M16.56,8.94L7.62,0L6.21,1.41l2.38,2.38L3.44,8.94c-0.59,0.59-0.59,1.54,0,2.12l5.5,5.5C9.23,16.85,9.62,17,10,17 s0.77-0.15,1.06-0.44l5.5-5.5C17.15,10.48,17.15,9.53,16.56,8.94z M5.21,10L10,5.21L14.79,10H5.21z M19,11.5c0,0-2,2.17-2,3.5 c0,1.1,0.9,2,2,2s2-0.9,2-2C21,13.67,19,11.5,19,11.5z M2',
|
||||
),
|
||||
];
|
||||
|
||||
const BRUSH = [
|
||||
new Path2D(
|
||||
'M7 14c-1.66 0-3 1.34-3 3 0 1.31-1.16 2-2 2 .92 1.22 2.49 2 4 2 2.21 0 4-1.79 4-4 0-1.66-1.34-3-3-3zm13.71-9.37l-1.34-1.34c-.39-.39-1.02-.39-1.41 0L9 12.25 11.75 15l8.96-8.96c.39-.39.39-1.02 0-1.41z',
|
||||
),
|
||||
];
|
||||
|
||||
const UNITY = [
|
||||
new Path2D(
|
||||
'M 46.523438 17.292969 L 61.820313 26.125 C 62.375 26.429688 62.386719 27.296875 61.820313 27.605469 L 43.636719 38.101563 C 43.089844 38.417969 42.4375 38.394531 41.921875 38.101563 L 23.742188 27.605469 C 23.1875 27.300781 23.171875 26.429688 23.742188 26.121094 L 39.039063 17.292969 L 39.039063 0 L 0 22.539063 L 0 67.617188 L 0 67.410156 L 0 67.617188 L 14.972656 58.972656 L 14.972656 41.308594 C 14.964844 40.675781 15.707031 40.230469 16.257813 40.570313 L 34.4375 51.070313 C 34.988281 51.386719 35.292969 51.960938 35.292969 52.554688 L 35.292969 73.546875 C 35.308594 74.175781 34.566406 74.625 34.019531 74.289063 L 18.71875 65.457031 L 3.742188 74.101563 L 42.78125 96.640625 L 81.820313 74.101563 L 66.84375 65.457031 L 51.550781 74.289063 C 51.007813 74.613281 50.25 74.191406 50.269531 73.546875 L 50.269531 52.550781 C 50.269531 51.917969 50.613281 51.363281 51.125 51.066406 L 69.304688 40.570313 C 69.847656 40.242188 70.609375 40.664063 70.589844 41.3125 L 70.589844 58.972656 L 85.5625 67.617188 L 85.5625 22.539063 L 46.523438 0 L 46.523438 17.292969 ',
|
||||
),
|
||||
];
|
||||
|
||||
export enum IconType {
|
||||
Fill,
|
||||
Brush,
|
||||
Unity,
|
||||
}
|
||||
|
||||
interface IconConfig extends LayoutShapeConfig {
|
||||
type?: IconType;
|
||||
}
|
||||
|
||||
@KonvaNode()
|
||||
export class Icon extends LayoutShape {
|
||||
private readonly paths: Path2D[];
|
||||
|
||||
constructor(config?: IconConfig) {
|
||||
super(config);
|
||||
|
||||
switch (config?.type ?? IconType.Fill) {
|
||||
case IconType.Brush:
|
||||
this.paths = BRUSH;
|
||||
break;
|
||||
case IconType.Fill:
|
||||
this.paths = FILL;
|
||||
break;
|
||||
case IconType.Unity:
|
||||
this.paths = UNITY;
|
||||
break;
|
||||
}
|
||||
|
||||
this._fillFunc = context => {
|
||||
for (const path of this.paths) {
|
||||
context.fill(path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_sceneFunc(context: Context) {
|
||||
context.fillShape(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Text, TextConfig} from 'konva/lib/shapes/Text';
|
||||
import {IRect, Vector2d} from 'konva/lib/types';
|
||||
import {GetSet, IRect, Vector2d} from 'konva/lib/types';
|
||||
import {ShapeGetClientRectConfig} from 'konva/lib/Shape';
|
||||
import {
|
||||
getOriginDelta,
|
||||
@@ -11,13 +11,16 @@ import {
|
||||
} from './ILayoutNode';
|
||||
import {Origin, Size, PossibleSpacing, Spacing} from '../types';
|
||||
import {Animator, tween, textTween, InterpolationFunction} from '../tweening';
|
||||
import {threadable} from '../decorators';
|
||||
import {getset, threadable} from '../decorators';
|
||||
|
||||
export interface LayoutTextConfig extends Partial<LayoutAttrs>, TextConfig {
|
||||
minWidth?: number;
|
||||
}
|
||||
|
||||
export class LayoutText extends Text implements ILayoutNode {
|
||||
@getset('', undefined, LayoutText.prototype.textTween)
|
||||
public text: GetSet<LayoutTextConfig['text'], this>;
|
||||
|
||||
private overrideWidth: number | null = null;
|
||||
private isConstructed = false;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {easeOutExpo, linear, tween} from '../tweening';
|
||||
import {GetSet, IRect} from 'konva/lib/types';
|
||||
import {getset, threadable} from '../decorators';
|
||||
import {Node} from 'konva/lib/Node';
|
||||
import {Reference} from '../utils';
|
||||
|
||||
export interface SurfaceMask {
|
||||
width: number;
|
||||
@@ -30,6 +31,7 @@ export interface CircleMask {
|
||||
}
|
||||
|
||||
export interface SurfaceConfig extends LayoutGroupConfig {
|
||||
ref?: Reference<Surface>;
|
||||
radius?: number;
|
||||
origin?: Origin;
|
||||
circleMask?: CircleMask;
|
||||
|
||||
7
src/global.d.ts
vendored
7
src/global.d.ts
vendored
@@ -27,3 +27,10 @@ declare module '*.wav?meta' {
|
||||
const value: import('./types/Waveform').Waveform;
|
||||
export = value;
|
||||
}
|
||||
|
||||
declare namespace JSX {
|
||||
type ElementClass = import('konva/lib/Node').Node;
|
||||
interface ElementChildrenAttribute {
|
||||
children: {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,45 @@
|
||||
import {Node} from 'konva/lib/Node';
|
||||
import type {Scene} from './Scene';
|
||||
import {Node, NodeConfig} from 'konva/lib/Node';
|
||||
import {Container} from 'konva/lib/Container';
|
||||
import {Surface} from './components';
|
||||
import {LayoutNode} from './components/ILayoutNode';
|
||||
|
||||
function isConstructor(fn: Function): fn is new (...args: any[]) => any {
|
||||
return !!fn.prototype?.name;
|
||||
}
|
||||
|
||||
export const Fragment = Symbol.for('mc.fragment');
|
||||
export function jsx<TNode extends Node, TConfig>(
|
||||
type: new (config?: TConfig) => TNode,
|
||||
config: TConfig & {children?: Node | Node[]; ref?: {value: TNode} | [any, string]},
|
||||
export function jsx(
|
||||
type:
|
||||
| (new (config?: NodeConfig) => Node)
|
||||
| ((config: NodeConfig) => Node)
|
||||
| typeof Fragment,
|
||||
config: NodeConfig & {
|
||||
children?: Node | Node[];
|
||||
ref?: {value: Node} | [any, string];
|
||||
},
|
||||
maybeKey: string,
|
||||
): TNode {
|
||||
): Node | Node[] {
|
||||
const {children, ref, ...rest} = config;
|
||||
const node = new type(<TConfig>rest);
|
||||
const flatChildren = Array.isArray(children) ? children.flat() : [children];
|
||||
|
||||
if (type === Fragment) {
|
||||
return flatChildren;
|
||||
}
|
||||
|
||||
if (!isConstructor(type)) {
|
||||
return type(config);
|
||||
}
|
||||
|
||||
const node = new type(rest);
|
||||
if (children) {
|
||||
if (node instanceof Surface) {
|
||||
if (Array.isArray(children)) {
|
||||
node.setChild(<LayoutNode>children[0]);
|
||||
} else {
|
||||
node.setChild(<LayoutNode>children);
|
||||
}
|
||||
node.setChild(<LayoutNode>flatChildren[0]);
|
||||
} else if (node instanceof Container) {
|
||||
if (Array.isArray(children)) {
|
||||
node.add(...children);
|
||||
} else {
|
||||
node.add(children);
|
||||
}
|
||||
node.add(...flatChildren);
|
||||
}
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
if (Array.isArray(ref)) {
|
||||
ref[0][ref[1]] = node;
|
||||
|
||||
@@ -132,7 +132,10 @@ export class Animator<Type, This extends Node> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public waitUntil(event: string): this
|
||||
public waitUntil(time: number): this
|
||||
public waitUntil(time: number | string): this {
|
||||
// @ts-ignore
|
||||
this.keys.push(() => waitUntil(time));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './pop';
|
||||
export * from './useRef';
|
||||
export * from './useScene';
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
import type {Node} from 'konva/lib/Node';
|
||||
|
||||
export function useRef<T extends Node>(): {value: T} {
|
||||
return {value: null};
|
||||
export type Reference<TValue> = TValue extends (config: {
|
||||
ref: infer TReference;
|
||||
}) => any
|
||||
? TReference
|
||||
: {value: TValue};
|
||||
|
||||
export function useRef<T>(): Reference<T> {
|
||||
return {} as Reference<T>;
|
||||
}
|
||||
|
||||
export function makeRef<TObject, TKey extends keyof TObject>(
|
||||
object: TObject,
|
||||
key: TKey,
|
||||
): Reference<TObject[TKey]> {
|
||||
return {
|
||||
get value(): TObject[TKey] {
|
||||
return object[key];
|
||||
},
|
||||
set value(value: TObject[TKey]) {
|
||||
object[key] = value;
|
||||
},
|
||||
} as Reference<TObject[TKey]>;
|
||||
}
|
||||
|
||||
11
src/utils/useScene.ts
Normal file
11
src/utils/useScene.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import {Scene} from '../Scene';
|
||||
|
||||
let currentScene: Scene = null;
|
||||
|
||||
export function useScene(): Scene {
|
||||
return currentScene;
|
||||
}
|
||||
|
||||
export function setScene(scene: Scene) {
|
||||
currentScene = scene;
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "esnext",
|
||||
"target": "es2017",
|
||||
"target": "es2020",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
||||
Reference in New Issue
Block a user