@@ -47,6 +78,7 @@ const props = withDefaults(defineProps<{
coarseStep?: number
label?: string
ariaLabel?: string
+ lockKey?: string
disabled?: boolean
compact?: boolean
digits?: number
@@ -56,6 +88,7 @@ const props = withDefaults(defineProps<{
coarseStep: 1,
label: '',
ariaLabel: '',
+ lockKey: '',
disabled: false,
compact: false,
digits: 1
@@ -63,12 +96,36 @@ const props = withDefaults(defineProps<{
const model = defineModel({ required: true })
const root = ref(null)
+const locked = ref(false)
+const dialName = computed(() => props.label || props.ariaLabel || 'dial')
+const storeKey = computed(() => {
+ const id = (props.lockKey || props.label || props.ariaLabel || '').trim().toLowerCase()
+ return id ? `aigen-thumb-lock:${id}` : ''
+})
+const frozen = computed(() => props.disabled || locked.value)
const span = computed(() => Math.max(props.max - props.min, 0.0001))
const pct = computed(() => ((clamp(model.value) - props.min) / span.value) * 100)
const display = computed(() => format(model.value))
const drumShift = computed(() => Math.round((pct.value / 100) * 72))
+function readLock() {
+ if (!storeKey.value || typeof localStorage === 'undefined') return
+ try {
+ locked.value = localStorage.getItem(storeKey.value) === '1'
+ } catch {
+ locked.value = false
+ }
+}
+
+function toggleLock() {
+ locked.value = !locked.value
+ if (!storeKey.value || typeof localStorage === 'undefined') return
+ try {
+ localStorage.setItem(storeKey.value, locked.value ? '1' : '0')
+ } catch { /* ignore */ }
+}
+
function clamp(value: number) {
if (!Number.isFinite(value)) return props.min
const step = props.step || 0.1
@@ -89,13 +146,14 @@ function nudge(delta: number) {
}
function onWheel(event: WheelEvent) {
- if (props.disabled) return
+ if (frozen.value) return
+ event.preventDefault()
const step = event.shiftKey ? props.coarseStep : props.fineStep
nudge(event.deltaY < 0 ? step : -step)
}
function onKey(event: KeyboardEvent) {
- if (props.disabled) return
+ if (frozen.value) return
const step = event.shiftKey ? props.coarseStep : props.fineStep
if (event.key === 'ArrowUp' || event.key === 'ArrowRight') {
event.preventDefault()
@@ -113,7 +171,7 @@ function onKey(event: KeyboardEvent) {
}
function onPointerDown(event: PointerEvent) {
- if (props.disabled || event.button !== 0) return
+ if (frozen.value || event.button !== 0) return
const el = root.value
if (!el) return
event.preventDefault()
@@ -134,6 +192,16 @@ function onPointerDown(event: PointerEvent) {
el.addEventListener('pointerup', onUp)
el.addEventListener('pointercancel', onUp)
}
+
+onMounted(() => {
+ readLock()
+ const el = root.value
+ if (!el) return
+ el.addEventListener('wheel', onWheel, { passive: false })
+ onBeforeUnmount(() => el.removeEventListener('wheel', onWheel))
+})
+
+watch(storeKey, readLock)