@tremolo-ui/vue 0.7.0 → 0.9.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.
Files changed (47) hide show
  1. package/dist/index.cjs +865 -611
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +934 -169
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +934 -169
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +339 -128
  8. package/dist/index.js.map +1 -1
  9. package/package.json +8 -8
  10. package/src/components/AnimationCanvas/AnimationCanvas.ts +27 -30
  11. package/src/components/AnimationCanvas/index.ts +1 -5
  12. package/src/components/DropZone/DropZone.ts +19 -9
  13. package/src/components/DropZone/index.ts +1 -1
  14. package/src/components/FileInput/FileInput.ts +28 -14
  15. package/src/components/FileInput/index.ts +1 -1
  16. package/src/components/Knob/Knob.ts +107 -57
  17. package/src/components/Knob/KnobThumb.ts +32 -22
  18. package/src/components/Knob/index.ts +2 -2
  19. package/src/components/NumberInput/NumberInput.ts +136 -53
  20. package/src/components/NumberInput/NumberInputField.ts +5 -2
  21. package/src/components/NumberInput/NumberInputStepper.ts +25 -4
  22. package/src/components/NumberInput/context.ts +12 -0
  23. package/src/components/NumberInput/index.ts +1 -1
  24. package/src/components/NumberInput/stepper-button.ts +8 -1
  25. package/src/components/Piano/Piano.ts +51 -43
  26. package/src/components/Piano/index.ts +6 -1
  27. package/src/components/PointsEditor/PointsEditor.ts +43 -35
  28. package/src/components/PointsEditor/PointsEditorContainer.ts +2 -6
  29. package/src/components/PointsEditor/PointsEditorPoint.ts +82 -42
  30. package/src/components/PointsEditor/context.ts +1 -1
  31. package/src/components/PointsEditor/index.ts +5 -2
  32. package/src/components/Slider/Slider.ts +92 -49
  33. package/src/components/Slider/SliderMarks.ts +28 -14
  34. package/src/components/Slider/SliderMarksOption.ts +54 -33
  35. package/src/components/Slider/SliderThumb.ts +26 -8
  36. package/src/components/Slider/SliderTrack.ts +31 -16
  37. package/src/components/Slider/context.ts +1 -1
  38. package/src/components/Slider/index.ts +8 -5
  39. package/src/components/XYPad/XYPad.ts +94 -56
  40. package/src/components/XYPad/XYPadThumb.ts +21 -14
  41. package/src/components/XYPad/index.ts +2 -2
  42. package/src/components/_util/change-gesture.ts +44 -0
  43. package/src/components/_util/useCheckSteps.ts +1 -1
  44. package/src/components/_util/visually-hidden-range-input.ts +1 -1
  45. package/src/composables/useInstance.ts +1 -1
  46. package/src/composables/useWheel.ts +5 -2
  47. package/src/index.ts +21 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tremolo-ui/vue",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Vue component library for audio app",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -19,15 +19,15 @@
19
19
  "clean:sb": "rimraf ./storybook-static"
20
20
  },
21
21
  "devDependencies": {
22
- "@storybook/addon-a11y": "10.6.0",
23
- "@storybook/addon-docs": "10.6.0",
24
- "@storybook/vue3-vite": "10.6.0",
22
+ "@storybook/addon-a11y": "10.6.1",
23
+ "@storybook/addon-docs": "10.6.1",
24
+ "@storybook/vue3-vite": "10.6.1",
25
25
  "@testing-library/jest-dom": "7.0.1",
26
26
  "@testing-library/vue": "8.1.0",
27
27
  "@vitejs/plugin-vue": "6.0.9",
28
28
  "@vue/test-utils": "2.5.1",
29
- "esbuild": "0.28.1",
30
- "storybook": "10.6.0",
29
+ "esbuild": "0.28.2",
30
+ "storybook": "10.6.1",
31
31
  "vue-tsc": "3.3.11",
32
32
  "vue": "3.5.43"
33
33
  },
@@ -35,8 +35,8 @@
35
35
  "vue": "^3.5.0"
36
36
  },
37
37
  "dependencies": {
38
- "@tremolo-ui/dom": "^0.7.0",
39
- "@tremolo-ui/functions": "^0.7.0"
38
+ "@tremolo-ui/dom": "0.9.0",
39
+ "@tremolo-ui/functions": "^0.9.0"
40
40
  },
41
41
  "files": [
42
42
  "dist",
@@ -1,53 +1,50 @@
1
1
  import {
2
+ type ComponentObjectPropsOptions,
2
3
  defineComponent,
4
+ type ExtractPublicPropTypes,
3
5
  h,
6
+ type PropType,
4
7
  ref,
5
8
  shallowRef,
6
9
  watch,
7
10
  watchEffect,
8
- type PropType,
9
11
  } from 'vue'
10
12
 
11
13
  import {
12
14
  createAnimationCanvas,
13
15
  type AnimationCanvasInstance,
14
- type AnimationFrame,
16
+ type CanvasDrawFunction,
17
+ type CanvasInitFunction,
15
18
  } from '@tremolo-ui/dom'
16
19
 
17
- /** Called once the canvas is ready, and again whenever it is resized. */
18
- export type InitFunction = (
19
- context: CanvasRenderingContext2D,
20
- size: { width: number; height: number },
21
- ) => void
20
+ const animationCanvasProps = {
21
+ /** Draws a frame. */
22
+ draw: { type: Function as PropType<CanvasDrawFunction>, required: true },
23
+ /** Sets the canvas up, once, before the first frame. */
24
+ init: Function as PropType<CanvasInitFunction>,
25
+ /** Draw on every animation frame. @default true */
26
+ animate: { type: Boolean, default: true },
27
+ /** Settings for the 2D context. Read once, when the canvas is created. */
28
+ options: Object as PropType<CanvasRenderingContext2DSettings>,
29
+ /** Keep the drawing while the canvas is resized. @default true */
30
+ reduceFlickering: { type: Boolean, default: true },
31
+ /** Follow the size of the parent element; `width` and `height` are ignored. */
32
+ resizable: Boolean,
33
+ /** Width in CSS pixels, while not `resizable`. @default 100 */
34
+ width: { type: Number, default: 100 },
35
+ /** Height in CSS pixels, while not `resizable`. @default 100 */
36
+ height: { type: Number, default: 100 },
37
+ } satisfies ComponentObjectPropsOptions
22
38
 
23
- /** Called on every frame while `animate` is on, and once otherwise. */
24
- export type DrawFunction = (
25
- context: CanvasRenderingContext2D,
26
- frame: AnimationFrame,
27
- ) => void
39
+ export type AnimationCanvasProps = ExtractPublicPropTypes<
40
+ typeof animationCanvasProps
41
+ >
28
42
 
29
43
  /** A `<canvas>` drawn by `draw` on every animation frame. */
30
44
  export const AnimationCanvas = /* @__PURE__ */ defineComponent({
31
45
  name: 'AnimationCanvas',
32
46
  inheritAttrs: false,
33
- props: {
34
- /** Draws a frame. */
35
- draw: { type: Function as PropType<DrawFunction>, required: true },
36
- /** Sets the canvas up before the first frame and after a resize. */
37
- init: Function as PropType<InitFunction>,
38
- /** Draw on every animation frame. @default true */
39
- animate: { type: Boolean, default: true },
40
- /** Settings for the 2D context. Read once, when the canvas is created. */
41
- options: Object as PropType<CanvasRenderingContext2DSettings>,
42
- /** Keep the drawing while the canvas is resized. @default true */
43
- reduceFlickering: { type: Boolean, default: true },
44
- /** Follow the size of the parent element; `width` and `height` are ignored. */
45
- resizable: Boolean,
46
- /** Width in CSS pixels, while not `resizable`. @default 100 */
47
- width: { type: Number, default: 100 },
48
- /** Height in CSS pixels, while not `resizable`. @default 100 */
49
- height: { type: Number, default: 100 },
50
- },
47
+ props: animationCanvasProps,
51
48
  setup(props, { attrs }) {
52
49
  const canvas = ref<HTMLCanvasElement | null>(null)
53
50
  const instance = shallowRef<AnimationCanvasInstance | null>(null)
@@ -1,5 +1 @@
1
- export {
2
- AnimationCanvas,
3
- type DrawFunction,
4
- type InitFunction,
5
- } from './AnimationCanvas'
1
+ export { AnimationCanvas, type AnimationCanvasProps } from './AnimationCanvas'
@@ -1,18 +1,28 @@
1
- import { defineComponent, h, ref } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ defineComponent,
4
+ type ExtractPublicPropTypes,
5
+ h,
6
+ ref,
7
+ } from 'vue'
2
8
 
3
9
  import { useDropZone } from '../../composables/useDropZone'
4
10
 
11
+ const dropZoneProps = {
12
+ /** Which files to take, as the `accept` attribute of a file input. */
13
+ accept: String,
14
+ /** Take every file dropped, rather than the first. */
15
+ multiple: Boolean,
16
+ /** Ignore drops. The zone carries `data-disabled`. */
17
+ disabled: Boolean,
18
+ } satisfies ComponentObjectPropsOptions
19
+
20
+ export type DropZoneProps = ExtractPublicPropTypes<typeof dropZoneProps>
21
+
5
22
  /** A region that takes dropped files. */
6
23
  export const DropZone = /* @__PURE__ */ defineComponent({
7
24
  name: 'DropZone',
8
- props: {
9
- /** Which files to take, as the `accept` attribute of a file input. */
10
- accept: String,
11
- /** Take every file dropped, rather than the first. */
12
- multiple: Boolean,
13
- /** Ignore drops. The zone carries `data-disabled`. */
14
- disabled: Boolean,
15
- },
25
+ props: dropZoneProps,
16
26
  emits: {
17
27
  /** The dropped files that satisfy `accept`. */
18
28
  drop: (files: File[], _event: DragEvent) => Array.isArray(files),
@@ -1 +1 @@
1
- export { DropZone } from './DropZone'
1
+ export { DropZone, type DropZoneProps } from './DropZone'
@@ -1,9 +1,34 @@
1
- import { defineComponent, h, provide, useId } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ defineComponent,
4
+ type ExtractPublicPropTypes,
5
+ h,
6
+ provide,
7
+ useId,
8
+ } from 'vue'
2
9
 
3
- import { partitionByAccept, visuallyHiddenStyle } from '@tremolo-ui/dom'
10
+ import {
11
+ partitionByAccept,
12
+ visuallyHiddenStyle,
13
+ } from '@tremolo-ui/dom/internal'
4
14
 
5
15
  import { FileInputKey } from './context'
6
16
 
17
+ const fileInputProps = {
18
+ /**
19
+ * Which files to take: extensions, MIME types and type groups. It is
20
+ * checked again when the files arrive, since the picker only takes it as
21
+ * a hint.
22
+ */
23
+ accept: String,
24
+ /** Let several files be picked at once. */
25
+ multiple: Boolean,
26
+ /** Make the input unusable. The parts carry `data-disabled`. */
27
+ disabled: Boolean,
28
+ } satisfies ComponentObjectPropsOptions
29
+
30
+ export type FileInputProps = ExtractPublicPropTypes<typeof fileInputProps>
31
+
7
32
  /**
8
33
  * Picks files. The control is the native file input, out of sight but in the
9
34
  * tab order, with `FileInputTrigger` as its label.
@@ -11,18 +36,7 @@ import { FileInputKey } from './context'
11
36
  export const FileInput = /* @__PURE__ */ defineComponent({
12
37
  name: 'FileInput',
13
38
  inheritAttrs: false,
14
- props: {
15
- /**
16
- * Which files to take: extensions, MIME types and type groups. It is
17
- * checked again when the files arrive, since the picker only takes it as
18
- * a hint.
19
- */
20
- accept: String,
21
- /** Let several files be picked at once. */
22
- multiple: Boolean,
23
- /** Make the input unusable. The parts carry `data-disabled`. */
24
- disabled: Boolean,
25
- },
39
+ props: fileInputProps,
26
40
  emits: {
27
41
  /** The picked files that satisfy `accept`. */
28
42
  change: (files: File[]) => Array.isArray(files),
@@ -1,3 +1,3 @@
1
1
  export { useFileInputContext, type FileInputContextValue } from './context'
2
- export { FileInput } from './FileInput'
2
+ export { FileInput, type FileInputProps } from './FileInput'
3
3
  export { FileInputTrigger } from './FileInputTrigger'
@@ -1,82 +1,118 @@
1
- import { computed, defineComponent, h, provide, ref, type PropType } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ computed,
4
+ defineComponent,
5
+ type ExtractPublicPropTypes,
6
+ h,
7
+ type PropType,
8
+ provide,
9
+ ref,
10
+ } from 'vue'
2
11
 
3
12
  import {
4
- applyDelta,
5
- arrowKeyDirection,
6
- cssLength,
7
13
  DEFAULT_DRAG_SENSITIVITY,
8
14
  DEFAULT_KEYBOARD_OPTIONS,
9
15
  DEFAULT_WHEEL_OPTIONS,
10
16
  knobAngles,
11
17
  relativeMapping,
12
- selectModifier,
13
- wheelDirection,
14
18
  type AxisOptions,
19
+ type ChangeSource,
15
20
  type InputEventOption,
16
21
  type ModifierValue,
17
22
  type XY,
18
23
  } from '@tremolo-ui/dom'
24
+ import {
25
+ applyDelta,
26
+ arrowKeyDirection,
27
+ cssLength,
28
+ selectModifier,
29
+ wheelDirection,
30
+ } from '@tremolo-ui/dom/internal'
19
31
  import { linearScale, type Scale } from '@tremolo-ui/functions'
20
32
 
21
33
  import { useDragValue } from '../../composables/useDragValue'
22
34
  import { useWheel } from '../../composables/useWheel'
35
+ import { useChangeGesture } from '../_util/change-gesture'
23
36
  import { useCheckSteps } from '../_util/useCheckSteps'
24
37
 
25
38
  import { KnobKey } from './context'
26
39
 
40
+ const knobProps = {
41
+ /** The current value. Bind it with `v-model`. */
42
+ modelValue: { type: Number, required: true },
43
+ /** The value with the knob turned all the way down. */
44
+ min: { type: Number, required: true },
45
+ /** The value with the knob turned all the way up. */
46
+ max: { type: Number, required: true },
47
+ /** Granularity of the value. @default 1 */
48
+ step: { type: Number, default: 1 },
49
+ /** How the value is distributed across the travel. @default linearScale */
50
+ scale: { type: Object as PropType<Scale>, default: () => linearScale },
51
+ /**
52
+ * The value a double click restores. `null` turns the double click off.
53
+ * @default startValue
54
+ */
55
+ resetValue: {
56
+ type: Number as PropType<number | null>,
57
+ default: undefined,
58
+ },
59
+ /** Where the active arc starts. @default min */
60
+ startValue: Number,
61
+ /** Width and height of the knob. Sets `--knob-size`. */
62
+ size: [Number, String],
63
+ /** The cursor to show while dragging. @default 'grabbing' */
64
+ dragCursor: { type: String, default: 'grabbing' },
65
+ /** How much one notch of the wheel moves the value. `null` turns it off. */
66
+ wheel: {
67
+ type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
68
+ default: () => DEFAULT_WHEEL_OPTIONS,
69
+ },
70
+ /** How much one arrow key press moves the value. `null` turns it off. */
71
+ keyboard: {
72
+ type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
73
+ default: () => DEFAULT_KEYBOARD_OPTIONS,
74
+ },
75
+ /** How much a drag moves the value, per modifier key. */
76
+ dragSensitivity: {
77
+ type: [Number, Object] as PropType<ModifierValue<number>>,
78
+ default: () => DEFAULT_DRAG_SENSITIVITY,
79
+ },
80
+ /** Hide the cursor while dragging and read the movement directly. */
81
+ pointerLock: Boolean,
82
+ /** Make the knob unchangeable and remove it from the tab order. */
83
+ disabled: Boolean,
84
+ /** Make the knob unchangeable while leaving it focusable. */
85
+ readonly: Boolean,
86
+ /**
87
+ * How long after the last wheel notch or arrow key a change counts as over,
88
+ * in milliseconds, for `change-end`.
89
+ * @default 500
90
+ */
91
+ changeEndDelay: { type: Number, default: 500 },
92
+ /** How far the knob turns from `min` to `max`, in degrees. @default 270 */
93
+ angleRange: { type: Number, default: 270 },
94
+ } satisfies ComponentObjectPropsOptions
95
+
96
+ export type KnobProps = ExtractPublicPropTypes<typeof knobProps>
97
+
27
98
  /**
28
99
  * Interactive rotary knob, drawn in SVG by `KnobSVGRoot` and the parts inside
29
100
  * it. Bind the value with `v-model`.
30
101
  */
31
102
  export const Knob = /* @__PURE__ */ defineComponent({
32
103
  name: 'Knob',
33
- props: {
34
- /** The current value. Bind it with `v-model`. */
35
- modelValue: { type: Number, required: true },
36
- /** The value with the knob turned all the way down. */
37
- min: { type: Number, required: true },
38
- /** The value with the knob turned all the way up. */
39
- max: { type: Number, required: true },
40
- /** Granularity of the value. @default 1 */
41
- step: { type: Number, default: 1 },
42
- /** How the value is distributed across the travel. @default linearScale */
43
- scale: { type: Object as PropType<Scale>, default: () => linearScale },
44
- /** The value a double click restores. @default min */
45
- defaultValue: Number,
46
- /** Where the active arc starts. @default min */
47
- startValue: Number,
48
- /** Width and height of the knob. Sets `--knob-size`. */
49
- size: [Number, String],
50
- /** The cursor to show while dragging. @default { cursor: 'grabbing' } */
51
- externalStyles: Object as PropType<{ cursor?: string }>,
52
- /** How much one notch of the wheel moves the value. `null` turns it off. */
53
- wheel: {
54
- type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
55
- default: () => DEFAULT_WHEEL_OPTIONS,
56
- },
57
- /** How much one arrow key press moves the value. `null` turns it off. */
58
- keyboard: {
59
- type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
60
- default: () => DEFAULT_KEYBOARD_OPTIONS,
61
- },
62
- /** How much a drag moves the value, per modifier key. */
63
- dragSensitivity: {
64
- type: [Number, Object] as PropType<ModifierValue<number>>,
65
- default: () => DEFAULT_DRAG_SENSITIVITY,
66
- },
67
- /** Hide the cursor while dragging and read the movement directly. */
68
- pointerLock: Boolean,
69
- /** Restore `defaultValue` on a double click. @default true */
70
- enableDoubleClickDefault: { type: Boolean, default: true },
71
- /** Make the knob unchangeable and remove it from the tab order. */
72
- disabled: Boolean,
73
- /** Make the knob unchangeable while leaving it focusable. */
74
- readonly: Boolean,
75
- /** How far the knob turns from `min` to `max`, in degrees. @default 270 */
76
- angleRange: { type: Number, default: 270 },
77
- },
104
+ props: knobProps,
78
105
  emits: {
79
106
  'update:modelValue': (value: number) => typeof value === 'number',
107
+ /**
108
+ * A change of the value started, with the value before it and what it is
109
+ * made with.
110
+ */
111
+ changeStart: (value: number, _source: ChangeSource) =>
112
+ typeof value === 'number',
113
+ /** The change ended, with the value it ended on. */
114
+ changeEnd: (value: number, _source: ChangeSource) =>
115
+ typeof value === 'number',
80
116
  },
81
117
  setup(props, { slots, emit, expose }) {
82
118
  const root = ref<HTMLDivElement | null>(null)
@@ -133,7 +169,17 @@ export const Knob = /* @__PURE__ */ defineComponent({
133
169
  },
134
170
  })
135
171
 
136
- const change = (next: number) => emit('update:modelValue', next)
172
+ const gesture = useChangeGesture({
173
+ value: () => props.modelValue,
174
+ inactive: () => inactive.value,
175
+ endDelay: () => props.changeEndDelay,
176
+ onStart: (value, source) => emit('changeStart', value, source),
177
+ onEnd: (value, source) => emit('changeEnd', value, source),
178
+ })
179
+ const change = (next: number) => {
180
+ gesture.changed(next)
181
+ emit('update:modelValue', next)
182
+ }
137
183
 
138
184
  // The knob has no travel of its own: 100px of movement spans the whole
139
185
  // range, and only the vertical axis carries a value, reversed so that
@@ -147,9 +193,7 @@ export const Knob = /* @__PURE__ */ defineComponent({
147
193
  }),
148
194
  getValue: (): XY<number> => [props.modelValue, props.modelValue],
149
195
  threshold: 1,
150
- cursor: inactive.value
151
- ? undefined
152
- : (props.externalStyles?.cursor ?? 'grabbing'),
196
+ cursor: inactive.value ? undefined : props.dragCursor,
153
197
  pointerLock: inactive.value ? false : props.pointerLock,
154
198
  shouldStart: () => !inactive.value,
155
199
  onChange: (v) => {
@@ -157,9 +201,11 @@ export const Knob = /* @__PURE__ */ defineComponent({
157
201
  },
158
202
  onDragStart: () => {
159
203
  dragging.value = true
204
+ if (!inactive.value) gesture.hold('pointer')
160
205
  },
161
206
  onDragEnd: () => {
162
207
  dragging.value = false
208
+ gesture.end()
163
209
  },
164
210
  }))
165
211
 
@@ -172,6 +218,7 @@ export const Knob = /* @__PURE__ */ defineComponent({
172
218
  const direction = wheelDirection(event)
173
219
  if (direction === null) return
174
220
  event.preventDefault()
221
+ gesture.pulse('wheel')
175
222
  change(
176
223
  applyDelta(
177
224
  props.modelValue,
@@ -215,6 +262,7 @@ export const Knob = /* @__PURE__ */ defineComponent({
215
262
  const direction = arrowKeyDirection(event.key)
216
263
  if (direction === null) return
217
264
  event.preventDefault()
265
+ gesture.pulse('keyboard')
218
266
  change(
219
267
  applyDelta(
220
268
  props.modelValue,
@@ -226,8 +274,10 @@ export const Knob = /* @__PURE__ */ defineComponent({
226
274
  )
227
275
  },
228
276
  onDblclick: () => {
229
- if (!inactive.value && props.enableDoubleClickDefault) {
230
- change(props.defaultValue ?? props.min)
277
+ if (!inactive.value && props.resetValue !== null) {
278
+ gesture.instant('doubleClick', () =>
279
+ change(props.resetValue ?? props.startValue ?? props.min),
280
+ )
231
281
  }
232
282
  },
233
283
  },
@@ -1,4 +1,10 @@
1
- import { defineComponent, h, type PropType } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ defineComponent,
4
+ type ExtractPublicPropTypes,
5
+ h,
6
+ type PropType,
7
+ } from 'vue'
2
8
 
3
9
  import { KNOB_VIEWBOX_SIZE } from '@tremolo-ui/dom'
4
10
  import { clamp } from '@tremolo-ui/functions'
@@ -7,23 +13,27 @@ import { checkPlacement } from '../_util/placement'
7
13
 
8
14
  import { useKnobContext } from './context'
9
15
 
16
+ const knobThumbProps = {
17
+ /** Fill colour of the circle. @default 'currentColor' */
18
+ color: { type: String, default: 'currentColor' },
19
+ /** Colour of the line that points at the value. @default 'currentColor' */
20
+ lineColor: { type: String, default: 'currentColor' },
21
+ /** Diameter of the circle, as a percentage of the knob. @default 84 */
22
+ size: { type: Number, default: 84 },
23
+ /** Thickness of the line, as a percentage of the knob. @default 6 */
24
+ lineWeight: { type: Number, default: 6 },
25
+ /** How far down the line reaches, as a percentage. @default 35 */
26
+ lineLength: { type: Number, default: 35 },
27
+ /** Classes for the line that points at the value. */
28
+ classes: Object as PropType<{ line?: string }>,
29
+ } satisfies ComponentObjectPropsOptions
30
+
31
+ export type KnobThumbProps = ExtractPublicPropTypes<typeof knobThumbProps>
32
+
10
33
  /** The circle that turns with the value, and the line on it that points at it. */
11
34
  export const KnobThumb = /* @__PURE__ */ defineComponent({
12
35
  name: 'KnobThumb',
13
- props: {
14
- /** Fill colour of the circle. @default 'currentColor' */
15
- thumb: { type: String, default: 'currentColor' },
16
- /** Colour of the line that points at the value. @default 'currentColor' */
17
- thumbLine: { type: String, default: 'currentColor' },
18
- /** Diameter of the circle, as a percentage of the knob. @default 84 */
19
- thumbSize: { type: Number, default: 84 },
20
- /** Thickness of the line, as a percentage of the knob. @default 6 */
21
- thumbLineWeight: { type: Number, default: 6 },
22
- /** How far down the line reaches, as a percentage. @default 35 */
23
- thumbLineLength: { type: Number, default: 35 },
24
- /** Classes for the line that points at the value. */
25
- classes: Object as PropType<{ thumbLine?: string }>,
26
- },
36
+ props: knobThumbProps,
27
37
  setup(props) {
28
38
  checkPlacement('KnobThumb', 'KnobSVGRoot')
29
39
  const knob = useKnobContext()
@@ -32,17 +42,17 @@ export const KnobThumb = /* @__PURE__ */ defineComponent({
32
42
  h('circle', {
33
43
  cx: '50%',
34
44
  cy: '50%',
35
- r: `${props.thumbSize / 2}%`,
36
- fill: props.thumb,
45
+ r: `${props.size / 2}%`,
46
+ fill: props.color,
37
47
  }),
38
48
  h('line', {
39
- class: props.classes?.thumbLine,
49
+ class: props.classes?.line,
40
50
  x1: '50%',
41
- y1: `${(KNOB_VIEWBOX_SIZE - clamp(props.thumbSize, 0, 100)) / 2}%`,
51
+ y1: `${(KNOB_VIEWBOX_SIZE - clamp(props.size, 0, 100)) / 2}%`,
42
52
  x2: '50%',
43
- y2: `${props.thumbLineLength}%`,
44
- stroke: props.thumbLine,
45
- 'stroke-width': `${props.thumbLineWeight}%`,
53
+ y2: `${props.lineLength}%`,
54
+ stroke: props.lineColor,
55
+ 'stroke-width': `${props.lineWeight}%`,
46
56
  style: {
47
57
  transform: `rotate(${knob.angles.r1 + knob.angles.p * knob.angleRange}deg)`,
48
58
  transformOrigin: '50% 50%',
@@ -1,6 +1,6 @@
1
1
  export { useKnobContext, type KnobContextValue } from './context'
2
- export { Knob } from './Knob'
2
+ export { Knob, type KnobProps } from './Knob'
3
3
  export { KnobActiveLine } from './KnobActiveLine'
4
4
  export { KnobInactiveLine } from './KnobInactiveLine'
5
5
  export { KnobSVGRoot } from './KnobSVGRoot'
6
- export { KnobThumb } from './KnobThumb'
6
+ export { KnobThumb, type KnobThumbProps } from './KnobThumb'