feat(SPA): media field type
This commit is contained in:
1 parent
a2d596f4ca
commit
3e7fc9a4a5
57 files changed
+6109
-75
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import type { MediaItem } from '@/composables/useMedia'
|
||||
import { imageOfItem, type MediaSummary } from '@/lib/mediaField'
|
||||
import {
|
||||
answerWrite,
|
||||
entry42,
|
||||
fieldWrapper,
|
||||
lookupNames,
|
||||
mountEditor,
|
||||
text,
|
||||
} from './entryEditorKit'
|
||||
import { fieldLibrary } from './mediaFieldKit'
|
||||
import { eventsWithThumbnail } from './schemaTestKit'
|
||||
import type { EntryWrite, SchemaMount } from './schemaTestKit'
|
||||
|
||||
export const LIBRARY_COUNTS = { all: 48, unused: 2, duplicates: 2 }
|
||||
|
||||
export function libraryBody(items: MediaItem[] = fieldLibrary()) {
|
||||
return { items, total: 48, page: 1, size: 25, counts: LIBRARY_COUNTS }
|
||||
}
|
||||
|
||||
export function summaryOf(id: number): MediaSummary {
|
||||
const item = fieldLibrary().find((candidate) => candidate.id === id)!
|
||||
return imageOfItem(item)
|
||||
}
|
||||
|
||||
export function entryWithThumbnail(thumbnail: number | null, media?: MediaSummary | 'none') {
|
||||
const shown =
|
||||
media === 'none' || thumbnail === null ? undefined : (media ?? summaryOf(thumbnail))
|
||||
return {
|
||||
...entry42,
|
||||
data: { ...entry42.data, thumbnail },
|
||||
...(shown ? { media: { thumbnail: shown } } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
export function answerMediaWrite(write: EntryWrite) {
|
||||
const answered = answerWrite(write)
|
||||
const id = (write.body.data as Record<string, unknown>).thumbnail
|
||||
return typeof id === 'number' ? { ...answered, media: { thumbnail: summaryOf(id) } } : answered
|
||||
}
|
||||
|
||||
export function mountMedia(
|
||||
path: string,
|
||||
options: SchemaMount & {
|
||||
required?: boolean
|
||||
thumbnail?: number | null
|
||||
media?: MediaSummary | 'none'
|
||||
} = {},
|
||||
) {
|
||||
const { required, thumbnail = null, media, ...rest } = options
|
||||
const type = eventsWithThumbnail({ required: required ?? false })
|
||||
return mountEditor(path, {
|
||||
type: () => type,
|
||||
content: () => [type],
|
||||
entry: () => entryWithThumbnail(thumbnail, media),
|
||||
writeEntry: answerMediaWrite,
|
||||
library: () => libraryBody(),
|
||||
lookup: lookupNames,
|
||||
...rest,
|
||||
})
|
||||
}
|
||||
|
||||
export function mediaControl() {
|
||||
return fieldWrapper('thumbnail').querySelector<HTMLElement>('[data-testid="media-control"]')!
|
||||
}
|
||||
|
||||
export function mediaState() {
|
||||
const box = mediaControl()
|
||||
if (box.querySelector('[data-testid="media-empty"]')) {
|
||||
return 'empty'
|
||||
}
|
||||
return box.querySelector('[data-testid="media-filled"]') ? 'filled' : 'missing'
|
||||
}
|
||||
|
||||
export function mediaText() {
|
||||
return text(fieldWrapper('thumbnail'))
|
||||
}
|
||||
|
||||
export function mediaButton(name: string) {
|
||||
return [...fieldWrapper('thumbnail').querySelectorAll<HTMLButtonElement>('button')].find(
|
||||
(button) => (button.getAttribute('aria-label') ?? text(button)) === name,
|
||||
)
|
||||
}
|
||||
|
||||
export function focusedName() {
|
||||
const active = document.activeElement
|
||||
return active?.getAttribute('aria-label') ?? text(active)
|
||||
}
|
||||
|
||||
export async function pickFromLibrary(filename: string, opener = 'Change image') {
|
||||
mediaButton(opener)!.click()
|
||||
await flushPromises()
|
||||
await flushPromises()
|
||||
const tile = [...document.body.querySelectorAll<HTMLButtonElement>('[data-picker-tile]')].find(
|
||||
(element) => element.getAttribute('aria-label')!.startsWith(`${filename},`),
|
||||
)!
|
||||
tile.click()
|
||||
await flushPromises()
|
||||
;[...document.body.querySelectorAll('button')]
|
||||
.find((button) => text(button) === 'Use this image')!
|
||||
.click()
|
||||
await flushPromises()
|
||||
await flushPromises()
|
||||
}
|
||||
Reference in new issue
Block a user