commit 60bce6002bc55339e17e058da596529bd614a49c
parent 6d05ae8af95954bd2ec4af0fd7c5966e87a0997e
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date: Sat, 21 Jun 2025 18:04:18 -0700
Convert composables to TypeScript
Diffstat:
9 files changed, 75 insertions(+), 70 deletions(-)
diff --git a/src/components/PaceInput.vue b/src/components/PaceInput.vue
@@ -48,7 +48,7 @@ const props = defineProps({
// Generate internal ref tied to modelValue prop
const emit = defineEmits(['update:modelValue']);
-const model = useObjectModel(props, emit, 'modelValue');
+const model = useObjectModel(() => props.modelValue, emit, 'modelValue');
</script>
<style scoped>
diff --git a/src/components/RaceOptions.vue b/src/components/RaceOptions.vue
@@ -36,5 +36,5 @@ const props = defineProps({
// Generate internal ref tied to modelValue prop
const emit = defineEmits(['update:modelValue']);
-const model = useObjectModel(props, emit, 'modelValue');
+const model = useObjectModel(() => props.modelValue, emit, 'modelValue');
</script>
diff --git a/src/components/SplitOutputTable.vue b/src/components/SplitOutputTable.vue
@@ -75,7 +75,7 @@ const props = defineProps({
// Generate internal ref tied to modelValue prop
const emit = defineEmits(['update:modelValue']);
-const model = useObjectModel(props, emit, 'modelValue');
+const model = useObjectModel(() => props.modelValue, emit, 'modelValue');
/**
* The target table results
diff --git a/src/components/TargetEditor.vue b/src/components/TargetEditor.vue
@@ -145,7 +145,7 @@ const props = defineProps({
const emit = defineEmits(['close', 'revert', 'update:modelValue']);
// Generate internal ref tied to modelValue prop
-const model = useObjectModel(props, emit, 'modelValue');
+const model = useObjectModel(() => props.modelValue, emit, 'modelValue');
/**
* Add a new distance based target
diff --git a/src/components/TargetSetSelector.vue b/src/components/TargetSetSelector.vue
@@ -74,7 +74,7 @@ const props = defineProps({
// Generate internal ref tied to modelValue prop
const emit = defineEmits(['update:targetSets']);
-const targetSets = useObjectModel(props, emit, 'targetSets');
+const targetSets = useObjectModel(() => props.targetSets, emit, 'targetSets');
/**
* The dialog element
diff --git a/src/composables/useObjectModel.js b/src/composables/useObjectModel.js
@@ -1,35 +0,0 @@
-import { ref, watch } from 'vue';
-
-import { deepCopy, deepEqual } from '@/utils/misc';
-
-/*
- * Generate an internal ref that implements support for v-model with objects
- * @param {Object} props The props object
- * @param {Object} emit The emit object
- * @param {String} name The name of the v-model prop
- * @returns {Object} The internal ref
- */
-export default function defineObjectModel(props, emit, name) {
- /**
- * The internal value
- */
- const internalValue = ref(deepCopy(props[name]));
-
- /**
- * Update the internal value when the component value changes
- */
- watch(() => props[name], (newValue) => {
- if (!deepEqual(internalValue.value, newValue)) {
- internalValue.value = deepCopy(newValue);
- }
- }, { deep: true });
-
- /**
- * Update the component value when the internal value changes
- */
- watch(internalValue, (newValue) => {
- emit(`update:${name}`, deepCopy(newValue));
- }, { deep: true });
-
- return internalValue;
-}
diff --git a/src/composables/useObjectModel.ts b/src/composables/useObjectModel.ts
@@ -0,0 +1,38 @@
+import { ref, watch } from 'vue';
+import type { Ref } from 'vue';
+
+import { deepCopy, deepEqual } from '@/utils/misc';
+
+/*
+ * Generate an internal ref that implements support for v-model with objects
+ * @param {Function} prop A function returning the prop
+ * @param {Function} emit The emit function
+ * @param {string} name The name of the v-model prop
+ * @returns {Ref<object>} The internal ref
+ */
+export default function defineObjectModel(prop: () => Ref<object>,
+ emit: (x: string, y: object) => void,
+ name: string): Ref<object> {
+ /**
+ * The internal value
+ */
+ const internalValue = ref(deepCopy(prop()));
+
+ /**
+ * Update the internal value when the component value changes
+ */
+ watch(prop, (newValue: object) => {
+ if (!deepEqual(internalValue.value, newValue)) {
+ internalValue.value = deepCopy(newValue);
+ }
+ }, { deep: true });
+
+ /**
+ * Update the component value when the internal value changes
+ */
+ watch(internalValue, (newValue: object) => {
+ emit(`update:${name}`, deepCopy(newValue));
+ }, { deep: true });
+
+ return internalValue;
+}
diff --git a/src/composables/useStorage.js b/src/composables/useStorage.js
@@ -1,30 +0,0 @@
-import { ref, onActivated, watchEffect } from 'vue';
-
-import * as storage from '@/utils/storage';
-
-/*
- * Create a reactive value that is synced with a localStorage item
- * @param {String} key The localStorage item's key
- * @defaultValue {Object} defaultValue The default value
- */
-export default function useStorage(key, defaultValue) {
- const clonedDefault = JSON.parse(JSON.stringify(defaultValue));
- const value = ref(clonedDefault);
-
- // (Re)load value from localStorage
- function updateValue() {
- let parsedValue = storage.get(key);
- if (parsedValue !== null) value.value = parsedValue;
- }
- updateValue();
- onActivated(updateValue);
-
- // Save value to localStorage when modified
- watchEffect(() => {
- if (typeof localStorage !== 'undefined') {
- storage.set(key, value.value);
- }
- })
-
- return value
-}
diff --git a/src/composables/useStorage.ts b/src/composables/useStorage.ts
@@ -0,0 +1,32 @@
+import { ref, onActivated, watchEffect } from 'vue';
+import type { Ref } from 'vue';
+
+import * as storage from '@/utils/storage';
+
+/*
+ * Create a reactive value that is synced with a localStorage item
+ * @param {string} key The localStorage item's key
+ * @param {object} defaultValue The default value
+ * @returns {Ref<object>} The synchronized ref
+ */
+export default function useStorage(key: string, defaultValue: object): Ref<object> {
+ const clonedDefault = JSON.parse(JSON.stringify(defaultValue));
+ const value = ref(clonedDefault);
+
+ // (Re)load value from localStorage
+ function updateValue() {
+ const parsedValue = storage.get(key);
+ if (parsedValue !== null) value.value = parsedValue;
+ }
+ updateValue();
+ onActivated(updateValue);
+
+ // Save value to localStorage when modified
+ watchEffect(() => {
+ if (typeof localStorage !== 'undefined') {
+ storage.set(key, value.value);
+ }
+ })
+
+ return value
+}