@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
@@ -1,27 +1,33 @@
1
1
  import {
2
+ type ComponentObjectPropsOptions,
2
3
  computed,
3
4
  defineComponent,
5
+ type ExtractPublicPropTypes,
4
6
  h,
5
7
  mergeProps,
8
+ type PropType,
6
9
  ref,
7
10
  useId,
8
11
  watch,
9
- type PropType,
10
12
  } from 'vue'
11
13
 
12
14
  import {
13
- arrowKeyMove,
14
- clampPoint,
15
15
  createDragValue,
16
16
  elementMapping,
17
- POINT_AXIS,
18
- selectModifier,
19
17
  type InputEventOption,
20
18
  type ModifierValue,
19
+ type ChangeSource,
21
20
  type PointPosition,
22
21
  type PointsEditorPoint as PointRegistration,
23
22
  } from '@tremolo-ui/dom'
23
+ import {
24
+ arrowKeyMove,
25
+ clampPoint,
26
+ POINT_AXIS,
27
+ selectModifier,
28
+ } from '@tremolo-ui/dom/internal'
24
29
 
30
+ import { useChangeGesture } from '../_util/change-gesture'
25
31
  import { checkPlacement } from '../_util/placement'
26
32
  import { visuallyHiddenRangeInput } from '../_util/visually-hidden-range-input'
27
33
 
@@ -32,44 +38,65 @@ type PerAxis = string | Partial<Record<'x' | 'y', string>>
32
38
  const perAxis = (setting: PerAxis | undefined, axis: 'x' | 'y') =>
33
39
  typeof setting === 'string' ? setting : setting?.[axis]
34
40
 
41
+ const pointsEditorPointProps = {
42
+ /** Where the point is, with `y` growing downwards. Bind it with `v-model`. */
43
+ modelValue: { type: Object as PropType<PointPosition>, required: true },
44
+ /** How the selection refers to this point. One is generated when left out. */
45
+ id: String,
46
+ /** The lowest position the point can take, per axis. */
47
+ min: Object as PropType<Partial<PointPosition>>,
48
+ /** The highest position the point can take, per axis. */
49
+ max: Object as PropType<Partial<PointPosition>>,
50
+ /** Sets `--color`, for the theme to colour the point with. */
51
+ color: String,
52
+ /** Overrides the `disabled` of `PointsEditor`. */
53
+ disabled: { type: Boolean, default: undefined },
54
+ /** Overrides the `readonly` of `PointsEditor`. */
55
+ readonly: { type: Boolean, default: undefined },
56
+ /**
57
+ * How long after the last wheel notch or arrow key a change counts as over,
58
+ * in milliseconds, for `change-end`.
59
+ * @default 500
60
+ */
61
+ changeEndDelay: { type: Number, default: 500 },
62
+ /** Overrides the `wheel` of `PointsEditor`; `null` turns it off. */
63
+ wheel: {
64
+ type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
65
+ default: undefined,
66
+ },
67
+ /** Overrides the `keyboard` of `PointsEditor`; `null` turns it off. */
68
+ keyboard: {
69
+ type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
70
+ default: undefined,
71
+ },
72
+ /** The accessible name of each axis, or one for both. */
73
+ ariaLabel: [String, Object] as PropType<PerAxis>,
74
+ /** What the value of each axis means, or one for both. */
75
+ ariaValuetext: [String, Object] as PropType<PerAxis>,
76
+ } satisfies ComponentObjectPropsOptions
77
+
78
+ export type PointsEditorPointProps = ExtractPublicPropTypes<
79
+ typeof pointsEditorPointProps
80
+ >
81
+
35
82
  /** One point, bound with `v-model` as `{ x, y }` from 0 to 1. */
36
83
  export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
37
84
  name: 'PointsEditorPoint',
38
85
  inheritAttrs: false,
39
- props: {
40
- /** Where the point is, with `y` growing downwards. Bind it with `v-model`. */
41
- modelValue: { type: Object as PropType<PointPosition>, required: true },
42
- /** How the selection refers to this point. One is generated when left out. */
43
- id: String,
44
- /** The lowest position the point can take, per axis. */
45
- min: Object as PropType<Partial<PointPosition>>,
46
- /** The highest position the point can take, per axis. */
47
- max: Object as PropType<Partial<PointPosition>>,
48
- /** Sets `--color`, for the theme to colour the point with. */
49
- color: String,
50
- /** Overrides the `disabled` of `PointsEditor`. */
51
- disabled: { type: Boolean, default: undefined },
52
- /** Overrides the `readonly` of `PointsEditor`. */
53
- readonly: { type: Boolean, default: undefined },
54
- /** Overrides the `wheel` of `PointsEditor`; `null` turns it off. */
55
- wheel: {
56
- type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
57
- default: undefined,
58
- },
59
- /** Overrides the `keyboard` of `PointsEditor`; `null` turns it off. */
60
- keyboard: {
61
- type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,
62
- default: undefined,
63
- },
64
- /** The accessible name of each axis, or one for both. */
65
- ariaLabel: [String, Object] as PropType<PerAxis>,
66
- /** What the value of each axis means, or one for both. */
67
- ariaValuetext: [String, Object] as PropType<PerAxis>,
68
- },
86
+ props: pointsEditorPointProps,
69
87
  emits: {
70
88
  'update:modelValue': (value: PointPosition) => typeof value === 'object',
71
- dragStart: (value: PointPosition) => typeof value === 'object',
72
- dragEnd: (value: PointPosition) => typeof value === 'object',
89
+ /**
90
+ * A change of this point started — a drag on it, the first wheel notch or
91
+ * arrow key while it has the focus — with where it is and what the change
92
+ * is made with. The points that move along with a selection report
93
+ * through `update:modelValue` only.
94
+ */
95
+ changeStart: (value: PointPosition, _source: ChangeSource) =>
96
+ typeof value === 'object',
97
+ /** The change ended, with where the point is. */
98
+ changeEnd: (value: PointPosition, _source: ChangeSource) =>
99
+ typeof value === 'object',
73
100
  },
74
101
  setup(props, { slots, attrs, emit }) {
75
102
  const points = usePointsEditorContext()
@@ -90,6 +117,14 @@ export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
90
117
  clampPoint(props.modelValue, props.min, props.max),
91
118
  )
92
119
 
120
+ const gesture = useChangeGesture({
121
+ value: () => current.value,
122
+ inactive: () => inactive.value,
123
+ endDelay: () => props.changeEndDelay,
124
+ onStart: (value, source) => emit('changeStart', value, source),
125
+ onEnd: (value, source) => emit('changeEnd', value, source),
126
+ })
127
+
93
128
  const el = ref<HTMLDivElement | null>(null)
94
129
  const x = ref<HTMLInputElement | null>(null)
95
130
  const dragging = ref(false)
@@ -101,9 +136,13 @@ export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
101
136
  min: props.min,
102
137
  max: props.max,
103
138
  readonly: inactive.value,
104
- onChange: (next) => emit('update:modelValue', next),
139
+ onChange: (next) => {
140
+ gesture.changed(next)
141
+ emit('update:modelValue', next)
142
+ },
105
143
  element: el.value,
106
144
  wheel: wheel.value,
145
+ beforeWheel: () => gesture.pulse('wheel'),
107
146
  })
108
147
  watch(
109
148
  id,
@@ -125,7 +164,7 @@ export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
125
164
  sensitivity: (state) =>
126
165
  selectModifier(points.dragSensitivity, state.event).value,
127
166
  }),
128
- cursor: inactive.value ? undefined : points.cursor,
167
+ cursor: inactive.value ? undefined : points.dragCursor,
129
168
  shouldStart: () => !disabled.value,
130
169
  // A move rather than a position: the point keeps the offset it was
131
170
  // grabbed at, and everything else selected moves with it.
@@ -142,16 +181,16 @@ export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
142
181
  origin = { x: px, y: py }
143
182
  dragging.value = true
144
183
  x.value?.focus()
145
- if (!inactive.value) emit('dragStart', current.value)
184
+ if (!inactive.value) gesture.hold('pointer')
146
185
  },
147
186
  onDragEnd: () => {
148
187
  origin = null
149
188
  dragging.value = false
150
- if (!inactive.value) emit('dragEnd', current.value)
189
+ gesture.end()
151
190
  },
152
191
  })
153
192
  const stop = watch(
154
- () => (inactive.value ? undefined : points.cursor),
193
+ () => (inactive.value ? undefined : points.dragCursor),
155
194
  (cursor) => drag.update({ cursor }),
156
195
  )
157
196
  onCleanup(() => {
@@ -234,6 +273,7 @@ export const PointsEditorPoint = /* @__PURE__ */ defineComponent({
234
273
  if (!move) return
235
274
  event.preventDefault()
236
275
  if (inactive.value || !keyboard.value) return
276
+ gesture.pulse('keyboard')
237
277
  points.editor.nudgePoint(
238
278
  id.value,
239
279
  move.axis === 0 ? 'x' : 'y',
@@ -16,7 +16,7 @@ export interface PointsEditorContextValue {
16
16
  readonly wheel: ModifierValue<InputEventOption> | null
17
17
  readonly keyboard: ModifierValue<InputEventOption> | null
18
18
  readonly dragSensitivity: ModifierValue<number>
19
- readonly cursor: string
19
+ readonly dragCursor: string
20
20
  readonly selectable: boolean
21
21
  /** Ids of the selected points. Always empty while `selectable` is off. */
22
22
  readonly selection: readonly string[]
@@ -2,8 +2,11 @@ export {
2
2
  usePointsEditorContext,
3
3
  type PointsEditorContextValue,
4
4
  } from './context'
5
- export { PointsEditor } from './PointsEditor'
5
+ export { PointsEditor, type PointsEditorProps } from './PointsEditor'
6
6
  export { PointsEditorBackground } from './PointsEditorBackground'
7
7
  export { PointsEditorContainer } from './PointsEditorContainer'
8
- export { PointsEditorPoint } from './PointsEditorPoint'
8
+ export {
9
+ PointsEditorPoint,
10
+ type PointsEditorPointProps,
11
+ } from './PointsEditorPoint'
9
12
  export { PointsEditorSelectionBox } from './PointsEditorSelectionBox'
@@ -1,58 +1,92 @@
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
13
  elementMapping,
7
- selectModifier,
8
14
  valuePercent,
9
- wheelDirection,
10
15
  type AxisOptions,
16
+ type ChangeSource,
11
17
  type XY,
12
18
  } from '@tremolo-ui/dom'
19
+ import {
20
+ applyDelta,
21
+ arrowKeyDirection,
22
+ selectModifier,
23
+ wheelDirection,
24
+ } from '@tremolo-ui/dom/internal'
13
25
  import { linearScale, type Scale } from '@tremolo-ui/functions'
14
26
 
15
27
  import { useDragValue } from '../../composables/useDragValue'
16
28
  import { useWheel } from '../../composables/useWheel'
29
+ import { useChangeGesture } from '../_util/change-gesture'
17
30
  import { dragSensitivityProp, keyboardProp, wheelProp } from '../_util/props'
18
31
  import { useCheckSteps } from '../_util/useCheckSteps'
19
32
 
20
33
  import { SliderKey } from './context'
21
34
 
35
+ const sliderProps = {
36
+ /** The current value. Bind it with `v-model`. */
37
+ modelValue: { type: Number, required: true },
38
+ /** The value at the start of the travel. */
39
+ min: { type: Number, required: true },
40
+ /** The value at the end of the travel. */
41
+ max: { type: Number, required: true },
42
+ /** Granularity of the value. @default 1 */
43
+ step: { type: Number, default: 1 },
44
+ /** How the value is distributed across the travel. @default linearScale */
45
+ scale: { type: Object as PropType<Scale>, default: () => linearScale },
46
+ /**
47
+ * Which way the slider runs. A vertical slider grows upwards.
48
+ * @default 'horizontal'
49
+ */
50
+ orientation: {
51
+ type: String as PropType<'horizontal' | 'vertical'>,
52
+ default: 'horizontal',
53
+ },
54
+ /** Grow the value the other way. */
55
+ reverse: Boolean,
56
+ /** The cursor to show while dragging. @default 'pointer' */
57
+ dragCursor: { type: String, default: 'pointer' },
58
+ wheel: wheelProp,
59
+ keyboard: keyboardProp,
60
+ dragSensitivity: dragSensitivityProp,
61
+ /** Make the slider unchangeable and remove it from the tab order. */
62
+ disabled: Boolean,
63
+ /** Make the value unchangeable. */
64
+ readonly: Boolean,
65
+ /**
66
+ * How long after the last wheel notch or arrow key a change counts as over,
67
+ * in milliseconds, for `change-end`.
68
+ * @default 500
69
+ */
70
+ changeEndDelay: { type: Number, default: 500 },
71
+ } satisfies ComponentObjectPropsOptions
72
+
73
+ export type SliderProps = ExtractPublicPropTypes<typeof sliderProps>
74
+
22
75
  /** Customizable slider. Bind the value with `v-model`. */
23
76
  export const Slider = /* @__PURE__ */ defineComponent({
24
77
  name: 'Slider',
25
- props: {
26
- /** The current value. Bind it with `v-model`. */
27
- modelValue: { type: Number, required: true },
28
- /** The value at the start of the travel. */
29
- min: { type: Number, required: true },
30
- /** The value at the end of the travel. */
31
- max: { type: Number, required: true },
32
- /** Granularity of the value. @default 1 */
33
- step: { type: Number, default: 1 },
34
- /** How the value is distributed across the travel. @default linearScale */
35
- scale: { type: Object as PropType<Scale>, default: () => linearScale },
36
- /** Run the slider vertically, with the value growing upwards. */
37
- vertical: Boolean,
38
- /** Grow the value the other way. */
39
- reverse: Boolean,
40
- /** The cursor to show while dragging. @default { cursor: 'pointer' } */
41
- externalStyles: Object as PropType<{ cursor?: string }>,
42
- wheel: wheelProp,
43
- keyboard: keyboardProp,
44
- dragSensitivity: dragSensitivityProp,
45
- /** Make the slider unchangeable and remove it from the tab order. */
46
- disabled: Boolean,
47
- /** Make the value unchangeable. */
48
- readonly: Boolean,
49
- },
78
+ props: sliderProps,
50
79
  emits: {
51
80
  'update:modelValue': (value: number) => typeof value === 'number',
52
- /** A drag started, with the value where the track was pressed. */
53
- dragStart: (value: number) => typeof value === 'number',
54
- /** The drag ended, with the value it ended on. */
55
- dragEnd: (value: number) => typeof value === 'number',
81
+ /**
82
+ * A change of the value started, with the value before it and what it is
83
+ * made with.
84
+ */
85
+ changeStart: (value: number, _source: ChangeSource) =>
86
+ typeof value === 'number',
87
+ /** The change ended, with the value it ended on. */
88
+ changeEnd: (value: number, _source: ChangeSource) =>
89
+ typeof value === 'number',
56
90
  },
57
91
  setup(props, { slots, emit, expose }) {
58
92
  const root = ref<HTMLDivElement | null>(null)
@@ -62,7 +96,8 @@ export const Slider = /* @__PURE__ */ defineComponent({
62
96
  const inactive = computed(() => props.disabled || props.readonly)
63
97
  // Measured from the left or the top, as CSS places things: vertical and
64
98
  // reverse each flip it, and together they cancel out.
65
- const displayReversed = computed(() => props.vertical !== props.reverse)
99
+ const vertical = computed(() => props.orientation === 'vertical')
100
+ const displayReversed = computed(() => vertical.value !== props.reverse)
66
101
  const percent = computed(() =>
67
102
  valuePercent(
68
103
  props.modelValue,
@@ -85,7 +120,17 @@ export const Slider = /* @__PURE__ */ defineComponent({
85
120
  wheel: props.wheel,
86
121
  }))
87
122
 
88
- const change = (next: number) => emit('update:modelValue', next)
123
+ const gesture = useChangeGesture({
124
+ value: () => props.modelValue,
125
+ inactive: () => inactive.value,
126
+ endDelay: () => props.changeEndDelay,
127
+ onStart: (value, source) => emit('changeStart', value, source),
128
+ onEnd: (value, source) => emit('changeEnd', value, source),
129
+ })
130
+ const change = (next: number) => {
131
+ gesture.changed(next)
132
+ emit('update:modelValue', next)
133
+ }
89
134
 
90
135
  provide(SliderKey, {
91
136
  get value() {
@@ -103,8 +148,8 @@ export const Slider = /* @__PURE__ */ defineComponent({
103
148
  get scale() {
104
149
  return props.scale
105
150
  },
106
- get vertical() {
107
- return props.vertical
151
+ get orientation() {
152
+ return props.orientation
108
153
  },
109
154
  get reverse() {
110
155
  return props.reverse
@@ -127,7 +172,7 @@ export const Slider = /* @__PURE__ */ defineComponent({
127
172
  },
128
173
  })
129
174
 
130
- const valueOf = (v: XY<number>) => v[props.vertical ? 1 : 0]
175
+ const valueOf = (v: XY<number>) => v[vertical.value ? 1 : 0]
131
176
 
132
177
  useDragValue(root, () => ({
133
178
  axis: axis.value,
@@ -135,22 +180,18 @@ export const Slider = /* @__PURE__ */ defineComponent({
135
180
  sensitivity: (state) =>
136
181
  selectModifier(props.dragSensitivity, state.event).value,
137
182
  }),
138
- cursor: inactive.value
139
- ? undefined
140
- : (props.externalStyles?.cursor ?? 'pointer'),
183
+ cursor: inactive.value ? undefined : props.dragCursor,
141
184
  shouldStart: () => !inactive.value,
142
185
  updateOnPointerDown: true,
143
186
  onChange: (v) => {
144
187
  if (!inactive.value) change(valueOf(v))
145
188
  },
146
- onDragStart: (v) => {
189
+ onDragStart: () => {
147
190
  if (inactive.value) return
191
+ gesture.hold('pointer')
148
192
  thumb?.focus()
149
- emit('dragStart', valueOf(v))
150
- },
151
- onDragEnd: (v) => {
152
- if (!inactive.value) emit('dragEnd', valueOf(v))
153
193
  },
194
+ onDragEnd: () => gesture.end(),
154
195
  }))
155
196
 
156
197
  useWheel(
@@ -159,9 +200,10 @@ export const Slider = /* @__PURE__ */ defineComponent({
159
200
  if (!props.wheel || inactive.value) return
160
201
  // A notch the slider does not read — a sideways scroll on a vertical
161
202
  // slider — is left to the page rather than swallowed.
162
- const direction = wheelDirection(event, { horizontal: !props.vertical })
203
+ const direction = wheelDirection(event, { horizontal: !vertical.value })
163
204
  if (direction === null) return
164
205
  event.preventDefault()
206
+ gesture.pulse('wheel')
165
207
  change(
166
208
  applyDelta(
167
209
  props.modelValue,
@@ -195,7 +237,7 @@ export const Slider = /* @__PURE__ */ defineComponent({
195
237
  ref: root,
196
238
  role: 'group',
197
239
  tabindex: -1,
198
- 'data-orientation': props.vertical ? 'vertical' : 'horizontal',
240
+ 'data-orientation': props.orientation,
199
241
  'data-disabled': props.disabled ? '' : undefined,
200
242
  'data-readonly': props.readonly ? '' : undefined,
201
243
  onKeydown: (event: KeyboardEvent) => {
@@ -203,6 +245,7 @@ export const Slider = /* @__PURE__ */ defineComponent({
203
245
  if (direction === null) return
204
246
  event.preventDefault()
205
247
  if (!props.keyboard || inactive.value) return
248
+ gesture.pulse('keyboard')
206
249
  change(
207
250
  applyDelta(
208
251
  props.modelValue,
@@ -1,25 +1,37 @@
1
- import { computed, defineComponent, h, type PropType } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ computed,
4
+ defineComponent,
5
+ type ExtractPublicPropTypes,
6
+ h,
7
+ type PropType,
8
+ } from 'vue'
2
9
 
3
- import { cssLength, sliderMarks, type MarksOptions } from '@tremolo-ui/dom'
10
+ import { type MarksOptions } from '@tremolo-ui/dom'
11
+ import { cssLength, sliderMarks } from '@tremolo-ui/dom/internal'
4
12
 
5
13
  import { providePlacement } from '../_util/placement'
6
14
 
7
15
  import { useSliderContext } from './context'
8
16
  import { SliderMarksOption } from './SliderMarksOption'
9
17
 
18
+ const sliderMarksProps = {
19
+ /** Space between the marks and the track. Sets `--gap`. */
20
+ gap: [Number, String],
21
+ /**
22
+ * Build the marks instead of writing `SliderMarksOption` out: a number
23
+ * puts one every that many, `'step'` one every `step`. The default slot
24
+ * is ignored while it is set.
25
+ */
26
+ options: [String, Number, Object] as PropType<MarksOptions>,
27
+ } satisfies ComponentObjectPropsOptions
28
+
29
+ export type SliderMarksProps = ExtractPublicPropTypes<typeof sliderMarksProps>
30
+
10
31
  /** The marks along the slider: written out as options, or built from `options`. */
11
32
  export const SliderMarks = /* @__PURE__ */ defineComponent({
12
33
  name: 'SliderMarks',
13
- props: {
14
- /** Space between the marks and the track. Sets `--gap`. */
15
- gap: [Number, String],
16
- /**
17
- * Build the marks instead of writing `SliderMarksOption` out: a number
18
- * puts one every that many, `'step'` one every `step`. The default slot
19
- * is ignored while it is set.
20
- */
21
- options: [String, Number, Object] as PropType<MarksOptions>,
22
- },
34
+ props: sliderMarksProps,
23
35
  setup(props, { slots }) {
24
36
  const slider = useSliderContext()
25
37
  providePlacement('SliderMarks')
@@ -32,14 +44,16 @@ export const SliderMarks = /* @__PURE__ */ defineComponent({
32
44
  slider.step,
33
45
  )
34
46
  // In the order they are on screen.
35
- return slider.vertical !== slider.reverse ? list.reverse() : list
47
+ return (slider.orientation === 'vertical') !== slider.reverse
48
+ ? list.reverse()
49
+ : list
36
50
  })
37
51
  // Each option inside is placed against this box.
38
52
  return () =>
39
53
  h(
40
54
  'div',
41
55
  {
42
- 'data-orientation': slider.vertical ? 'vertical' : 'horizontal',
56
+ 'data-orientation': slider.orientation,
43
57
  style: { '--gap': cssLength(props.gap), position: 'relative' },
44
58
  },
45
59
  props.options !== undefined
@@ -1,38 +1,52 @@
1
- import { computed, defineComponent, h, type PropType } from 'vue'
1
+ import {
2
+ type ComponentObjectPropsOptions,
3
+ computed,
4
+ defineComponent,
5
+ type ExtractPublicPropTypes,
6
+ h,
7
+ type PropType,
8
+ } from 'vue'
2
9
 
3
- import { cssLength, valuePercent } from '@tremolo-ui/dom'
10
+ import { valuePercent } from '@tremolo-ui/dom'
11
+ import { cssLength } from '@tremolo-ui/dom/internal'
4
12
 
5
13
  import { checkPlacement } from '../_util/placement'
6
14
 
7
15
  import { useSliderContext } from './context'
8
16
 
17
+ const sliderMarksOptionProps = {
18
+ /** Where the mark sits, on the same scale as the thumb. */
19
+ value: { type: Number, required: true },
20
+ /** Draw the mark itself. @default true */
21
+ mark: { type: Boolean, default: true },
22
+ /**
23
+ * Text shown next to the mark. Leave it out to show the value; `null`
24
+ * leaves the label out.
25
+ */
26
+ label: {
27
+ type: [Number, String, null] as PropType<number | string | null>,
28
+ default: undefined,
29
+ },
30
+ /** Thickness of the mark. Sets `--thickness`. */
31
+ thickness: [Number, String],
32
+ /** Length of the mark. Sets `--length`. */
33
+ length: [Number, String],
34
+ /** Space between the mark and the label. Sets `--gap`. */
35
+ gap: [Number, String],
36
+ /** Classes for the mark and the label inside the option. */
37
+ classes: Object as PropType<{ mark?: string; label?: string }>,
38
+ /** Styles for the mark and the label inside the option. */
39
+ styles: Object as PropType<{ mark?: string; label?: string }>,
40
+ } satisfies ComponentObjectPropsOptions
41
+
42
+ export type SliderMarksOptionProps = ExtractPublicPropTypes<
43
+ typeof sliderMarksOptionProps
44
+ >
45
+
9
46
  /** One mark along the slider, and its label. */
10
47
  export const SliderMarksOption = /* @__PURE__ */ defineComponent({
11
48
  name: 'SliderMarksOption',
12
- props: {
13
- /** Where the mark sits, on the same scale as the thumb. */
14
- value: { type: Number, required: true },
15
- /** Draw the mark itself. @default true */
16
- mark: { type: Boolean, default: true },
17
- /**
18
- * Text shown next to the mark. Leave it out to show the value; `null`
19
- * leaves the label out.
20
- */
21
- label: {
22
- type: [Number, String, null] as PropType<number | string | null>,
23
- default: undefined,
24
- },
25
- /** Thickness of the mark. Sets `--thickness`. */
26
- thickness: [Number, String],
27
- /** Length of the mark. Sets `--length`. */
28
- length: [Number, String],
29
- /** Space between the mark and the label. Sets `--gap`. */
30
- gap: [Number, String],
31
- /** Classes for the mark and the label inside the option. */
32
- classes: Object as PropType<{ mark?: string; label?: string }>,
33
- /** Styles for the mark and the label inside the option. */
34
- styles: Object as PropType<{ mark?: string; label?: string }>,
35
- },
49
+ props: sliderMarksOptionProps,
36
50
  setup(props) {
37
51
  const slider = useSliderContext()
38
52
  checkPlacement('SliderMarksOption', 'SliderMarks')
@@ -41,11 +55,11 @@ export const SliderMarksOption = /* @__PURE__ */ defineComponent({
41
55
  valuePercent(
42
56
  props.value,
43
57
  { min: slider.min, max: slider.max, scale: slider.scale },
44
- slider.vertical !== slider.reverse,
58
+ (slider.orientation === 'vertical') !== slider.reverse,
45
59
  ),
46
60
  )
47
61
  return () => {
48
- const orientation = slider.vertical ? 'vertical' : 'horizontal'
62
+ const orientation = slider.orientation
49
63
  return h(
50
64
  'div',
51
65
  {
@@ -55,12 +69,19 @@ export const SliderMarksOption = /* @__PURE__ */ defineComponent({
55
69
  '--length': cssLength(props.length),
56
70
  '--gap': cssLength(props.gap),
57
71
  position: 'absolute',
58
- translate: slider.vertical
59
- ? 'var(--translate, 0 -50%)'
60
- : 'var(--translate, -50% 0)',
72
+ translate:
73
+ slider.orientation === 'vertical'
74
+ ? 'var(--translate, 0 -50%)'
75
+ : 'var(--translate, -50% 0)',
61
76
  zIndex: 10,
62
- left: slider.vertical ? undefined : `${percent.value}%`,
63
- top: slider.vertical ? `${percent.value}%` : undefined,
77
+ left:
78
+ slider.orientation === 'vertical'
79
+ ? undefined
80
+ : `${percent.value}%`,
81
+ top:
82
+ slider.orientation === 'vertical'
83
+ ? `${percent.value}%`
84
+ : undefined,
64
85
  },
65
86
  },
66
87
  [