Added dashboard migration, reworked types
This commit is contained in:
parent
7846a09668
commit
e74c9d0793
|
|
@ -1,4 +1,4 @@
|
||||||
import { DashboardContent } from '@/utils/parseDashboard'
|
import { DashboardContent } from '@/utils/dashboard/parseDashboard'
|
||||||
import { request } from './request'
|
import { request } from './request'
|
||||||
|
|
||||||
export type DashboardInfo = {
|
export type DashboardInfo = {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
} from '@/api/dashboards'
|
} from '@/api/dashboards'
|
||||||
import { UserLayout } from '@/layouts/UserLayout/UserLayout'
|
import { UserLayout } from '@/layouts/UserLayout/UserLayout'
|
||||||
import { createDashboardContent } from '@/utils/createDashboardContent'
|
import { createDashboardContent } from '@/utils/createDashboardContent'
|
||||||
import { parseDashboard } from '@/utils/parseDashboard'
|
import { parseDashboard } from '@/utils/dashboard/parseDashboard'
|
||||||
import { useEffect, useMemo, useState } from 'preact/hooks'
|
import { useEffect, useMemo, useState } from 'preact/hooks'
|
||||||
import { useQuery, useQueryClient } from 'react-query'
|
import { useQuery, useQueryClient } from 'react-query'
|
||||||
import { DashboardGrid } from './components/DashboardGrid/DashboardGrid'
|
import { DashboardGrid } from './components/DashboardGrid/DashboardGrid'
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { getSensors } from '@/api/sensors'
|
import { getSensors } from '@/api/sensors'
|
||||||
import { Modal } from '@/components/Modal'
|
import { Modal } from '@/components/Modal'
|
||||||
import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
|
import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
|
||||||
import { DashboardDialData, DashboardGraphData } from '@/utils/parseDashboard'
|
import {
|
||||||
|
DashboardDialData,
|
||||||
|
DashboardGraphData,
|
||||||
|
} from '@/utils/dashboard/parseDashboard'
|
||||||
|
import { useForm } from '@/utils/hooks/useForm'
|
||||||
import { useState } from 'preact/hooks'
|
import { useState } from 'preact/hooks'
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { BoxDefinition } from '../../types'
|
import { BoxDefinition } from '../../types'
|
||||||
|
|
@ -18,14 +22,28 @@ type Props = {
|
||||||
export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
||||||
const sensors = useQuery(['/sensors'], getSensors)
|
const sensors = useQuery(['/sensors'], getSensors)
|
||||||
|
|
||||||
const [formState, setFormState] = useState(() => ({
|
|
||||||
sensor: value.sensor,
|
|
||||||
title: value.title,
|
|
||||||
type: value.data?.type ?? 'graph',
|
|
||||||
}))
|
|
||||||
|
|
||||||
const [data, setData] = useState(() => value.data)
|
const [data, setData] = useState(() => value.data)
|
||||||
|
|
||||||
|
const {
|
||||||
|
value: formState,
|
||||||
|
handleChange,
|
||||||
|
handleSubmit,
|
||||||
|
} = useForm({
|
||||||
|
defaultValue: () => ({
|
||||||
|
title: value.title,
|
||||||
|
type: value.data?.type ?? '',
|
||||||
|
}),
|
||||||
|
onSubmit: async (v) => {
|
||||||
|
onClose()
|
||||||
|
|
||||||
|
onSave({
|
||||||
|
...value,
|
||||||
|
title: v.title,
|
||||||
|
data: data,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const deleteConfirm = useConfirmModal({
|
const deleteConfirm = useConfirmModal({
|
||||||
content: 'Are you sure you want to delete the box?',
|
content: 'Are you sure you want to delete the box?',
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
|
|
@ -33,48 +51,10 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleSave = async (e: Event) => {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
|
|
||||||
onClose()
|
|
||||||
|
|
||||||
onSave({
|
|
||||||
...value,
|
|
||||||
sensor: formState.sensor,
|
|
||||||
title: formState.title,
|
|
||||||
data: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleChange = (e: Event) => {
|
|
||||||
const target = e.target as HTMLSelectElement | HTMLInputElement
|
|
||||||
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
[target.name]: target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal onClose={onClose} open>
|
<Modal onClose={onClose} open>
|
||||||
<form onSubmit={handleSave}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="input">
|
{
|
||||||
<label>Sensor</label>
|
|
||||||
<select
|
|
||||||
name="sensor"
|
|
||||||
value={formState.sensor || ''}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{sensors.data?.map((s) => (
|
|
||||||
<option key={s.id} value={s.id}>
|
|
||||||
{s.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{formState.sensor && (
|
|
||||||
<>
|
<>
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<label>Title</label>
|
<label>Title</label>
|
||||||
|
|
@ -90,6 +70,7 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
||||||
name="type"
|
name="type"
|
||||||
value={formState.type}
|
value={formState.type}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
required
|
||||||
>
|
>
|
||||||
<option value="graph">Graph</option>
|
<option value="graph">Graph</option>
|
||||||
<option value="dial">Dial</option>
|
<option value="dial">Dial</option>
|
||||||
|
|
@ -100,6 +81,7 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
||||||
<GraphSettings
|
<GraphSettings
|
||||||
value={data as DashboardGraphData}
|
value={data as DashboardGraphData}
|
||||||
onChange={setData}
|
onChange={setData}
|
||||||
|
sensors={sensors.data ?? []}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -107,10 +89,11 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
||||||
<DialSettings
|
<DialSettings
|
||||||
value={data as DashboardDialData}
|
value={data as DashboardDialData}
|
||||||
onChange={setData}
|
onChange={setData}
|
||||||
|
sensors={sensors.data ?? []}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
}
|
||||||
|
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<button className="remove" type="button" onClick={deleteConfirm.show}>
|
<button className="remove" type="button" onClick={deleteConfirm.show}>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,21 @@
|
||||||
import { DashboardDialData } from '@/utils/parseDashboard'
|
import { SensorInfo } from '@/api/sensors'
|
||||||
import { useEffect, useState } from 'preact/hooks'
|
import { DashboardDialData } from '@/utils/dashboard/parseDashboard'
|
||||||
|
import { useForm } from '@/utils/hooks/useForm'
|
||||||
|
import { omit } from '@/utils/omit'
|
||||||
|
import { useEffect } from 'preact/hooks'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
sensors: SensorInfo[]
|
||||||
value?: DashboardDialData
|
value?: DashboardDialData
|
||||||
onChange: (data: DashboardDialData) => void
|
onChange: (data: DashboardDialData) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DialSettings = ({ value, onChange }: Props) => {
|
export const DialSettings = ({ sensors, value, onChange }: Props) => {
|
||||||
const [formState, setFormState] = useState(() => ({
|
const { value: formState, handleChange } = useForm({
|
||||||
unit: value?.unit,
|
defaultValue: () => ({
|
||||||
decimals: value?.decimals,
|
...(value && omit(value, ['type'])),
|
||||||
multiplier: value?.multiplier,
|
}),
|
||||||
}))
|
})
|
||||||
|
|
||||||
const handleChange = (e: Event) => {
|
|
||||||
const target = e.target as HTMLSelectElement | HTMLInputElement
|
|
||||||
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
[target.name]: target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChange({ ...formState, type: 'dial' })
|
onChange({ ...formState, type: 'dial' })
|
||||||
|
|
@ -28,6 +23,21 @@ export const DialSettings = ({ value, onChange }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="input">
|
||||||
|
<label>Sensor</label>
|
||||||
|
<select
|
||||||
|
name="sensor"
|
||||||
|
value={formState.sensor || ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
{sensors.map((s) => (
|
||||||
|
<option key={s.id} value={s.id}>
|
||||||
|
{s.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<label>Unit</label>
|
<label>Unit</label>
|
||||||
<input name="unit" value={formState.unit} onChange={handleChange} />
|
<input name="unit" value={formState.unit} onChange={handleChange} />
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
|
import { SensorInfo } from '@/api/sensors'
|
||||||
|
import { DashboardGraphData } from '@/utils/dashboard/parseDashboard'
|
||||||
|
import { useForm } from '@/utils/hooks/useForm'
|
||||||
import { omit } from '@/utils/omit'
|
import { omit } from '@/utils/omit'
|
||||||
import { DashboardGraphData } from '@/utils/parseDashboard'
|
import { useEffect } from 'preact/hooks'
|
||||||
import { useEffect, useState } from 'preact/hooks'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
sensors: SensorInfo[]
|
||||||
value?: DashboardGraphData
|
value?: DashboardGraphData
|
||||||
onChange: (data: DashboardGraphData) => void
|
onChange: (data: DashboardGraphData) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GraphSettings = ({ value, onChange }: Props) => {
|
export const GraphSettings = ({ value, onChange, sensors }: Props) => {
|
||||||
const [formState, setFormState] = useState(() => ({
|
const { value: formState, handleChange } = useForm({
|
||||||
...(value && omit(value, ['type'])),
|
defaultValue: () => ({
|
||||||
}))
|
...(value && omit(value, ['type'])),
|
||||||
|
}),
|
||||||
const handleChange = (e: Event) => {
|
})
|
||||||
const target = e.target as HTMLSelectElement | HTMLInputElement
|
|
||||||
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
[target.name]: target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChange({ ...formState, type: 'graph' })
|
onChange({ ...formState, type: 'graph' })
|
||||||
|
|
@ -27,6 +23,22 @@ export const GraphSettings = ({ value, onChange }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="input">
|
||||||
|
<label>Sensor</label>
|
||||||
|
<select
|
||||||
|
name="sensor"
|
||||||
|
value={formState.sensor || ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
{sensors.map((s) => (
|
||||||
|
<option key={s.id} value={s.id}>
|
||||||
|
{s.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<label>Graph Type</label>
|
<label>Graph Type</label>
|
||||||
<select
|
<select
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getLatestSensorValue } from '@/api/sensorValues'
|
import { getLatestSensorValue } from '@/api/sensorValues'
|
||||||
import { DashboardDialData } from '@/utils/parseDashboard'
|
import { DashboardDialData } from '@/utils/dashboard/parseDashboard'
|
||||||
import { RefObject } from 'preact'
|
import { RefObject } from 'preact'
|
||||||
import { useMemo } from 'preact/hooks'
|
import { useMemo } from 'preact/hooks'
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
|
|
@ -13,16 +13,18 @@ type Props = {
|
||||||
refreshRef: RefObject<() => void>
|
refreshRef: RefObject<() => void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BoxDialContent = ({ box, data, refreshRef }: Props) => {
|
export const BoxDialContent = ({ data, refreshRef }: Props) => {
|
||||||
const { filter } = useDashboardContext()
|
const { filter } = useDashboardContext()
|
||||||
|
|
||||||
const valuesQuery = {
|
const valuesQuery = {
|
||||||
sensor: box.sensor ?? '-1',
|
sensor: data.sensor ?? '-1',
|
||||||
to: filter.customTo,
|
to: filter.customTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = useQuery(['/sensor/values/latest', valuesQuery], () =>
|
const value = useQuery(
|
||||||
getLatestSensorValue(valuesQuery)
|
['/sensor/values/latest', valuesQuery],
|
||||||
|
() => getLatestSensorValue(valuesQuery),
|
||||||
|
{ enabled: !!data.sensor }
|
||||||
)
|
)
|
||||||
|
|
||||||
refreshRef.current = () => {
|
refreshRef.current = () => {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext
|
||||||
import { BoxDefinition } from '@/pages/dashboard/types'
|
import { BoxDefinition } from '@/pages/dashboard/types'
|
||||||
import { max } from '@/utils/max'
|
import { max } from '@/utils/max'
|
||||||
import { min } from '@/utils/min'
|
import { min } from '@/utils/min'
|
||||||
import { DashboardGraphData } from '@/utils/parseDashboard'
|
import { DashboardGraphData } from '@/utils/dashboard/parseDashboard'
|
||||||
import { RefObject } from 'preact'
|
import { RefObject } from 'preact'
|
||||||
import { useEffect, useRef } from 'preact/hooks'
|
import { useEffect, useRef } from 'preact/hooks'
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
|
|
@ -21,13 +21,15 @@ export const BoxGraphContent = ({ box, data, refreshRef }: Props) => {
|
||||||
const bodyRef = useRef<HTMLDivElement>(null)
|
const bodyRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const valuesQuery = {
|
const valuesQuery = {
|
||||||
sensor: box.sensor ?? '-1',
|
sensor: data.sensor ?? '-1',
|
||||||
from: filter.customFrom,
|
from: filter.customFrom,
|
||||||
to: filter.customTo,
|
to: filter.customTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = useQuery(['/sensor/values', valuesQuery], () =>
|
const values = useQuery(
|
||||||
getSensorValues(valuesQuery)
|
['/sensor/values', valuesQuery],
|
||||||
|
() => getSensorValues(valuesQuery),
|
||||||
|
{ enabled: !!data.sensor }
|
||||||
)
|
)
|
||||||
|
|
||||||
refreshRef.current = () => {
|
refreshRef.current = () => {
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ export const EditableBox = ({
|
||||||
<div className="box" style={{ height: '100%' }}>
|
<div className="box" style={{ height: '100%' }}>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="drag-handle" onMouseDown={handleMouseDown}>
|
<div className="drag-handle" onMouseDown={handleMouseDown}>
|
||||||
<div className="name">{box.title || box.sensor || ''}</div>
|
<div className="name">{box.title || ''}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<div className="action" onClick={() => refreshRef.current?.()}>
|
<div className="action" onClick={() => refreshRef.current?.()}>
|
||||||
|
|
@ -144,14 +144,14 @@ export const EditableBox = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="body">
|
<div className="body">
|
||||||
{box.sensor && box.data?.type === 'graph' && (
|
{box.data?.type === 'graph' && (
|
||||||
<BoxGraphContent
|
<BoxGraphContent
|
||||||
box={box}
|
box={box}
|
||||||
data={box.data}
|
data={box.data}
|
||||||
refreshRef={refreshRef}
|
refreshRef={refreshRef}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{box.sensor && box.data?.type === 'dial' && (
|
{box.data?.type === 'dial' && (
|
||||||
<BoxDialContent
|
<BoxDialContent
|
||||||
box={box}
|
box={box}
|
||||||
data={box.data}
|
data={box.data}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
import { DashboardContentBox } from '@/utils/parseDashboard'
|
import { DashboardContentBox } from '@/utils/dashboard/parseDashboard'
|
||||||
|
|
||||||
export type BoxDefinition = DashboardContentBox
|
export type BoxDefinition = DashboardContentBox
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { DashboardContent } from './parseDashboard'
|
import { DashboardContent } from './dashboard/parseDashboard'
|
||||||
|
|
||||||
export const createDashboardContent = (): DashboardContent => ({
|
export const createDashboardContent = (): DashboardContent => ({
|
||||||
version: '1.0',
|
version: '1.0',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export type DashboardMigration = {
|
||||||
|
from: string
|
||||||
|
to: string
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
migrate: (v: any) => any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createDashboardMigration = (migration: DashboardMigration) =>
|
||||||
|
migration
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import * as migrations from './migrations'
|
||||||
|
|
||||||
|
export const getDashboardMigrations = (version: string) => {
|
||||||
|
const sortedMigrations = Object.values(migrations).sort((a, b) =>
|
||||||
|
a.from.localeCompare(b.to)
|
||||||
|
)
|
||||||
|
|
||||||
|
const migration = sortedMigrations.findIndex((m) => m.from === version)
|
||||||
|
|
||||||
|
return migration < 0 ? [] : sortedMigrations.slice(migration)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './migrationOf10to11'
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { createDashboardMigration } from '../createDashboardMigration'
|
||||||
|
|
||||||
|
export const migrationOf100To101 = createDashboardMigration({
|
||||||
|
from: '1.0',
|
||||||
|
to: '1.1',
|
||||||
|
migrate(v) {
|
||||||
|
for (const box of v.boxes) {
|
||||||
|
if (box.data) {
|
||||||
|
box.data.sensor = box.sensor
|
||||||
|
}
|
||||||
|
|
||||||
|
delete box.sensor
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { getDashboardMigrations } from './getDashboardMigrations'
|
||||||
|
|
||||||
export type DashboardContent = {
|
export type DashboardContent = {
|
||||||
version: string
|
version: string
|
||||||
boxes: DashboardContentBox[]
|
boxes: DashboardContentBox[]
|
||||||
|
|
@ -9,13 +11,13 @@ export type DashboardContentBox = {
|
||||||
y: number
|
y: number
|
||||||
w: number
|
w: number
|
||||||
h: number
|
h: number
|
||||||
sensor?: string
|
|
||||||
title?: string
|
title?: string
|
||||||
data?: DashboardGraphData | DashboardDialData
|
data?: DashboardGraphData | DashboardDialData
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DashboardGraphData = {
|
export type DashboardGraphData = {
|
||||||
type: 'graph'
|
type: 'graph'
|
||||||
|
sensor?: string
|
||||||
min?: string
|
min?: string
|
||||||
max?: string
|
max?: string
|
||||||
unit?: string
|
unit?: string
|
||||||
|
|
@ -34,11 +36,20 @@ export type DashboardGraphData = {
|
||||||
|
|
||||||
export type DashboardDialData = {
|
export type DashboardDialData = {
|
||||||
type: 'dial'
|
type: 'dial'
|
||||||
|
sensor?: string
|
||||||
unit?: string
|
unit?: string
|
||||||
decimals?: string
|
decimals?: string
|
||||||
multiplier?: string
|
multiplier?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseDashboard = (input: string) => {
|
export const parseDashboard = (input: string) => {
|
||||||
return JSON.parse(input) as DashboardContent
|
const data = JSON.parse(input) as DashboardContent
|
||||||
|
const migrations = getDashboardMigrations(data.version)
|
||||||
|
|
||||||
|
return migrations.reduce((acc, migration) => {
|
||||||
|
const res = migration.migrate(acc)
|
||||||
|
res.version = migration.to
|
||||||
|
|
||||||
|
return res
|
||||||
|
}, data)
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useCallback, useRef, useState } from 'preact/hooks'
|
import { useCallback, useRef, useState } from 'preact/hooks'
|
||||||
|
|
||||||
type Props<TValue> = {
|
type Props<TValue> = {
|
||||||
onSubmit: (value: TValue) => void
|
onSubmit?: (value: TValue) => void
|
||||||
defaultValue: TValue | (() => TValue)
|
defaultValue: TValue | (() => TValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ export const useForm = <TValue = unknown>({
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
submitRef.current(stateRef.current)
|
submitRef.current?.(stateRef.current)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue