arnog / mathlive

A web component for easy math input
https://cortexjs.io/mathlive
MIT License
1.54k stars 269 forks source link

a smaple of VUE3+VITE5+TS , it works, I spend 48H , pls enjoy... #2191

Open digitalboy opened 9 months ago

digitalboy commented 9 months ago
<template>
    <div ref="mathfieldContainer"></div>
</template>

<script lang="ts">
import '../../node_modules/mathlive/dist/mathlive-fonts.css';
import { ref, onMounted } from 'vue';
import { MathfieldElement } from 'mathlive';

export default {
    setup() {
        const mathfieldContainer = ref<HTMLElement | null>(null);
        const mathfield = ref<MathfieldElement | null>(null);

        onMounted(() => {
            mathfield.value = new MathfieldElement();
            if (mathfieldContainer.value) {
                mathfieldContainer.value.appendChild(mathfield.value as Node);
            }
        });       
        return {
            mathfieldContainer,
            mathfield
        };
    },
};
</script>
// src/types/mathlive.d.ts
import { MathfieldElement as MathfieldElementBase } from 'mathlive';

declare module 'mathlive' {
    export class MathfieldElement extends MathfieldElementBase { }
}
hsellik commented 9 months ago

Here is an alternative solution:

<template>
  <math-field :id="id" v-model="modelValue" @input="handleChange">
    {{ modelValue }}
  </math-field>
</template>

<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { MathfieldOptions } from 'mathlive/dist/types/options';
import MathfieldElement from 'mathlive/dist/types/mathfield-element';

interface MathFieldProps {
  id: string;
  modelValue: string;
  options?: Partial<MathfieldOptions>;
}

const props = defineProps<MathFieldProps>();

// Safe to delete when not using methods from the element
const mathfield = ref<MathfieldElement | null>(null);

const emit = defineEmits(['update:modelValue']);

const modelValue = ref(props.modelValue);

watch(
  () => props.modelValue,
  () => {
    if (props.modelValue !== modelValue.value) {
      modelValue.value = props.modelValue;
    }
  },
);

// Safe to delete when not using methods from the element
onMounted(() => {
  mathfield.value = document.getElementById(props.id) as MathfieldElement;
});

const handleChange = (event: InputEvent): void => {
  const target = event.target as MathfieldElement;
  emit('update:modelValue', target.getValue());
};

// Safe to delete when not using methods from the element
function getValue(): string | undefined {
  return mathfield.value?.getValue();
}
</script>

Usage:

<VueMathField id="field-1" v-model="formula" />
<p>Value: {{ formula }}</p>

To access the original math-field methods, you create additional functions in the VueMathfield component and use ref:

<template>
  <VueMathfield ref="mathfieldRef" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import VueMathfield from "@/location/to/VueMathfield.vue";

// declare a ref to hold the element reference
// the name must match template ref value
const mathfieldRef = ref(null)

onMounted(() => {
  mathfieldRef.value.getValue()
})
</script>

Additional approach could be getting the element by id in the parent, but the child component might dissapear, so it's not as robust.

@digitalboy , could you elaborate on how to use the declare module feature? Perhaps it's better than using ref?