Continuation of separting logic into domain specific composables
This commit is contained in:
85
src/composables/useZoom.ts
Normal file
85
src/composables/useZoom.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
export interface ZoomOptionsStep {
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
initial?: number;
|
||||
}
|
||||
|
||||
export interface ZoomOptionsAllowed {
|
||||
allowedValues: number[];
|
||||
initial?: number;
|
||||
}
|
||||
|
||||
export type ZoomOptions = ZoomOptionsStep | ZoomOptionsAllowed;
|
||||
|
||||
function isStepOptions(options: ZoomOptions): options is ZoomOptionsStep {
|
||||
return 'step' in options;
|
||||
}
|
||||
|
||||
export function useZoom(options: ZoomOptions) {
|
||||
const initial = options.initial ?? (isStepOptions(options) ? 1 : options.allowedValues[1] ?? options.allowedValues[0]);
|
||||
const zoom = ref(initial);
|
||||
|
||||
const zoomPercent = computed(() => Math.round(zoom.value * 100));
|
||||
|
||||
const increase = () => {
|
||||
if (isStepOptions(options)) {
|
||||
zoom.value = Math.min(options.max, zoom.value + options.step);
|
||||
} else {
|
||||
const currentIndex = options.allowedValues.indexOf(zoom.value);
|
||||
if (currentIndex < options.allowedValues.length - 1) {
|
||||
zoom.value = options.allowedValues[currentIndex + 1];
|
||||
} else if (currentIndex === -1) {
|
||||
// Find the nearest higher value
|
||||
const higher = options.allowedValues.find(v => v > zoom.value);
|
||||
if (higher !== undefined) {
|
||||
zoom.value = higher;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const decrease = () => {
|
||||
if (isStepOptions(options)) {
|
||||
zoom.value = Math.max(options.min, zoom.value - options.step);
|
||||
} else {
|
||||
const currentIndex = options.allowedValues.indexOf(zoom.value);
|
||||
if (currentIndex > 0) {
|
||||
zoom.value = options.allowedValues[currentIndex - 1];
|
||||
} else if (currentIndex === -1) {
|
||||
// Find the nearest lower value
|
||||
const lower = [...options.allowedValues].reverse().find(v => v < zoom.value);
|
||||
if (lower !== undefined) {
|
||||
zoom.value = lower;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
zoom.value = initial;
|
||||
};
|
||||
|
||||
const setZoom = (value: number) => {
|
||||
if (isStepOptions(options)) {
|
||||
zoom.value = Math.max(options.min, Math.min(options.max, value));
|
||||
} else {
|
||||
// Snap to nearest allowed value
|
||||
const nearest = options.allowedValues.reduce((prev, curr) =>
|
||||
Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev
|
||||
);
|
||||
zoom.value = nearest;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
zoom,
|
||||
zoomPercent,
|
||||
increase,
|
||||
decrease,
|
||||
reset,
|
||||
setZoom,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user