@tremolo-ui/svelte 0.7.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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/actions/drag-value.d.ts +22 -0
- package/dist/actions/drag-value.d.ts.map +1 -0
- package/dist/actions/drag-value.js +30 -0
- package/dist/actions/drag.d.ts +14 -0
- package/dist/actions/drag.d.ts.map +1 -0
- package/dist/actions/drag.js +22 -0
- package/dist/actions/drop-zone.d.ts +12 -0
- package/dist/actions/drop-zone.d.ts.map +1 -0
- package/dist/actions/drop-zone.js +20 -0
- package/dist/actions/long-press.d.ts +11 -0
- package/dist/actions/long-press.d.ts.map +1 -0
- package/dist/actions/long-press.js +24 -0
- package/dist/actions/wheel.d.ts +15 -0
- package/dist/actions/wheel.d.ts.map +1 -0
- package/dist/actions/wheel.js +32 -0
- package/dist/components/AnimationCanvas/AnimationCanvas.svelte +69 -0
- package/dist/components/AnimationCanvas/AnimationCanvas.svelte.d.ts +7 -0
- package/dist/components/AnimationCanvas/AnimationCanvas.svelte.d.ts.map +1 -0
- package/dist/components/AnimationCanvas/types.d.ts +46 -0
- package/dist/components/AnimationCanvas/types.d.ts.map +1 -0
- package/dist/components/AnimationCanvas/types.js +1 -0
- package/dist/components/DropZone/Root.svelte +47 -0
- package/dist/components/DropZone/Root.svelte.d.ts +7 -0
- package/dist/components/DropZone/Root.svelte.d.ts.map +1 -0
- package/dist/components/DropZone/index.d.ts +2 -0
- package/dist/components/DropZone/index.d.ts.map +1 -0
- package/dist/components/DropZone/index.js +1 -0
- package/dist/components/DropZone/types.d.ts +26 -0
- package/dist/components/DropZone/types.d.ts.map +1 -0
- package/dist/components/DropZone/types.js +1 -0
- package/dist/components/FileInput/Root.svelte +68 -0
- package/dist/components/FileInput/Root.svelte.d.ts +7 -0
- package/dist/components/FileInput/Root.svelte.d.ts.map +1 -0
- package/dist/components/FileInput/Trigger.svelte +28 -0
- package/dist/components/FileInput/Trigger.svelte.d.ts +11 -0
- package/dist/components/FileInput/Trigger.svelte.d.ts.map +1 -0
- package/dist/components/FileInput/context.d.ts +10 -0
- package/dist/components/FileInput/context.d.ts.map +1 -0
- package/dist/components/FileInput/context.js +5 -0
- package/dist/components/FileInput/index.d.ts +3 -0
- package/dist/components/FileInput/index.d.ts.map +1 -0
- package/dist/components/FileInput/index.js +2 -0
- package/dist/components/FileInput/types.d.ts +28 -0
- package/dist/components/FileInput/types.d.ts.map +1 -0
- package/dist/components/FileInput/types.js +1 -0
- package/dist/components/Knob/ActiveLine.svelte +29 -0
- package/dist/components/Knob/ActiveLine.svelte.d.ts +6 -0
- package/dist/components/Knob/ActiveLine.svelte.d.ts.map +1 -0
- package/dist/components/Knob/InactiveLine.svelte +41 -0
- package/dist/components/Knob/InactiveLine.svelte.d.ts +6 -0
- package/dist/components/Knob/InactiveLine.svelte.d.ts.map +1 -0
- package/dist/components/Knob/Root.svelte +189 -0
- package/dist/components/Knob/Root.svelte.d.ts +10 -0
- package/dist/components/Knob/Root.svelte.d.ts.map +1 -0
- package/dist/components/Knob/SVGRoot.svelte +28 -0
- package/dist/components/Knob/SVGRoot.svelte.d.ts +13 -0
- package/dist/components/Knob/SVGRoot.svelte.d.ts.map +1 -0
- package/dist/components/Knob/Thumb.svelte +43 -0
- package/dist/components/Knob/Thumb.svelte.d.ts +7 -0
- package/dist/components/Knob/Thumb.svelte.d.ts.map +1 -0
- package/dist/components/Knob/context.d.ts +22 -0
- package/dist/components/Knob/context.d.ts.map +1 -0
- package/dist/components/Knob/context.js +5 -0
- package/dist/components/Knob/index.d.ts +6 -0
- package/dist/components/Knob/index.d.ts.map +1 -0
- package/dist/components/Knob/index.js +5 -0
- package/dist/components/Knob/types.d.ts +139 -0
- package/dist/components/Knob/types.d.ts.map +1 -0
- package/dist/components/Knob/types.js +1 -0
- package/dist/components/NumberInput/DecrementStepper.svelte +11 -0
- package/dist/components/NumberInput/DecrementStepper.svelte.d.ts +9 -0
- package/dist/components/NumberInput/DecrementStepper.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/IncrementStepper.svelte +11 -0
- package/dist/components/NumberInput/IncrementStepper.svelte.d.ts +9 -0
- package/dist/components/NumberInput/IncrementStepper.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/InputField.svelte +134 -0
- package/dist/components/NumberInput/InputField.svelte.d.ts +8 -0
- package/dist/components/NumberInput/InputField.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/Root.svelte +209 -0
- package/dist/components/NumberInput/Root.svelte.d.ts +10 -0
- package/dist/components/NumberInput/Root.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/Stepper.svelte +61 -0
- package/dist/components/NumberInput/Stepper.svelte.d.ts +10 -0
- package/dist/components/NumberInput/Stepper.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/StepperButton.svelte +63 -0
- package/dist/components/NumberInput/StepperButton.svelte.d.ts +10 -0
- package/dist/components/NumberInput/StepperButton.svelte.d.ts.map +1 -0
- package/dist/components/NumberInput/context.d.ts +48 -0
- package/dist/components/NumberInput/context.d.ts.map +1 -0
- package/dist/components/NumberInput/context.js +8 -0
- package/dist/components/NumberInput/index.d.ts +6 -0
- package/dist/components/NumberInput/index.d.ts.map +1 -0
- package/dist/components/NumberInput/index.js +5 -0
- package/dist/components/NumberInput/types.d.ts +104 -0
- package/dist/components/NumberInput/types.d.ts.map +1 -0
- package/dist/components/NumberInput/types.js +1 -0
- package/dist/components/Piano/Root.svelte +177 -0
- package/dist/components/Piano/Root.svelte.d.ts +10 -0
- package/dist/components/Piano/Root.svelte.d.ts.map +1 -0
- package/dist/components/Piano/index.d.ts +2 -0
- package/dist/components/Piano/index.d.ts.map +1 -0
- package/dist/components/Piano/index.js +1 -0
- package/dist/components/Piano/types.d.ts +90 -0
- package/dist/components/Piano/types.d.ts.map +1 -0
- package/dist/components/Piano/types.js +1 -0
- package/dist/components/PointsEditor/Background.svelte +14 -0
- package/dist/components/PointsEditor/Background.svelte.d.ts +9 -0
- package/dist/components/PointsEditor/Background.svelte.d.ts.map +1 -0
- package/dist/components/PointsEditor/Container.svelte +82 -0
- package/dist/components/PointsEditor/Container.svelte.d.ts +10 -0
- package/dist/components/PointsEditor/Container.svelte.d.ts.map +1 -0
- package/dist/components/PointsEditor/Point.svelte +213 -0
- package/dist/components/PointsEditor/Point.svelte.d.ts +7 -0
- package/dist/components/PointsEditor/Point.svelte.d.ts.map +1 -0
- package/dist/components/PointsEditor/Root.svelte +107 -0
- package/dist/components/PointsEditor/Root.svelte.d.ts +7 -0
- package/dist/components/PointsEditor/Root.svelte.d.ts.map +1 -0
- package/dist/components/PointsEditor/SelectionBox.svelte +32 -0
- package/dist/components/PointsEditor/SelectionBox.svelte.d.ts +9 -0
- package/dist/components/PointsEditor/SelectionBox.svelte.d.ts.map +1 -0
- package/dist/components/PointsEditor/context.d.ts +28 -0
- package/dist/components/PointsEditor/context.d.ts.map +1 -0
- package/dist/components/PointsEditor/context.js +5 -0
- package/dist/components/PointsEditor/index.d.ts +6 -0
- package/dist/components/PointsEditor/index.d.ts.map +1 -0
- package/dist/components/PointsEditor/index.js +5 -0
- package/dist/components/PointsEditor/types.d.ts +84 -0
- package/dist/components/PointsEditor/types.d.ts.map +1 -0
- package/dist/components/PointsEditor/types.js +1 -0
- package/dist/components/Slider/Marks.svelte +42 -0
- package/dist/components/Slider/Marks.svelte.d.ts +7 -0
- package/dist/components/Slider/Marks.svelte.d.ts.map +1 -0
- package/dist/components/Slider/MarksOption.svelte +63 -0
- package/dist/components/Slider/MarksOption.svelte.d.ts +7 -0
- package/dist/components/Slider/MarksOption.svelte.d.ts.map +1 -0
- package/dist/components/Slider/Root.svelte +217 -0
- package/dist/components/Slider/Root.svelte.d.ts +10 -0
- package/dist/components/Slider/Root.svelte.d.ts.map +1 -0
- package/dist/components/Slider/Thumb.svelte +84 -0
- package/dist/components/Slider/Thumb.svelte.d.ts +10 -0
- package/dist/components/Slider/Thumb.svelte.d.ts.map +1 -0
- package/dist/components/Slider/Track.svelte +51 -0
- package/dist/components/Slider/Track.svelte.d.ts +7 -0
- package/dist/components/Slider/Track.svelte.d.ts.map +1 -0
- package/dist/components/Slider/context.d.ts +28 -0
- package/dist/components/Slider/context.d.ts.map +1 -0
- package/dist/components/Slider/context.js +5 -0
- package/dist/components/Slider/index.d.ts +6 -0
- package/dist/components/Slider/index.d.ts.map +1 -0
- package/dist/components/Slider/index.js +5 -0
- package/dist/components/Slider/types.d.ts +138 -0
- package/dist/components/Slider/types.d.ts.map +1 -0
- package/dist/components/Slider/types.js +1 -0
- package/dist/components/XYPad/Area.svelte +29 -0
- package/dist/components/XYPad/Area.svelte.d.ts +10 -0
- package/dist/components/XYPad/Area.svelte.d.ts.map +1 -0
- package/dist/components/XYPad/Root.svelte +238 -0
- package/dist/components/XYPad/Root.svelte.d.ts +10 -0
- package/dist/components/XYPad/Root.svelte.d.ts.map +1 -0
- package/dist/components/XYPad/Thumb.svelte +109 -0
- package/dist/components/XYPad/Thumb.svelte.d.ts +10 -0
- package/dist/components/XYPad/Thumb.svelte.d.ts.map +1 -0
- package/dist/components/XYPad/context.d.ts +25 -0
- package/dist/components/XYPad/context.d.ts.map +1 -0
- package/dist/components/XYPad/context.js +5 -0
- package/dist/components/XYPad/index.d.ts +4 -0
- package/dist/components/XYPad/index.d.ts.map +1 -0
- package/dist/components/XYPad/index.js +3 -0
- package/dist/components/XYPad/types.d.ts +80 -0
- package/dist/components/XYPad/types.d.ts.map +1 -0
- package/dist/components/XYPad/types.js +1 -0
- package/dist/components/_util/VisuallyHiddenRangeInput.svelte +17 -0
- package/dist/components/_util/VisuallyHiddenRangeInput.svelte.d.ts +8 -0
- package/dist/components/_util/VisuallyHiddenRangeInput.svelte.d.ts.map +1 -0
- package/dist/components/_util/check-steps.svelte.d.ts +10 -0
- package/dist/components/_util/check-steps.svelte.d.ts.map +1 -0
- package/dist/components/_util/check-steps.svelte.js +17 -0
- package/dist/components/_util/placement.d.ts +15 -0
- package/dist/components/_util/placement.d.ts.map +1 -0
- package/dist/components/_util/placement.js +30 -0
- package/dist/components/_util/style.d.ts +5 -0
- package/dist/components/_util/style.d.ts.map +1 -0
- package/dist/components/_util/style.js +9 -0
- package/dist/hooks/useMIDIAccess.svelte.d.ts +29 -0
- package/dist/hooks/useMIDIAccess.svelte.d.ts.map +1 -0
- package/dist/hooks/useMIDIAccess.svelte.js +62 -0
- package/dist/hooks/useMIDIInput.svelte.d.ts +18 -0
- package/dist/hooks/useMIDIInput.svelte.d.ts.map +1 -0
- package/dist/hooks/useMIDIInput.svelte.js +31 -0
- package/dist/hooks/useMIDIMessage.svelte.d.ts +9 -0
- package/dist/hooks/useMIDIMessage.svelte.d.ts.map +1 -0
- package/dist/hooks/useMIDIMessage.svelte.js +23 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/package.json +72 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
arrowKeyMove,
|
|
4
|
+
clampPoint,
|
|
5
|
+
createDragValue,
|
|
6
|
+
elementMapping,
|
|
7
|
+
POINT_AXIS,
|
|
8
|
+
selectModifier,
|
|
9
|
+
type PointPosition,
|
|
10
|
+
type PointsEditorPoint,
|
|
11
|
+
} from '@tremolo-ui/dom'
|
|
12
|
+
import { untrack } from 'svelte'
|
|
13
|
+
|
|
14
|
+
import { checkPlacement } from '../_util/placement.js'
|
|
15
|
+
import VisuallyHiddenRangeInput from '../_util/VisuallyHiddenRangeInput.svelte'
|
|
16
|
+
|
|
17
|
+
import { usePointsEditorContext } from './context.js'
|
|
18
|
+
import type { PointsEditorPointProps } from './types.js'
|
|
19
|
+
|
|
20
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
21
|
+
|
|
22
|
+
type Props = PointsEditorPointProps &
|
|
23
|
+
Omit<HTMLAttributes<HTMLDivElement>, keyof PointsEditorPointProps>
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
value,
|
|
27
|
+
id: idProp,
|
|
28
|
+
min,
|
|
29
|
+
max,
|
|
30
|
+
color,
|
|
31
|
+
disabled: disabledProp,
|
|
32
|
+
readonly: readonlyProp,
|
|
33
|
+
wheel: wheelProp,
|
|
34
|
+
keyboard: keyboardProp,
|
|
35
|
+
'aria-label': ariaLabel,
|
|
36
|
+
'aria-valuetext': ariaValuetext,
|
|
37
|
+
onChange,
|
|
38
|
+
onDragStart,
|
|
39
|
+
onDragEnd,
|
|
40
|
+
children,
|
|
41
|
+
style,
|
|
42
|
+
onfocus,
|
|
43
|
+
onkeydown,
|
|
44
|
+
...rest
|
|
45
|
+
}: Props = $props()
|
|
46
|
+
|
|
47
|
+
const points = usePointsEditorContext()
|
|
48
|
+
checkPlacement('PointsEditor.Point', 'PointsEditor.Container')
|
|
49
|
+
|
|
50
|
+
const generatedId = $props.id()
|
|
51
|
+
const id = $derived(idProp ?? generatedId)
|
|
52
|
+
const disabled = $derived(disabledProp ?? points.disabled)
|
|
53
|
+
const readonly = $derived(readonlyProp ?? points.readonly)
|
|
54
|
+
const inactive = $derived(disabled || readonly)
|
|
55
|
+
// `null` means "no event" and has to survive the fallback, so `??` is not
|
|
56
|
+
// enough: only an omitted prop inherits from the root.
|
|
57
|
+
const wheel = $derived(wheelProp === undefined ? points.wheel : wheelProp)
|
|
58
|
+
const keyboard = $derived(
|
|
59
|
+
keyboardProp === undefined ? points.keyboard : keyboardProp,
|
|
60
|
+
)
|
|
61
|
+
const selected = $derived(points.selection.includes(id))
|
|
62
|
+
const current = $derived(clampPoint(value, min, max))
|
|
63
|
+
|
|
64
|
+
let element: HTMLDivElement | null = $state(null)
|
|
65
|
+
let xInput: HTMLInputElement | null = $state(null)
|
|
66
|
+
let dragging = $state(false)
|
|
67
|
+
|
|
68
|
+
// Read by the editor whenever it moves the selection, so the value can
|
|
69
|
+
// change on every frame of a drag without registering again.
|
|
70
|
+
const read = (): PointsEditorPoint => ({
|
|
71
|
+
value,
|
|
72
|
+
min,
|
|
73
|
+
max,
|
|
74
|
+
readonly: inactive,
|
|
75
|
+
onChange,
|
|
76
|
+
element,
|
|
77
|
+
wheel,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
$effect(() => points.editor.registerPoint(id, read))
|
|
81
|
+
|
|
82
|
+
/** Where the pointer was when the drag started, to measure the move from. */
|
|
83
|
+
let origin: PointPosition | null = null
|
|
84
|
+
|
|
85
|
+
$effect(() => {
|
|
86
|
+
const node = element
|
|
87
|
+
if (!node) return
|
|
88
|
+
// The value is the position itself: no scaling, and no rounding to a step.
|
|
89
|
+
const drag = createDragValue(node, {
|
|
90
|
+
axis: POINT_AXIS,
|
|
91
|
+
mapping: elementMapping(() => points.container, {
|
|
92
|
+
sensitivity: (state) =>
|
|
93
|
+
selectModifier(points.dragSensitivity, state.event).value,
|
|
94
|
+
}),
|
|
95
|
+
cursor: untrack(() => (inactive ? undefined : points.cursor)),
|
|
96
|
+
shouldStart: () => !disabled,
|
|
97
|
+
// The value is a move rather than a position: the point keeps the
|
|
98
|
+
// offset it was grabbed at, and everything else selected moves with it.
|
|
99
|
+
onChange: ([x, y]) => {
|
|
100
|
+
if (origin)
|
|
101
|
+
points.editor.movePointDrag({ x: x - origin.x, y: y - origin.y })
|
|
102
|
+
},
|
|
103
|
+
onDragStart: ([x, y], state) => {
|
|
104
|
+
points.editor.beginPointDrag(id, state.event)
|
|
105
|
+
origin = { x, y }
|
|
106
|
+
dragging = true
|
|
107
|
+
xInput?.focus()
|
|
108
|
+
if (!inactive) onDragStart?.(clampPoint(value, min, max))
|
|
109
|
+
},
|
|
110
|
+
onDragEnd: () => {
|
|
111
|
+
origin = null
|
|
112
|
+
dragging = false
|
|
113
|
+
if (!inactive) onDragEnd?.(clampPoint(value, min, max))
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
$effect(() => {
|
|
117
|
+
drag.update({ cursor: inactive ? undefined : points.cursor })
|
|
118
|
+
})
|
|
119
|
+
return () => drag.destroy()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
function perAxis(
|
|
123
|
+
setting: string | Partial<Record<'x' | 'y', string>> | undefined,
|
|
124
|
+
axis: 'x' | 'y',
|
|
125
|
+
) {
|
|
126
|
+
return typeof setting === 'string' ? setting : setting?.[axis]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function onInput(axis: 'x' | 'y', target: HTMLInputElement) {
|
|
130
|
+
if (readonly) {
|
|
131
|
+
target.value = String(current[axis])
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
const delta = target.valueAsNumber - value[axis]
|
|
135
|
+
points.editor.nudgeSelection(id, {
|
|
136
|
+
x: axis === 'x' ? delta : 0,
|
|
137
|
+
y: axis === 'y' ? delta : 0,
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
</script>
|
|
141
|
+
|
|
142
|
+
<!-- The visual point has two values, so its semantics live on the two range
|
|
143
|
+
inputs nested inside it rather than on this drag handle. A press lands on
|
|
144
|
+
the point, which cannot hold focus, and the browser answers that by
|
|
145
|
+
clearing the focus — tabindex -1 keeps it inside. -->
|
|
146
|
+
<div
|
|
147
|
+
bind:this={element}
|
|
148
|
+
tabindex="-1"
|
|
149
|
+
role="presentation"
|
|
150
|
+
data-disabled={disabled ? '' : undefined}
|
|
151
|
+
data-readonly={readonly ? '' : undefined}
|
|
152
|
+
data-dragging={dragging ? '' : undefined}
|
|
153
|
+
data-selected={selected ? '' : undefined}
|
|
154
|
+
{...rest}
|
|
155
|
+
style="position: absolute; translate: var(--translate, -50% -50%); {style ??
|
|
156
|
+
''}"
|
|
157
|
+
style:--color={color}
|
|
158
|
+
style:left="{value.x * 100}%"
|
|
159
|
+
style:top="{value.y * 100}%"
|
|
160
|
+
onfocus={(event) => {
|
|
161
|
+
// The point itself is not the control: whatever reaches it is handed to
|
|
162
|
+
// the first input.
|
|
163
|
+
if (!disabled && event.target === event.currentTarget) xInput?.focus()
|
|
164
|
+
onfocus?.(event)
|
|
165
|
+
}}
|
|
166
|
+
onkeydown={(event) => {
|
|
167
|
+
// The key picks the axis, whichever of the two inputs holds the focus.
|
|
168
|
+
// y grows downwards, so ArrowUp moves the point towards 0.
|
|
169
|
+
const move = arrowKeyMove(event.key)
|
|
170
|
+
if (move) {
|
|
171
|
+
event.preventDefault()
|
|
172
|
+
if (onChange && !inactive && keyboard) {
|
|
173
|
+
points.editor.nudgePoint(
|
|
174
|
+
id,
|
|
175
|
+
move.axis === 0 ? 'x' : 'y',
|
|
176
|
+
move.direction,
|
|
177
|
+
keyboard,
|
|
178
|
+
event,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
onkeydown?.(event)
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<VisuallyHiddenRangeInput
|
|
186
|
+
bind:ref={xInput}
|
|
187
|
+
data-axis="x"
|
|
188
|
+
value={current.x}
|
|
189
|
+
min={min?.x ?? 0}
|
|
190
|
+
max={max?.x ?? 1}
|
|
191
|
+
step="any"
|
|
192
|
+
{disabled}
|
|
193
|
+
aria-readonly={readonly}
|
|
194
|
+
aria-orientation="horizontal"
|
|
195
|
+
aria-label={perAxis(ariaLabel, 'x') ?? 'x'}
|
|
196
|
+
aria-valuetext={perAxis(ariaValuetext, 'x')}
|
|
197
|
+
oninput={(event) => onInput('x', event.currentTarget)}
|
|
198
|
+
/>
|
|
199
|
+
<VisuallyHiddenRangeInput
|
|
200
|
+
data-axis="y"
|
|
201
|
+
value={current.y}
|
|
202
|
+
min={min?.y ?? 0}
|
|
203
|
+
max={max?.y ?? 1}
|
|
204
|
+
step="any"
|
|
205
|
+
{disabled}
|
|
206
|
+
aria-readonly={readonly}
|
|
207
|
+
aria-orientation="vertical"
|
|
208
|
+
aria-label={perAxis(ariaLabel, 'y') ?? 'y'}
|
|
209
|
+
aria-valuetext={perAxis(ariaValuetext, 'y')}
|
|
210
|
+
oninput={(event) => onInput('y', event.currentTarget)}
|
|
211
|
+
/>
|
|
212
|
+
{@render children?.()}
|
|
213
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PointsEditorPointProps } from './types.js';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = PointsEditorPointProps & Omit<HTMLAttributes<HTMLDivElement>, keyof PointsEditorPointProps>;
|
|
4
|
+
declare const Point: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type Point = ReturnType<typeof Point>;
|
|
6
|
+
export default Point;
|
|
7
|
+
//# sourceMappingURL=Point.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Point.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/Point.svelte.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,KAAK,GAAG,sBAAsB,GACjC,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,sBAAsB,CAAC,CAAC;AAmKvE,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
createPointsEditor,
|
|
4
|
+
DEFAULT_DRAG_SENSITIVITY,
|
|
5
|
+
POINTS_EDITOR_DEFAULT_KEYBOARD,
|
|
6
|
+
POINTS_EDITOR_DEFAULT_WHEEL,
|
|
7
|
+
type SelectionBoxRect,
|
|
8
|
+
} from '@tremolo-ui/dom'
|
|
9
|
+
|
|
10
|
+
import { setPointsEditorContext } from './context.js'
|
|
11
|
+
import type { PointsEditorProps } from './types.js'
|
|
12
|
+
|
|
13
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
14
|
+
|
|
15
|
+
type Props = PointsEditorProps &
|
|
16
|
+
Omit<HTMLAttributes<HTMLDivElement>, keyof PointsEditorProps>
|
|
17
|
+
|
|
18
|
+
let {
|
|
19
|
+
disabled = false,
|
|
20
|
+
readonly = false,
|
|
21
|
+
externalStyles,
|
|
22
|
+
wheel = POINTS_EDITOR_DEFAULT_WHEEL,
|
|
23
|
+
keyboard = POINTS_EDITOR_DEFAULT_KEYBOARD,
|
|
24
|
+
dragSensitivity = DEFAULT_DRAG_SENSITIVITY,
|
|
25
|
+
selectable = false,
|
|
26
|
+
selection = $bindable([]),
|
|
27
|
+
onSelectionChange,
|
|
28
|
+
ref = $bindable(null),
|
|
29
|
+
children,
|
|
30
|
+
style,
|
|
31
|
+
...rest
|
|
32
|
+
}: Props = $props()
|
|
33
|
+
|
|
34
|
+
let selectionBox: SelectionBoxRect | null = $state(null)
|
|
35
|
+
let container: HTMLElement | null = $state(null)
|
|
36
|
+
|
|
37
|
+
// Nothing is selected while selection is off, so a drag picks up only the
|
|
38
|
+
// point it started on and `data-selected` never turns on.
|
|
39
|
+
const current = $derived(selectable ? selection : [])
|
|
40
|
+
|
|
41
|
+
// The selection lives here, where Svelte state can hold it; which points a
|
|
42
|
+
// press or a box selects, and how a selection moves, is the core's.
|
|
43
|
+
const editor = createPointsEditor({
|
|
44
|
+
onSelectionBoxChange: (rect) => {
|
|
45
|
+
selectionBox = rect
|
|
46
|
+
},
|
|
47
|
+
onSelectionChange: (next) => {
|
|
48
|
+
selection = next
|
|
49
|
+
onSelectionChange?.(next)
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Pushed before the DOM updates, so that the next press already sees it.
|
|
54
|
+
$effect.pre(() => {
|
|
55
|
+
editor.update({ selectable, selection: current })
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
$effect(() => () => editor.destroy())
|
|
59
|
+
|
|
60
|
+
setPointsEditorContext({
|
|
61
|
+
get disabled() {
|
|
62
|
+
return disabled
|
|
63
|
+
},
|
|
64
|
+
get readonly() {
|
|
65
|
+
return readonly
|
|
66
|
+
},
|
|
67
|
+
get wheel() {
|
|
68
|
+
return wheel
|
|
69
|
+
},
|
|
70
|
+
get keyboard() {
|
|
71
|
+
return keyboard
|
|
72
|
+
},
|
|
73
|
+
get dragSensitivity() {
|
|
74
|
+
return dragSensitivity
|
|
75
|
+
},
|
|
76
|
+
get cursor() {
|
|
77
|
+
return externalStyles?.cursor ?? 'grabbing'
|
|
78
|
+
},
|
|
79
|
+
get selectable() {
|
|
80
|
+
return selectable
|
|
81
|
+
},
|
|
82
|
+
get selection() {
|
|
83
|
+
return current
|
|
84
|
+
},
|
|
85
|
+
get selectionBox() {
|
|
86
|
+
return selectionBox
|
|
87
|
+
},
|
|
88
|
+
get container() {
|
|
89
|
+
return container
|
|
90
|
+
},
|
|
91
|
+
editor,
|
|
92
|
+
setContainer: (element) => {
|
|
93
|
+
container = element
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<!-- The layers inside are placed against this box. -->
|
|
99
|
+
<div
|
|
100
|
+
bind:this={ref}
|
|
101
|
+
data-disabled={disabled ? '' : undefined}
|
|
102
|
+
data-readonly={readonly ? '' : undefined}
|
|
103
|
+
style="position: relative; {style ?? ''}"
|
|
104
|
+
{...rest}
|
|
105
|
+
>
|
|
106
|
+
{@render children()}
|
|
107
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PointsEditorProps } from './types.js';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = PointsEditorProps & Omit<HTMLAttributes<HTMLDivElement>, keyof PointsEditorProps>;
|
|
4
|
+
declare const Root: import("svelte").Component<Props, {}, "ref" | "selection">;
|
|
5
|
+
type Root = ReturnType<typeof Root>;
|
|
6
|
+
export default Root;
|
|
7
|
+
//# sourceMappingURL=Root.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Root.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/Root.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,KAAK,GAAG,iBAAiB,GAC5B,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,iBAAiB,CAAC,CAAC;AAiGlE,QAAA,MAAM,IAAI,4DAAwC,CAAC;AACnD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AACpC,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { checkPlacement } from '../_util/placement.js'
|
|
3
|
+
|
|
4
|
+
import { usePointsEditorContext } from './context.js'
|
|
5
|
+
|
|
6
|
+
import type { Snippet } from 'svelte'
|
|
7
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
8
|
+
|
|
9
|
+
type Props = HTMLAttributes<HTMLDivElement> & { children?: Snippet }
|
|
10
|
+
|
|
11
|
+
let { children, style, ...rest }: Props = $props()
|
|
12
|
+
|
|
13
|
+
const points = usePointsEditorContext()
|
|
14
|
+
checkPlacement('PointsEditor.SelectionBox', 'PointsEditor.Container')
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<!-- Drawn over the points while a drag runs, and taking none of the pointer:
|
|
18
|
+
the drag underneath is what it is reporting on. Nothing is rendered while no
|
|
19
|
+
drag is running. -->
|
|
20
|
+
{#if points.selectionBox}
|
|
21
|
+
{@const box = points.selectionBox}
|
|
22
|
+
<div
|
|
23
|
+
{...rest}
|
|
24
|
+
style="position: absolute; z-index: 20; pointer-events: none; {style ?? ''}"
|
|
25
|
+
style:left="{box.x * 100}%"
|
|
26
|
+
style:top="{box.y * 100}%"
|
|
27
|
+
style:width="{box.width * 100}%"
|
|
28
|
+
style:height="{box.height * 100}%"
|
|
29
|
+
>
|
|
30
|
+
{@render children?.()}
|
|
31
|
+
</div>
|
|
32
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
};
|
|
6
|
+
declare const SelectionBox: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type SelectionBox = ReturnType<typeof SelectionBox>;
|
|
8
|
+
export default SelectionBox;
|
|
9
|
+
//# sourceMappingURL=SelectionBox.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionBox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/SelectionBox.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,KAAK,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA0BvE,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { InputEventOption, ModifierValue, PointsEditorInstance, SelectionBoxRect } from '@tremolo-ui/dom';
|
|
2
|
+
/** What `PointsEditor.Root` shares with its parts. Every field is a getter. */
|
|
3
|
+
export interface PointsEditorContextValue {
|
|
4
|
+
readonly disabled: boolean;
|
|
5
|
+
readonly readonly: boolean;
|
|
6
|
+
readonly wheel: ModifierValue<InputEventOption> | null;
|
|
7
|
+
readonly keyboard: ModifierValue<InputEventOption> | null;
|
|
8
|
+
readonly dragSensitivity: ModifierValue<number>;
|
|
9
|
+
readonly cursor: string;
|
|
10
|
+
readonly selectable: boolean;
|
|
11
|
+
/** Ids of the selected points. Always empty while `selectable` is off. */
|
|
12
|
+
readonly selection: readonly string[];
|
|
13
|
+
/** The selection box, while one is being dragged. */
|
|
14
|
+
readonly selectionBox: SelectionBoxRect | null;
|
|
15
|
+
/** The element points are placed in and measured against. */
|
|
16
|
+
readonly container: HTMLElement | null;
|
|
17
|
+
/**
|
|
18
|
+
* The selection and the moves, from `createPointsEditor` in
|
|
19
|
+
* `@tremolo-ui/dom`: every `Point` registers with it.
|
|
20
|
+
*/
|
|
21
|
+
readonly editor: PointsEditorInstance;
|
|
22
|
+
/** @internal `Container` registers its element. */
|
|
23
|
+
setContainer: (element: HTMLElement | null) => void;
|
|
24
|
+
}
|
|
25
|
+
/** The context of the enclosing `PointsEditor.Root`, for a part of your own. */
|
|
26
|
+
export declare const usePointsEditorContext: () => PointsEditorContextValue;
|
|
27
|
+
export declare const setPointsEditorContext: (context: PointsEditorContextValue) => PointsEditorContextValue;
|
|
28
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,iBAAiB,CAAA;AAExB,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IACzD,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC9C,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAA;IACtC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAA;IACrC,mDAAmD;IACnD,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;CACpD;AAID,gFAAgF;AAChF,eAAO,MAAM,sBAAsB,gCAAM,CAAA;AACzC,eAAO,MAAM,sBAAsB,iEAAM,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as Background } from './Background.svelte';
|
|
2
|
+
export { default as Container } from './Container.svelte';
|
|
3
|
+
export { default as Point } from './Point.svelte';
|
|
4
|
+
export { default as Root } from './Root.svelte';
|
|
5
|
+
export { default as SelectionBox } from './SelectionBox.svelte';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Background } from './Background.svelte';
|
|
2
|
+
export { default as Container } from './Container.svelte';
|
|
3
|
+
export { default as Point } from './Point.svelte';
|
|
4
|
+
export { default as Root } from './Root.svelte';
|
|
5
|
+
export { default as SelectionBox } from './SelectionBox.svelte';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { InputEventOption, ModifierValue, PointPosition } from '@tremolo-ui/dom';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
export interface PointsEditorProps {
|
|
4
|
+
/** Make the points unchangeable and remove them from the tab order. */
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/** Make the points unmovable. */
|
|
7
|
+
readonly?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The cursor to show while dragging a point.
|
|
10
|
+
* @default { cursor: 'grabbing' }
|
|
11
|
+
*/
|
|
12
|
+
externalStyles?: {
|
|
13
|
+
cursor?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* How much one notch of the wheel moves the focused `Point`. Scrolling
|
|
17
|
+
* sideways, or with shift held, moves x. A `Point` can override it.
|
|
18
|
+
* @default ['normalized', 0.01]
|
|
19
|
+
*/
|
|
20
|
+
wheel?: ModifierValue<InputEventOption> | null;
|
|
21
|
+
/**
|
|
22
|
+
* How much one arrow key press moves a `Point`. A `Point` can override it.
|
|
23
|
+
* @default { default: ['normalized', 0.01], shift: ['normalized', 0.001] }
|
|
24
|
+
*/
|
|
25
|
+
keyboard?: ModifierValue<InputEventOption> | null;
|
|
26
|
+
/**
|
|
27
|
+
* How much a drag moves a `Point`, per modifier key.
|
|
28
|
+
* @default { default: 1, shift: 0.1 }
|
|
29
|
+
*/
|
|
30
|
+
dragSensitivity?: ModifierValue<number>;
|
|
31
|
+
/**
|
|
32
|
+
* Let points be selected, and a selection be moved as one. A selection
|
|
33
|
+
* calls `onChange` on several points in the same tick.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
selectable?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Ids of the selected points. Bind it (`bind:selection`) to hold the
|
|
39
|
+
* selection yourself.
|
|
40
|
+
*/
|
|
41
|
+
selection?: string[];
|
|
42
|
+
/** Called whenever the selection changes. */
|
|
43
|
+
onSelectionChange?: (selection: string[]) => void;
|
|
44
|
+
/** The root element, bound with `bind:ref`. */
|
|
45
|
+
ref?: HTMLDivElement | null;
|
|
46
|
+
/** The editor renders exactly what you compose here. */
|
|
47
|
+
children: Snippet;
|
|
48
|
+
}
|
|
49
|
+
export interface PointsEditorPointProps {
|
|
50
|
+
/** Where the point is, as `{ x, y }` from 0 to 1, with `y` growing downwards. */
|
|
51
|
+
value: PointPosition;
|
|
52
|
+
/**
|
|
53
|
+
* How the selection refers to this point. One is generated when it is left
|
|
54
|
+
* out, which lasts as long as the point is mounted.
|
|
55
|
+
*/
|
|
56
|
+
id?: string;
|
|
57
|
+
/** The lowest position the point can take, per axis. */
|
|
58
|
+
min?: Partial<PointPosition>;
|
|
59
|
+
/** The highest position the point can take, per axis. */
|
|
60
|
+
max?: Partial<PointPosition>;
|
|
61
|
+
/** Sets `--color`, for the theme to colour the point with. */
|
|
62
|
+
color?: string;
|
|
63
|
+
/** Overrides the `disabled` of `PointsEditor.Root`. */
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
/** Overrides the `readonly` of `PointsEditor.Root`. */
|
|
66
|
+
readonly?: boolean;
|
|
67
|
+
/** Overrides the `wheel` of `PointsEditor.Root`. */
|
|
68
|
+
wheel?: ModifierValue<InputEventOption> | null;
|
|
69
|
+
/** Overrides the `keyboard` of `PointsEditor.Root`. */
|
|
70
|
+
keyboard?: ModifierValue<InputEventOption> | null;
|
|
71
|
+
/** The accessible name of each axis, or one for both. */
|
|
72
|
+
'aria-label'?: string | Partial<Record<'x' | 'y', string>>;
|
|
73
|
+
/** What the value of each axis means, or one for both. */
|
|
74
|
+
'aria-valuetext'?: string | Partial<Record<'x' | 'y', string>>;
|
|
75
|
+
/**
|
|
76
|
+
* Called with the new position when the point is moved, including when it
|
|
77
|
+
* moves along with a selection.
|
|
78
|
+
*/
|
|
79
|
+
onChange?: (value: PointPosition) => void;
|
|
80
|
+
onDragStart?: (value: PointPosition) => void;
|
|
81
|
+
onDragEnd?: (value: PointPosition) => void;
|
|
82
|
+
children?: Snippet;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/PointsEditor/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,EACd,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IAC9C;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IACjD;;;OAGG;IACH,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACjD,+CAA+C;IAC/C,GAAG,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IAC3B,wDAAwD;IACxD,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,KAAK,EAAE,aAAa,CAAA;IACpB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,wDAAwD;IACxD,GAAG,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC5B,yDAAyD;IACzD,GAAG,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC5B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,oDAAoD;IACpD,KAAK,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IAC9C,uDAAuD;IACvD,QAAQ,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;IACjD,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1D,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9D;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IACzC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cssLength, sliderMarks } from '@tremolo-ui/dom'
|
|
3
|
+
|
|
4
|
+
import { setPlacement } from '../_util/placement.js'
|
|
5
|
+
|
|
6
|
+
import { useSliderContext } from './context.js'
|
|
7
|
+
import MarksOption from './MarksOption.svelte'
|
|
8
|
+
import type { SliderMarksProps } from './types.js'
|
|
9
|
+
|
|
10
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
11
|
+
|
|
12
|
+
type Props = SliderMarksProps &
|
|
13
|
+
Omit<HTMLAttributes<HTMLDivElement>, keyof SliderMarksProps>
|
|
14
|
+
|
|
15
|
+
let { gap, options, children, style, ...rest }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const slider = useSliderContext()
|
|
18
|
+
setPlacement('Slider.Marks')
|
|
19
|
+
|
|
20
|
+
const marks = $derived.by(() => {
|
|
21
|
+
if (!options) return []
|
|
22
|
+
const list = sliderMarks(options, slider.min, slider.max, slider.step)
|
|
23
|
+
// In the order they are on screen.
|
|
24
|
+
return slider.vertical !== slider.reverse ? list.reverse() : list
|
|
25
|
+
})
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<!-- Each option inside is placed against this box. -->
|
|
29
|
+
<div
|
|
30
|
+
data-orientation={slider.vertical ? 'vertical' : 'horizontal'}
|
|
31
|
+
style="position: relative; {style ?? ''}"
|
|
32
|
+
style:--gap={cssLength(gap)}
|
|
33
|
+
{...rest}
|
|
34
|
+
>
|
|
35
|
+
{#if options}
|
|
36
|
+
{#each marks as { value, mark, label } (value)}
|
|
37
|
+
<MarksOption {value} {mark} label={label ? undefined : null} />
|
|
38
|
+
{/each}
|
|
39
|
+
{:else}
|
|
40
|
+
{@render children?.()}
|
|
41
|
+
{/if}
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SliderMarksProps } from './types.js';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = SliderMarksProps & Omit<HTMLAttributes<HTMLDivElement>, keyof SliderMarksProps>;
|
|
4
|
+
declare const Marks: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type Marks = ReturnType<typeof Marks>;
|
|
6
|
+
export default Marks;
|
|
7
|
+
//# sourceMappingURL=Marks.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Marks.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/Marks.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGpD,KAAK,KAAK,GAAG,gBAAgB,GAC3B,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,gBAAgB,CAAC,CAAC;AAuCjE,QAAA,MAAM,KAAK,2CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cssLength, valuePercent } from '@tremolo-ui/dom'
|
|
3
|
+
|
|
4
|
+
import { checkPlacement } from '../_util/placement.js'
|
|
5
|
+
|
|
6
|
+
import { useSliderContext } from './context.js'
|
|
7
|
+
import type { SliderMarksOptionProps } from './types.js'
|
|
8
|
+
|
|
9
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
10
|
+
|
|
11
|
+
type Props = SliderMarksOptionProps &
|
|
12
|
+
Omit<HTMLAttributes<HTMLDivElement>, keyof SliderMarksOptionProps>
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
value,
|
|
16
|
+
mark = true,
|
|
17
|
+
label,
|
|
18
|
+
thickness,
|
|
19
|
+
length,
|
|
20
|
+
gap,
|
|
21
|
+
classes,
|
|
22
|
+
styles,
|
|
23
|
+
style,
|
|
24
|
+
...rest
|
|
25
|
+
}: Props = $props()
|
|
26
|
+
|
|
27
|
+
const slider = useSliderContext()
|
|
28
|
+
checkPlacement('Slider.MarksOption', 'Slider.Marks')
|
|
29
|
+
|
|
30
|
+
// The marks sit on the same curve the thumb runs along.
|
|
31
|
+
const percent = $derived(
|
|
32
|
+
valuePercent(
|
|
33
|
+
value,
|
|
34
|
+
{ min: slider.min, max: slider.max, scale: slider.scale },
|
|
35
|
+
slider.vertical !== slider.reverse,
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
const orientation = $derived(slider.vertical ? 'vertical' : 'horizontal')
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<div
|
|
42
|
+
data-orientation={orientation}
|
|
43
|
+
{...rest}
|
|
44
|
+
style="position: absolute; translate: {slider.vertical
|
|
45
|
+
? 'var(--translate, 0 -50%)'
|
|
46
|
+
: 'var(--translate, -50% 0)'}; z-index: 10; {style ?? ''}"
|
|
47
|
+
style:--thickness={cssLength(thickness)}
|
|
48
|
+
style:--length={cssLength(length)}
|
|
49
|
+
style:--gap={cssLength(gap)}
|
|
50
|
+
style:left={slider.vertical ? undefined : `${percent}%`}
|
|
51
|
+
style:top={slider.vertical ? `${percent}%` : undefined}
|
|
52
|
+
>
|
|
53
|
+
{#if mark}
|
|
54
|
+
<div
|
|
55
|
+
class={classes?.mark}
|
|
56
|
+
style={styles?.mark}
|
|
57
|
+
data-orientation={orientation}
|
|
58
|
+
></div>
|
|
59
|
+
{/if}
|
|
60
|
+
{#if label !== null}
|
|
61
|
+
<div class={classes?.label} style={styles?.label}>{label ?? value}</div>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SliderMarksOptionProps } from './types.js';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = SliderMarksOptionProps & Omit<HTMLAttributes<HTMLDivElement>, keyof SliderMarksOptionProps>;
|
|
4
|
+
declare const MarksOption: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type MarksOption = ReturnType<typeof MarksOption>;
|
|
6
|
+
export default MarksOption;
|
|
7
|
+
//# sourceMappingURL=MarksOption.svelte.d.ts.map
|