@tremolo-ui/react 0.0.9 → 0.0.11

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.
Files changed (148) hide show
  1. package/dist/cjs/index.js +434 -271
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +9 -4
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/AnimationKnob/index.d.ts +2 -0
  6. package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -1
  7. package/dist/cjs/types/components/DragObserver/index.d.ts +3 -1
  8. package/dist/cjs/types/components/DragObserver/index.d.ts.map +1 -1
  9. package/dist/cjs/types/components/Knob/index.d.ts +2 -0
  10. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  11. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts +7 -0
  12. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
  13. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts +7 -0
  14. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
  15. package/dist/cjs/types/components/NumberInput/Stepper.d.ts +8 -0
  16. package/dist/cjs/types/components/NumberInput/Stepper.d.ts.map +1 -0
  17. package/dist/cjs/types/components/NumberInput/context.d.ts +27 -0
  18. package/dist/cjs/types/components/NumberInput/context.d.ts.map +1 -0
  19. package/dist/cjs/types/components/NumberInput/index.d.ts +31 -16
  20. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  21. package/dist/cjs/types/components/Piano/BlackKey.d.ts +1 -0
  22. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
  23. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +2 -0
  24. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
  25. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +2 -0
  26. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
  27. package/dist/cjs/types/components/Piano/index.d.ts +6 -4
  28. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
  29. package/dist/cjs/types/components/Piano/key.d.ts +8 -2
  30. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
  31. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +2 -0
  32. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  33. package/dist/cjs/types/components/Slider/Scale.d.ts +2 -0
  34. package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -1
  35. package/dist/cjs/types/components/Slider/ScaleOption.d.ts +2 -0
  36. package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +1 -1
  37. package/dist/cjs/types/components/Slider/Thumb.d.ts +4 -0
  38. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  39. package/dist/cjs/types/components/Slider/Track.d.ts +4 -1
  40. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  41. package/dist/cjs/types/components/Slider/context.d.ts +7 -12
  42. package/dist/cjs/types/components/Slider/context.d.ts.map +1 -1
  43. package/dist/cjs/types/components/Slider/index.d.ts +8 -5
  44. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  45. package/dist/cjs/types/components/WheelObserver/index.d.ts +1 -0
  46. package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -1
  47. package/dist/cjs/types/components/XYPad/Area.d.ts +2 -0
  48. package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -1
  49. package/dist/cjs/types/components/XYPad/Thumb.d.ts +3 -0
  50. package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -1
  51. package/dist/cjs/types/components/XYPad/index.d.ts +4 -0
  52. package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -1
  53. package/dist/cjs/types/hooks/useAnimationFrame.d.ts +3 -0
  54. package/dist/cjs/types/hooks/useAnimationFrame.d.ts.map +1 -0
  55. package/dist/cjs/types/hooks/useDrag.d.ts +15 -0
  56. package/dist/cjs/types/hooks/useDrag.d.ts.map +1 -0
  57. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts +1 -4
  58. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
  59. package/dist/esm/index.js +432 -262
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/types/components/AnimationCanvas/index.d.ts +9 -4
  62. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  63. package/dist/esm/types/components/AnimationKnob/index.d.ts +2 -0
  64. package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -1
  65. package/dist/esm/types/components/DragObserver/index.d.ts +3 -1
  66. package/dist/esm/types/components/DragObserver/index.d.ts.map +1 -1
  67. package/dist/esm/types/components/Knob/index.d.ts +2 -0
  68. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  69. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts +7 -0
  70. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
  71. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts +7 -0
  72. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
  73. package/dist/esm/types/components/NumberInput/Stepper.d.ts +8 -0
  74. package/dist/esm/types/components/NumberInput/Stepper.d.ts.map +1 -0
  75. package/dist/esm/types/components/NumberInput/context.d.ts +27 -0
  76. package/dist/esm/types/components/NumberInput/context.d.ts.map +1 -0
  77. package/dist/esm/types/components/NumberInput/index.d.ts +31 -16
  78. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  79. package/dist/esm/types/components/Piano/BlackKey.d.ts +1 -0
  80. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
  81. package/dist/esm/types/components/Piano/KeyLabel.d.ts +2 -0
  82. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
  83. package/dist/esm/types/components/Piano/WhiteKey.d.ts +2 -0
  84. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
  85. package/dist/esm/types/components/Piano/index.d.ts +6 -4
  86. package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
  87. package/dist/esm/types/components/Piano/key.d.ts +8 -2
  88. package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
  89. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +2 -0
  90. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  91. package/dist/esm/types/components/Slider/Scale.d.ts +2 -0
  92. package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -1
  93. package/dist/esm/types/components/Slider/ScaleOption.d.ts +2 -0
  94. package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +1 -1
  95. package/dist/esm/types/components/Slider/Thumb.d.ts +4 -0
  96. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  97. package/dist/esm/types/components/Slider/Track.d.ts +4 -1
  98. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  99. package/dist/esm/types/components/Slider/context.d.ts +7 -12
  100. package/dist/esm/types/components/Slider/context.d.ts.map +1 -1
  101. package/dist/esm/types/components/Slider/index.d.ts +8 -5
  102. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  103. package/dist/esm/types/components/WheelObserver/index.d.ts +1 -0
  104. package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -1
  105. package/dist/esm/types/components/XYPad/Area.d.ts +2 -0
  106. package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -1
  107. package/dist/esm/types/components/XYPad/Thumb.d.ts +3 -0
  108. package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -1
  109. package/dist/esm/types/components/XYPad/index.d.ts +4 -0
  110. package/dist/esm/types/components/XYPad/index.d.ts.map +1 -1
  111. package/dist/esm/types/hooks/useAnimationFrame.d.ts +3 -0
  112. package/dist/esm/types/hooks/useAnimationFrame.d.ts.map +1 -0
  113. package/dist/esm/types/hooks/useDrag.d.ts +15 -0
  114. package/dist/esm/types/hooks/useDrag.d.ts.map +1 -0
  115. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts +1 -4
  116. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
  117. package/dist/styles/index.css +110 -14
  118. package/package.json +41 -37
  119. package/src/components/AnimationCanvas/index.tsx +14 -5
  120. package/src/components/AnimationKnob/index.tsx +24 -42
  121. package/src/components/DragObserver/index.tsx +14 -52
  122. package/src/components/Knob/index.tsx +23 -40
  123. package/src/components/NumberInput/DecrementStepper.tsx +52 -0
  124. package/src/components/NumberInput/IncrementStepper.tsx +52 -0
  125. package/src/components/NumberInput/Stepper.tsx +25 -0
  126. package/src/components/NumberInput/context.tsx +150 -0
  127. package/src/components/NumberInput/index.css +102 -14
  128. package/src/components/NumberInput/index.tsx +164 -55
  129. package/src/components/Piano/BlackKey.tsx +13 -10
  130. package/src/components/Piano/KeyLabel.tsx +2 -0
  131. package/src/components/Piano/WhiteKey.tsx +14 -10
  132. package/src/components/Piano/index.tsx +14 -12
  133. package/src/components/Piano/key.ts +8 -2
  134. package/src/components/Piano/keyboardShortcuts.ts +2 -0
  135. package/src/components/Slider/Scale.tsx +8 -6
  136. package/src/components/Slider/ScaleOption.tsx +8 -6
  137. package/src/components/Slider/Thumb.tsx +9 -3
  138. package/src/components/Slider/Track.tsx +25 -15
  139. package/src/components/Slider/context.tsx +50 -51
  140. package/src/components/Slider/index.css +8 -0
  141. package/src/components/Slider/index.tsx +20 -10
  142. package/src/components/WheelObserver/index.tsx +1 -0
  143. package/src/components/XYPad/Area.tsx +2 -0
  144. package/src/components/XYPad/Thumb.tsx +3 -0
  145. package/src/components/XYPad/index.tsx +6 -2
  146. package/src/hooks/useAnimationFrame.ts +18 -0
  147. package/src/hooks/useDrag.ts +92 -0
  148. package/src/hooks/useRefCallbackEvent.ts +4 -7
@@ -1,5 +1,6 @@
1
1
  import React, { ReactElement } from 'react';
2
2
  import { InputEventOption } from '@tremolo-ui/functions';
3
+ /** @category XYPad */
3
4
  export interface ValueOptions {
4
5
  value: number;
5
6
  min: number;
@@ -16,6 +17,7 @@ export interface ValueOptions {
16
17
  */
17
18
  keyboard?: InputEventOption | null;
18
19
  }
20
+ /** @category XYPad */
19
21
  export interface XYPadProps {
20
22
  x: ValueOptions;
21
23
  y: ValueOptions;
@@ -26,12 +28,14 @@ export interface XYPadProps {
26
28
  /** \<XYPadThumb /> | \<XYPadArea /> */
27
29
  children?: ReactElement | ReactElement[];
28
30
  }
31
+ /** @category XYPad */
29
32
  export interface XYPadMethods {
30
33
  focus: () => void;
31
34
  blur: () => void;
32
35
  }
33
36
  /**
34
37
  * Simple XYPad
38
+ * @category XYPad
35
39
  */
36
40
  export declare const XYPad: React.ForwardRefExoticComponent<XYPadProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof XYPadProps> & React.RefAttributes<XYPadMethods>>;
37
41
  export * from './Thumb';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/XYPad/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAGZ,YAAY,EAKb,MAAM,OAAO,CAAA;AAEd,OAAO,EAML,gBAAgB,EAEjB,MAAM,uBAAuB,CAAA;AAS9B,MAAM,WAAW,YAAY;IAE3B,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,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC/B;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,YAAY,CAAA;IACf,CAAC,EAAE,YAAY,CAAA;IAEf,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD,uCAAuC;IACvC,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAA;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAaD;;GAEG;AACH,eAAO,MAAM,KAAK,sMA0OjB,CAAA;AAED,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/XYPad/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAGZ,YAAY,EAKb,MAAM,OAAO,CAAA;AAEd,OAAO,EAML,gBAAgB,EAEjB,MAAM,uBAAuB,CAAA;AAS9B,sBAAsB;AACtB,MAAM,WAAW,YAAY;IAE3B,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,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC/B;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACnC;AAED,sBAAsB;AACtB,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,YAAY,CAAA;IACf,CAAC,EAAE,YAAY,CAAA;IAEf,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD,uCAAuC;IACvC,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAA;CACzC;AAED,sBAAsB;AACtB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAaD;;;GAGG;AACH,eAAO,MAAM,KAAK,sMA0OjB,CAAA;AAED,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { DependencyList } from 'react';
2
+ export declare const useAnimationFrame: (callback?: () => void, deps?: DependencyList) => void;
3
+ //# sourceMappingURL=useAnimationFrame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAnimationFrame.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useAnimationFrame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAkC,MAAM,OAAO,CAAA;AAEtE,eAAO,MAAM,iBAAiB,GAC5B,qBAAmB,EACnB,OAAM,cAAmB,SAa1B,CAAA"}
@@ -0,0 +1,15 @@
1
+ interface Props {
2
+ threshold?: number;
3
+ onDrag: (x: number, y: number, deltaX: number, deltaY: number) => void;
4
+ onDragStart?: () => void;
5
+ onDragEnd?: () => void;
6
+ }
7
+ /**
8
+ * @returns [refCallback, pointerDownHandler]
9
+ */
10
+ export declare function useDrag<T extends Element>({ threshold, onDrag, onDragStart, onDragEnd, }: Props): [
11
+ (div: EventTarget | null) => void,
12
+ (event: React.PointerEvent<T>) => void
13
+ ];
14
+ export {};
15
+ //# sourceMappingURL=useDrag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDrag.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useDrag.ts"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACtE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EACzC,SAAa,EACb,MAAM,EACN,WAAW,EACX,SAAS,GACV,EAAE,KAAK,GAAG;IACT,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI;IACjC,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI;CACvC,CAmEA"}
@@ -1,5 +1,2 @@
1
- type Options = boolean | AddEventListenerOptions;
2
- type CallbackFunc = (div: EventTarget | null) => void;
3
- export declare function useRefCallbackEvent<K extends keyof DocumentEventMap>(event: K, handler: (event: DocumentEventMap[K]) => void, options?: Options, deps?: React.DependencyList): CallbackFunc;
4
- export {};
1
+ export declare function useRefCallbackEvent<K extends keyof DocumentEventMap>(event: K, handler: (event: DocumentEventMap[K]) => void, options?: boolean | AddEventListenerOptions, deps?: React.DependencyList): (div: EventTarget | null) => void;
5
2
  //# sourceMappingURL=useRefCallbackEvent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useRefCallbackEvent.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useRefCallbackEvent.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG,OAAO,GAAG,uBAAuB,CAAA;AAChD,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;AAErD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAClE,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,OAAO,EACjB,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,GAC1B,YAAY,CAAA"}
1
+ {"version":3,"file":"useRefCallbackEvent.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useRefCallbackEvent.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAClE,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,EAC3C,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,GAC1B,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA"}
@@ -56,31 +56,119 @@
56
56
  color: #eee;
57
57
  }
58
58
 
59
- .tremolo-number-input {
60
- display: inline-block;
61
- background-color: inherit;
62
- font: inherit;
63
- margin: 0px;
64
- padding-top: 6px;
65
- padding-bottom: 6px;
66
- padding-left: 10px;
67
- padding-right: 10px;
59
+ .tremolo-number-input-wrapper {
60
+ --tremolo-number-input-border-radius: 4px;
61
+ --tremolo-number-input-stepper-width: 20px;
62
+
63
+ display: inline-flex;
64
+ flex-direction: row;
65
+ position: relative;
66
+
68
67
  border-style: solid;
69
68
  border-width: 1px;
70
69
  border-color: #bbb;
71
- border-radius: 4px;
72
- outline: 0px;
73
- transition: all 0.1s linear;
74
- appearance: textfield;
70
+ border-radius: var(--tremolo-number-input-border-radius);
71
+
72
+ width: 140px;
73
+ height: min-content;
75
74
 
76
75
  &:hover {
77
76
  border-color: var(--tremolo-theme-color);
78
77
  }
79
78
 
80
- &:focus {
79
+ &:not(:focus-within):has(> .tremolo-number-input[data-error='true']) {
80
+ border-color: #f34343;
81
+ }
82
+
83
+ &:focus-within {
81
84
  border-color: var(--tremolo-theme-color);
82
85
  box-shadow: 0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1);
83
86
  }
87
+
88
+ &[data-stepper='false'] {
89
+ --tremolo-number-input-stepper-width: 0px;
90
+ }
91
+ }
92
+
93
+ .tremolo-number-input {
94
+ display: block;
95
+ width: calc(100% - 20px - var(--tremolo-number-input-stepper-width));
96
+ background-color: inherit;
97
+ font: inherit;
98
+ padding: 6px 10px;
99
+
100
+ margin: 0;
101
+ border: none;
102
+ outline: none;
103
+ appearance: textfield;
104
+ }
105
+
106
+ .tremolo-number-input-stepper {
107
+ display: flex;
108
+ flex-direction: column;
109
+ height: 100%;
110
+ position: absolute;
111
+ top: 0;
112
+ right: 0;
113
+ width: var(--tremolo-number-input-stepper-width);
114
+ transition: all 0.1s linear;
115
+
116
+ &[data-dynamic='true'] {
117
+ opacity: 0;
118
+ transform: translateX(40%);
119
+ }
120
+ }
121
+
122
+ .tremolo-number-input-wrapper:hover .tremolo-number-input-stepper {
123
+ opacity: 1;
124
+ transform: translateX(0);
125
+ }
126
+
127
+ .tremolo-number-input-increment-stepper {
128
+ border-inline-start-width: 1px;
129
+ border-inline-start-style: solid;
130
+ border-inline-start-color: #ccc;
131
+ font-size: calc(0.75rem);
132
+ display: flex;
133
+ justify-content: center;
134
+ align-items: center;
135
+ flex: 1 1 0%;
136
+ max-height: 50%;
137
+ user-select: none;
138
+ cursor: pointer;
139
+ border-top-right-radius: var(--tremolo-number-input-border-radius);
140
+
141
+ &[aria-disabled='false']:active {
142
+ background-color: #3443560e;
143
+ }
144
+
145
+ &[aria-disabled='true'] {
146
+ cursor: not-allowed;
147
+ }
148
+ }
149
+
150
+ .tremolo-number-input-decrement-stepper {
151
+ border-inline-start-width: 1px;
152
+ border-inline-start-style: solid;
153
+ border-inline-start-color: #ccc;
154
+ border-top: 1px solid #ccc;
155
+ font-size: calc(0.75rem);
156
+ display: flex;
157
+ justify-content: center;
158
+ align-items: center;
159
+ flex: 1 1 0%;
160
+ max-height: 50%;
161
+ user-select: none;
162
+ cursor: pointer;
163
+ border-bottom-right-radius: var(--tremolo-number-input-border-radius);
164
+
165
+ &[aria-disabled='false']:active {
166
+ background-color: #3443560e;
167
+ }
168
+
169
+ &[aria-disabled='true'] {
170
+ cursor: not-allowed;
171
+ }
84
172
  }
85
173
 
86
174
  .tremolo-piano {
@@ -184,6 +272,14 @@
184
272
 
185
273
  position: relative;
186
274
 
275
+ &[data-vertical='false'] {
276
+ min-width: 50px;
277
+ }
278
+
279
+ &[data-vertical='true'] {
280
+ min-height: 50px;
281
+ }
282
+
187
283
  &:hover {
188
284
  --active: #6387e9;
189
285
  --inactive: #e0e0e0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tremolo-ui/react",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "React component library for audio app",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -8,28 +8,43 @@
8
8
  "types": "dist/cjs/types/index.d.ts",
9
9
  "scripts": {
10
10
  "sb": "storybook dev -p 6006",
11
+ "typecheck": "tsc",
11
12
  "build:sb": "storybook build",
12
13
  "serve": "http-server ./storybook-static",
13
14
  "lint": "eslint --fix --ext .ts,.tsx .",
14
15
  "format": "prettier --write .",
15
16
  "test": "echo 'No test yet.'",
16
- "build:package": "rollup -c",
17
+ "build:package": "tsc && rollup -c",
17
18
  "clean": "npm run clean:build && npm run clean:sb",
18
19
  "clean:build": "rimraf ./dist .rollup.cache",
19
20
  "clean:sb": "rimraf ./storybook-static"
20
21
  },
21
- "exports": {
22
- ".": {
23
- "require": {
24
- "types": "./dist/cjs/types/index.d.ts",
25
- "default": "./dist/cjs/index.js"
26
- },
27
- "import": {
28
- "types": "./dist/esm/types/index.d.ts",
29
- "default": "./dist/esm/index.js"
30
- }
31
- },
32
- "./styles/index.css": "./dist/styles/index.css"
22
+ "devDependencies": {
23
+ "@storybook/addon-essentials": "^8.6.7",
24
+ "@storybook/addon-interactions": "^8.6.7",
25
+ "@storybook/addon-links": "^8.6.7",
26
+ "@storybook/blocks": "^8.6.7",
27
+ "@storybook/react": "^8.6.7",
28
+ "@storybook/react-vite": "^8.6.7",
29
+ "@storybook/test": "^8.6.7",
30
+ "@testing-library/react": "^16.0.1",
31
+ "@types/react": "^19.0.10",
32
+ "@types/react-dom": "^19.0.4",
33
+ "jest-environment-jsdom": "^29.7.0",
34
+ "jotai": "^2.12.1",
35
+ "react": "19.x",
36
+ "react-dom": "19.x",
37
+ "storybook": "^8.6.7",
38
+ "tone": "^15.0.4"
39
+ },
40
+ "peerDependencies": {
41
+ "react": "^18 ||^19",
42
+ "react-dom": "^18 || ^19"
43
+ },
44
+ "dependencies": {
45
+ "@tremolo-ui/functions": "0.0.11",
46
+ "clsx": "^2.1.1",
47
+ "zustand": "^5.0.3"
33
48
  },
34
49
  "files": [
35
50
  "dist",
@@ -56,28 +71,17 @@
56
71
  "components",
57
72
  "web-audio"
58
73
  ],
59
- "devDependencies": {
60
- "@storybook/addon-essentials": "^8.3.3",
61
- "@storybook/addon-interactions": "^8.3.3",
62
- "@storybook/addon-links": "^8.3.3",
63
- "@storybook/blocks": "^8.3.3",
64
- "@storybook/react": "^8.3.3",
65
- "@storybook/react-vite": "^8.3.3",
66
- "@storybook/test": "^8.3.3",
67
- "@testing-library/react": "^16.0.1",
68
- "jest-environment-jsdom": "^29.7.0",
69
- "react": "^18.3.1",
70
- "react-component-benchmark": "^2.0.0",
71
- "react-dom": "^18.3.1",
72
- "storybook": "^8.3.3",
73
- "tone": "^15.0.4"
74
- },
75
- "peerDependencies": {
76
- "react": "18.x || 19.x",
77
- "react-dom": "18.x || 19.x"
78
- },
79
- "dependencies": {
80
- "@tremolo-ui/functions": "file:../functions",
81
- "clsx": "^2.1.1"
74
+ "exports": {
75
+ ".": {
76
+ "require": {
77
+ "types": "./dist/cjs/types/index.d.ts",
78
+ "default": "./dist/cjs/index.js"
79
+ },
80
+ "import": {
81
+ "types": "./dist/esm/types/index.d.ts",
82
+ "default": "./dist/esm/index.js"
83
+ }
84
+ },
85
+ "./styles/index.css": "./dist/styles/index.css"
82
86
  }
83
87
  }
@@ -24,14 +24,18 @@ function setDprConfig(
24
24
  canvas.style.height = `${height}px`
25
25
  }
26
26
 
27
+ /** @category AnimationCanvas */
27
28
  export type DrawFunction = (
29
+ // TODO: saving scale and translate
30
+ // context: Omit<CanvasRenderingContext2D, 'save' | 'restore' | 'scale'>,
28
31
  context: CanvasRenderingContext2D,
29
32
  width: MutableRefObject<number>,
30
33
  height: MutableRefObject<number>,
31
34
  count: number,
32
35
  ) => void
33
36
 
34
- interface CommonProps {
37
+ /** @category AnimationCanvas */
38
+ export interface CommonProps {
35
39
  /**
36
40
  * @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes
37
41
  */
@@ -40,22 +44,26 @@ interface CommonProps {
40
44
  draw: DrawFunction
41
45
  }
42
46
 
43
- interface AbsoluteSizingProps {
47
+ /** @category AnimationCanvas */
48
+ export interface AbsoluteSizingProps {
44
49
  width?: number
45
50
  height?: number
46
51
  }
47
52
 
48
- interface RelativeSizingProps {
53
+ /** @category AnimationCanvas */
54
+ export interface RelativeSizingProps {
49
55
  relativeSize?: boolean
50
56
  reduceFlickering?: boolean
51
57
  }
52
58
 
59
+ /** @category AnimationCanvas */
53
60
  export type AnimationCanvasProps = AbsoluteSizingProps &
54
61
  RelativeSizingProps &
55
62
  CommonProps
56
63
 
57
64
  /**
58
65
  * A simple animatable canvas with requestAnimationFrame()
66
+ * @category AnimationCanvas
59
67
  */
60
68
  export function AnimationCanvas(
61
69
  props: AbsoluteSizingProps &
@@ -84,7 +92,7 @@ export function AnimationCanvas({
84
92
  >): ReactElement {
85
93
  const canvasRef = useRef<HTMLCanvasElement>(null)
86
94
  const memoCanvasRef = useRef<HTMLCanvasElement>(null)
87
- const reqIdRef = useRef<number>()
95
+ const reqIdRef = useRef(-1)
88
96
  const widthRef = useRef(0)
89
97
  const heightRef = useRef(0)
90
98
 
@@ -108,7 +116,7 @@ export function AnimationCanvas({
108
116
  const canvas = canvasRef.current
109
117
  const context = canvas.getContext('2d', options)
110
118
  if (!context) throw new Error('Cannot get canvas context.')
111
- const dpr = window.devicePixelRatio
119
+ const dpr = globalThis.window.devicePixelRatio
112
120
 
113
121
  if (relativeSize) {
114
122
  const parent = canvas.parentElement
@@ -122,6 +130,7 @@ export function AnimationCanvas({
122
130
  // 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
123
131
  for (const entry of entries) {
124
132
  // Prevents loss of some context when the canvas is resized
133
+ // TODO: saving scale and translate
125
134
  const contextMemo = {} as DrawingContext
126
135
  for (const prop of drawingState) {
127
136
  ;(contextMemo[prop] as DrawingStateValue) = context[prop]
@@ -15,11 +15,12 @@ import {
15
15
  InputEventOption,
16
16
  } from '@tremolo-ui/functions'
17
17
 
18
- import { useEventListener } from '../../hooks/useEventListener'
18
+ import { useDrag } from '../../hooks/useDrag'
19
19
  import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
20
20
  import { addNoSelect, removeNoSelect } from '../_util'
21
21
  import { AnimationCanvas, DrawFunction } from '../AnimationCanvas'
22
22
 
23
+ /** @category AnimationKnob */
23
24
  export type AnimationKnobProps = {
24
25
  // required
25
26
  value: number
@@ -77,6 +78,7 @@ export type AnimationKnobProps = {
77
78
 
78
79
  /**
79
80
  * simple rotary Knob.
81
+ * @category AnimationKnob
80
82
  */
81
83
  export function AnimationKnob({
82
84
  value,
@@ -107,35 +109,21 @@ export function AnimationKnob({
107
109
  }: AnimationKnobProps &
108
110
  Omit<ComponentPropsWithoutRef<'div'>, keyof AnimationKnobProps>) {
109
111
  // -- state and ref ---
110
- // const [privateValue, setPrivateValue] = useState(value);
111
- const dragOffsetY = useRef<number | undefined>(undefined)
112
+ const valueRef = useRef(0)
112
113
 
113
114
  // --- interpret props ---
114
- // const percent = normalizeValue(value, min, max, skew)
115
-
116
115
  const isRelativeSize =
117
116
  typeof (size ?? width) == 'string' || typeof height == 'string'
118
117
 
119
- const handleEvent = (
120
- event:
121
- | MouseEvent
122
- | React.MouseEvent<HTMLDivElement, MouseEvent>
123
- | TouchEvent,
124
- ) => {
125
- const isTouch = event instanceof TouchEvent
126
- if (isTouch && event.cancelable) event.preventDefault()
127
- if (dragOffsetY.current) {
128
- if (bodyNoSelect) addNoSelect()
129
- const screenY = isTouch ? event.touches[0].screenY : event.screenY
130
- const delta = dragOffsetY.current - screenY
131
- if (Math.abs(delta) < 1) return
132
- dragOffsetY.current = screenY
133
- const n = normalizeValue(value, min, max, skew)
134
- const v = rawValue(n + delta / 100, min, max, skew)
118
+ const onDrag = useCallback(
119
+ (_x: number, y: number) => {
120
+ if (!onChange) return
121
+ const v = rawValue(valueRef.current - y / 100, min, max, skew)
135
122
  const v2 = clamp(stepValue(v, step), min, max)
136
- if (onChange) onChange(v2)
137
- }
138
- }
123
+ onChange(v2)
124
+ },
125
+ [max, min, onChange, skew, step],
126
+ )
139
127
 
140
128
  const handleKeyDown = useCallback(
141
129
  (event: React.KeyboardEvent<HTMLDivElement>) => {
@@ -159,6 +147,17 @@ export function AnimationKnob({
159
147
  )
160
148
 
161
149
  // --- hooks ---
150
+ const [touchMoveRefCallback, pointerDownHandler] = useDrag<HTMLDivElement>({
151
+ onDrag: onDrag,
152
+ onDragStart: () => {
153
+ valueRef.current = normalizeValue(value, min, max, skew)
154
+ if (bodyNoSelect) addNoSelect()
155
+ },
156
+ onDragEnd: () => {
157
+ if (bodyNoSelect) removeNoSelect()
158
+ },
159
+ })
160
+
162
161
  const wheelRefCallback = useRefCallbackEvent(
163
162
  'wheel',
164
163
  (event) => {
@@ -178,20 +177,6 @@ export function AnimationKnob({
178
177
  [wheel, value, min, max, skew, step, onChange],
179
178
  )
180
179
 
181
- const touchMoveRefCallback = useRefCallbackEvent(
182
- 'touchmove',
183
- handleEvent,
184
- { passive: false },
185
- [value, min, max, skew, step, onChange, bodyNoSelect],
186
- )
187
-
188
- useEventListener(window, 'mousemove', handleEvent)
189
-
190
- useEventListener(window, 'pointerup', () => {
191
- dragOffsetY.current = undefined
192
- if (bodyNoSelect) removeNoSelect()
193
- })
194
-
195
180
  return (
196
181
  <div
197
182
  className={clsx('tremolo-animation-knob', className)}
@@ -212,10 +197,7 @@ export function AnimationKnob({
212
197
  WebkitTapHighlightColor: 'transparent',
213
198
  ...style,
214
199
  }}
215
- onPointerDown={(event) => {
216
- dragOffsetY.current = event.screenY
217
- handleEvent(event)
218
- }}
200
+ onPointerDown={pointerDownHandler}
219
201
  onDoubleClick={() => {
220
202
  if (enableDoubleClickDefault && onChange) {
221
203
  onChange(defaultValue)
@@ -1,8 +1,8 @@
1
- import { ComponentPropsWithoutRef, ElementType, ReactNode, useRef } from 'react'
1
+ import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react'
2
2
 
3
- import { useEventListener } from '../../hooks/useEventListener'
4
- import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
3
+ import { useDrag } from '../../hooks/useDrag'
5
4
 
5
+ /** @category DragObserver */
6
6
  export interface DragObserverProps<T extends ElementType> {
7
7
  /**
8
8
  * React.ElementType
@@ -17,75 +17,37 @@ export interface DragObserverProps<T extends ElementType> {
17
17
  threshold?: number
18
18
 
19
19
  children?: ReactNode
20
- onDrag: (x: number, y: number) => void
20
+ onDrag: (x: number, y: number, deltaX: number, deltaY: number) => void
21
21
  onDragStart?: () => void
22
22
  onDragEnd?: () => void
23
23
  }
24
24
 
25
+ /** @category DragObserver */
25
26
  export function DragObserver<T extends ElementType = 'div'>(
26
27
  props: DragObserverProps<T> &
27
28
  Omit<ComponentPropsWithoutRef<T>, keyof DragObserverProps<T>>,
28
29
  ) {
29
30
  const {
31
+ as: Component = 'div',
32
+ threshold = 1,
30
33
  children,
31
34
  onDrag,
32
35
  onDragStart,
33
36
  onDragEnd,
34
- as: Component = 'div',
35
37
  ...attributes
36
38
  } = props
37
39
 
38
- const dragOffsetX = useRef<number | undefined>(undefined)
39
- const dragOffsetY = useRef<number | undefined>(undefined)
40
-
41
- const handleEvent = (
42
- event:
43
- | MouseEvent
44
- | React.MouseEvent<HTMLDivElement, MouseEvent>
45
- | TouchEvent,
46
- ) => {
47
- const isTouch = event instanceof TouchEvent
48
- if (isTouch && event.cancelable) event.preventDefault()
49
- const screenX = isTouch ? event.touches[0].screenX : event.screenX
50
- const screenY = isTouch ? event.touches[0].screenY : event.screenY
51
- let deltaX = 0,
52
- deltaY = 0
53
- if (dragOffsetX.current) {
54
- deltaX = screenX - dragOffsetX.current
55
- dragOffsetX.current = screenX
56
- }
57
- if (dragOffsetY.current) {
58
- deltaY = screenY - dragOffsetY.current
59
- dragOffsetY.current = screenY
60
- }
61
- if (Math.abs(deltaX) < 1 && Math.abs(deltaY) < 1) return
62
- if (onDrag) onDrag(deltaX, deltaY)
63
- }
64
-
65
- const touchMoveRefCallback = useRefCallbackEvent(
66
- 'touchmove',
67
- handleEvent,
68
- { passive: false },
69
- [onDrag],
70
- )
71
-
72
- useEventListener(window, 'mousemove', handleEvent)
73
-
74
- useEventListener(window, 'pointerup', () => {
75
- dragOffsetX.current = undefined
76
- dragOffsetY.current = undefined
77
- onDragEnd?.()
40
+ const [refCallback, pointerDownHandler] = useDrag({
41
+ threshold: threshold,
42
+ onDrag: onDrag,
43
+ onDragStart: onDragStart,
44
+ onDragEnd: onDragEnd,
78
45
  })
79
46
 
80
47
  return (
81
48
  <Component
82
- ref={touchMoveRefCallback}
83
- onPointerDown={(event) => {
84
- dragOffsetX.current = event.screenX
85
- dragOffsetY.current = event.screenY
86
- handleEvent(event)
87
- onDragStart?.()
88
- }}
49
+ ref={refCallback}
50
+ onPointerDown={pointerDownHandler}
89
51
  {...attributes}
90
52
  >
91
53
  {children}