106 lines
2.5 KiB
TypeScript
106 lines
2.5 KiB
TypeScript
import { computed, ref } from 'vue'
|
|
import type { BuiltinField, ContentEntry } from '@/lib/contentTypes'
|
|
import type { MediaMap, MediaSummary } from '@/lib/mediaField'
|
|
import type { RelationSummaries, RelationSummary } from '@/lib/relationField'
|
|
import {
|
|
carriesDefault,
|
|
firstIssueKey,
|
|
initialImages,
|
|
initialRelations,
|
|
initialValues,
|
|
valuesDiffer,
|
|
type EntryIssues,
|
|
type EntryValues,
|
|
type FieldIssue,
|
|
} from '@/lib/entryForm'
|
|
|
|
export function useEntryForm(fields: () => BuiltinField[], creating: () => boolean) {
|
|
const values = ref<EntryValues>({})
|
|
const saved = ref<EntryValues>({})
|
|
const images = ref<MediaMap>({})
|
|
const relations = ref<RelationSummaries>({})
|
|
const issues = ref<EntryIssues>({})
|
|
const rejected = ref(false)
|
|
|
|
const dirty = computed(() => valuesDiffer(fields(), values.value, saved.value))
|
|
const firstIssue = computed(() => firstIssueKey(fields(), issues.value))
|
|
const hasIssues = computed(() => Object.keys(issues.value).length > 0)
|
|
|
|
function reset(entry: ContentEntry | null) {
|
|
const next = initialValues(fields(), entry)
|
|
values.value = { ...next }
|
|
saved.value = { ...next }
|
|
images.value = initialImages(fields(), entry)
|
|
relations.value = initialRelations(fields(), entry)
|
|
issues.value = {}
|
|
rejected.value = false
|
|
}
|
|
|
|
function setImage(key: string, image: MediaSummary | null | undefined) {
|
|
if (image === undefined) {
|
|
return
|
|
}
|
|
const next = { ...images.value }
|
|
if (image === null) {
|
|
delete next[key]
|
|
} else {
|
|
next[key] = image
|
|
}
|
|
images.value = next
|
|
}
|
|
|
|
function setRelations(key: string, summaries: RelationSummary[] | undefined) {
|
|
if (summaries !== undefined) {
|
|
relations.value = { ...relations.value, [key]: summaries }
|
|
}
|
|
}
|
|
|
|
function setValue(
|
|
key: string,
|
|
value: unknown,
|
|
image?: MediaSummary | null,
|
|
summaries?: RelationSummary[],
|
|
) {
|
|
values.value = { ...values.value, [key]: value }
|
|
setImage(key, image)
|
|
setRelations(key, summaries)
|
|
rejected.value = false
|
|
if (issues.value[key]) {
|
|
const rest = { ...issues.value }
|
|
delete rest[key]
|
|
issues.value = rest
|
|
}
|
|
}
|
|
|
|
function reject(next: EntryIssues) {
|
|
issues.value = next
|
|
rejected.value = true
|
|
}
|
|
|
|
function rejectField(key: string, issue: FieldIssue) {
|
|
reject({ [key]: issue })
|
|
}
|
|
|
|
function isDefault(field: BuiltinField) {
|
|
return creating() && carriesDefault(field, values.value[field.key])
|
|
}
|
|
|
|
return {
|
|
values,
|
|
images,
|
|
relations,
|
|
issues,
|
|
rejected,
|
|
dirty,
|
|
firstIssue,
|
|
hasIssues,
|
|
reset,
|
|
setValue,
|
|
reject,
|
|
rejectField,
|
|
isDefault,
|
|
}
|
|
}
|
|
|
|
export type EntryForm = ReturnType<typeof useEntryForm>
|