@tremolo-ui/react 0.1.0-alpha.2 → 0.1.0
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/cjs/index.js +108 -103
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts +26 -6
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/context.d.ts +1 -1
- package/dist/cjs/types/components/Piano/context.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
- package/dist/esm/index.js +108 -103
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AnimationCanvas/index.d.ts +26 -6
- package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/context.d.ts +1 -1
- package/dist/esm/types/components/Piano/context.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AnimationCanvas/index.tsx +84 -32
- package/src/components/AnimationKnob/index.tsx +4 -6
- package/src/components/NumberInput/InternalInput.tsx +2 -2
- package/src/components/Piano/context.tsx +4 -37
- package/src/components/Piano/index.tsx +16 -12
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { ComponentPropsWithoutRef, ReactElement
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactElement } from 'react';
|
|
2
2
|
/** @category AnimationCanvas */
|
|
3
|
-
export type
|
|
3
|
+
export type InitFunction = (context: CanvasRenderingContext2D, option: {
|
|
4
|
+
/** current canvas width */
|
|
5
|
+
width: number;
|
|
6
|
+
/** current canvas height */
|
|
7
|
+
height: number;
|
|
8
|
+
}) => void;
|
|
9
|
+
/** @category AnimationCanvas */
|
|
10
|
+
export type DrawFunction = (context: CanvasRenderingContext2D, option: {
|
|
11
|
+
/** current canvas width */
|
|
12
|
+
width: number;
|
|
13
|
+
/** current canvas height */
|
|
14
|
+
height: number;
|
|
15
|
+
/** frame count */
|
|
16
|
+
count: number;
|
|
17
|
+
/** delta time (ms) */
|
|
18
|
+
deltaTime: number;
|
|
19
|
+
/** elapsed time (ms) */
|
|
20
|
+
elapsedTime: number;
|
|
21
|
+
/** frame per second */
|
|
22
|
+
fps: number;
|
|
23
|
+
}) => void;
|
|
4
24
|
/** @category AnimationCanvas */
|
|
5
25
|
export interface CommonProps {
|
|
6
26
|
/**
|
|
7
27
|
* @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes
|
|
8
28
|
*/
|
|
9
29
|
options?: CanvasRenderingContext2DSettings;
|
|
10
|
-
init?:
|
|
30
|
+
init?: InitFunction;
|
|
11
31
|
draw: DrawFunction;
|
|
12
32
|
}
|
|
13
33
|
/** @category AnimationCanvas */
|
|
@@ -21,11 +41,11 @@ export interface RelativeSizingProps {
|
|
|
21
41
|
reduceFlickering?: boolean;
|
|
22
42
|
}
|
|
23
43
|
/** @category AnimationCanvas */
|
|
24
|
-
export type AnimationCanvasProps =
|
|
44
|
+
export type AnimationCanvasProps = CommonProps & AbsoluteSizingProps & RelativeSizingProps;
|
|
25
45
|
/**
|
|
26
46
|
* A simple animatable canvas with requestAnimationFrame()
|
|
27
47
|
* @category AnimationCanvas
|
|
28
48
|
*/
|
|
29
|
-
export declare function AnimationCanvas(props:
|
|
30
|
-
export declare function AnimationCanvas(
|
|
49
|
+
export declare function AnimationCanvas(props: CommonProps & AbsoluteSizingProps & Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>): ReactElement;
|
|
50
|
+
export declare function AnimationCanvas(pros: CommonProps & RelativeSizingProps & Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>): ReactElement;
|
|
31
51
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/AnimationCanvas/index.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,wBAAwB,EACxB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/AnimationCanvas/index.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,wBAAwB,EACxB,YAAY,EAKb,MAAM,OAAO,CAAA;AA2Bd,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE;IACN,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;CACf,KACE,IAAI,CAAA;AAET,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG,CAGzB,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE;IACN,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAA;CACZ,KACE,IAAI,CAAA;AAET,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,OAAO,CAAC,EAAE,gCAAgC,CAAA;IAC1C,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,IAAI,EAAE,YAAY,CAAA;CACnB;AAED,gCAAgC;AAChC,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,gCAAgC;AAChC,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,gCAAgC;AAChC,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAC5C,mBAAmB,GACnB,mBAAmB,CAAA;AAErB;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,GAChB,mBAAmB,GACnB,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,EAAE,MAAM,oBAAoB,CAAC,GACrE,YAAY,CAAA;AACf,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,GACf,mBAAmB,GACnB,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,EAAE,MAAM,oBAAoB,CAAC,GACrE,YAAY,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/AnimationKnob/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,aAAa,EAKd,MAAM,OAAO,CAAA;AAEd,OAAO,EAML,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAK9B,OAAO,EAAmB,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG;IAE/B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IAGX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAE5B,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAE9B,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uBAAuB;IACvB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,IAAI,CAAC,EAAE,YAAY,CAAA;IAEnB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC/B;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAClC,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAKD;;;GAGG;AACH,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/AnimationKnob/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,aAAa,EAKd,MAAM,OAAO,CAAA;AAEd,OAAO,EAML,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAK9B,OAAO,EAAmB,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG;IAE/B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IAGX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAE5B,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IAE9B,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uBAAuB;IACvB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,IAAI,CAAC,EAAE,YAAY,CAAA;IAEnB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC/B;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAClC,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAKD;;;GAGG;AACH,eAAO,MAAM,aAAa,8NA0NzB,CAAA"}
|
|
@@ -16,7 +16,7 @@ type State = {
|
|
|
16
16
|
type Action = {
|
|
17
17
|
notePosition: (note: number) => number;
|
|
18
18
|
};
|
|
19
|
-
type PianoProviderProps = React.PropsWithChildren<Partial<State
|
|
19
|
+
type PianoProviderProps = React.PropsWithChildren<Partial<State> & Action>;
|
|
20
20
|
export declare function PianoProvider({ children, ...props }: PianoProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
21
21
|
/** @category Piano */
|
|
22
22
|
export declare function usePianoContext<T>(selector: (state: State & Action) => T): T;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,SAAS,EAAiC,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,SAAS,EAAiC,MAAM,OAAO,CAAA;AAG/E,sBAAsB;AACtB,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,KAAK,KAAK,GAAG;IACX,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;CAClD,CAAA;AAED,KAAK,MAAM,GAAG;IACZ,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CACvC,CAAA;AAyBD,KAAK,kBAAkB,GAAG,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAA;AAE1E,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,2CAmBvE;AAED,sBAAsB;AACtB,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAI5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/index.tsx"],"names":[],"mappings":"AACA,OAAc,EACZ,wBAAwB,EAExB,aAAa,EACb,YAAY,EACZ,SAAS,EAOV,MAAM,OAAO,CAAA;AAad,OAAO,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAA;AAQpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;;GAKG;AAEH,sBAAsB;AACtB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,YAKrD;AAED,sBAAsB;AACtB,MAAM,WAAW,UAAU;IAEzB,SAAS,EAAE,SAAS,CAAA;IAGpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAExB,KAAK,CAAC,EAAE,aAAa,CAAA;IAErB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAEzC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;IAElD;;OAEG;IACH,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAA;CACzC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/index.tsx"],"names":[],"mappings":"AACA,OAAc,EACZ,wBAAwB,EAExB,aAAa,EACb,YAAY,EACZ,SAAS,EAOV,MAAM,OAAO,CAAA;AAad,OAAO,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAA;AAQpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;;GAKG;AAEH,sBAAsB;AACtB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,YAKrD;AAED,sBAAsB;AACtB,MAAM,WAAW,UAAU;IAEzB,SAAS,EAAE,SAAS,CAAA;IAGpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAExB,KAAK,CAAC,EAAE,aAAa,CAAA;IAErB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;IAEzC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;IAElD;;OAEG;IACH,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAA;CACzC;AAID;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,SAAgB,EAChB,OAAa,EACb,iBAAiB,EACjB,IAAY,EACZ,MAA4B,EAC5B,cAAc,EAAE,eAAsC,EACtD,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,KAAK,EACL,QAAQ,EACR,aAAa,EACb,GAAG,KAAK,EACT,EAAE,UAAU,GAAG,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,UAAU,CAAC,2CAiNtE;AAED,cAAc,qBAAqB,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAA;AAC1E,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA"}
|
package/package.json
CHANGED
|
@@ -10,6 +10,13 @@ import {
|
|
|
10
10
|
|
|
11
11
|
import { DrawingContext, drawingState, DrawingStateValue } from './canvas'
|
|
12
12
|
|
|
13
|
+
/*
|
|
14
|
+
TODO
|
|
15
|
+
AbsoluteSizingProps, RelativeSizingPropsの型付けを強くする
|
|
16
|
+
AbsoluteSizingPropsの場合、width, heightは必須
|
|
17
|
+
RelativeSizingPropsのの場合、relativeSizeは必須、reduceFlickeringはオプショナル
|
|
18
|
+
*/
|
|
19
|
+
|
|
13
20
|
function setDprConfig(
|
|
14
21
|
canvas: HTMLCanvasElement,
|
|
15
22
|
context: CanvasRenderingContext2D,
|
|
@@ -19,19 +26,43 @@ function setDprConfig(
|
|
|
19
26
|
) {
|
|
20
27
|
canvas.width = width * dpr
|
|
21
28
|
canvas.height = height * dpr
|
|
29
|
+
// Reset current transformation matrix to the identity matrix
|
|
30
|
+
context.setTransform(1, 0, 0, 1, 0, 0)
|
|
22
31
|
context.scale(dpr, dpr)
|
|
23
32
|
canvas.style.width = `${width}px`
|
|
24
33
|
canvas.style.height = `${height}px`
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
/** @category AnimationCanvas */
|
|
37
|
+
export type InitFunction = (
|
|
38
|
+
context: CanvasRenderingContext2D,
|
|
39
|
+
option: {
|
|
40
|
+
/** current canvas width */
|
|
41
|
+
width: number
|
|
42
|
+
/** current canvas height */
|
|
43
|
+
height: number
|
|
44
|
+
},
|
|
45
|
+
) => void
|
|
46
|
+
|
|
27
47
|
/** @category AnimationCanvas */
|
|
28
48
|
export type DrawFunction = (
|
|
29
49
|
// TODO: saving scale and translate
|
|
30
50
|
// context: Omit<CanvasRenderingContext2D, 'save' | 'restore' | 'scale'>,
|
|
31
51
|
context: CanvasRenderingContext2D,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
option: {
|
|
53
|
+
/** current canvas width */
|
|
54
|
+
width: number
|
|
55
|
+
/** current canvas height */
|
|
56
|
+
height: number
|
|
57
|
+
/** frame count */
|
|
58
|
+
count: number
|
|
59
|
+
/** delta time (ms) */
|
|
60
|
+
deltaTime: number
|
|
61
|
+
/** elapsed time (ms) */
|
|
62
|
+
elapsedTime: number
|
|
63
|
+
/** frame per second */
|
|
64
|
+
fps: number
|
|
65
|
+
},
|
|
35
66
|
) => void
|
|
36
67
|
|
|
37
68
|
/** @category AnimationCanvas */
|
|
@@ -40,7 +71,7 @@ export interface CommonProps {
|
|
|
40
71
|
* @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes
|
|
41
72
|
*/
|
|
42
73
|
options?: CanvasRenderingContext2DSettings
|
|
43
|
-
init?:
|
|
74
|
+
init?: InitFunction
|
|
44
75
|
draw: DrawFunction
|
|
45
76
|
}
|
|
46
77
|
|
|
@@ -57,32 +88,36 @@ export interface RelativeSizingProps {
|
|
|
57
88
|
}
|
|
58
89
|
|
|
59
90
|
/** @category AnimationCanvas */
|
|
60
|
-
export type AnimationCanvasProps =
|
|
61
|
-
|
|
62
|
-
|
|
91
|
+
export type AnimationCanvasProps = CommonProps &
|
|
92
|
+
AbsoluteSizingProps &
|
|
93
|
+
RelativeSizingProps
|
|
63
94
|
|
|
64
95
|
/**
|
|
65
96
|
* A simple animatable canvas with requestAnimationFrame()
|
|
66
97
|
* @category AnimationCanvas
|
|
67
98
|
*/
|
|
68
99
|
export function AnimationCanvas(
|
|
69
|
-
props:
|
|
70
|
-
|
|
100
|
+
props: CommonProps &
|
|
101
|
+
AbsoluteSizingProps &
|
|
71
102
|
Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>,
|
|
72
103
|
): ReactElement
|
|
73
104
|
export function AnimationCanvas(
|
|
74
|
-
|
|
75
|
-
|
|
105
|
+
pros: CommonProps &
|
|
106
|
+
RelativeSizingProps &
|
|
76
107
|
Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>,
|
|
77
108
|
): ReactElement
|
|
78
109
|
export function AnimationCanvas({
|
|
79
|
-
|
|
80
|
-
height = 100,
|
|
81
|
-
relativeSize = false,
|
|
82
|
-
reduceFlickering = true,
|
|
110
|
+
// common
|
|
83
111
|
options,
|
|
84
112
|
init,
|
|
85
113
|
draw,
|
|
114
|
+
// absolute
|
|
115
|
+
width = 100,
|
|
116
|
+
height = 100,
|
|
117
|
+
// relative
|
|
118
|
+
relativeSize,
|
|
119
|
+
reduceFlickering = true,
|
|
120
|
+
// canvas props
|
|
86
121
|
className,
|
|
87
122
|
onContextMenu = (event) => event.preventDefault(),
|
|
88
123
|
...props
|
|
@@ -96,6 +131,8 @@ export function AnimationCanvas({
|
|
|
96
131
|
const reqIdRef = useRef(-1)
|
|
97
132
|
const widthRef = useRef(0)
|
|
98
133
|
const heightRef = useRef(0)
|
|
134
|
+
const deltaMemoRef = useRef(-1)
|
|
135
|
+
const startTimeRef = useRef(-1)
|
|
99
136
|
|
|
100
137
|
const loop = useCallback(
|
|
101
138
|
(
|
|
@@ -104,10 +141,21 @@ export function AnimationCanvas({
|
|
|
104
141
|
height: RefObject<number>,
|
|
105
142
|
count: number,
|
|
106
143
|
) => {
|
|
144
|
+
const now = performance.now()
|
|
145
|
+
const deltaTime = now - deltaMemoRef.current
|
|
146
|
+
const elapsedTime = now - startTimeRef.current
|
|
147
|
+
deltaMemoRef.current = now
|
|
107
148
|
reqIdRef.current = requestAnimationFrame(() =>
|
|
108
149
|
loop(context, width, height, count + 1),
|
|
109
150
|
)
|
|
110
|
-
draw(context,
|
|
151
|
+
draw(context, {
|
|
152
|
+
width: width.current,
|
|
153
|
+
height: height.current,
|
|
154
|
+
count: count + 1,
|
|
155
|
+
deltaTime,
|
|
156
|
+
elapsedTime,
|
|
157
|
+
fps: 1000 / deltaTime,
|
|
158
|
+
})
|
|
111
159
|
},
|
|
112
160
|
[draw],
|
|
113
161
|
)
|
|
@@ -117,7 +165,7 @@ export function AnimationCanvas({
|
|
|
117
165
|
const canvas = canvasRef.current
|
|
118
166
|
const context = canvas.getContext('2d', options)
|
|
119
167
|
if (!context) throw new Error('Cannot get canvas context.')
|
|
120
|
-
const dpr = globalThis.
|
|
168
|
+
const dpr = globalThis.devicePixelRatio
|
|
121
169
|
|
|
122
170
|
if (relativeSize) {
|
|
123
171
|
const parent = canvas.parentElement
|
|
@@ -125,20 +173,16 @@ export function AnimationCanvas({
|
|
|
125
173
|
const memoCanvas = memoCanvasRef.current
|
|
126
174
|
const memoContext = memoCanvas?.getContext('2d', options)
|
|
127
175
|
|
|
128
|
-
const
|
|
129
|
-
// TODO: If the parent element has no absolute height, the height increases infinitely.
|
|
130
|
-
// : 親要素に絶対的な高さを持たない場合、高さは無限に増加します。
|
|
131
|
-
// https://zenn.dev/megeton/articles/be1c677e174c84#%E6%A0%B9%E6%9C%AC%E7%9A%84%E3%81%AB-resizeobserver-loop-limit-exceeded-%E3%81%8C%E5%87%BA%E3%82%8B%E5%95%8F%E9%A1%8C%E3%81%AB%E5%90%91%E3%81%8D%E5%90%88%E3%81%86
|
|
176
|
+
const ro = new ResizeObserver((entries) => {
|
|
132
177
|
for (const entry of entries) {
|
|
133
178
|
// Prevents loss of some context when the canvas is resized
|
|
134
|
-
// TODO: saving scale and translate
|
|
135
179
|
const contextMemo = {} as DrawingContext
|
|
136
180
|
for (const prop of drawingState) {
|
|
137
181
|
;(contextMemo[prop] as DrawingStateValue) = context[prop]
|
|
138
182
|
}
|
|
139
183
|
|
|
140
|
-
const w =
|
|
141
|
-
const h =
|
|
184
|
+
const w = entry.contentRect.width
|
|
185
|
+
const h = entry.contentRect.height
|
|
142
186
|
|
|
143
187
|
if (reduceFlickering && memoCanvas && memoContext) {
|
|
144
188
|
memoCanvas.width = w * dpr
|
|
@@ -168,18 +212,22 @@ export function AnimationCanvas({
|
|
|
168
212
|
}
|
|
169
213
|
}
|
|
170
214
|
})
|
|
171
|
-
|
|
215
|
+
ro.observe(parent)
|
|
172
216
|
|
|
173
|
-
const w =
|
|
174
|
-
const h =
|
|
217
|
+
const w = parent.clientWidth
|
|
218
|
+
const h = parent.clientHeight
|
|
175
219
|
setDprConfig(canvas, context, w, h, dpr)
|
|
176
220
|
|
|
177
|
-
if (init)
|
|
178
|
-
|
|
221
|
+
if (init)
|
|
222
|
+
init(context, { width: widthRef.current, height: heightRef.current })
|
|
223
|
+
const now = performance.now()
|
|
224
|
+
deltaMemoRef.current = now
|
|
225
|
+
startTimeRef.current = now
|
|
226
|
+
loop(context, widthRef, heightRef, -1)
|
|
179
227
|
|
|
180
228
|
return () => {
|
|
181
229
|
if (reqIdRef.current) cancelAnimationFrame(reqIdRef.current)
|
|
182
|
-
|
|
230
|
+
ro.disconnect()
|
|
183
231
|
}
|
|
184
232
|
} else {
|
|
185
233
|
const rect = canvas.getBoundingClientRect()
|
|
@@ -187,8 +235,12 @@ export function AnimationCanvas({
|
|
|
187
235
|
widthRef.current = rect.width
|
|
188
236
|
heightRef.current = rect.height
|
|
189
237
|
|
|
190
|
-
if (init)
|
|
191
|
-
|
|
238
|
+
if (init)
|
|
239
|
+
init(context, { width: widthRef.current, height: heightRef.current })
|
|
240
|
+
const now = performance.now()
|
|
241
|
+
deltaMemoRef.current = now
|
|
242
|
+
startTimeRef.current = now
|
|
243
|
+
loop(context, widthRef, heightRef, -1)
|
|
192
244
|
|
|
193
245
|
return () => {
|
|
194
246
|
if (reqIdRef.current) cancelAnimationFrame(reqIdRef.current)
|
|
@@ -245,18 +245,16 @@ export const AnimationKnob = forwardRef<AnimationKnobMethods, Props>(
|
|
|
245
245
|
draw={
|
|
246
246
|
draw
|
|
247
247
|
? draw
|
|
248
|
-
: (ctx, width, height) => {
|
|
248
|
+
: (ctx, { width, height }) => {
|
|
249
249
|
const p = normalizeValue(value, min, max, skew)
|
|
250
250
|
const startP = normalizeValue(startValue, min, max, skew)
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
const h = height.current,
|
|
254
|
-
cy = h / 2
|
|
251
|
+
const cx = width / 2
|
|
252
|
+
const cy = height / 2
|
|
255
253
|
const r = Math.min(cx, cy)
|
|
256
254
|
if (r <= 0) return
|
|
257
255
|
|
|
258
256
|
// reset
|
|
259
|
-
ctx.clearRect(0, 0,
|
|
257
|
+
ctx.clearRect(0, 0, width, height)
|
|
260
258
|
ctx.lineCap = 'butt'
|
|
261
259
|
|
|
262
260
|
// bg
|
|
@@ -117,7 +117,7 @@ export const InternalInput = forwardRef<
|
|
|
117
117
|
event.preventDefault()
|
|
118
118
|
const x = key == 'ArrowUp' ? keyboard[1] : -keyboard[1]
|
|
119
119
|
const parsed = parseValue(String(updateValueByEvent(keyboard[0], x)))
|
|
120
|
-
console.log('key control')
|
|
120
|
+
// console.log('key control')
|
|
121
121
|
onChange?.(parsed.rawValue, parsed.formatValue)
|
|
122
122
|
},
|
|
123
123
|
[keyboard, readonly, onChange, updateValueByEvent],
|
|
@@ -131,7 +131,7 @@ export const InternalInput = forwardRef<
|
|
|
131
131
|
if (!onChange || event.deltaY == 0) return
|
|
132
132
|
const x = Math.sign(event.deltaY) * -wheel[1]
|
|
133
133
|
const parsed = parseValue(String(updateValueByEvent(wheel[0], x)))
|
|
134
|
-
console.log('wheel control')
|
|
134
|
+
// console.log('wheel control')
|
|
135
135
|
onChange?.(parsed.rawValue, parsed.formatValue)
|
|
136
136
|
},
|
|
137
137
|
{ passive: false },
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { createContext, ReactNode, useContext, useEffect, useRef } from 'react'
|
|
2
2
|
import { createStore, useStore } from 'zustand'
|
|
3
3
|
|
|
4
|
-
import { isBlackKey, noteKey, NoteKey, noteKeys } from '@tremolo-ui/functions'
|
|
5
|
-
|
|
6
|
-
import { defaultBlackKeyWidth, defaultWhiteKeyWidth } from './key'
|
|
7
|
-
|
|
8
4
|
/** @category Piano */
|
|
9
5
|
export type NoteRange = {
|
|
10
6
|
first: number
|
|
@@ -27,8 +23,8 @@ type Action = {
|
|
|
27
23
|
|
|
28
24
|
type PianoStore = ReturnType<typeof createPianoStore>
|
|
29
25
|
|
|
30
|
-
const createPianoStore = (initProps
|
|
31
|
-
const noteRange = initProps
|
|
26
|
+
const createPianoStore = (initProps: Partial<State> & Action) => {
|
|
27
|
+
// const noteRange = initProps.noteRange || { first: 0, last: 127 }
|
|
32
28
|
const DEFAULT_PROPS: State = {
|
|
33
29
|
noteRange: { first: 0, last: 127 },
|
|
34
30
|
glissando: true,
|
|
@@ -42,42 +38,13 @@ const createPianoStore = (initProps?: Partial<State>) => {
|
|
|
42
38
|
return createStore<State & Action>()(() => ({
|
|
43
39
|
...DEFAULT_PROPS,
|
|
44
40
|
...initProps,
|
|
45
|
-
notePosition:
|
|
46
|
-
const pitchPositions: Record<NoteKey, number> = {
|
|
47
|
-
C: 0,
|
|
48
|
-
'C#': 1,
|
|
49
|
-
D: 1,
|
|
50
|
-
'D#': 2,
|
|
51
|
-
E: 2,
|
|
52
|
-
F: 3,
|
|
53
|
-
'F#': 4,
|
|
54
|
-
G: 4,
|
|
55
|
-
'G#': 5,
|
|
56
|
-
A: 5,
|
|
57
|
-
'A#': 6,
|
|
58
|
-
B: 6,
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const whiteNoteWidth = defaultWhiteKeyWidth
|
|
62
|
-
const blackNoteWidth = defaultBlackKeyWidth
|
|
63
|
-
const padding = 1
|
|
64
|
-
|
|
65
|
-
const targetNoteKey = noteKey(note)
|
|
66
|
-
const firstNoteKey = noteKey(noteRange.first)
|
|
67
|
-
const octave = Math.floor((note - noteRange.first) / 12)
|
|
68
|
-
const octaveOffset =
|
|
69
|
-
noteKeys.indexOf(firstNoteKey) > noteKeys.indexOf(targetNoteKey) ? 1 : 0
|
|
70
|
-
const w = whiteNoteWidth + padding
|
|
71
|
-
const pos = pitchPositions[targetNoteKey] - pitchPositions[firstNoteKey]
|
|
72
|
-
const blackKeyOffset = isBlackKey(note) ? blackNoteWidth / 2 : 0
|
|
73
|
-
return pos * w + (octave + octaveOffset) * 7 * w - blackKeyOffset
|
|
74
|
-
},
|
|
41
|
+
notePosition: initProps.notePosition,
|
|
75
42
|
}))
|
|
76
43
|
}
|
|
77
44
|
|
|
78
45
|
const PianoContext = createContext<PianoStore | null>(null)
|
|
79
46
|
|
|
80
|
-
type PianoProviderProps = React.PropsWithChildren<Partial<State
|
|
47
|
+
type PianoProviderProps = React.PropsWithChildren<Partial<State> & Action>
|
|
81
48
|
|
|
82
49
|
export function PianoProvider({ children, ...props }: PianoProviderProps) {
|
|
83
50
|
const storeRef = useRef<PianoStore>(null)
|
|
@@ -76,6 +76,8 @@ export interface PianoProps {
|
|
|
76
76
|
children?: ReactElement | ReactElement[]
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
const blackPerWhiteWidth = defaultBlackKeyWidth / defaultWhiteKeyWidth // 0.65
|
|
80
|
+
|
|
79
81
|
/**
|
|
80
82
|
* Customizable piano component.
|
|
81
83
|
* @category Piano
|
|
@@ -115,21 +117,20 @@ export function Piano({
|
|
|
115
117
|
const staticWidth = (whiteNoteWidth + padding) * whiteNoteCount
|
|
116
118
|
// const blackNoteShiftPercent = 0.3
|
|
117
119
|
|
|
118
|
-
// TODO: if fill setWhiteNoteWidth
|
|
119
|
-
// useMemo
|
|
120
|
-
// __width
|
|
121
120
|
const childrenWithProps = useMemo(() => {
|
|
122
121
|
return (
|
|
123
122
|
children &&
|
|
124
123
|
React.Children.map(children, (child, index) => {
|
|
125
124
|
if (React.isValidElement(child)) {
|
|
126
|
-
const
|
|
125
|
+
const __width =
|
|
126
|
+
child.type == WhiteKey ? whiteNoteWidth : whiteNoteWidth * 0.65
|
|
127
|
+
const props = { ref: keyRefs.current[index], __width }
|
|
127
128
|
return React.cloneElement(child, props)
|
|
128
129
|
}
|
|
129
130
|
return child
|
|
130
131
|
})
|
|
131
132
|
)
|
|
132
|
-
}, [children])
|
|
133
|
+
}, [children, whiteNoteWidth])
|
|
133
134
|
|
|
134
135
|
// --- internal functions ---
|
|
135
136
|
const notePosition = useCallback(
|
|
@@ -149,10 +150,8 @@ export function Piano({
|
|
|
149
150
|
B: 6,
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
const
|
|
153
|
-
const blackNoteWidth = defaultBlackKeyWidth
|
|
153
|
+
const blackNoteWidth = whiteNoteWidth * blackPerWhiteWidth
|
|
154
154
|
const padding = 1
|
|
155
|
-
|
|
156
155
|
const targetNoteKey = noteKey(note)
|
|
157
156
|
const firstNoteKey = noteKey(noteRange.first)
|
|
158
157
|
const octave = Math.floor((note - noteRange.first) / 12)
|
|
@@ -163,7 +162,7 @@ export function Piano({
|
|
|
163
162
|
const blackKeyOffset = isBlackKey(note) ? blackNoteWidth / 2 : 0
|
|
164
163
|
return pos * w + (octave + octaveOffset) * 7 * w - blackKeyOffset
|
|
165
164
|
},
|
|
166
|
-
[noteRange.first],
|
|
165
|
+
[noteRange.first, whiteNoteWidth],
|
|
167
166
|
)
|
|
168
167
|
|
|
169
168
|
const getHitKeyIndex = useCallback(
|
|
@@ -174,7 +173,9 @@ export function Piano({
|
|
|
174
173
|
for (let i = 0; i < notes.length; i++) {
|
|
175
174
|
const note = notes[i]
|
|
176
175
|
const pos = notePosition(note)
|
|
177
|
-
const w = isWhiteKey(note)
|
|
176
|
+
const w = isWhiteKey(note)
|
|
177
|
+
? whiteNoteWidth
|
|
178
|
+
: whiteNoteWidth * blackPerWhiteWidth
|
|
178
179
|
const h = isWhiteKey(note) ? containerHeight : containerHeight * 0.6
|
|
179
180
|
if (pos <= x && x < pos + w && 0 <= y && y < h) {
|
|
180
181
|
return note
|
|
@@ -182,7 +183,7 @@ export function Piano({
|
|
|
182
183
|
}
|
|
183
184
|
return -1
|
|
184
185
|
},
|
|
185
|
-
[blackNotes, notePosition, whiteNotes],
|
|
186
|
+
[blackNotes, notePosition, whiteNoteWidth, whiteNotes],
|
|
186
187
|
)
|
|
187
188
|
|
|
188
189
|
// TODO: 単一のポインターに対しては、useDragで対応可能だが、
|
|
@@ -259,6 +260,7 @@ export function Piano({
|
|
|
259
260
|
|
|
260
261
|
return (
|
|
261
262
|
<PianoProvider
|
|
263
|
+
notePosition={notePosition}
|
|
262
264
|
noteRange={noteRange}
|
|
263
265
|
glissando={glissando}
|
|
264
266
|
midiMax={midiMax}
|
|
@@ -285,18 +287,20 @@ export function Piano({
|
|
|
285
287
|
{...props}
|
|
286
288
|
>
|
|
287
289
|
{childrenWithProps ||
|
|
288
|
-
|
|
290
|
+
noteRangeArray.map((note, index) =>
|
|
289
291
|
isWhiteKey(note) ? (
|
|
290
292
|
<WhiteKey
|
|
291
293
|
ref={keyRefs.current[index]}
|
|
292
294
|
key={note}
|
|
293
295
|
noteNumber={note}
|
|
296
|
+
__width={whiteNoteWidth}
|
|
294
297
|
/>
|
|
295
298
|
) : (
|
|
296
299
|
<BlackKey
|
|
297
300
|
ref={keyRefs.current[index]}
|
|
298
301
|
key={note}
|
|
299
302
|
noteNumber={note}
|
|
303
|
+
__width={whiteNoteWidth * blackPerWhiteWidth}
|
|
300
304
|
/>
|
|
301
305
|
),
|
|
302
306
|
)}
|