@gramps-connect/story 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/editor/StoryEditor.tsx", "../src/image.ts", "../spec/1.0/story.schema.json", "../src/generated/schemaValidator.js", "../src/version.ts", "../src/validate.ts", "../src/player/geo.ts", "../src/player/StoryPlayer.tsx", "../src/player/dates.ts", "../src/player/MapBackground.tsx", "../src/player/mapStyles.ts", "../src/player/theme.ts", "../src/player/MapModeControl.tsx", "../src/player/text.ts", "../src/player/strings.ts", "../src/player/TimelineStrip.tsx", "../src/player/timelineLayout.ts", "../src/editor/dates.ts", "../src/editor/DateField.tsx", "../src/editor/model.ts", "../src/editor/PhotosField.tsx", "../src/editor/PlaceField.tsx", "../src/editor/PlaceMap.tsx", "../src/editor/PlaceMapDialog.tsx", "../src/mapEdit/model.ts", "../src/mapEdit/mapFile.ts", "../src/mapEdit/geometry.ts", "../src/editor/MapEditor.tsx", "../src/editor/mapEditorStrings.ts", "../src/editor/placeShapes.ts", "../src/editor/placeSearch.ts", "../src/editor/SlideList.tsx", "../src/editor/StoryTextField.tsx", "../src/editor/strings.ts"],
4
- "sourcesContent": ["// Edits a story document: a list of slides on the left, the selected\n// slide's (or the story's own) fields in the middle, and the real player\n// on the right showing that slide as it's changed. Works on the document\n// only -- opening and saving files is the host's (the viewer site's editor\n// page does it with the File System Access API or a download).\n//\n// Needs Mantine: wrap it in a MantineProvider and load @mantine/core's\n// stylesheet, as with any Mantine component.\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n ActionIcon, Badge, Box, Button, Divider, Group, Modal, Popover, Select, Stack, Text, TextInput, Tooltip, UnstyledButton,\n} from \"@mantine/core\";\nimport { useMediaQuery } from \"@mantine/hooks\";\nimport type { MediaItem, Slide, SlideMedia, StoryDoc } from \"../types\";\nimport { optimizeImage } from \"../image\";\nimport { validate, type StoryIssue } from \"../validate\";\nimport { storyPlaces } from \"../player/geo\";\nimport { StoryPlayer } from \"../player/StoryPlayer\";\nimport type { PlayerStrings } from \"../player/strings\";\nimport { suggestEdtf, type DateTextParser } from \"./dates\";\nimport { DateField } from \"./DateField\";\nimport {\n addImage, addSlide, deleteSlide, findMedia, duplicateSlide, moveSlide, record, redo, setSlidePhotos, startHistory, storyPlaceChoices,\n undo, updateMedia, updateSlide, updateStory, type History, type NewImage,\n} from \"./model\";\nimport { PhotosField } from \"./PhotosField\";\nimport { PlaceField, type PlaceUpdate } from \"./PlaceField\";\nimport { PlaceMapDialog } from \"./PlaceMapDialog\";\nimport type { MapEditorStrings } from \"./mapEditorStrings\";\nimport { WIKIDATA_PLACE_SEARCH, type PlaceSearch } from \"./placeSearch\";\nimport { SlideList } from \"./SlideList\";\nimport { StoryTextField } from \"./StoryTextField\";\nimport { EDITOR_ENGLISH, type EditorStrings } from \"./strings\";\n\nconst BAR_HEIGHT = 56;\n/** The story's own settings, in place of a slide index. */\nconst STORY = -1;\n\nexport interface StoryEditorProps {\n /** The story to start from, and its files (paths as in media `src`).\n * Changing these later has no effect: remount (a new `key`) to edit\n * another story. */\n initialStory: StoryDoc;\n initialFiles?: Map<string, Uint8Array>;\n /** Called with the document and its files after every change, undo and\n * redo included. The files only grow while editing (an undone photo's\n * file stays); pruneMedia leaves out what nothing uses when saving. */\n onChange?: (doc: StoryDoc, files: Map<string, Uint8Array>) => void;\n /** Turns a chosen image file into what's stored. By default\n * optimizeImage: 1600px WebP (JPEG where the browser can't), with the\n * original's metadata left behind. */\n prepareImage?: (file: Blob) => Promise<NewImage>;\n /** The host's own buttons (Open, Save, ...), at the right of the top bar. */\n toolbar?: ReactNode;\n /** Shown first in the top bar, e.g. ViewerBrand. */\n brand?: ReactNode;\n dark?: boolean;\n strings?: Partial<EditorStrings>;\n playerStrings?: Partial<PlayerStrings>;\n /** Date text -> EDTF. By default gramps-date, in the story's language. */\n parseDateText?: DateTextParser;\n /** Finding a place by name. By default Wikidata, and only when the\n * person asks; null leaves the search out. */\n placeSearch?: PlaceSearch | null;\n /** The map editor's words (Edit map), over its English. */\n mapStrings?: Partial<MapEditorStrings>;\n}\n\n/** The slide an issue's JSON Pointer is about, or STORY. */\nfunction issueSlide(issue: StoryIssue): number {\n const match = /^\\/slides\\/(\\d+)/.exec(issue.path);\n return match ? Number(match[1]) : STORY;\n}\n\ntype Resolve = (key: string, item: MediaItem) => Promise<string | null>;\n\n/** The default prepareImage. */\nexport async function prepareImage(file: Blob): Promise<NewImage> {\n const image = await optimizeImage(file);\n return { data: new Uint8Array(await image.blob.arrayBuffer()), mime: image.mime, ext: image.ext, width: image.width, height: image.height };\n}\n\nfunction Thumb({ doc, slide, resolveMedia }: { doc: StoryDoc; slide: Slide; resolveMedia: Resolve }) {\n const ref = slide.media?.[0]?.ref;\n const item = ref && Object.prototype.hasOwnProperty.call(doc.media, ref) ? doc.media[ref] : undefined;\n const [url, setUrl] = useState<string | null>(null);\n useEffect(() => {\n let live = true;\n setUrl(null);\n if (ref && item) void resolveMedia(ref, item).then((u) => { if (live) setUrl(u); });\n return () => { live = false; };\n }, [ref, item, resolveMedia]);\n return (\n <Box\n w={40} h={40}\n style={{ flex: \"none\", borderRadius: 4, background: \"var(--mantine-color-default-hover)\", overflow: \"hidden\" }}\n >\n {url && <img src={url} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </Box>\n );\n}\n\nexport function StoryEditor({\n initialStory, initialFiles, onChange, prepareImage: prepare = prepareImage, toolbar, brand, dark = false,\n strings: stringOverrides, playerStrings, parseDateText = suggestEdtf, placeSearch = WIKIDATA_PLACE_SEARCH, mapStrings,\n}: StoryEditorProps) {\n const strings = useMemo(() => ({ ...EDITOR_ENGLISH, ...stringOverrides }), [stringOverrides]);\n const [history, setHistory] = useState<History>(() => startHistory(initialStory));\n const [selected, setSelected] = useState(0);\n const [presenting, setPresenting] = useState(false);\n const [problemsOpen, setProblemsOpen] = useState(false);\n const wide = useMediaQuery(\"(min-width: 1000px)\", true);\n const doc = history.present;\n const [files, setFiles] = useState(() => new Map(initialFiles ?? []));\n const [busy, setBusy] = useState(false);\n const [photoError, setPhotoError] = useState<string | null>(null);\n // The latest of each, for work that finishes after a render (photos).\n const docRef = useRef(doc);\n docRef.current = doc;\n const filesRef = useRef(files);\n filesRef.current = files;\n\n // A blob: URL per stored file, made once and released with the editor.\n const urls = useRef(new Map<string, string>());\n useEffect(() => () => {\n for (const url of urls.current.values()) URL.revokeObjectURL(url);\n }, []);\n const resolveMedia = useCallback<Resolve>(async (_key, item) => {\n const cached = urls.current.get(item.src);\n if (cached) return cached;\n const data = filesRef.current.get(item.src);\n if (!data) return null;\n const url = URL.createObjectURL(new Blob([data as Uint8Array<ArrayBuffer>], { type: item.mime }));\n urls.current.set(item.src, url);\n return url;\n }, []);\n const urlFor = useCallback((key: string) => {\n const item = Object.prototype.hasOwnProperty.call(docRef.current.media, key) ? docRef.current.media[key] : undefined;\n return item ? resolveMedia(key, item) : Promise.resolve(null);\n }, [resolveMedia]);\n\n // Every change goes through here (and so into history and to the host).\n const apply = useCallback((next: StoryDoc, key?: string) => {\n setHistory((h) => record(h, next, key));\n }, []);\n useEffect(() => { onChange?.(doc, files); }, [doc, files, onChange]);\n\n const index = selected === STORY ? STORY : Math.min(selected, doc.slides.length - 1);\n const slide = index === STORY ? undefined : doc.slides[index];\n const setSlide = (patch: Partial<Slide>, key: string) => {\n if (index !== STORY) apply(updateSlide(history.present, index, patch), `${slide!.id}:${key}`);\n };\n\n // A place change applies to the slide as it is by then: a name typed and\n // a place picked in the same moment both land.\n const setPlace = (slideId: string, update: PlaceUpdate, key: string) => {\n setHistory((h) => {\n const at = h.present.slides.findIndex((s) => s.id === slideId);\n if (at < 0) return h;\n const before = h.present.slides[at].place;\n const after = update(before);\n return after === before ? h : record(h, updateSlide(h.present, at, { place: after }), `${slideId}:${key}`);\n });\n };\n // The slide whose map (shapes, old maps) is open full screen.\n const [mapSlideId, setMapSlideId] = useState<string | null>(null);\n const mapSlide = mapSlideId ? doc.slides.find((s) => s.id === mapSlideId) : undefined;\n const placeChoices = useMemo(() => storyPlaceChoices(doc, index), [doc, index]);\n const around = useMemo(() => storyPlaces(doc.slides.map((s) => s.place))?.bounds ?? null, [doc.slides]);\n\n const issues = useMemo(() => validate(doc, files).errors, [doc, files]);\n\n /** Prepares image files and puts them on a slide: added at the end, or\n * in place of photo `replace` (keeping its caption and credit). */\n const addPhotos = useCallback(async (chosen: File[], slideId: string, replace?: number) => {\n setBusy(true);\n setPhotoError(null);\n // A file already in the story (chosen again) is used as it is;\n // anything else is prepared first.\n const chosenImages: (NewImage | string)[] = [];\n for (const file of chosen) {\n try {\n const known = findMedia(docRef.current, filesRef.current, new Uint8Array(await file.arrayBuffer()));\n chosenImages.push(known ?? await prepare(file));\n } catch {\n setPhotoError(strings.photoFailed(file.name || \"the image\"));\n }\n }\n setBusy(false);\n if (!chosenImages.length) return;\n let next = docRef.current;\n let nextFiles = filesRef.current;\n const keys: string[] = [];\n for (const image of chosenImages) {\n if (typeof image === \"string\") {\n keys.push(image);\n continue;\n }\n const added = addImage(next, nextFiles, image);\n next = added.doc;\n nextFiles = added.files;\n keys.push(added.key);\n }\n const at = next.slides.findIndex((s) => s.id === slideId);\n if (at < 0) return;\n const photos: SlideMedia[] = [...(next.slides[at].media ?? [])];\n if (replace !== undefined && photos[replace]) photos[replace] = { ...photos[replace], ref: keys[0] };\n else photos.push(...keys.map((ref) => ({ ref })));\n setFiles(nextFiles);\n apply(setSlidePhotos(next, at, photos));\n }, [apply, prepare, strings]);\n\n // Pasting an image (outside a text field) adds it to the slide.\n const slideId = slide?.id;\n useEffect(() => {\n if (!slideId) return;\n const onPaste = (e: ClipboardEvent) => {\n if ((e.target as HTMLElement | null)?.closest(\"input, textarea, [contenteditable=true]\")) return;\n const images = [...(e.clipboardData?.files ?? [])].filter((f) => f.type.startsWith(\"image/\"));\n if (!images.length) return;\n e.preventDefault();\n void addPhotos(images, slideId);\n };\n window.addEventListener(\"paste\", onPaste);\n return () => window.removeEventListener(\"paste\", onPaste);\n }, [slideId, addPhotos]);\n\n // Undo/redo from the keyboard, except where a text field has its own.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (!(e.ctrlKey || e.metaKey) || e.altKey) return;\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"input, textarea, [contenteditable=true]\")) return;\n const key = e.key.toLowerCase();\n if (key === \"z\" && !e.shiftKey) { e.preventDefault(); setHistory(undo); }\n else if ((key === \"z\" && e.shiftKey) || key === \"y\") { e.preventDefault(); setHistory(redo); }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, []);\n\n const slideActions = slide && (\n <Group gap={6}>\n <Tooltip label={strings.moveUp}>\n <ActionIcon variant=\"default\" aria-label={strings.moveUp} disabled={index === 0}\n onClick={() => { apply(moveSlide(doc, index, index - 1)); setSelected(index - 1); }}>\u2191</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.moveDown}>\n <ActionIcon variant=\"default\" aria-label={strings.moveDown} disabled={index === doc.slides.length - 1}\n onClick={() => { apply(moveSlide(doc, index, index + 1)); setSelected(index + 1); }}>\u2193</ActionIcon>\n </Tooltip>\n <Button variant=\"default\" size=\"xs\" onClick={() => { const r = duplicateSlide(doc, index); apply(r.doc); setSelected(r.index); }}>\n {strings.duplicateSlide}\n </Button>\n <Button variant=\"default\" size=\"xs\" color=\"red\" disabled={doc.slides.length <= 1}\n onClick={() => { const r = deleteSlide(doc, index); apply(r.doc); setSelected(r.index); }}>\n {strings.deleteSlide}\n </Button>\n </Group>\n );\n\n const storyForm = (\n <Stack gap=\"md\">\n <Text fw={600} size=\"lg\">{strings.story}</Text>\n <TextInput\n label={strings.title} required value={doc.title}\n onChange={(e) => apply(updateStory(doc, { title: e.currentTarget.value }), \"story:title\")}\n />\n <TextInput\n label={strings.language} description={strings.languageHint} w={260} value={doc.language ?? \"\"}\n onChange={(e) => apply(updateStory(doc, { language: e.currentTarget.value.trim() || undefined }), \"story:language\")}\n />\n <Select\n label={strings.map} w={320} allowDeselect={false}\n data={[\n { value: \"auto\", label: strings.mapAuto },\n { value: \"standard\", label: strings.mapStandard },\n { value: \"historical\", label: strings.mapHistorical },\n { value: \"none\", label: strings.mapNone },\n ]}\n value={doc.presentation?.basemap ?? \"auto\"}\n onChange={(value) => value && apply(updateStory(doc, {\n presentation: { ...doc.presentation, basemap: value as NonNullable<StoryDoc[\"presentation\"]>[\"basemap\"] },\n }))}\n />\n </Stack>\n );\n\n const slideForm = slide && (\n <Stack gap=\"md\" key={slide.id}>\n <Group justify=\"space-between\" wrap=\"wrap\" gap=\"xs\">\n <Text fw={600} size=\"lg\">{index === 0 ? strings.openingSlide : `${index + 1} / ${doc.slides.length}`}</Text>\n {slideActions}\n </Group>\n <TextInput\n label={strings.slideTitle} value={slide.title ?? \"\"}\n onChange={(e) => setSlide({ title: e.currentTarget.value || undefined }, \"title\")}\n />\n <DateField\n value={slide.date} language={doc.language} parse={parseDateText} strings={strings}\n onChange={(date) => setSlide({ date }, \"date\")}\n />\n <StoryTextField\n label={strings.text} value={slide.text ?? \"\"} boldLabel={strings.bold} italicLabel={strings.italic} minRows={5}\n onChange={(text) => setSlide({ text: text || undefined }, \"text\")}\n />\n <PlaceField\n place={slide.place} choices={placeChoices} around={around} language={doc.language} search={placeSearch} dark={dark} strings={strings}\n onChange={(update, key) => setPlace(slide.id, update, key)}\n onEditMap={() => setMapSlideId(slide.id)}\n />\n <PhotosField\n photos={slide.media ?? []} media={doc.media} urlFor={urlFor} strings={strings} busy={busy}\n onChange={(photos, key) => apply(setSlidePhotos(doc, index, photos), `${slide.id}:${key}`)}\n onFiles={(chosen, replace) => void addPhotos(chosen, slide.id, replace)}\n onDescription={(key, alt) => apply(updateMedia(doc, key, { alt: alt || undefined }), `media:${key}:alt`)}\n />\n {photoError && <Text size=\"xs\" c=\"red\" role=\"alert\">{photoError}</Text>}\n </Stack>\n );\n\n const list = (\n <Stack gap=\"xs\">\n <UnstyledButton\n onClick={() => setSelected(STORY)}\n style={{ padding: \"8px\", borderRadius: 6, background: index === STORY ? \"var(--mantine-primary-color-light)\" : undefined }}\n >\n <Text fw={600} size=\"sm\">{strings.story}</Text>\n <Text size=\"xs\" c=\"dimmed\">{strings.storySettings}</Text>\n </UnstyledButton>\n <Divider label={strings.slides} labelPosition=\"left\" />\n <SlideList\n label={strings.slides}\n items={doc.slides}\n selected={index}\n onSelect={setSelected}\n onMove={(from, to) => { apply(moveSlide(doc, from, to)); setSelected(to); }}\n getKey={(s) => s.id}\n renderItem={(s, i) => (\n <Group gap=\"sm\" wrap=\"nowrap\">\n <Thumb doc={doc} slide={s} resolveMedia={resolveMedia} />\n <Box style={{ minWidth: 0 }}>\n <Text size=\"sm\" fw={500} truncate dir=\"auto\" c={s.title ? undefined : \"dimmed\"}>\n {s.title || strings.untitledSlide}\n </Text>\n <Text size=\"xs\" c=\"dimmed\" truncate>{i === 0 ? strings.openingSlide : s.date?.text ?? \"\"}</Text>\n </Box>\n </Group>\n )}\n />\n <Button\n variant=\"light\" size=\"xs\" mt={4}\n onClick={() => { const r = addSlide(doc, index === STORY ? doc.slides.length - 1 : index); apply(r.doc); setSelected(r.index); }}\n >\n + {strings.addSlide}\n </Button>\n </Stack>\n );\n\n const preview = (\n <Box style={{ position: \"relative\", height: wide ? \"100%\" : 460, borderRadius: 8, overflow: \"hidden\", border: \"1px solid var(--mantine-color-default-border)\" }}>\n <StoryPlayer\n story={doc} resolveMedia={resolveMedia} dark={dark} strings={playerStrings}\n keyboard={false} initialSlide={index === STORY ? 0 : index}\n onSlideChange={(i) => { if (i !== index && index !== STORY) setSelected(i); }}\n />\n </Box>\n );\n\n const column = (children: ReactNode, width?: number | string) => (\n <Box\n style={{\n width, flex: width ? \"none\" : 1, minWidth: 0, padding: 16,\n overflowY: wide ? \"auto\" : undefined, height: wide ? \"100%\" : undefined,\n }}\n >\n {children}\n </Box>\n );\n\n return (\n <Box style={{ height: \"100%\", display: \"flex\", flexDirection: \"column\" }}>\n <Group\n h={BAR_HEIGHT} px=\"md\" gap=\"sm\" wrap=\"nowrap\" justify=\"space-between\"\n style={{ flex: \"none\", borderBottom: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Group gap=\"sm\" wrap=\"nowrap\" style={{ minWidth: 0 }}>\n {brand}\n <Text fw={600} truncate dir=\"auto\">{doc.title}</Text>\n </Group>\n <Group gap=\"xs\" wrap=\"nowrap\">\n {issues.length > 0 && (\n <Popover opened={problemsOpen} onChange={setProblemsOpen} width={360} position=\"bottom-end\" withArrow>\n <Popover.Target>\n <Badge color=\"red\" variant=\"light\" style={{ cursor: \"pointer\" }} onClick={() => setProblemsOpen((o) => !o)}>\n {strings.problems(issues.length)}\n </Badge>\n </Popover.Target>\n <Popover.Dropdown>\n <Stack gap={6}>\n {issues.map((issue, i) => {\n const at = issueSlide(issue);\n return (\n <UnstyledButton key={i} onClick={() => { setSelected(at); setProblemsOpen(false); }}>\n <Text size=\"sm\" fw={500}>{at === STORY ? strings.story : (doc.slides[at]?.title || `${strings.untitledSlide} ${at + 1}`)}</Text>\n <Text size=\"xs\" c=\"dimmed\">{issue.path} {issue.message}</Text>\n </UnstyledButton>\n );\n })}\n </Stack>\n </Popover.Dropdown>\n </Popover>\n )}\n <Tooltip label={strings.undo}>\n <ActionIcon variant=\"default\" size=\"lg\" aria-label={strings.undo} disabled={history.past.length === 0} onClick={() => setHistory(undo)}>\u21B6</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.redo}>\n <ActionIcon variant=\"default\" size=\"lg\" aria-label={strings.redo} disabled={history.future.length === 0} onClick={() => setHistory(redo)}>\u21B7</ActionIcon>\n </Tooltip>\n <Button variant=\"default\" onClick={() => setPresenting(true)}>{strings.present}</Button>\n {toolbar}\n </Group>\n </Group>\n <Box\n style={{\n flex: 1, minHeight: 0, display: \"flex\", flexDirection: wide ? \"row\" : \"column\",\n overflowY: wide ? undefined : \"auto\",\n }}\n >\n {column(list, wide ? 280 : undefined)}\n {column(index === STORY ? storyForm : slideForm, wide ? \"min(520px, 36%)\" : undefined)}\n {column(preview)}\n </Box>\n {mapSlide && (\n <PlaceMapDialog\n place={mapSlide.place} doc={doc} files={files} dark={dark} parseDateText={parseDateText}\n strings={strings} mapStrings={mapStrings}\n onCancel={() => setMapSlideId(null)}\n onDone={(place, media, nextFiles) => {\n const at = doc.slides.findIndex((s) => s.id === mapSlide.id);\n setMapSlideId(null);\n if (at < 0) return;\n setFiles(nextFiles);\n // One step for undo: the map's images and the place together.\n apply(updateSlide({ ...doc, media }, at, { place }));\n }}\n />\n )}\n <Modal opened={presenting} onClose={() => setPresenting(false)} fullScreen withCloseButton={false} padding={0}>\n <Box style={{ position: \"fixed\", inset: 0 }}>\n <StoryPlayer\n story={doc} resolveMedia={resolveMedia} dark={dark} strings={playerStrings}\n initialSlide={index === STORY ? 0 : index} onClose={() => setPresenting(false)}\n />\n </Box>\n </Modal>\n </Box>\n );\n}\n", "// Re-encodes an image for presentation (spec/1.0/README.md section 5):\n// scaled to fit a long-edge limit and written through a canvas, which also\n// drops every bit of EXIF/GPS metadata the original carried. Browser-only\n// (createImageBitmap + OffscreenCanvas); the sizing and format decisions are\n// split out as plain functions so they can be tested anywhere.\n\nexport type ImagePurpose = \"photo\" | \"overlay\";\n\nexport interface OptimizeOptions {\n /** \"photo\" (default): slide pictures, 1600px, WebP. \"overlay\": map\n * overlays, 2048px, PNG when they have transparency. */\n purpose?: ImagePurpose;\n /** Overrides the purpose's long-edge limit. Never scales up. */\n maxEdge?: number;\n /** Lossy quality, 0-1. Default 0.82. */\n quality?: number;\n}\n\nexport interface OptimizedImage {\n blob: Blob;\n mime: \"image/webp\" | \"image/jpeg\" | \"image/png\";\n /** File extension without the dot, matching `mime`. */\n ext: \"webp\" | \"jpg\" | \"png\";\n width: number;\n height: number;\n}\n\nexport const DEFAULT_MAX_EDGE: Record<ImagePurpose, number> = { photo: 1600, overlay: 2048 };\n\n/** Scales (width, height) down to fit within maxEdge on the longer side,\n * keeping the aspect ratio; never scales up. */\nexport function fitWithin(width: number, height: number, maxEdge: number): { width: number; height: number } {\n const longEdge = Math.max(width, height);\n if (longEdge <= maxEdge) return { width, height };\n const scale = maxEdge / longEdge;\n return { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)) };\n}\n\n/** Which encodings to try, best first. An overlay with transparency must\n * keep its alpha channel, and lossless PNG keeps hard map edges clean;\n * everything else goes lossy. JPEG is the fallback for a browser that\n * can't encode WebP (convertToBlob silently returns PNG then). */\nexport function encodingCandidates(purpose: ImagePurpose, hasAlpha: boolean): OptimizedImage[\"mime\"][] {\n if (hasAlpha) return purpose === \"overlay\" ? [\"image/png\"] : [\"image/webp\", \"image/png\"];\n return [\"image/webp\", \"image/jpeg\"];\n}\n\nconst EXT: Record<OptimizedImage[\"mime\"], OptimizedImage[\"ext\"]> = {\n \"image/webp\": \"webp\",\n \"image/jpeg\": \"jpg\",\n \"image/png\": \"png\",\n};\n\n/** Any pixel not fully opaque. Checked on the already-scaled canvas, so the\n * cost is bounded by maxEdge, not by the original's size. */\nfunction canvasHasAlpha(ctx: OffscreenCanvasRenderingContext2D, width: number, height: number): boolean {\n const data = ctx.getImageData(0, 0, width, height).data;\n for (let i = 3; i < data.length; i += 4) {\n if (data[i] < 255) return true;\n }\n return false;\n}\n\nexport async function optimizeImage(input: Blob, options: OptimizeOptions = {}): Promise<OptimizedImage> {\n const purpose = options.purpose ?? \"photo\";\n const maxEdge = options.maxEdge ?? DEFAULT_MAX_EDGE[purpose];\n const quality = options.quality ?? 0.82;\n\n // imageOrientation \"from-image\" applies the EXIF rotation before the\n // metadata is lost, so a sideways phone photo stays upright.\n const bitmap = await createImageBitmap(input, { imageOrientation: \"from-image\" });\n try {\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxEdge);\n const canvas = new OffscreenCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"No 2D canvas context available.\");\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(bitmap, 0, 0, width, height);\n const hasAlpha = canvasHasAlpha(ctx, width, height);\n\n for (const mime of encodingCandidates(purpose, hasAlpha)) {\n const blob = await canvas.convertToBlob({ type: mime, quality });\n if (blob.type === mime) return { blob, mime, ext: EXT[mime], width, height };\n }\n // Every browser can encode PNG; it's convertToBlob's own fallback.\n const blob = await canvas.convertToBlob({ type: \"image/png\" });\n return { blob, mime: \"image/png\", ext: \"png\", width, height };\n } finally {\n bitmap.close();\n }\n}\n", "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\",\n \"title\": \"Gramps Connect Story, format 1.0\",\n \"description\": \"The story.json at the root of a .story.zip. See spec/1.0/README.md for the rules this schema can't express (every ref resolves, every src exists in the zip, unknown fields are ignored).\",\n \"type\": \"object\",\n \"required\": [\"format\", \"version\", \"title\", \"slides\", \"media\"],\n \"properties\": {\n \"$schema\": { \"type\": \"string\" },\n \"format\": { \"const\": \"gramps-connect-story\" },\n \"version\": {\n \"description\": \"MAJOR.MINOR. This schema validates any 1.x file: newer minor versions only add optional fields.\",\n \"type\": \"string\",\n \"pattern\": \"^1\\\\.(0|[1-9][0-9]*)$\"\n },\n \"title\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"language\": {\n \"description\": \"BCP 47 language tag of the story's text, e.g. \\\"en\\\", \\\"de-CH\\\".\",\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"\n },\n \"created\": {\n \"description\": \"When the file was written, as an RFC 3339 date-time.\",\n \"type\": \"string\",\n \"pattern\": \"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"\n },\n \"generator\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"version\": { \"type\": \"string\" },\n \"url\": { \"type\": \"string\" }\n }\n },\n \"authors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"url\": { \"type\": \"string\" }\n }\n }\n },\n \"license\": {\n \"description\": \"License of the story's content (text and media), as an SPDX identifier or free text.\",\n \"type\": \"string\"\n },\n \"presentation\": {\n \"type\": \"object\",\n \"properties\": {\n \"basemap\": { \"enum\": [\"standard\", \"historical\", \"auto\", \"none\"] }\n }\n },\n \"slides\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/$defs/slide\" }\n },\n \"media\": {\n \"description\": \"Every media file in the story, keyed by an id that slides and overlays refer to.\",\n \"type\": \"object\",\n \"propertyNames\": { \"$ref\": \"#/$defs/id\" },\n \"additionalProperties\": { \"$ref\": \"#/$defs/mediaItem\" }\n },\n \"extensions\": {\n \"description\": \"Producer-specific data, keyed by namespace. Viewers ignore it.\",\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"object\" }\n }\n },\n \"$defs\": {\n \"id\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z0-9_-]{1,64}$\"\n },\n \"storyDate\": {\n \"type\": \"object\",\n \"required\": [\"text\"],\n \"properties\": {\n \"text\": {\n \"description\": \"The date as it should be shown, in the story's language.\",\n \"type\": \"string\",\n \"pattern\": \"\\\\S\"\n },\n \"edtf\": {\n \"description\": \"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\n \"type\": \"string\",\n \"pattern\": \"\\\\S\"\n },\n \"sortYear\": {\n \"description\": \"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\n \"type\": \"integer\"\n }\n }\n },\n \"slide\": {\n \"type\": \"object\",\n \"required\": [\"id\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/id\" },\n \"title\": { \"type\": \"string\" },\n \"text\": {\n \"description\": \"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\n \"type\": \"string\"\n },\n \"date\": { \"$ref\": \"#/$defs/storyDate\" },\n \"place\": { \"$ref\": \"#/$defs/place\" },\n \"media\": {\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/slideMedia\" }\n },\n \"people\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"role\": { \"type\": \"string\" }\n }\n }\n }\n }\n },\n \"slideMedia\": {\n \"type\": \"object\",\n \"required\": [\"ref\"],\n \"properties\": {\n \"ref\": { \"$ref\": \"#/$defs/id\" },\n \"caption\": { \"type\": \"string\" },\n \"credit\": { \"type\": \"string\" }\n }\n },\n \"place\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": { \"type\": \"string\" },\n \"lat\": { \"type\": \"number\", \"minimum\": -90, \"maximum\": 90 },\n \"lon\": { \"type\": \"number\", \"minimum\": -180, \"maximum\": 180 },\n \"geometry\": {\n \"description\": \"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\n \"type\": \"object\",\n \"required\": [\"type\"],\n \"properties\": { \"type\": { \"type\": \"string\" } },\n \"additionalProperties\": true\n },\n \"overlays\": {\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/overlay\" }\n }\n },\n \"dependentRequired\": {\n \"lat\": [\"lon\"],\n \"lon\": [\"lat\"]\n }\n },\n \"lonLat\": {\n \"type\": \"array\",\n \"prefixItems\": [\n { \"type\": \"number\", \"minimum\": -180, \"maximum\": 180 },\n { \"type\": \"number\", \"minimum\": -90, \"maximum\": 90 }\n ],\n \"minItems\": 2,\n \"maxItems\": 2\n },\n \"overlay\": {\n \"type\": \"object\",\n \"required\": [\"media\", \"corners\"],\n \"properties\": {\n \"media\": { \"$ref\": \"#/$defs/id\" },\n \"corners\": {\n \"description\": \"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/lonLat\" },\n \"minItems\": 4,\n \"maxItems\": 4\n },\n \"opacity\": { \"type\": \"number\", \"minimum\": 0, \"maximum\": 1 },\n \"order\": {\n \"description\": \"Stacking order among a slide's overlays; lower is drawn first.\",\n \"type\": \"integer\"\n },\n \"date\": { \"$ref\": \"#/$defs/storyDate\" }\n }\n },\n \"mediaItem\": {\n \"type\": \"object\",\n \"required\": [\"src\", \"mime\"],\n \"properties\": {\n \"src\": {\n \"description\": \"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\n \"type\": \"string\",\n \"pattern\": \"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"\n },\n \"mime\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-z]+/[A-Za-z0-9.+-]+$\"\n },\n \"width\": { \"type\": \"integer\", \"minimum\": 1 },\n \"height\": { \"type\": \"integer\", \"minimum\": 1 },\n \"alt\": { \"type\": \"string\" }\n }\n }\n }\n}\n", "// GENERATED by scripts/generate-validator.mjs from spec/1.0/story.schema.json -- do not edit.\n// @ts-nocheck\n\"use strict\";export const validate = validate20;export default validate20;const schema31 = {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\",\"title\":\"Gramps Connect Story, format 1.0\",\"description\":\"The story.json at the root of a .story.zip. See spec/1.0/README.md for the rules this schema can't express (every ref resolves, every src exists in the zip, unknown fields are ignored).\",\"type\":\"object\",\"required\":[\"format\",\"version\",\"title\",\"slides\",\"media\"],\"properties\":{\"$schema\":{\"type\":\"string\"},\"format\":{\"const\":\"gramps-connect-story\"},\"version\":{\"description\":\"MAJOR.MINOR. This schema validates any 1.x file: newer minor versions only add optional fields.\",\"type\":\"string\",\"pattern\":\"^1\\\\.(0|[1-9][0-9]*)$\"},\"title\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"language\":{\"description\":\"BCP 47 language tag of the story's text, e.g. \\\"en\\\", \\\"de-CH\\\".\",\"type\":\"string\",\"pattern\":\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"},\"created\":{\"description\":\"When the file was written, as an RFC 3339 date-time.\",\"type\":\"string\",\"pattern\":\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"},\"generator\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"version\":{\"type\":\"string\"},\"url\":{\"type\":\"string\"}}},\"authors\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"url\":{\"type\":\"string\"}}}},\"license\":{\"description\":\"License of the story's content (text and media), as an SPDX identifier or free text.\",\"type\":\"string\"},\"presentation\":{\"type\":\"object\",\"properties\":{\"basemap\":{\"enum\":[\"standard\",\"historical\",\"auto\",\"none\"]}}},\"slides\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/$defs/slide\"}},\"media\":{\"description\":\"Every media file in the story, keyed by an id that slides and overlays refer to.\",\"type\":\"object\",\"propertyNames\":{\"$ref\":\"#/$defs/id\"},\"additionalProperties\":{\"$ref\":\"#/$defs/mediaItem\"}},\"extensions\":{\"description\":\"Producer-specific data, keyed by namespace. Viewers ignore it.\",\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"$defs\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[A-Za-z0-9_-]{1,64}$\"},\"storyDate\":{\"type\":\"object\",\"required\":[\"text\"],\"properties\":{\"text\":{\"description\":\"The date as it should be shown, in the story's language.\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"edtf\":{\"description\":\"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"sortYear\":{\"description\":\"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\"type\":\"integer\"}}},\"slide\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"$ref\":\"#/$defs/id\"},\"title\":{\"type\":\"string\"},\"text\":{\"description\":\"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\"type\":\"string\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"},\"place\":{\"$ref\":\"#/$defs/place\"},\"media\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/slideMedia\"}},\"people\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"role\":{\"type\":\"string\"}}}}}},\"slideMedia\":{\"type\":\"object\",\"required\":[\"ref\"],\"properties\":{\"ref\":{\"$ref\":\"#/$defs/id\"},\"caption\":{\"type\":\"string\"},\"credit\":{\"type\":\"string\"}}},\"place\":{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"},\"lat\":{\"type\":\"number\",\"minimum\":-90,\"maximum\":90},\"lon\":{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},\"geometry\":{\"description\":\"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\"type\":\"object\",\"required\":[\"type\"],\"properties\":{\"type\":{\"type\":\"string\"}},\"additionalProperties\":true},\"overlays\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/overlay\"}}},\"dependentRequired\":{\"lat\":[\"lon\"],\"lon\":[\"lat\"]}},\"lonLat\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},{\"type\":\"number\",\"minimum\":-90,\"maximum\":90}],\"minItems\":2,\"maxItems\":2},\"overlay\":{\"type\":\"object\",\"required\":[\"media\",\"corners\"],\"properties\":{\"media\":{\"$ref\":\"#/$defs/id\"},\"corners\":{\"description\":\"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/lonLat\"},\"minItems\":4,\"maxItems\":4},\"opacity\":{\"type\":\"number\",\"minimum\":0,\"maximum\":1},\"order\":{\"description\":\"Stacking order among a slide's overlays; lower is drawn first.\",\"type\":\"integer\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"}}},\"mediaItem\":{\"type\":\"object\",\"required\":[\"src\",\"mime\"],\"properties\":{\"src\":{\"description\":\"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\"type\":\"string\",\"pattern\":\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},\"mime\":{\"type\":\"string\",\"pattern\":\"^[a-z]+/[A-Za-z0-9.+-]+$\"},\"width\":{\"type\":\"integer\",\"minimum\":1},\"height\":{\"type\":\"integer\",\"minimum\":1},\"alt\":{\"type\":\"string\"}}}}};const schema33 = {\"type\":\"string\",\"pattern\":\"^[A-Za-z0-9_-]{1,64}$\"};const schema43 = {\"type\":\"object\",\"required\":[\"src\",\"mime\"],\"properties\":{\"src\":{\"description\":\"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\"type\":\"string\",\"pattern\":\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},\"mime\":{\"type\":\"string\",\"pattern\":\"^[a-z]+/[A-Za-z0-9.+-]+$\"},\"width\":{\"type\":\"integer\",\"minimum\":1},\"height\":{\"type\":\"integer\",\"minimum\":1},\"alt\":{\"type\":\"string\"}}};const pattern4 = new RegExp(\"^1\\\\.(0|[1-9][0-9]*)$\", \"u\");const pattern5 = new RegExp(\"\\\\S\", \"u\");const pattern6 = new RegExp(\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\", \"u\");const pattern7 = new RegExp(\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\", \"u\");const pattern10 = new RegExp(\"^[A-Za-z0-9_-]{1,64}$\", \"u\");const pattern19 = new RegExp(\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\", \"u\");const pattern20 = new RegExp(\"^[a-z]+/[A-Za-z0-9.+-]+$\", \"u\");const schema32 = {\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"$ref\":\"#/$defs/id\"},\"title\":{\"type\":\"string\"},\"text\":{\"description\":\"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\"type\":\"string\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"},\"place\":{\"$ref\":\"#/$defs/place\"},\"media\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/slideMedia\"}},\"people\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"role\":{\"type\":\"string\"}}}}}};const schema34 = {\"type\":\"object\",\"required\":[\"text\"],\"properties\":{\"text\":{\"description\":\"The date as it should be shown, in the story's language.\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"edtf\":{\"description\":\"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"sortYear\":{\"description\":\"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\"type\":\"integer\"}}};const schema35 = {\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"},\"lat\":{\"type\":\"number\",\"minimum\":-90,\"maximum\":90},\"lon\":{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},\"geometry\":{\"description\":\"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\"type\":\"object\",\"required\":[\"type\"],\"properties\":{\"type\":{\"type\":\"string\"}},\"additionalProperties\":true},\"overlays\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/overlay\"}}},\"dependentRequired\":{\"lat\":[\"lon\"],\"lon\":[\"lat\"]}};const schema36 = {\"type\":\"object\",\"required\":[\"media\",\"corners\"],\"properties\":{\"media\":{\"$ref\":\"#/$defs/id\"},\"corners\":{\"description\":\"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/lonLat\"},\"minItems\":4,\"maxItems\":4},\"opacity\":{\"type\":\"number\",\"minimum\":0,\"maximum\":1},\"order\":{\"description\":\"Stacking order among a slide's overlays; lower is drawn first.\",\"type\":\"integer\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"}}};const schema38 = {\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},{\"type\":\"number\",\"minimum\":-90,\"maximum\":90}],\"minItems\":2,\"maxItems\":2};function validate23(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate23.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.media === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"media\"},message:\"must have required property '\"+\"media\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.corners === undefined){const err1 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"corners\"},message:\"must have required property '\"+\"corners\"+\"'\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.media !== undefined){let data0 = data.media;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err2 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}else {const err3 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.corners !== undefined){let data1 = data.corners;if(Array.isArray(data1)){if(data1.length > 4){const err4 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/maxItems\",keyword:\"maxItems\",params:{limit: 4},message:\"must NOT have more than 4 items\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data1.length < 4){const err5 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/minItems\",keyword:\"minItems\",params:{limit: 4},message:\"must NOT have fewer than 4 items\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}const len0 = data1.length;for(let i0=0; i0<len0; i0++){let data2 = data1[i0];if(Array.isArray(data2)){if(data2.length > 2){const err6 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/maxItems\",keyword:\"maxItems\",params:{limit: 2},message:\"must NOT have more than 2 items\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(data2.length < 2){const err7 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/minItems\",keyword:\"minItems\",params:{limit: 2},message:\"must NOT have fewer than 2 items\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}const len1 = data2.length;if(len1 > 0){let data3 = data2[0];if((typeof data3 == \"number\") && (isFinite(data3))){if(data3 > 180 || isNaN(data3)){const err8 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 180},message:\"must be <= 180\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}if(data3 < -180 || isNaN(data3)){const err9 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -180},message:\"must be >= -180\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(len1 > 1){let data4 = data2[1];if((typeof data4 == \"number\") && (isFinite(data4))){if(data4 > 90 || isNaN(data4)){const err11 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 90},message:\"must be <= 90\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}if(data4 < -90 || isNaN(data4)){const err12 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -90},message:\"must be >= -90\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}}else {const err14 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}}else {const err15 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.opacity !== undefined){let data5 = data.opacity;if((typeof data5 == \"number\") && (isFinite(data5))){if(data5 > 1 || isNaN(data5)){const err16 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 1},message:\"must be <= 1\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}if(data5 < 0 || isNaN(data5)){const err17 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 0},message:\"must be >= 0\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}else {const err18 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}if(data.order !== undefined){let data6 = data.order;if(!(((typeof data6 == \"number\") && (!(data6 % 1) && !isNaN(data6))) && (isFinite(data6)))){const err19 = {instancePath:instancePath+\"/order\",schemaPath:\"#/properties/order/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}if(data.date !== undefined){let data7 = data.date;if(data7 && typeof data7 == \"object\" && !Array.isArray(data7)){if(data7.text === undefined){const err20 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/required\",keyword:\"required\",params:{missingProperty: \"text\"},message:\"must have required property '\"+\"text\"+\"'\"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data7.text !== undefined){let data8 = data7.text;if(typeof data8 === \"string\"){if(!pattern5.test(data8)){const err21 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}else {const err22 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data7.edtf !== undefined){let data9 = data7.edtf;if(typeof data9 === \"string\"){if(!pattern5.test(data9)){const err23 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}else {const err24 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data7.sortYear !== undefined){let data10 = data7.sortYear;if(!(((typeof data10 == \"number\") && (!(data10 % 1) && !isNaN(data10))) && (isFinite(data10)))){const err25 = {instancePath:instancePath+\"/date/sortYear\",schemaPath:\"#/$defs/storyDate/properties/sortYear/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}else {const err26 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}validate23.errors = vErrors;return errors === 0;}validate23.evaluated = {\"props\":{\"media\":true,\"corners\":true,\"opacity\":true,\"order\":true,\"date\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate22(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate22.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.name !== undefined){if(typeof data.name !== \"string\"){const err0 = {instancePath:instancePath+\"/name\",schemaPath:\"#/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}}if(data.lat !== undefined){let data1 = data.lat;if((typeof data1 == \"number\") && (isFinite(data1))){if(data1 > 90 || isNaN(data1)){const err1 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 90},message:\"must be <= 90\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data1 < -90 || isNaN(data1)){const err2 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -90},message:\"must be >= -90\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}else {const err3 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.lon !== undefined){let data2 = data.lon;if((typeof data2 == \"number\") && (isFinite(data2))){if(data2 > 180 || isNaN(data2)){const err4 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 180},message:\"must be <= 180\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data2 < -180 || isNaN(data2)){const err5 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -180},message:\"must be >= -180\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}else {const err6 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.geometry !== undefined){let data3 = data.geometry;if(data3 && typeof data3 == \"object\" && !Array.isArray(data3)){if(data3.type === undefined){const err7 = {instancePath:instancePath+\"/geometry\",schemaPath:\"#/properties/geometry/required\",keyword:\"required\",params:{missingProperty: \"type\"},message:\"must have required property '\"+\"type\"+\"'\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}if(data3.type !== undefined){if(typeof data3.type !== \"string\"){const err8 = {instancePath:instancePath+\"/geometry/type\",schemaPath:\"#/properties/geometry/properties/type/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}else {const err9 = {instancePath:instancePath+\"/geometry\",schemaPath:\"#/properties/geometry/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.overlays !== undefined){let data5 = data.overlays;if(Array.isArray(data5)){const len0 = data5.length;for(let i0=0; i0<len0; i0++){if(!(validate23(data5[i0], {instancePath:instancePath+\"/overlays/\" + i0,parentData:data5,parentDataProperty:i0,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}}}else {const err10 = {instancePath:instancePath+\"/overlays\",schemaPath:\"#/properties/overlays/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.lat !== undefined){if(data.lon === undefined){const err11 = {instancePath,schemaPath:\"#/dependentRequired\",keyword:\"dependentRequired\",params:{property: \"lat\",\n missingProperty: \"lon\",\n depsCount: 1,\n deps: \"lon\"},message:\"must have property lon when property lat is present\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.lon !== undefined){if(data.lat === undefined){const err12 = {instancePath,schemaPath:\"#/dependentRequired\",keyword:\"dependentRequired\",params:{property: \"lon\",\n missingProperty: \"lat\",\n depsCount: 1,\n deps: \"lat\"},message:\"must have property lat when property lon is present\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}}else {const err13 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}validate22.errors = vErrors;return errors === 0;}validate22.evaluated = {\"props\":{\"name\":true,\"lat\":true,\"lon\":true,\"geometry\":true,\"overlays\":true},\"dynamicProps\":false,\"dynamicItems\":false};const schema40 = {\"type\":\"object\",\"required\":[\"ref\"],\"properties\":{\"ref\":{\"$ref\":\"#/$defs/id\"},\"caption\":{\"type\":\"string\"},\"credit\":{\"type\":\"string\"}}};function validate26(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate26.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.ref === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"ref\"},message:\"must have required property '\"+\"ref\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.ref !== undefined){let data0 = data.ref;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err1 = {instancePath:instancePath+\"/ref\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}else {const err2 = {instancePath:instancePath+\"/ref\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.caption !== undefined){if(typeof data.caption !== \"string\"){const err3 = {instancePath:instancePath+\"/caption\",schemaPath:\"#/properties/caption/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.credit !== undefined){if(typeof data.credit !== \"string\"){const err4 = {instancePath:instancePath+\"/credit\",schemaPath:\"#/properties/credit/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}validate26.errors = vErrors;return errors === 0;}validate26.evaluated = {\"props\":{\"ref\":true,\"caption\":true,\"credit\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate21(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate21.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.id === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"id\"},message:\"must have required property '\"+\"id\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.id !== undefined){let data0 = data.id;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err1 = {instancePath:instancePath+\"/id\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}else {const err2 = {instancePath:instancePath+\"/id\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.title !== undefined){if(typeof data.title !== \"string\"){const err3 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.text !== undefined){if(typeof data.text !== \"string\"){const err4 = {instancePath:instancePath+\"/text\",schemaPath:\"#/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.date !== undefined){let data3 = data.date;if(data3 && typeof data3 == \"object\" && !Array.isArray(data3)){if(data3.text === undefined){const err5 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/required\",keyword:\"required\",params:{missingProperty: \"text\"},message:\"must have required property '\"+\"text\"+\"'\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}if(data3.text !== undefined){let data4 = data3.text;if(typeof data4 === \"string\"){if(!pattern5.test(data4)){const err6 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}else {const err7 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data3.edtf !== undefined){let data5 = data3.edtf;if(typeof data5 === \"string\"){if(!pattern5.test(data5)){const err8 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}else {const err9 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data3.sortYear !== undefined){let data6 = data3.sortYear;if(!(((typeof data6 == \"number\") && (!(data6 % 1) && !isNaN(data6))) && (isFinite(data6)))){const err10 = {instancePath:instancePath+\"/date/sortYear\",schemaPath:\"#/$defs/storyDate/properties/sortYear/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}else {const err11 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.place !== undefined){if(!(validate22(data.place, {instancePath:instancePath+\"/place\",parentData:data,parentDataProperty:\"place\",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate22.errors : vErrors.concat(validate22.errors);errors = vErrors.length;}}if(data.media !== undefined){let data8 = data.media;if(Array.isArray(data8)){const len0 = data8.length;for(let i0=0; i0<len0; i0++){if(!(validate26(data8[i0], {instancePath:instancePath+\"/media/\" + i0,parentData:data8,parentDataProperty:i0,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate26.errors : vErrors.concat(validate26.errors);errors = vErrors.length;}}}else {const err12 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.people !== undefined){let data10 = data.people;if(Array.isArray(data10)){const len1 = data10.length;for(let i1=0; i1<len1; i1++){let data11 = data10[i1];if(data11 && typeof data11 == \"object\" && !Array.isArray(data11)){if(data11.name === undefined){const err13 = {instancePath:instancePath+\"/people/\" + i1,schemaPath:\"#/properties/people/items/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}if(data11.name !== undefined){let data12 = data11.name;if(typeof data12 === \"string\"){if(!pattern5.test(data12)){const err14 = {instancePath:instancePath+\"/people/\" + i1+\"/name\",schemaPath:\"#/properties/people/items/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}else {const err15 = {instancePath:instancePath+\"/people/\" + i1+\"/name\",schemaPath:\"#/properties/people/items/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data11.role !== undefined){if(typeof data11.role !== \"string\"){const err16 = {instancePath:instancePath+\"/people/\" + i1+\"/role\",schemaPath:\"#/properties/people/items/properties/role/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath:instancePath+\"/people/\" + i1,schemaPath:\"#/properties/people/items/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}}else {const err18 = {instancePath:instancePath+\"/people\",schemaPath:\"#/properties/people/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}}else {const err19 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}validate21.errors = vErrors;return errors === 0;}validate21.evaluated = {\"props\":{\"id\":true,\"title\":true,\"text\":true,\"date\":true,\"place\":true,\"media\":true,\"people\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate20(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL=\"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\" */;let vErrors = null;let errors = 0;const evaluated0 = validate20.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.format === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"format\"},message:\"must have required property '\"+\"format\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.version === undefined){const err1 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"version\"},message:\"must have required property '\"+\"version\"+\"'\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.title === undefined){const err2 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"title\"},message:\"must have required property '\"+\"title\"+\"'\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.slides === undefined){const err3 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"slides\"},message:\"must have required property '\"+\"slides\"+\"'\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(data.media === undefined){const err4 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"media\"},message:\"must have required property '\"+\"media\"+\"'\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data.$schema !== undefined){if(typeof data.$schema !== \"string\"){const err5 = {instancePath:instancePath+\"/$schema\",schemaPath:\"#/properties/%24schema/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.format !== undefined){if(\"gramps-connect-story\" !== data.format){const err6 = {instancePath:instancePath+\"/format\",schemaPath:\"#/properties/format/const\",keyword:\"const\",params:{allowedValue: \"gramps-connect-story\"},message:\"must be equal to constant\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.version !== undefined){let data2 = data.version;if(typeof data2 === \"string\"){if(!pattern4.test(data2)){const err7 = {instancePath:instancePath+\"/version\",schemaPath:\"#/properties/version/pattern\",keyword:\"pattern\",params:{pattern: \"^1\\\\.(0|[1-9][0-9]*)$\"},message:\"must match pattern \\\"\"+\"^1\\\\.(0|[1-9][0-9]*)$\"+\"\\\"\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}else {const err8 = {instancePath:instancePath+\"/version\",schemaPath:\"#/properties/version/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.title !== undefined){let data3 = data.title;if(typeof data3 === \"string\"){if(!pattern5.test(data3)){const err9 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.language !== undefined){let data4 = data.language;if(typeof data4 === \"string\"){if(!pattern6.test(data4)){const err11 = {instancePath:instancePath+\"/language\",schemaPath:\"#/properties/language/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"+\"\\\"\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}else {const err12 = {instancePath:instancePath+\"/language\",schemaPath:\"#/properties/language/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.created !== undefined){let data5 = data.created;if(typeof data5 === \"string\"){if(!pattern7.test(data5)){const err13 = {instancePath:instancePath+\"/created\",schemaPath:\"#/properties/created/pattern\",keyword:\"pattern\",params:{pattern: \"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"},message:\"must match pattern \\\"\"+\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"+\"\\\"\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}else {const err14 = {instancePath:instancePath+\"/created\",schemaPath:\"#/properties/created/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.generator !== undefined){let data6 = data.generator;if(data6 && typeof data6 == \"object\" && !Array.isArray(data6)){if(data6.name === undefined){const err15 = {instancePath:instancePath+\"/generator\",schemaPath:\"#/properties/generator/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}if(data6.name !== undefined){let data7 = data6.name;if(typeof data7 === \"string\"){if(!pattern5.test(data7)){const err16 = {instancePath:instancePath+\"/generator/name\",schemaPath:\"#/properties/generator/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}else {const err17 = {instancePath:instancePath+\"/generator/name\",schemaPath:\"#/properties/generator/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data6.version !== undefined){if(typeof data6.version !== \"string\"){const err18 = {instancePath:instancePath+\"/generator/version\",schemaPath:\"#/properties/generator/properties/version/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}if(data6.url !== undefined){if(typeof data6.url !== \"string\"){const err19 = {instancePath:instancePath+\"/generator/url\",schemaPath:\"#/properties/generator/properties/url/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}}else {const err20 = {instancePath:instancePath+\"/generator\",schemaPath:\"#/properties/generator/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}if(data.authors !== undefined){let data10 = data.authors;if(Array.isArray(data10)){const len0 = data10.length;for(let i0=0; i0<len0; i0++){let data11 = data10[i0];if(data11 && typeof data11 == \"object\" && !Array.isArray(data11)){if(data11.name === undefined){const err21 = {instancePath:instancePath+\"/authors/\" + i0,schemaPath:\"#/properties/authors/items/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}if(data11.name !== undefined){let data12 = data11.name;if(typeof data12 === \"string\"){if(!pattern5.test(data12)){const err22 = {instancePath:instancePath+\"/authors/\" + i0+\"/name\",schemaPath:\"#/properties/authors/items/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}else {const err23 = {instancePath:instancePath+\"/authors/\" + i0+\"/name\",schemaPath:\"#/properties/authors/items/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data11.url !== undefined){if(typeof data11.url !== \"string\"){const err24 = {instancePath:instancePath+\"/authors/\" + i0+\"/url\",schemaPath:\"#/properties/authors/items/properties/url/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}}else {const err25 = {instancePath:instancePath+\"/authors/\" + i0,schemaPath:\"#/properties/authors/items/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}else {const err26 = {instancePath:instancePath+\"/authors\",schemaPath:\"#/properties/authors/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}if(data.license !== undefined){if(typeof data.license !== \"string\"){const err27 = {instancePath:instancePath+\"/license\",schemaPath:\"#/properties/license/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}}if(data.presentation !== undefined){let data15 = data.presentation;if(data15 && typeof data15 == \"object\" && !Array.isArray(data15)){if(data15.basemap !== undefined){let data16 = data15.basemap;if(!((((data16 === \"standard\") || (data16 === \"historical\")) || (data16 === \"auto\")) || (data16 === \"none\"))){const err28 = {instancePath:instancePath+\"/presentation/basemap\",schemaPath:\"#/properties/presentation/properties/basemap/enum\",keyword:\"enum\",params:{allowedValues: schema31.properties.presentation.properties.basemap.enum},message:\"must be equal to one of the allowed values\"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}}}else {const err29 = {instancePath:instancePath+\"/presentation\",schemaPath:\"#/properties/presentation/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}}if(data.slides !== undefined){let data17 = data.slides;if(Array.isArray(data17)){if(data17.length < 1){const err30 = {instancePath:instancePath+\"/slides\",schemaPath:\"#/properties/slides/minItems\",keyword:\"minItems\",params:{limit: 1},message:\"must NOT have fewer than 1 items\"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}const len1 = data17.length;for(let i1=0; i1<len1; i1++){if(!(validate21(data17[i1], {instancePath:instancePath+\"/slides/\" + i1,parentData:data17,parentDataProperty:i1,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate21.errors : vErrors.concat(validate21.errors);errors = vErrors.length;}}}else {const err31 = {instancePath:instancePath+\"/slides\",schemaPath:\"#/properties/slides/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}if(data.media !== undefined){let data19 = data.media;if(data19 && typeof data19 == \"object\" && !Array.isArray(data19)){for(const key0 in data19){const _errs38 = errors;if(typeof key0 === \"string\"){if(!pattern10.test(key0)){const err32 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\",propertyName:key0};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}}else {const err33 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\",propertyName:key0};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}var valid8 = _errs38 === errors;if(!valid8){const err34 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/propertyNames\",keyword:\"propertyNames\",params:{propertyName: key0},message:\"property name must be valid\"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}for(const key1 in data19){let data20 = data19[key1];if(data20 && typeof data20 == \"object\" && !Array.isArray(data20)){if(data20.src === undefined){const err35 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/required\",keyword:\"required\",params:{missingProperty: \"src\"},message:\"must have required property '\"+\"src\"+\"'\"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}if(data20.mime === undefined){const err36 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/required\",keyword:\"required\",params:{missingProperty: \"mime\"},message:\"must have required property '\"+\"mime\"+\"'\"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}if(data20.src !== undefined){let data21 = data20.src;if(typeof data21 === \"string\"){if(!pattern19.test(data21)){const err37 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/src\",schemaPath:\"#/$defs/mediaItem/properties/src/pattern\",keyword:\"pattern\",params:{pattern: \"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},message:\"must match pattern \\\"\"+\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"+\"\\\"\"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}}else {const err38 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/src\",schemaPath:\"#/$defs/mediaItem/properties/src/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}}if(data20.mime !== undefined){let data22 = data20.mime;if(typeof data22 === \"string\"){if(!pattern20.test(data22)){const err39 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/mime\",schemaPath:\"#/$defs/mediaItem/properties/mime/pattern\",keyword:\"pattern\",params:{pattern: \"^[a-z]+/[A-Za-z0-9.+-]+$\"},message:\"must match pattern \\\"\"+\"^[a-z]+/[A-Za-z0-9.+-]+$\"+\"\\\"\"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}else {const err40 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/mime\",schemaPath:\"#/$defs/mediaItem/properties/mime/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}}if(data20.width !== undefined){let data23 = data20.width;if(!(((typeof data23 == \"number\") && (!(data23 % 1) && !isNaN(data23))) && (isFinite(data23)))){const err41 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/width\",schemaPath:\"#/$defs/mediaItem/properties/width/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}if((typeof data23 == \"number\") && (isFinite(data23))){if(data23 < 1 || isNaN(data23)){const err42 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/width\",schemaPath:\"#/$defs/mediaItem/properties/width/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 1},message:\"must be >= 1\"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}}if(data20.height !== undefined){let data24 = data20.height;if(!(((typeof data24 == \"number\") && (!(data24 % 1) && !isNaN(data24))) && (isFinite(data24)))){const err43 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/height\",schemaPath:\"#/$defs/mediaItem/properties/height/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}if((typeof data24 == \"number\") && (isFinite(data24))){if(data24 < 1 || isNaN(data24)){const err44 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/height\",schemaPath:\"#/$defs/mediaItem/properties/height/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 1},message:\"must be >= 1\"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}}}if(data20.alt !== undefined){if(typeof data20.alt !== \"string\"){const err45 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/alt\",schemaPath:\"#/$defs/mediaItem/properties/alt/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}}}else {const err46 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}}else {const err47 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.extensions !== undefined){let data26 = data.extensions;if(data26 && typeof data26 == \"object\" && !Array.isArray(data26)){for(const key2 in data26){let data27 = data26[key2];if(!(data27 && typeof data27 == \"object\" && !Array.isArray(data27))){const err48 = {instancePath:instancePath+\"/extensions/\" + key2.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/properties/extensions/additionalProperties/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}}}else {const err49 = {instancePath:instancePath+\"/extensions\",schemaPath:\"#/properties/extensions/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}}}else {const err50 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}validate20.errors = vErrors;return errors === 0;}validate20.evaluated = {\"props\":{\"$schema\":true,\"format\":true,\"version\":true,\"title\":true,\"language\":true,\"created\":true,\"generator\":true,\"authors\":true,\"license\":true,\"presentation\":true,\"slides\":true,\"media\":true,\"extensions\":true},\"dynamicProps\":false,\"dynamicItems\":false};\n", "// Format identity and versioning (spec/1.0/README.md section 2), and the\n// chain of upgraders that lets this package keep opening every older major\n// version of the format.\nimport type { StoryDoc } from \"./types\";\n\nexport const FORMAT_ID = \"gramps-connect-story\";\n\n/** The version this package writes. */\nexport const FORMAT_VERSION = \"1.0\";\n\nexport const CURRENT_MAJOR = 1;\n\n/** Upgraders, keyed by the major version they upgrade *from*: UPGRADERS[1]\n * turns a 1.x document into a 2.0 one, and so on. Never remove one -- each\n * is the only thing that keeps old files opening -- and give each a fixture\n * from its source version under examples/. Empty while 1 is the only major.\n * Each receives a document that already passed its own version's checks. */\nconst UPGRADERS: Record<number, (doc: Record<string, unknown>) => Record<string, unknown>> = {};\n\n/** Every major version upgradeStory() can open. */\nexport const SUPPORTED_FORMAT_MAJORS: readonly number[] = Object.freeze(\n Array.from({ length: CURRENT_MAJOR }, (_, i) => i + 1).filter(\n (major) => major === CURRENT_MAJOR || UPGRADERS[major] !== undefined,\n ),\n);\n\nexport type StoryErrorCode =\n | \"not-a-zip\"\n | \"no-story-json\"\n | \"bad-json\"\n | \"not-a-story\"\n | \"bad-version\"\n | \"newer-version\"\n | \"too-large\"\n | \"invalid\";\n\nexport class StoryFormatError extends Error {\n readonly code: StoryErrorCode;\n constructor(code: StoryErrorCode, message: string) {\n super(message);\n this.name = \"StoryFormatError\";\n this.code = code;\n }\n}\n\nexport interface ParsedVersion {\n major: number;\n minor: number;\n}\n\nexport function parseVersion(version: unknown): ParsedVersion | null {\n if (typeof version !== \"string\") return null;\n const match = /^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$/.exec(version);\n if (!match) return null;\n return { major: Number(match[1]), minor: Number(match[2]) };\n}\n\n/** Checks `raw` is a story at all and brings it up to CURRENT_MAJOR.\n * Doesn't validate the result -- see validate.ts -- only what it needs to\n * pick upgraders: `format` and `version`. Throws StoryFormatError. */\nexport function upgradeStory(raw: unknown): StoryDoc {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new StoryFormatError(\"not-a-story\", \"story.json is not a JSON object.\");\n }\n let doc = raw as Record<string, unknown>;\n if (doc.format !== FORMAT_ID) {\n throw new StoryFormatError(\"not-a-story\", `story.json's \"format\" is not \"${FORMAT_ID}\".`);\n }\n const parsed = parseVersion(doc.version);\n if (!parsed || parsed.major < 1) {\n throw new StoryFormatError(\"bad-version\", `story.json's \"version\" (${JSON.stringify(doc.version)}) is not a valid MAJOR.MINOR version.`);\n }\n if (parsed.major > CURRENT_MAJOR) {\n throw new StoryFormatError(\n \"newer-version\",\n `This story uses format version ${doc.version}, which is newer than this viewer supports (up to ${CURRENT_MAJOR}.x). A newer viewer is needed to open it.`,\n );\n }\n for (let major = parsed.major; major < CURRENT_MAJOR; major++) {\n const upgrade = UPGRADERS[major];\n if (!upgrade) {\n throw new StoryFormatError(\"bad-version\", `No upgrade path from format version ${major}.x.`);\n }\n doc = upgrade(doc);\n }\n return doc as unknown as StoryDoc;\n}\n", "// Everything that makes a story.json valid: the JSON Schema (compiled ahead\n// of time into generated/schemaValidator.js -- see\n// scripts/generate-validator.mjs for why) plus the cross-references the\n// schema can't express (spec/1.0/README.md section 8).\nimport schema from \"../spec/1.0/story.schema.json\" with { type: \"json\" };\nimport { validate as schemaValidate } from \"./generated/schemaValidator.js\";\nimport { CURRENT_MAJOR, parseVersion } from \"./version\";\nimport type { StoryDoc } from \"./types\";\n\n/** Minor version of the schema bundled here: unknown fields in a file of\n * this minor version or older are probably typos, not newer features. */\nconst SCHEMA_MINOR = 0;\n\nexport interface StoryIssue {\n /** JSON Pointer into story.json (\"\" for the root), e.g. \"/slides/2/media/0/ref\". */\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: StoryIssue[];\n /** Not wrong, but probably not intended: unknown fields in a file that\n * claims a version this package fully knows, media nothing uses. */\n warnings: StoryIssue[];\n}\n\n/** Checks a story document. `files`, when given, is the set of paths in the\n * zip (relative to its story root), so every media `src` can be checked\n * too; without it only story.json itself is checked. */\nexport function validate(doc: unknown, files?: { has(path: string): boolean }): ValidationResult {\n const errors: StoryIssue[] = [];\n const warnings: StoryIssue[] = [];\n\n if (!schemaValidate(doc)) {\n for (const err of schemaValidate.errors ?? []) {\n errors.push({ path: err.instancePath, message: describeSchemaError(err) });\n }\n // Cross-reference checks below assume the basic shape is right.\n return { valid: false, errors, warnings };\n }\n const story = doc as StoryDoc;\n\n const slideIds = new Set<string>();\n const usedMedia = new Set<string>();\n const checkRef = (key: string, path: string) => {\n usedMedia.add(key);\n if (!Object.prototype.hasOwnProperty.call(story.media, key)) {\n errors.push({ path, message: `refers to media \"${key}\", which isn't in \"media\".` });\n }\n };\n story.slides.forEach((slide, i) => {\n if (slideIds.has(slide.id)) {\n errors.push({ path: `/slides/${i}/id`, message: `duplicate slide id \"${slide.id}\".` });\n }\n slideIds.add(slide.id);\n slide.media?.forEach((m, j) => checkRef(m.ref, `/slides/${i}/media/${j}/ref`));\n slide.place?.overlays?.forEach((o, j) => checkRef(o.media, `/slides/${i}/place/overlays/${j}/media`));\n });\n\n for (const [key, item] of Object.entries(story.media)) {\n const path = `/media/${escapePointer(key)}`;\n if (files && !files.has(item.src)) {\n errors.push({ path: `${path}/src`, message: `file \"${item.src}\" is not in the zip.` });\n }\n if (!usedMedia.has(key)) {\n warnings.push({ path, message: `media \"${key}\" isn't used by any slide or overlay.` });\n }\n }\n\n const version = parseVersion(story.version);\n if (version && version.major === CURRENT_MAJOR && version.minor <= SCHEMA_MINOR) {\n findUnknownFields(story, schema as unknown as SchemaNode, \"\", warnings);\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\ninterface AjvError {\n instancePath: string;\n keyword: string;\n params: Record<string, unknown>;\n message?: string;\n}\n\nfunction describeSchemaError(err: AjvError): string {\n if (err.keyword === \"pattern\" && err.params.pattern === \"\\\\S\") return \"must not be empty.\";\n if (err.keyword === \"required\") return `is missing required field \"${String(err.params.missingProperty)}\".`;\n if (err.keyword === \"const\") return `must be ${JSON.stringify(err.params.allowedValue)}.`;\n if (err.keyword === \"enum\") return `must be one of ${(err.params.allowedValues as unknown[]).map((v) => JSON.stringify(v)).join(\", \")}.`;\n return `${err.message ?? \"is invalid\"}.`;\n}\n\nfunction escapePointer(key: string): string {\n return key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n}\n\ntype SchemaNode = {\n $ref?: string;\n properties?: Record<string, SchemaNode>;\n additionalProperties?: SchemaNode | boolean;\n items?: SchemaNode;\n prefixItems?: SchemaNode[];\n};\n\nfunction resolveRef(node: SchemaNode, root: Record<string, unknown>): SchemaNode {\n if (!node.$ref) return node;\n const name = node.$ref.replace(/^#\\/\\$defs\\//, \"\");\n return (root.$defs as Record<string, SchemaNode>)[name];\n}\n\n/** Walks the document alongside the schema, warning about any key an\n * object's schema doesn't name. An object whose schema says\n * `additionalProperties: true` (GeoJSON) or gives a schema for extra keys\n * (`media`, `extensions`) is open, not a typo trap. */\nfunction findUnknownFields(value: unknown, node: SchemaNode, path: string, warnings: StoryIssue[], root = schema as unknown as Record<string, unknown>) {\n node = resolveRef(node, root);\n if (Array.isArray(value)) {\n value.forEach((item, i) => {\n const itemNode = node.prefixItems?.[i] ?? node.items;\n if (itemNode) findUnknownFields(item, itemNode, `${path}/${i}`, warnings, root);\n });\n return;\n }\n if (typeof value !== \"object\" || value === null) return;\n for (const [key, child] of Object.entries(value)) {\n const childPath = `${path}/${escapePointer(key)}`;\n const known = node.properties?.[key];\n if (known) {\n findUnknownFields(child, known, childPath, warnings, root);\n } else if (typeof node.additionalProperties === \"object\") {\n findUnknownFields(child, node.additionalProperties, childPath, warnings, root);\n } else if (node.properties && node.additionalProperties !== true) {\n warnings.push({ path: childPath, message: `unknown field \"${key}\" (ignored).` });\n }\n }\n}\n", "// Where a slide is on the map: its point, or the box around its shape and\n// overlays -- pure geometry, no map library.\nimport type { LonLat, Place } from \"../types\";\n\nexport type Bounds = [west: number, south: number, east: number, north: number];\n\nfunction visit(coords: unknown, bounds: Bounds): void {\n if (!Array.isArray(coords)) return;\n if (coords.length >= 2 && typeof coords[0] === \"number\" && typeof coords[1] === \"number\") {\n const [lon, lat] = coords as number[];\n bounds[0] = Math.min(bounds[0], lon);\n bounds[1] = Math.min(bounds[1], lat);\n bounds[2] = Math.max(bounds[2], lon);\n bounds[3] = Math.max(bounds[3], lat);\n return;\n }\n for (const child of coords) visit(child, bounds);\n}\n\n/** Every coordinate in a GeoJSON object, whatever its nesting. */\nfunction visitGeoJson(node: unknown, bounds: Bounds): void {\n if (!node || typeof node !== \"object\") return;\n const obj = node as { type?: string; coordinates?: unknown; geometry?: unknown; geometries?: unknown[]; features?: unknown[] };\n if (obj.coordinates !== undefined) visit(obj.coordinates, bounds);\n if (obj.geometry) visitGeoJson(obj.geometry, bounds);\n for (const g of obj.geometries ?? []) visitGeoJson(g, bounds);\n for (const f of obj.features ?? []) visitGeoJson(f, bounds);\n}\n\n/** The box around a place's shape and overlays, or null when it has\n * neither (or they hold no coordinates). */\nexport function placeBounds(place: Place | undefined): Bounds | null {\n if (!place) return null;\n const bounds: Bounds = [Infinity, Infinity, -Infinity, -Infinity];\n visitGeoJson(place.geometry, bounds);\n for (const overlay of place.overlays ?? []) visit(overlay.corners as LonLat[], bounds);\n return Number.isFinite(bounds[0]) ? bounds : null;\n}\n\n/** Where to put the pin: the place's own point, else the middle of its\n * shape and overlays. Null for a slide with no position at all. */\nexport function placeCenter(place: Place | undefined): LonLat | null {\n if (place?.lat !== undefined && place.lon !== undefined) return [place.lon, place.lat];\n const bounds = placeBounds(place);\n return bounds ? [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2] : null;\n}\n\nexport interface StoryPlaces {\n points: LonLat[];\n bounds: Bounds;\n}\n\n/** Every place in the story at once, for its opening view: one point per\n * distinct place, and the box around all of them, shapes and overlays\n * included. Null when no slide has a position. */\nexport function storyPlaces(places: (Place | undefined)[]): StoryPlaces | null {\n const bounds: Bounds = [Infinity, Infinity, -Infinity, -Infinity];\n const points = new Map<string, LonLat>();\n for (const place of places) {\n const center = placeCenter(place);\n if (!center) continue;\n points.set(`${center[0].toFixed(5)},${center[1].toFixed(5)}`, center);\n visit(center, bounds);\n const box = placeBounds(place);\n if (box) visit([[box[0], box[1]], [box[2], box[3]]], bounds);\n }\n return points.size ? { points: [...points.values()], bounds } : null;\n}\n", "// Presents a story: one slide at a time, with a full-bleed map behind the\n// slides when any of them has a place (modeled on a Knight Lab StoryMapJS\n// slide), or a plain centered card when none does, plus a timeline strip\n// when two or more slides are dated. Fills its container; the host decides\n// whether that's a fullscreen modal, a page, or a box on a blog.\nimport { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type TouchEvent } from \"react\";\nimport type { MediaItem, Slide, StoryDoc } from \"../types\";\nimport { timelineYear } from \"./dates\";\nimport { placeCenter, storyPlaces } from \"./geo\";\nimport { MapBackground, type MapSlide } from \"./MapBackground\";\nimport { MapModeControl, type MapMode, type MapModeControlProps } from \"./MapModeControl\";\nimport { parseStoryText } from \"./text\";\nimport { stringsFor, type PlayerStrings } from \"./strings\";\nimport { defaultColors, type PlayerColors } from \"./theme\";\nimport { TIMELINE_HEIGHT, TimelineStrip, type TimelinePoint } from \"./TimelineStrip\";\n\n/** How much of the width the slide panel takes over a map; the map\n * centers each point in what's left. */\nconst PANEL_FRACTION = 0.62;\nconst BAR_HEIGHT = 56;\n\nexport interface StoryPlayerProps {\n story: StoryDoc;\n /** A URL the browser can load for a media key: a blob: URL for a file\n * out of a zip, or anything else the host serves. The host owns these\n * URLs (and revoking them); the player may ask for the same key again.\n * Null when it can't be had: the slide shows without it. */\n resolveMedia: (key: string, item: MediaItem) => Promise<string | null>;\n dark?: boolean;\n colors?: Partial<PlayerColors>;\n /** The player's own words. By default, the built-in table for the\n * story's language, else the browser's, else English (strings.ts). */\n strings?: Partial<PlayerStrings>;\n /** Shows a close button that calls this. */\n onClose?: () => void;\n /** Arrow keys move between slides: true listens on the whole window (a\n * fullscreen presentation), \"focus\" only while the player has focus (one\n * of several on a page), false not at all. Default true. */\n keyboard?: boolean | \"focus\";\n /** Called with the new index whenever the slide changes. */\n onSlideChange?: (index: number) => void;\n /** Replaces the built-in map-mode control, e.g. with one from the host's\n * own UI kit. */\n renderMapModeControl?: (props: MapModeControlProps) => ReactNode;\n /** Shown before the title, e.g. ViewerBrand on a standalone page. */\n brand?: ReactNode;\n /** The host's own buttons, at the right of the title bar (before the\n * close button), e.g. the viewer site's Edit. */\n actions?: ReactNode;\n initialSlide?: number;\n}\n\n/** The story's basemap hint (spec section 6) as the control's starting mode:\n * \"historical\" -- a map of each slide's era -- is what the control calls\n * Auto; \"auto\" (viewer's choice) starts on the standard map. */\nfunction initialMapMode(story: StoryDoc): MapMode {\n return story.presentation?.basemap === \"historical\" ? \"auto\" : \"standard\";\n}\n\nfunction SlideText({ text, colors }: { text: string; colors: PlayerColors }) {\n return (\n <>\n {parseStoryText(text).map((lines, p) => (\n <p key={p} dir=\"auto\" style={{ margin: \"0 0 0.6em\", color: colors.text, lineHeight: 1.55 }}>\n {lines.map((spans, l) => (\n <span key={l}>\n {l > 0 && <br />}\n {spans.map((span, s) => {\n if (span.bold) return <b key={s}>{span.text}</b>;\n if (span.italic) return <i key={s}>{span.text}</i>;\n return <span key={s}>{span.text}</span>;\n })}\n </span>\n ))}\n </p>\n ))}\n </>\n );\n}\n\nfunction SlidePhoto({ mediaKey, item, caption, credit, resolveMedia, colors }: {\n mediaKey: string;\n item: MediaItem;\n caption?: string;\n credit?: string;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n}) {\n const [src, setSrc] = useState<string | null>(null);\n useEffect(() => {\n setSrc(null);\n let cancelled = false;\n resolveMedia(mediaKey, item).then((url) => { if (!cancelled) setSrc(url); }, () => {});\n return () => {\n cancelled = true;\n };\n }, [mediaKey, item, resolveMedia]);\n if (!src) return null;\n return (\n <figure style={{ margin: 0, display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n <img\n src={src}\n alt={item.alt ?? \"\"}\n width={item.width}\n height={item.height}\n style={{ maxHeight: \"42vh\", maxWidth: \"100%\", width: \"auto\", height: \"auto\", objectFit: \"contain\", borderRadius: 4 }}\n />\n {(caption || credit) && (\n <figcaption style={{ fontSize: 13, color: colors.muted }}>\n {[caption, credit && `\u00A9 ${credit}`].filter(Boolean).join(\" \u00B7 \")}\n </figcaption>\n )}\n </figure>\n );\n}\n\n/** A small button showing one of a slide's photos. */\nfunction PhotoThumb({ mediaKey, item, label, selected, onSelect, resolveMedia, colors }: {\n mediaKey: string;\n item: MediaItem;\n label: string;\n selected: boolean;\n onSelect: () => void;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n}) {\n const [src, setSrc] = useState<string | null>(null);\n useEffect(() => {\n let cancelled = false;\n resolveMedia(mediaKey, item).then((url) => { if (!cancelled) setSrc(url); }, () => {});\n return () => { cancelled = true; };\n }, [mediaKey, item, resolveMedia]);\n return (\n <button\n type=\"button\" aria-label={label} title={label} aria-pressed={selected} onClick={onSelect}\n style={{\n width: 44, height: 44, padding: 0, borderRadius: 4, overflow: \"hidden\", cursor: \"pointer\",\n border: `2px solid ${selected ? colors.mark : \"transparent\"}`, background: colors.border,\n opacity: selected ? 1 : 0.7,\n }}\n >\n {src && <img src={src} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </button>\n );\n}\n\nfunction SlideContent({ slide, story, resolveMedia, colors, strings }: {\n slide: Slide | undefined;\n story: StoryDoc;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n strings: PlayerStrings;\n}) {\n // Every photo whose media exists; with several, thumbnails pick which\n // one is shown. Keyed by slide in the caller, so each slide starts on\n // its first photo.\n const photos = (slide?.media ?? []).filter((m) => Object.prototype.hasOwnProperty.call(story.media, m.ref));\n const [shown, setShown] = useState(0);\n const photo = photos[Math.min(shown, photos.length - 1)];\n const eyebrow = [slide?.date?.text, slide?.place?.name].filter(Boolean).join(\" \u00B7 \");\n return (\n <>\n {photo && (\n <SlidePhoto\n mediaKey={photo.ref}\n item={story.media[photo.ref]}\n caption={photo.caption}\n credit={photo.credit}\n resolveMedia={resolveMedia}\n colors={colors}\n />\n )}\n {photos.length > 1 && (\n <div style={{ display: \"flex\", gap: 6, flexWrap: \"wrap\", justifyContent: \"center\" }}>\n {photos.map((m, i) => (\n <PhotoThumb\n key={`${i}:${m.ref}`}\n mediaKey={m.ref}\n item={story.media[m.ref]}\n label={strings.photoOf(i + 1, photos.length)}\n selected={photo === m}\n onSelect={() => setShown(i)}\n resolveMedia={resolveMedia}\n colors={colors}\n />\n ))}\n </div>\n )}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 4, alignItems: \"center\", maxWidth: 640, textAlign: \"center\" }}>\n {eyebrow && <div dir=\"auto\" style={{ fontSize: 14, color: colors.muted }}>{eyebrow}</div>}\n {slide?.title && <div dir=\"auto\" style={{ fontSize: 20, fontWeight: 700, color: colors.text }}>{slide.title}</div>}\n {slide?.text && <div><SlideText text={slide.text} colors={colors} /></div>}\n </div>\n </>\n );\n}\n\nfunction RoundButton({ label, onClick, disabled, size, children, style }: {\n label: string;\n onClick: () => void;\n disabled?: boolean;\n size: number;\n children: ReactNode;\n style?: CSSProperties;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n onClick={onClick}\n disabled={disabled}\n style={{\n width: size, height: size, borderRadius: \"50%\", border: \"none\",\n background: \"#25262b\", color: \"#ffffff\", fontSize: size >= 48 ? 22 : 18,\n cursor: disabled ? \"default\" : \"pointer\", opacity: disabled ? 0.35 : 0.8,\n display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, fontFamily: \"inherit\",\n ...style,\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction NavArrows({ index, total, onPrev, onNext, variant, strings, colors }: {\n index: number;\n total: number;\n onPrev: () => void;\n onNext: () => void;\n /** \"edge\": large buttons at the screen edges, dark so they stay legible\n * over any map. \"inline\": small buttons and an \"n / N\" counter. */\n variant: \"inline\" | \"edge\";\n strings: PlayerStrings;\n colors: PlayerColors;\n}) {\n if (variant === \"edge\") {\n const edge: CSSProperties = { position: \"absolute\", top: \"50%\", transform: \"translateY(-50%)\", zIndex: 2 };\n return (\n <>\n <RoundButton label={strings.previous} size={56} disabled={index === 0} onClick={onPrev} style={{ ...edge, left: 24 }}>\u2190</RoundButton>\n <RoundButton label={strings.next} size={56} disabled={index === total - 1} onClick={onNext} style={{ ...edge, right: 24 }}>\u2192</RoundButton>\n </>\n );\n }\n return (\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"center\", gap: 16, marginTop: 16 }}>\n <RoundButton label={strings.previous} size={34} disabled={index === 0} onClick={onPrev}>\u2190</RoundButton>\n <span style={{ fontSize: 14, color: colors.muted }}>{index + 1} / {total}</span>\n <RoundButton label={strings.next} size={34} disabled={index === total - 1} onClick={onNext}>\u2192</RoundButton>\n </div>\n );\n}\n\nexport function StoryPlayer({\n story, resolveMedia, dark = false, colors: colorOverrides, strings: stringOverrides, onClose,\n keyboard = true, onSlideChange, renderMapModeControl, brand, actions, initialSlide = 0,\n}: StoryPlayerProps) {\n const colors = useMemo(() => ({ ...defaultColors(dark), ...colorOverrides }), [dark, colorOverrides]);\n const strings = useMemo(\n () => ({\n ...stringsFor(story.language, typeof navigator === \"undefined\" ? undefined : navigator.language),\n ...stringOverrides,\n }),\n [story.language, stringOverrides],\n );\n const rootRef = useRef<HTMLDivElement>(null);\n const slides = story.slides;\n const [index, setIndex] = useState(initialSlide);\n const slide = slides[index];\n\n useEffect(() => {\n setIndex(Math.min(Math.max(initialSlide, 0), Math.max(slides.length - 1, 0)));\n }, [story, initialSlide, slides.length]);\n\n const datedSlides = useMemo(() => {\n const points: TimelinePoint[] = [];\n slides.forEach((s, i) => {\n const year = timelineYear(s.date);\n if (year !== null) points.push({ index: i, year });\n });\n return points;\n }, [slides]);\n const showTimeline = datedSlides.length >= 2;\n\n // Map modes: \"auto\" follows the current slide's year as the story moves.\n const [mapMode, setMapMode] = useState<MapMode>(() => initialMapMode(story));\n const [historicalYear, setHistoricalYear] = useState(() => new Date().getFullYear());\n const currentYear = timelineYear(slide?.date);\n const autoYear = currentYear !== null ? Math.floor(currentYear) : null;\n const yearBounds = useMemo<[number, number]>(() => {\n if (datedSlides.length === 0) {\n const thisYear = new Date().getFullYear();\n return [thisYear - 200, thisYear];\n }\n const years = datedSlides.map((d) => d.year);\n return [Math.floor(Math.min(...years)), Math.ceil(Math.max(...years))];\n }, [datedSlides]);\n // Entering Historical starts the slider on this slide's year.\n const wasHistoricalRef = useRef(false);\n useEffect(() => {\n if (mapMode === \"historical\" && !wasHistoricalRef.current) setHistoricalYear(autoYear ?? yearBounds[1]);\n wasHistoricalRef.current = mapMode === \"historical\";\n }, [mapMode, autoYear, yearBounds]);\n const ohmYear = mapMode === \"standard\" ? null : mapMode === \"auto\" ? autoYear : historicalYear;\n\n const goPrev = () => setIndex((i) => Math.max(i - 1, 0));\n const goNext = () => setIndex((i) => Math.min(i + 1, slides.length - 1));\n\n const onSlideChangeRef = useRef(onSlideChange);\n onSlideChangeRef.current = onSlideChange;\n useEffect(() => {\n onSlideChangeRef.current?.(index);\n }, [index]);\n\n useEffect(() => {\n if (!keyboard) return;\n const target: HTMLElement | Window | null = keyboard === \"focus\" ? rootRef.current : window;\n if (!target) return;\n function onKey(e: Event) {\n const key = (e as KeyboardEvent).key;\n const from = e.target as HTMLElement | null;\n // Not while typing a year into the map control.\n if (from && (from.tagName === \"INPUT\" || from.tagName === \"TEXTAREA\" || from.isContentEditable)) return;\n if (key === \"ArrowRight\") setIndex((i) => Math.min(i + 1, slides.length - 1));\n if (key === \"ArrowLeft\") setIndex((i) => Math.max(i - 1, 0));\n }\n target.addEventListener(\"keydown\", onKey);\n return () => target.removeEventListener(\"keydown\", onKey);\n }, [keyboard, slides.length]);\n\n // A horizontal swipe on the slide (not the map, which a drag pans)\n // moves between slides.\n const swipeStart = useRef<{ x: number; y: number } | null>(null);\n const swipeHandlers = {\n onTouchStart: (e: TouchEvent) => {\n const t = e.touches[0];\n swipeStart.current = e.touches.length === 1 ? { x: t.clientX, y: t.clientY } : null;\n },\n onTouchEnd: (e: TouchEvent) => {\n const start = swipeStart.current;\n swipeStart.current = null;\n const t = e.changedTouches[0];\n if (!start || !t) return;\n const dx = t.clientX - start.x;\n const dy = t.clientY - start.y;\n if (Math.abs(dx) < 50 || Math.abs(dx) < Math.abs(dy) * 1.5) return;\n if (dx < 0) goNext();\n else goPrev();\n },\n };\n\n // Stable per slide, so a re-render for an unrelated reason (a map-mode\n // click) never looks like a new slide to the map's camera.\n const places = useMemo(() => storyPlaces(slides.map((s) => s.place)), [slides]);\n const mapSlide = useMemo<MapSlide>(() => ({\n key: slide?.id ?? String(index),\n place: slide?.place,\n // The opening card, with no place of its own, shows where the story goes.\n overview: index === 0 && !placeCenter(slide?.place) ? places : null,\n }), [slide, index, places]);\n const firstCenter = useMemo(() => {\n if (story.presentation?.basemap === \"none\") return null;\n for (const s of slides) {\n const center = placeCenter(s.place);\n if (center) return center;\n }\n return null;\n }, [story, slides]);\n\n const modeControlProps: MapModeControlProps = {\n mode: mapMode, onModeChange: setMapMode, autoYear, year: historicalYear, onYearChange: setHistoricalYear, yearBounds,\n };\n const mediaResolver = useMemo(() => (key: string) => {\n const item = Object.prototype.hasOwnProperty.call(story.media, key) ? story.media[key] : undefined;\n return item ? resolveMedia(key, item) : Promise.resolve(null);\n }, [story, resolveMedia]);\n\n const content = (\n <SlideContent key={slide?.id ?? index} slide={slide} story={story} resolveMedia={resolveMedia} colors={colors} strings={strings} />\n );\n const timeline = showTimeline && (\n <TimelineStrip points={datedSlides} currentIndex={index} onSelect={setIndex} colors={colors} />\n );\n\n return (\n <div\n ref={rootRef}\n lang={story.language}\n tabIndex={keyboard === \"focus\" ? 0 : undefined}\n style={{\n position: \"relative\", width: \"100%\", height: \"100%\", overflow: \"hidden\",\n background: colors.surface, color: colors.text,\n }}\n >\n {/* Title bar: translucent, so it reads over the map too. */}\n <div\n style={{\n position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3,\n background: dark ? \"rgba(20,20,20,0.55)\" : \"rgba(255,255,255,0.55)\",\n }}\n />\n <div\n dir=\"auto\"\n style={{\n position: \"absolute\", top: 0, left: 20, height: BAR_HEIGHT, maxWidth: \"26%\", zIndex: 3,\n display: \"flex\", alignItems: \"center\", gap: 10, fontWeight: 600,\n }}\n >\n {brand && <span style={{ flex: \"none\", display: \"flex\" }}>{brand}</span>}\n <span style={{ whiteSpace: \"nowrap\", overflow: \"hidden\", textOverflow: \"ellipsis\" }}>{story.title}</span>\n </div>\n {/* Centered on the whole bar, as a toolbar for the presentation; the\n full-width wrapper lets clicks through to anything under it. */}\n {firstCenter && (\n <div\n style={{\n position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3,\n display: \"flex\", alignItems: \"center\", justifyContent: \"center\", pointerEvents: \"none\",\n }}\n >\n <div style={{ pointerEvents: \"auto\" }}>\n {renderMapModeControl\n ? renderMapModeControl(modeControlProps)\n : <MapModeControl {...modeControlProps} strings={strings} colors={colors} />}\n </div>\n </div>\n )}\n {actions && (\n <div\n style={{\n position: \"absolute\", top: 0, right: onClose ? 60 : 12, height: BAR_HEIGHT, zIndex: 3,\n display: \"flex\", alignItems: \"center\", gap: 8,\n }}\n >\n {actions}\n </div>\n )}\n {onClose && (\n <RoundButton\n label={strings.close} size={36} onClick={onClose}\n style={{ position: \"absolute\", top: 10, right: 12, zIndex: 3 }}\n >\n \u00D7\n </RoundButton>\n )}\n\n {firstCenter ? (\n <div style={{ position: \"absolute\", inset: 0 }}>\n <MapBackground\n initialCenter={firstCenter}\n current={mapSlide}\n dark={dark}\n colors={colors}\n panelFraction={PANEL_FRACTION}\n ohmYear={ohmYear}\n resolveMedia={mediaResolver}\n />\n <div\n style={{\n position: \"absolute\", top: 0, bottom: 0, right: 0, width: `${PANEL_FRACTION * 100}%`, zIndex: 1,\n padding: `${BAR_HEIGHT}px 32px ${showTimeline ? TIMELINE_HEIGHT : 32}px`, boxSizing: \"border-box\",\n display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", alignItems: \"center\", gap: 16,\n overflowY: \"auto\",\n // Transparent where the panel starts, mid-screen, and solid\n // well before the centered content, so text never sits on map.\n background: `linear-gradient(to right, transparent 0%, ${colors.panel} 22%)`,\n }}\n {...swipeHandlers}\n >\n {content}\n </div>\n <NavArrows index={index} total={slides.length} onPrev={goPrev} onNext={goNext} variant=\"edge\" strings={strings} colors={colors} />\n {timeline}\n </div>\n ) : (\n <div\n style={{\n position: \"absolute\", inset: 0, overflowY: \"auto\", boxSizing: \"border-box\",\n padding: `${BAR_HEIGHT + 16}px 24px ${showTimeline ? TIMELINE_HEIGHT + 16 : 24}px`,\n display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", gap: 16,\n }}\n {...swipeHandlers}\n >\n {content}\n <NavArrows index={index} total={slides.length} onPrev={goPrev} onNext={goNext} variant=\"inline\" strings={strings} colors={colors} />\n {timeline}\n </div>\n )}\n </div>\n );\n}\n", "// What the player needs from a story's dates: which years an EDTF value\n// covers (to show a historical map overlay only in its own era), and a\n// position on the timeline finer than a whole year when the date allows.\nimport type { StoryDate } from \"../types\";\n\nexport interface YearRange {\n /** Undefined for an open start (\"../1850\"). */\n min?: number;\n /** Undefined for an open end (\"1850/..\"). */\n max?: number;\n}\n\nconst DATE = /^(-?\\d{4})(?:-(\\d{2}|XX))?(?:-(\\d{2}|XX))?[~?%]?$/;\n\nfunction yearOf(part: string): number | null {\n const match = DATE.exec(part.trim());\n return match ? Number(match[1]) : null;\n}\n\n/** The years an EDTF date covers, or null when it can't be read (which\n * callers treat the same as having no date). Handles single dates\n * (\"1850\", \"1850-03-12\", \"1850~\"), intervals (\"1850/1860\", \"../1850\",\n * \"1850/..\") and one-of sets (\"[1850..1860]\"). */\nexport function edtfYearRange(edtf: string | undefined): YearRange | null {\n if (!edtf) return null;\n const value = edtf.trim();\n const set = /^\\[(.+)\\.\\.(.+)\\]$/.exec(value);\n if (set) {\n const min = yearOf(set[1]);\n const max = yearOf(set[2]);\n return min !== null && max !== null ? { min: Math.min(min, max), max: Math.max(min, max) } : null;\n }\n if (value.includes(\"/\")) {\n const [startText, endText] = value.split(\"/\");\n const openStart = startText === \"..\" || startText === \"\";\n const openEnd = endText === \"..\" || endText === \"\";\n const start = openStart ? undefined : yearOf(startText);\n const end = openEnd ? undefined : yearOf(endText);\n if (start === null || end === null) return null;\n if (start === undefined && end === undefined) return null;\n if (start !== undefined && end !== undefined) return { min: Math.min(start, end), max: Math.max(start, end) };\n return { min: start, max: end };\n }\n const year = yearOf(value);\n return year === null ? null : { min: year, max: year };\n}\n\n/** Whether something dated `date` belongs on a map of `year`. No date, an\n * unreadable one, or no year to compare against (a standard, non-historical\n * map) all mean visible: an undated overlay is never hidden. */\nexport function dateCoversYear(date: StoryDate | undefined, year: number | null): boolean {\n if (!date || year === null) return true;\n const range = edtfYearRange(date.edtf);\n if (!range) return true;\n if (range.min !== undefined && year < range.min) return false;\n if (range.max !== undefined && year > range.max) return false;\n return true;\n}\n\n/** A slide's position on the timeline, as a fractional year: its\n * `sortYear`, nudged within the year by the EDTF month and day when they\n * agree with it -- so two events in the same year don't land on the exact\n * same spot. Null for a slide that isn't on the timeline. */\nexport function timelineYear(date: StoryDate | undefined): number | null {\n if (!date) return null;\n const match = date.edtf ? DATE.exec(date.edtf.trim()) : null;\n const sortYear = date.sortYear ?? (match ? Number(match[1]) : undefined);\n if (sortYear === undefined) return null;\n if (!match || Number(match[1]) !== sortYear) return sortYear;\n const month = match[2] && match[2] !== \"XX\" ? Number(match[2]) : 0;\n const day = match[3] && match[3] !== \"XX\" ? Number(match[3]) : 0;\n if (!month) return sortYear;\n return sortYear + (month - 1) / 12 + (day ? (day - 1) / 365 : 0);\n}\n", "// The full-bleed map behind a located story's slides: flies to the current\n// slide's place (or frames its shape and overlays), draws that shape and\n// those overlays, and holds still -- marker dimmed -- on a slide with no\n// place. Its own small maplibre instance; the host page loads no map of\n// its own for this.\nimport { useEffect, useRef, useState } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\n// Positions the marker and styles the attribution control; without it the\n// pin sits in normal flow at the top left instead of on its coordinate.\nimport \"maplibre-gl/dist/maplibre-gl.css\";\nimport type { GeoJSONSource, Map as MapLibreMap, Marker as MapLibreMarker } from \"maplibre-gl\";\nimport type { FeatureCollection, GeoJSON } from \"geojson\";\nimport type { Overlay, Place } from \"../types\";\nimport { dateCoversYear } from \"./dates\";\nimport { placeBounds, placeCenter, type StoryPlaces } from \"./geo\";\nimport { applyOhmYear, crossfadeStyleSwap, mapStyleKey, mapStyleUrl } from \"./mapStyles\";\nimport { PIN_PATH_D, type PlayerColors } from \"./theme\";\n\nconst SHAPE_SOURCE = \"story-shape\";\nconst FILL_LAYER = \"story-shape-fill\";\nconst LINE_LAYER = \"story-shape-line\";\nconst POINT_LAYER = \"story-shape-points\";\nconst LABEL_LAYER = \"story-shape-labels\";\nconst OVERLAY_PREFIX = \"story-overlay-\";\nconst PLACES_SOURCE = \"story-places\";\nconst PLACES_LAYER = \"story-places-dots\";\n// Room around the outermost dots of the opening view, inside the part of\n// the map the slide panel leaves free.\nconst OVERVIEW_PADDING = 60;\nconst EMPTY: FeatureCollection = { type: \"FeatureCollection\", features: [] };\n\n/** The current slide, as far as the map cares. `key` is the slide id:\n * what tells \"a new slide\" from \"the same slide, re-rendered\". */\nexport interface MapSlide {\n key: string;\n place: Place | undefined;\n /** Every place in the story, on an opening slide with no place of its\n * own: framed together, a dot each, instead of the pin. */\n overview: StoryPlaces | null;\n}\n\n/** Frame the story's places for an overview; else the place's shape or\n * overlays (usually a field, a route or an old map, far tighter than a\n * town-level zoom); else fly to its point. */\nfunction moveCamera(map: MapLibreMap, slide: MapSlide, duration: number) {\n if (slide.overview) {\n const [west, south, east, north] = slide.overview.bounds;\n map.fitBounds([[west, south], [east, north]], { maxZoom: 9, padding: OVERVIEW_PADDING, duration });\n return;\n }\n const place = slide.place;\n const bounds = placeBounds(place);\n if (bounds) {\n map.fitBounds([[bounds[0], bounds[1]], [bounds[2], bounds[3]]], { maxZoom: 17, duration });\n return;\n }\n const center = placeCenter(place);\n if (center) map.flyTo({ center, zoom: 9, essential: true, duration });\n}\n\n/** The pin on the place; hidden for an overview (the dots stand in for\n * it), else held where it was, dimmed, for a slide with no place. */\nfunction placeMarker(marker: MapLibreMarker | null, slide: MapSlide) {\n if (!marker) return;\n const center = placeCenter(slide.place);\n if (center) marker.setLngLat(center);\n // Through the marker, not its element's style: maplibre rewrites that\n // from the marker's own opacity every frame.\n marker.setOpacity(slide.overview ? 0 : center ? 1 : 0.4);\n}\n\nconst placeDots = (overview: StoryPlaces | null): FeatureCollection => ({\n type: \"FeatureCollection\",\n features: (overview?.points ?? []).map((coordinates) => ({\n type: \"Feature\", properties: {}, geometry: { type: \"Point\", coordinates },\n })),\n});\n\nexport function MapBackground({ initialCenter, current, dark, colors, panelFraction, ohmYear, resolveMedia }: {\n initialCenter: [number, number];\n current: MapSlide;\n dark: boolean;\n colors: PlayerColors;\n /** How much of the right side the slide panel covers: a point is\n * centered in the remaining left part, not the whole width. */\n panelFraction: number;\n /** Non-null switches to OpenHistoricalMap filtered to this year. */\n ohmYear: number | null;\n resolveMedia: (key: string) => Promise<string | null>;\n}) {\n // A callback ref (via state), not useRef: a host that mounts the player\n // inside a modal may not have it in the DOM on the first render, and a\n // plain ref would leave the create-effect below nothing to re-run on.\n const [containerEl, setContainerEl] = useState<HTMLDivElement | null>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markerRef = useRef<MapLibreMarker | null>(null);\n // True after each \"style.load\" (initial load, and again after every\n // style swap, which wipes the layers this component adds).\n const [ready, setReady] = useState(false);\n\n const darkRef = useRef(dark);\n darkRef.current = dark;\n const ohmYearRef = useRef(ohmYear);\n ohmYearRef.current = ohmYear;\n const colorsRef = useRef(colors);\n colorsRef.current = colors;\n // overlay layer id -> its date, for re-checking visibility on a year change.\n const overlayDatesRef = useRef<Map<string, Overlay[\"date\"]>>(new Map());\n // What the map was built or last swapped with, so a re-render with the\n // same effective style never triggers a reload.\n const appliedStyleKeyRef = useRef(mapStyleKey(dark, ohmYear));\n const currentRef = useRef(current);\n currentRef.current = current;\n\n useEffect(() => {\n if (!containerEl) return;\n setReady(false);\n appliedStyleKeyRef.current = mapStyleKey(darkRef.current, ohmYearRef.current);\n const map = new maplibregl.Map({\n container: containerEl,\n style: mapStyleUrl(darkRef.current, ohmYearRef.current),\n zoom: 5,\n attributionControl: { compact: true },\n // So crossfadeStyleSwap's snapshot has the last frame in it.\n canvasContextAttributes: { preserveDrawingBuffer: true },\n });\n mapRef.current = map;\n map.on(\"style.load\", () => setReady(true));\n // Center points in the part of the map the slide panel doesn't cover.\n map.setPadding({ top: 0, bottom: 0, left: 0, right: containerEl.clientWidth * panelFraction });\n // Straight to the opening slide's place, unanimated. The camera effect\n // below ran for it before this map existed (the container arrives a\n // render late), so a story opened partway through starts there too.\n const start = currentRef.current;\n map.jumpTo({ center: placeCenter(start.place) ?? initialCenter });\n moveCamera(map, start, 0);\n map.on(\"load\", () => {\n const c = colorsRef.current;\n const el = document.createElement(\"div\");\n el.style.width = \"26px\";\n el.style.height = \"26px\";\n el.style.transition = \"opacity 300ms\";\n el.innerHTML = `<svg viewBox=\"0 0 24 24\" width=\"26\" height=\"26\">`\n + `<path d=\"${PIN_PATH_D}\" fill=\"${c.mark}\" stroke=\"${c.surface}\" stroke-width=\"1.5\" />`\n + `</svg>`;\n // The pin's tip, not its middle, sits on the coordinate.\n markerRef.current = new maplibregl.Marker({ element: el, anchor: \"bottom\" }).setLngLat(initialCenter).addTo(map);\n placeMarker(markerRef.current, currentRef.current);\n });\n return () => {\n markerRef.current?.remove();\n markerRef.current = null;\n map.remove();\n mapRef.current = null;\n };\n // initialCenter is only the first frame; moving is the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [containerEl]);\n\n useEffect(() => {\n const map = mapRef.current;\n const key = mapStyleKey(dark, ohmYear);\n if (!map || appliedStyleKeyRef.current === key) return;\n appliedStyleKeyRef.current = key;\n crossfadeStyleSwap(map, mapStyleUrl(dark, ohmYear), () => setReady(false));\n }, [dark, ohmYear]);\n\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready || ohmYear == null) return;\n applyOhmYear(map, ohmYear);\n }, [ready, ohmYear]);\n\n // The shape layers, (re-)added after every style load, under the marker.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready || map.getSource(SHAPE_SOURCE)) return;\n const c = colorsRef.current;\n map.addSource(SHAPE_SOURCE, { type: \"geojson\", data: EMPTY });\n // A feature's own `color` property (simplestyle-ish) wins over the mark color.\n const color = [\"coalesce\", [\"get\", \"color\"], c.mark] as maplibregl.ExpressionSpecification;\n map.addLayer({\n id: FILL_LAYER, type: \"fill\", source: SHAPE_SOURCE,\n filter: [\"==\", [\"geometry-type\"], \"Polygon\"],\n // And its own `opacity` (what the map editor sets on an area) over\n // a light default.\n paint: { \"fill-color\": color, \"fill-opacity\": [\"coalesce\", [\"to-number\", [\"get\", \"opacity\"], 0.25], 0.25] },\n });\n map.addLayer({\n id: LINE_LAYER, type: \"line\", source: SHAPE_SOURCE,\n filter: [\"any\", [\"==\", [\"geometry-type\"], \"Polygon\"], [\"==\", [\"geometry-type\"], \"LineString\"]],\n paint: { \"line-color\": color, \"line-width\": 2 },\n });\n map.addLayer({\n id: POINT_LAYER, type: \"circle\", source: SHAPE_SOURCE,\n // A named point is a label (next layer), drawn as text only.\n filter: [\"all\", [\"==\", [\"geometry-type\"], \"Point\"], [\"!\", [\"has\", \"name\"]]],\n paint: { \"circle-radius\": 5, \"circle-color\": color, \"circle-stroke-width\": 1, \"circle-stroke-color\": c.surface },\n });\n map.addLayer({\n id: LABEL_LAYER, type: \"symbol\", source: SHAPE_SOURCE,\n filter: [\"all\", [\"==\", [\"geometry-type\"], \"Point\"], [\"has\", \"name\"]],\n layout: {\n \"text-field\": [\"get\", \"name\"],\n \"text-size\": 12,\n \"text-font\": [\"Noto Sans Regular\"],\n \"text-anchor\": \"left\",\n \"text-offset\": [0.6, 0],\n },\n paint: {\n \"text-color\": [\"coalesce\", [\"get\", \"color\"], c.text],\n \"text-halo-color\": c.surface,\n \"text-halo-width\": 1.5,\n },\n });\n map.addSource(PLACES_SOURCE, { type: \"geojson\", data: EMPTY });\n map.addLayer({\n id: PLACES_LAYER, type: \"circle\", source: PLACES_SOURCE,\n paint: { \"circle-radius\": 6, \"circle-color\": c.mark, \"circle-stroke-width\": 2, \"circle-stroke-color\": c.surface },\n });\n }, [ready]);\n\n const place = current.place;\n\n // The current slide's shape, or the overview's dots. Re-supplied after each style load, since a\n // swap empties the source.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n const source = map.getSource(SHAPE_SOURCE) as GeoJSONSource | undefined;\n source?.setData((place?.geometry as GeoJSON | undefined) ?? EMPTY);\n const dots = map.getSource(PLACES_SOURCE) as GeoJSONSource | undefined;\n dots?.setData(placeDots(current.overview));\n }, [ready, current.key, place, current.overview]);\n\n // Camera: once per slide (see moveCamera). Keyed to the slide, not to `ready`, so a\n // map-mode switch never yanks the view back from wherever the viewer\n // has since panned.\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n placeMarker(markerRef.current, current);\n // No place and no overview: the camera stays put.\n moveCamera(map, current, 900);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [current.key]);\n\n // Image overlays: one image source + raster layer each, under the shape\n // layers, lowest `order` first so the highest ends up on top. Keyed by\n // the overlays themselves, so consecutive slides at the same place keep\n // theirs instead of reloading them.\n const overlayKey = JSON.stringify(place?.overlays ?? []);\n useEffect(() => {\n const map = mapRef.current;\n const overlays = place?.overlays ?? [];\n if (!map || !ready || overlays.length === 0) return;\n let cancelled = false;\n const added: string[] = [];\n (async () => {\n const sorted = overlays\n .map((overlay, i) => ({ overlay, i }))\n .sort((a, b) => (a.overlay.order ?? a.i) - (b.overlay.order ?? b.i));\n for (const { overlay, i } of sorted) {\n const url = await resolveMedia(overlay.media);\n if (cancelled) return;\n if (!url) continue;\n const id = `${OVERLAY_PREFIX}${i}`;\n if (map.getSource(id)) continue;\n map.addSource(id, { type: \"image\", url, coordinates: overlay.corners });\n map.addLayer({ id, type: \"raster\", source: id }, FILL_LAYER);\n map.setPaintProperty(id, \"raster-opacity\", overlay.opacity ?? 1);\n overlayDatesRef.current.set(id, overlay.date);\n map.setLayoutProperty(id, \"visibility\", dateCoversYear(overlay.date, ohmYearRef.current) ? \"visible\" : \"none\");\n added.push(id);\n }\n })();\n return () => {\n cancelled = true;\n for (const id of added) {\n overlayDatesRef.current.delete(id);\n if (map.getLayer(id)) map.removeLayer(id);\n if (map.getSource(id)) map.removeSource(id);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [overlayKey, ready]);\n\n // A new map year alone: re-check each overlay's era.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n for (const [id, date] of overlayDatesRef.current) {\n if (!map.getLayer(id)) continue;\n map.setLayoutProperty(id, \"visibility\", dateCoversYear(date, ohmYear) ? \"visible\" : \"none\");\n }\n }, [ohmYear, ready]);\n\n return <div ref={setContainerEl} style={{ position: \"absolute\", inset: 0 }} />;\n}\n", "// Basemaps for the story map: OpenFreeMap (light), CARTO Dark Matter (dark)\n// and OpenHistoricalMap (historical, filtered to a year), plus the\n// crossfade used when switching between them. Gramps Connect's own map\n// view uses these too (its visuals/mapStyles.ts re-exports them), so the\n// app and the story player can't drift into two versions of the same three\n// map modes.\nimport type { Map as MapLibreMap } from \"maplibre-gl\";\n// A CJS module with no browser global to patch onto (it only self-attaches\n// to `window.maplibregl`, which our namespace import never creates) -- the\n// named export below is what its `module.exports` branch actually produces,\n// and it's what both callers use directly rather than the `map.filterByDate`\n// method the plugin's own README shows for a script-tag install.\nimport { filterByDate } from \"@openhistoricalmap/maplibre-gl-dates\";\n\n/** The same OpenFreeMap \"liberty\" style gramps-web uses for its light\n * basemap, so the two clients' maps look like the same product in light\n * mode. Free, key-less, and hosted -- which does mean a map (unlike every\n * other view in this app) needs the network even though its *data* is\n * local. */\nexport const STYLE_LIGHT = \"https://tiles.openfreemap.org/styles/liberty\";\n/** OpenFreeMap's own \"dark\" style renders every layer, including water, in\n * the same near-zero-saturation gray (confirmed against their own demo at\n * openfreemap.org) -- there's no hue anywhere to tell land from water at a\n * glance. CARTO's Dark Matter style is the free, key-less alternative with\n * an actual (if muted) blue-gray palette -- water and major roads read as\n * distinct from background and from each other. */\nexport const STYLE_DARK = \"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json\";\n\n/** OHM's own vector style -- one cartography regardless of light/dark,\n * matching gramps-web's choice. */\nexport const OHM_STYLE = \"https://www.openhistoricalmap.org/map-styles/main/main.json\";\n\n/** The three selectable modes wherever a historical map is shown. \"auto\" and\n * \"historical\" both render OHM tiles filtered to a year -- they differ only\n * in where that year comes from (context vs. a user-dragged slider), which\n * is why both map components take a single `ohmYear: number | null` rather\n * than the mode itself: \"standard\" and an \"auto\" with nothing to derive a\n * year from look identical to the map, and are meant to. */\nexport type MapMode = \"auto\" | \"standard\" | \"historical\";\n\n/** A stable key for \"would setStyle() actually change anything\" -- swapping\n * light/dark never matters once OHM is showing (its cartography doesn't\n * have a dark variant), so a slider drag that changes `ohmYear`'s value\n * without leaving historical/auto mode must not trip a style reload. */\nexport function mapStyleKey(dark: boolean, ohmYear: number | null): string {\n return ohmYear != null ? \"ohm\" : dark ? \"dark\" : \"light\";\n}\n\nexport function mapStyleUrl(dark: boolean, ohmYear: number | null): string {\n return ohmYear != null ? OHM_STYLE : dark ? STYLE_DARK : STYLE_LIGHT;\n}\n\n/** Swaps a map's style as a true crossfade -- the old and new basemaps\n * dissolving into each other, not one fading out before the other fades in.\n * A single WebGL map can only ever show one style at a time, so this fakes\n * it: a snapshot of the *old* style (a plain `<img>`, frozen) is overlaid\n * over the live map at full opacity, the live map underneath is swapped to\n * the new style immediately and left to load, and once it's actually\n * finished drawing (`idle`, not `style.load` -- that fires before a single\n * tile of the new style has painted) the snapshot dissolves away, revealing\n * the new style continuously as it goes rather than snapping to it. This\n * also means the old map stays on screen, fully intact, for however long\n * the new style's tiles take to fetch -- no blank/loading gap either way,\n * unlike fading through transparent would give.\n *\n * Requires `preserveDrawingBuffer: true` on the map (see both callers'\n * constructors) -- without it, `toDataURL()` on the canvas can come back\n * blank depending on exactly when the browser clears the drawing buffer\n * after compositing. Falls back to an instant, unfaded swap if the snapshot\n * can't be taken at all (a tainted canvas, or a browser that disallows it) --\n * a plain setStyle() rather than no swap.\n *\n * `beforeSwap` runs at the same moment as setStyle(), so a caller's own\n * `setReady(false)` -- which gates its layer re-add effect -- flips exactly\n * when setStyle() actually discards those layers. */\nexport function crossfadeStyleSwap(map: MapLibreMap, styleUrl: string, beforeSwap: () => void, duration = 300): void {\n const container = map.getContainer();\n // The container is `position: absolute` but neither caller gives it its\n // own `z-index` -- which means it *doesn't* establish a stacking context\n // of its own, and the overlay's z-index below would then be compared not\n // just against the container's own children but against the container's\n // own siblings elsewhere on the page (StoryView.tsx's content panel,\n // MapView.tsx's PlaceCard popup, both positioned with their own z-index).\n // Found live: the overlay ended up painting over the story's content\n // panel instead of staying confined beneath it. Setting a z-index here\n // (any value; 0 keeps this box in the same paint bucket it was already\n // in) traps the overlay inside this container instead.\n if (!container.style.zIndex) container.style.zIndex = \"0\";\n let snapshotUrl: string | null = null;\n try {\n snapshotUrl = map.getCanvas().toDataURL(\"image/png\");\n } catch {\n // Tainted canvas or an unsupported browser -- no crossfade, just swap.\n }\n\n beforeSwap();\n map.setStyle(styleUrl);\n if (!snapshotUrl) return;\n\n const overlay = document.createElement(\"img\");\n overlay.src = snapshotUrl;\n overlay.alt = \"\";\n Object.assign(overlay.style, {\n position: \"absolute\", inset: \"0\", width: \"100%\", height: \"100%\",\n zIndex: \"5\", pointerEvents: \"none\", transition: `opacity ${duration}ms ease`,\n });\n container.appendChild(overlay);\n map.once(\"idle\", () => {\n // rAF, not set on the same tick as append -- a transition needs the\n // browser to have painted the starting opacity (1, the element's\n // default) at least once before a change to it will animate rather\n // than just jumping straight to the end state.\n requestAnimationFrame(() => { overlay.style.opacity = \"0\"; });\n window.setTimeout(() => overlay.remove(), duration + 50);\n });\n}\n\n/** Filters an OHM style's own vector layers to a year. A no-op on any layer\n * without a `source-layer` -- which is every layer either map component\n * adds itself (GeoJSON place markers, clusters, the story's pin) -- and\n * idempotent to call again on every year change: the plugin rewrites a\n * `let`-bound variable in place rather than re-wrapping each layer's filter,\n * so a slider drag never needs a style reload to take effect. */\nexport function applyOhmYear(map: MapLibreMap, year: number): void {\n filterByDate(map, String(Math.round(year)));\n}\n", "// The player's look, as plain values a host can override (a host app\n// passes its own theme's colors, so the story matches it). Its words are\n// in strings.ts.\n\nexport interface PlayerColors {\n /** Page and strip background. */\n surface: string;\n text: string;\n muted: string;\n border: string;\n /** The pin, timeline dots and default shape color. */\n mark: string;\n /** The slide panel's solid color, fading in over the map. */\n panel: string;\n}\n\n/** The marks' blue clears 3:1 against both surfaces. */\nexport function defaultColors(dark: boolean): PlayerColors {\n return dark\n ? { surface: \"#242424\", text: \"#c9c9c9\", muted: \"#828282\", border: \"#424242\", mark: \"#3987e5\", panel: \"rgb(20,20,20)\" }\n : { surface: \"#ffffff\", text: \"#000000\", muted: \"#868e96\", border: \"#dee2e6\", mark: \"#2a78d6\", panel: \"rgb(255,255,255)\" };\n}\n\n/** A map pin (round top, point at the bottom) in a 24x24 box with its tip\n * at (12, 24): the map marker and the current timeline dot share it, and\n * every use aligns that tip to the point it marks. */\nexport const PIN_PATH_D = \"M12 0C7.03 0 3 4.03 3 9c0 6.25 9 15 9 15s9-8.75 9-15c0-4.97-4.03-9-9-9z\";\n", "// The Auto / Standard / Historical map picker, in plain HTML. A host app\n// with its own UI kit can supply its own control instead (StoryPlayer's\n// renderMapModeControl), taking the same props.\nimport type { PlayerStrings } from \"./strings\";\nimport type { PlayerColors } from \"./theme\";\n\n/** \"standard\" is today's map; \"historical\" a map of the year the viewer\n * picks; \"auto\" a map of each slide's own year as the story moves. */\nexport type MapMode = \"auto\" | \"standard\" | \"historical\";\n\nexport interface MapModeControlProps {\n mode: MapMode;\n onModeChange: (mode: MapMode) => void;\n /** What Auto resolves to on this slide, or null with no date to use. */\n autoYear: number | null;\n /** The viewer's own pick, live while mode is \"historical\". */\n year: number;\n onYearChange: (year: number) => void;\n yearBounds: [number, number];\n}\n\nexport function MapModeControl({ mode, onModeChange, autoYear, year, onYearChange, yearBounds, strings, colors }:\n MapModeControlProps & { strings: PlayerStrings; colors: PlayerColors }) {\n const modes: [MapMode, string][] = [[\"auto\", strings.auto], [\"standard\", strings.standard], [\"historical\", strings.historical]];\n const font = { fontSize: 12, fontFamily: \"inherit\" };\n return (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, whiteSpace: \"nowrap\" }}>\n <div role=\"radiogroup\" aria-label={strings.mapMode} style={{ display: \"flex\", border: `1px solid ${colors.border}`, borderRadius: 6, overflow: \"hidden\", background: colors.surface }}>\n {modes.map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={mode === value}\n onClick={() => onModeChange(value)}\n style={{\n ...font, padding: \"4px 10px\", border: \"none\", cursor: \"pointer\",\n background: mode === value ? colors.mark : \"transparent\",\n color: mode === value ? \"#ffffff\" : colors.text,\n }}\n >\n {label}\n </button>\n ))}\n </div>\n {mode === \"auto\" && (\n <span style={{ ...font, color: colors.muted }}>\n {autoYear != null ? strings.historicalMapYear(autoYear) : strings.noDateStandardMap}\n </span>\n )}\n {mode === \"historical\" && (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <input\n type=\"range\"\n min={yearBounds[0]}\n max={yearBounds[1]}\n step={1}\n value={year}\n onChange={(e) => onYearChange(Number(e.currentTarget.value))}\n aria-label={strings.historicalYear}\n style={{ width: 150, accentColor: colors.mark }}\n />\n <input\n type=\"number\"\n min={yearBounds[0]}\n max={yearBounds[1]}\n step={1}\n value={year}\n onChange={(e) => {\n const value = Number(e.currentTarget.value);\n if (Number.isFinite(value) && e.currentTarget.value !== \"\") onYearChange(Math.round(value));\n }}\n aria-label={strings.historicalYear}\n style={{ ...font, width: 70, padding: \"3px 4px\", border: `1px solid ${colors.border}`, borderRadius: 4, background: colors.surface, color: colors.text }}\n />\n </span>\n )}\n </div>\n );\n}\n", "// Slide text markup (spec/1.0/README.md section 4): **bold**, *italic*,\n// line breaks, and blank lines between paragraphs -- nothing else. Parsed\n// into plain data rather than HTML, so a viewer can never be tricked into\n// rendering markup a story file smuggles in.\n\nexport interface TextSpan {\n text: string;\n bold?: boolean;\n italic?: boolean;\n}\n\n/** Paragraphs of lines of spans. */\nexport type ParsedText = TextSpan[][][];\n\n// Bold before italic, so a bold span's own ** pair isn't read as two empty\n// italic spans. Neither crosses a line break.\nconst MARKERS = /\\*\\*([^\\n]+?)\\*\\*|\\*([^\\n]+?)\\*/g;\n\nfunction parseLine(line: string): TextSpan[] {\n const spans: TextSpan[] = [];\n let last = 0;\n for (const match of line.matchAll(MARKERS)) {\n const index = match.index ?? 0;\n if (index > last) spans.push({ text: line.slice(last, index) });\n if (match[1] !== undefined) spans.push({ text: match[1], bold: true });\n else spans.push({ text: match[2], italic: true });\n last = index + match[0].length;\n }\n if (last < line.length) spans.push({ text: line.slice(last) });\n return spans;\n}\n\nexport function parseStoryText(text: string): ParsedText {\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(/\\n[ \\t]*\\n+/)\n .map((paragraph) => paragraph.replace(/^\\n+|\\n+$/g, \"\"))\n .filter((paragraph) => paragraph.length > 0)\n .map((paragraph) => paragraph.split(\"\\n\").map(parseLine));\n}\n", "// The player's own words -- the few on its buttons and map control, never\n// the story's -- in a handful of languages, chosen by the story's language\n// and then the browser's. A host with its own translations passes\n// StoryPlayer's `strings` instead.\n\nexport interface PlayerStrings {\n previous: string;\n next: string;\n close: string;\n mapMode: string;\n auto: string;\n standard: string;\n historical: string;\n /** The Auto mode's readout. */\n historicalMapYear: (year: number) => string;\n noDateStandardMap: string;\n historicalYear: string;\n /** A photo's thumbnail button, on a slide with several. */\n photoOf: (n: number, total: number) => string;\n}\n\nexport const ENGLISH: PlayerStrings = {\n previous: \"Previous\",\n next: \"Next\",\n close: \"Close\",\n mapMode: \"Map\",\n auto: \"Auto\",\n standard: \"Standard\",\n historical: \"Historical\",\n historicalMapYear: (year) => `Historical map, ${year}`,\n noDateStandardMap: \"No date here \u2014 standard map\",\n historicalYear: \"Historical map year\",\n photoOf: (n, total) => `Photo ${n} of ${total}`,\n};\n\nconst TABLE: Record<string, PlayerStrings> = {\n en: ENGLISH,\n de: {\n previous: \"Zur\u00FCck\",\n next: \"Weiter\",\n close: \"Schlie\u00DFen\",\n mapMode: \"Karte\",\n auto: \"Automatisch\",\n standard: \"Standard\",\n historical: \"Historisch\",\n historicalMapYear: (year) => `Historische Karte, ${year}`,\n noDateStandardMap: \"Kein Datum hier \u2014 Standardkarte\",\n historicalYear: \"Jahr der historischen Karte\",\n photoOf: (n, total) => `Foto ${n} von ${total}`,\n },\n es: {\n previous: \"Anterior\",\n next: \"Siguiente\",\n close: \"Cerrar\",\n mapMode: \"Mapa\",\n auto: \"Autom\u00E1tico\",\n standard: \"Est\u00E1ndar\",\n historical: \"Hist\u00F3rico\",\n historicalMapYear: (year) => `Mapa hist\u00F3rico, ${year}`,\n noDateStandardMap: \"Sin fecha aqu\u00ED \u2014 mapa est\u00E1ndar\",\n historicalYear: \"A\u00F1o del mapa hist\u00F3rico\",\n photoOf: (n, total) => `Foto ${n} de ${total}`,\n },\n fr: {\n previous: \"Pr\u00E9c\u00E9dent\",\n next: \"Suivant\",\n close: \"Fermer\",\n mapMode: \"Carte\",\n auto: \"Auto\",\n standard: \"Standard\",\n historical: \"Historique\",\n historicalMapYear: (year) => `Carte historique, ${year}`,\n noDateStandardMap: \"Pas de date ici \u2014 carte standard\",\n historicalYear: \"Ann\u00E9e de la carte historique\",\n photoOf: (n, total) => `Photo ${n} sur ${total}`,\n },\n nl: {\n previous: \"Vorige\",\n next: \"Volgende\",\n close: \"Sluiten\",\n mapMode: \"Kaart\",\n auto: \"Automatisch\",\n standard: \"Standaard\",\n historical: \"Historisch\",\n historicalMapYear: (year) => `Historische kaart, ${year}`,\n noDateStandardMap: \"Geen datum hier \u2014 standaardkaart\",\n historicalYear: \"Jaar van de historische kaart\",\n photoOf: (n, total) => `Foto ${n} van ${total}`,\n },\n};\n\n/** The best table for a list of BCP 47 tags, most preferred first:\n * \"de-CH\" matches \"de\"; English when nothing does. */\nexport function stringsFor(...languages: (string | undefined)[]): PlayerStrings {\n for (const tag of languages) {\n const base = tag?.toLowerCase().split(/[-_]/)[0];\n if (base && TABLE[base]) return TABLE[base];\n }\n return ENGLISH;\n}\n\n/** Languages with a built-in table. */\nexport const PLAYER_LANGUAGES = Object.keys(TABLE);\n", "// \"A line with years on it, and a dot\": where the current slide sits among\n// the story's dated slides, with click-to-jump per dot. SVG, since a story\n// has at most a few dozen dated slides and SVG rescales for free.\nimport { useEffect, useRef, useState } from \"react\";\nimport { axisTicks, storyDomain, tickLabel, xForYear } from \"./timelineLayout\";\nimport { PIN_PATH_D, type PlayerColors } from \"./theme\";\n\nexport const TIMELINE_HEIGHT = 70;\nconst MARGIN = 28;\n/** Where each pin's tip touches the axis. */\nconst AXIS_Y = 42;\nconst LABEL_Y = 62;\nconst CURRENT_SCALE = 0.95;\n\nexport interface TimelinePoint {\n index: number;\n year: number;\n}\n\nexport function TimelineStrip({ points, currentIndex, onSelect, colors }: {\n points: TimelinePoint[];\n currentIndex: number;\n onSelect: (index: number) => void;\n colors: PlayerColors;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const plotWidth = Math.max(0, width - MARGIN * 2);\n const domain = storyDomain(points.map((p) => p.year));\n const ticks = plotWidth > 0 ? axisTicks(domain, plotWidth) : [];\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"absolute\", left: 0, right: 0, bottom: 0, height: TIMELINE_HEIGHT, background: colors.surface,\n // Above the slide panel, whose fading background would otherwise\n // wash out any dot beneath it.\n zIndex: 2,\n }}\n >\n {width > 0 && (\n <svg width={width} height={TIMELINE_HEIGHT} style={{ display: \"block\", overflow: \"visible\" }}>\n <line x1={MARGIN} y1={AXIS_Y} x2={width - MARGIN} y2={AXIS_Y} stroke={colors.border} strokeWidth={1} />\n {ticks.map((tick) => (\n <text key={tick.x} x={MARGIN + tick.x} y={LABEL_Y} fontSize={15} fill={colors.muted} textAnchor=\"middle\">\n {tick.label}\n </text>\n ))}\n {points.map((point) => {\n const cx = MARGIN + xForYear(point.year, domain, plotWidth);\n const current = point.index === currentIndex;\n return current ? (\n <path\n key={point.index}\n d={PIN_PATH_D}\n transform={`translate(${cx - 12 * CURRENT_SCALE} ${AXIS_Y - 24 * CURRENT_SCALE}) scale(${CURRENT_SCALE})`}\n fill={colors.mark}\n stroke={colors.text}\n strokeWidth={1.5}\n style={{ cursor: \"pointer\" }}\n onClick={() => onSelect(point.index)}\n >\n <title>{tickLabel(point.year)}</title>\n </path>\n ) : (\n <circle\n key={point.index}\n cx={cx}\n cy={AXIS_Y}\n r={3.5}\n fill={colors.mark}\n stroke={colors.surface}\n strokeWidth={1.5}\n style={{ cursor: \"pointer\" }}\n onClick={() => onSelect(point.index)}\n >\n <title>{tickLabel(point.year)}</title>\n </circle>\n );\n })}\n </svg>\n )}\n </div>\n );\n}\n", "// Layout math for the timeline strip along the bottom of a story -- pure\n// numbers, no DOM.\n\n/** The year range the strip covers, with a little padding, so a lone dot\n * (or two dots in the same year) still sits on a real span. */\nexport function storyDomain(years: number[]): [number, number] {\n const min = Math.min(...years);\n const max = Math.max(...years);\n if (max - min < 1) return [min - 5, min + 5];\n const padding = (max - min) * 0.05;\n return [min - padding, max + padding];\n}\n\n/** Where a year lands across a `width`-px strip for `domain`. */\nexport function xForYear(year: number, domain: [number, number], width: number): number {\n const [start, end] = domain;\n const span = end - start;\n if (!(span > 0)) return width / 2;\n return ((year - start) / span) * width;\n}\n\nexport interface AxisTick {\n x: number;\n label: string;\n}\n\n/** Candidate tick spacings in years, coarse to fine. */\nconst TICK_STEPS = [1000, 500, 250, 100, 50, 25, 10, 5, 2, 1];\n/** Aim for roughly this many labelled ticks. */\nconst TARGET_TICKS = 8;\n\nexport function axisTicks(domain: [number, number], width: number): AxisTick[] {\n const [start, end] = domain;\n const span = end - start;\n if (!(span > 0) || width <= 0) return [];\n const step = TICK_STEPS.find((candidate) => span / candidate >= TARGET_TICKS) ?? 1;\n const ticks: AxisTick[] = [];\n for (let year = Math.ceil(start / step) * step; year < end; year += step) {\n ticks.push({ x: ((year - start) / span) * width, label: tickLabel(year) });\n }\n return ticks;\n}\n\n/** Negative years are BC: genealogical calendars have no year 0. */\nexport function tickLabel(year: number): string {\n const whole = Math.floor(year);\n return whole < 0 ? `${-whole} BC` : String(whole);\n}\n", "// A date as typed (\"about 1850\", \"um 1850\") to its precise form (EDTF),\n// read the way Gramps reads dates, in the story's language: the player\n// needs the precise form for the timeline and for picking historical maps.\nimport { loadLocale, parseDate, resolveLocaleCode, toEdtf } from \"@gramps-connect/gramps-date\";\n\n/** Turns date text into EDTF, or undefined when the text isn't a date\n * that has one (\"spring 1850\", a non-Gregorian date). */\nexport type DateTextParser = (text: string, language: string | undefined) => Promise<string | undefined>;\n\n/** The default parser: gramps-date in the story's language (loaded on first\n * use), English when the story has none or gramps-date doesn't know it. */\nexport const suggestEdtf: DateTextParser = async (text, language) => {\n if (!text.trim()) return undefined;\n const code = (language && resolveLocaleCode(language.replace(/-/g, \"_\"))) || \"en\";\n if (code !== \"en\" && !(await loadLocale(code))) return undefined;\n try {\n return toEdtf(parseDate(text, { locale: code }));\n } catch {\n return undefined;\n }\n};\n", "// A slide's date: the text readers see, and its precise form (EDTF), which\n// follows the text as it's typed until someone changes it by hand.\nimport { useEffect, useRef, useState } from \"react\";\nimport { Anchor, Group, Stack, Text, TextInput } from \"@mantine/core\";\nimport type { StoryDate } from \"../types\";\nimport { edtfYearRange } from \"../player/dates\";\nimport type { DateTextParser } from \"./dates\";\nimport { slideDate } from \"./model\";\nimport type { EditorStrings } from \"./strings\";\n\nexport interface DateFieldProps {\n value: StoryDate | undefined;\n language: string | undefined;\n parse: DateTextParser;\n strings: EditorStrings;\n onChange: (date: StoryDate | undefined) => void;\n}\n\n/** Keyed by slide in the parent, so `following` starts over per slide. */\nexport function DateField({ value, language, parse, strings, onChange }: DateFieldProps) {\n // Whether the precise form is worked out from the text. Unknown (null)\n // until the stored one has been compared with what the text gives.\n const [following, setFollowing] = useState<boolean | null>(value?.edtf ? null : true);\n const latest = useRef(value);\n latest.current = value;\n const request = useRef(0);\n\n useEffect(() => {\n if (following !== null) return;\n let live = true;\n void parse(value?.text ?? \"\", language).then((edtf) => {\n if (live) setFollowing(edtf === value?.edtf);\n });\n return () => { live = false; };\n // Once, for the stored date.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const follow = (text: string) => {\n const id = ++request.current;\n void parse(text, language).then((edtf) => {\n // Only the latest text's answer, and only onto the date as it is now.\n if (id !== request.current || latest.current?.text !== text) return;\n onChange(slideDate(latest.current, text, edtf));\n });\n };\n\n const onText = (text: string) => {\n onChange(slideDate(latest.current, text, latest.current?.edtf));\n if (following !== false) follow(text);\n };\n\n const edtf = value?.edtf ?? \"\";\n const understood = !edtf || edtfYearRange(edtf) !== null;\n let note: string;\n if (edtf && !understood) note = strings.preciseDateNotUnderstood;\n else if (!edtf) note = strings.noPreciseDate;\n else if (following) note = strings.preciseDateFollows;\n else note = strings.preciseDateHint;\n\n return (\n <Stack gap={6}>\n <TextInput\n label={strings.date}\n description={strings.dateHint}\n value={value?.text ?? \"\"}\n onChange={(e) => onText(e.currentTarget.value)}\n />\n {value?.text && (\n <Group gap=\"sm\" align=\"flex-end\" wrap=\"nowrap\">\n <TextInput\n label={strings.preciseDate}\n size=\"xs\"\n w={200}\n value={edtf}\n error={!understood}\n styles={{ input: { fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\" } }}\n onChange={(e) => {\n setFollowing(false);\n onChange(slideDate(latest.current, latest.current?.text ?? \"\", e.currentTarget.value.trim() || undefined));\n }}\n />\n <Stack gap={0} pb={4}>\n <Text size=\"xs\" c={understood ? \"dimmed\" : \"red\"}>{note}</Text>\n {following === false && (\n <Anchor component=\"button\" type=\"button\" size=\"xs\" onClick={() => { setFollowing(true); follow(value.text); }}>\n {strings.matchDateAsWritten}\n </Anchor>\n )}\n </Stack>\n </Group>\n )}\n </Stack>\n );\n}\n", "// The editor's changes to a story, as pure functions from one StoryDoc to\n// the next -- never mutating, so undo is just keeping the old ones. Every\n// change spreads the object it touches, so fields this version doesn't\n// know (a newer minor version's, an extension's) ride along untouched:\n// opening and saving a story must never lose anything.\nimport { FORMAT_ID, FORMAT_VERSION } from \"../version\";\nimport type { MediaItem, Place, Slide, SlideMedia, StoryDate, StoryDoc } from \"../types\";\n\n/** A story with one empty slide: the smallest valid one. */\nexport function blankStory(title: string, language?: string): StoryDoc {\n return {\n format: FORMAT_ID,\n version: FORMAT_VERSION,\n title,\n ...(language ? { language } : {}),\n slides: [{ id: \"s0\", title }],\n media: {},\n };\n}\n\n/** \"s<n>\" past every id already of that form, so it's unique however the\n * story's other ids were made. */\nexport function nextSlideId(doc: StoryDoc): string {\n let max = -1;\n for (const slide of doc.slides) {\n const match = /^s(\\d+)$/.exec(slide.id);\n if (match) max = Math.max(max, Number(match[1]));\n }\n let n = max + 1;\n const ids = new Set(doc.slides.map((s) => s.id));\n while (ids.has(`s${n}`)) n += 1;\n return `s${n}`;\n}\n\nfunction withSlides(doc: StoryDoc, slides: Slide[]): StoryDoc {\n return { ...doc, slides };\n}\n\n/** A new empty slide after `index`; returns the story and the new slide's\n * index. */\nexport function addSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n const slides = [...doc.slides];\n const at = Math.min(Math.max(index + 1, 0), slides.length);\n slides.splice(at, 0, { id: nextSlideId(doc) });\n return { doc: withSlides(doc, slides), index: at };\n}\n\n/** A copy of the slide right after it, with its own id. */\nexport function duplicateSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n const slides = [...doc.slides];\n const copy = structuredClone(slides[index]);\n copy.id = nextSlideId(doc);\n slides.splice(index + 1, 0, copy);\n return { doc: withSlides(doc, slides), index: index + 1 };\n}\n\n/** Removes a slide, unless it's the only one (a story has at least one). */\nexport function deleteSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n if (doc.slides.length <= 1) return { doc, index };\n const slides = doc.slides.filter((_, i) => i !== index);\n return { doc: withSlides(doc, slides), index: Math.min(index, slides.length - 1) };\n}\n\nexport function moveSlide(doc: StoryDoc, from: number, to: number): StoryDoc {\n if (from === to || to < 0 || to >= doc.slides.length) return doc;\n const slides = [...doc.slides];\n const [slide] = slides.splice(from, 1);\n slides.splice(to, 0, slide);\n return withSlides(doc, slides);\n}\n\n/** Sets fields on an object; an undefined value removes the field, so\n * cleared text doesn't linger as \"\". */\nfunction patched<T extends object>(base: T, patch: Partial<T>): T {\n const next = { ...base } as Record<string, unknown>;\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) delete next[key];\n else next[key] = value;\n }\n return next as T;\n}\n\nexport function updateSlide(doc: StoryDoc, index: number, patch: Partial<Slide>): StoryDoc {\n const slides = [...doc.slides];\n slides[index] = patched(slides[index], patch);\n return withSlides(doc, slides);\n}\n\nexport function updateStory(doc: StoryDoc, patch: Partial<Omit<StoryDoc, \"slides\" | \"media\">>): StoryDoc {\n return patched(doc, patch as Partial<StoryDoc>);\n}\n\n/** A slide date from what was typed and its precise form. Empty text is no\n * date at all. A new precise form drops a `sortYear` it would contradict\n * (the timeline reads sortYear first); the date's other fields stay. */\nexport function slideDate(previous: StoryDate | undefined, text: string, edtf: string | undefined): StoryDate | undefined {\n if (!text.trim()) return undefined;\n const next = patched(previous ?? { text }, { text, edtf: edtf || undefined });\n if (next.edtf !== previous?.edtf) delete next.sortYear;\n return next;\n}\n\n/** A place with some fields set or (undefined) removed; one left with\n * nothing in it is no place at all. Its shape and overlays, and any field\n * this version doesn't know, stay as they were. */\nexport function patchPlace(place: Place | undefined, patch: Partial<Place>): Place | undefined {\n if (place && Object.entries(patch).every(([key, value]) => place[key as keyof Place] === value)) return place;\n const next = patched(place ?? {}, patch);\n return Object.keys(next).length ? next : undefined;\n}\n\n/** Degrees to 5 decimals: about a metre, and no float noise. */\nexport const roundDegrees = (value: number) => Math.round(value * 1e5) / 1e5;\n\n/** \"47.3769, 8.5417\" (or with a space or semicolon between) -> a point;\n * null when that's not two numbers in range. */\nexport function parseLatLon(text: string): { lat: number; lon: number } | null {\n const parts = text.trim().split(/\\s*[,;\\s]\\s*/);\n if (parts.length !== 2 || parts.some((p) => !/^[-+]?(\\d+\\.?\\d*|\\.\\d+)$/.test(p))) return null;\n const [lat, lon] = parts.map(Number);\n if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return null;\n return { lat, lon };\n}\n\nexport function formatLatLon(lat: number, lon: number): string {\n return `${roundDegrees(lat)}, ${roundDegrees(lon)}`;\n}\n\n/** The places of the story's other slides, one per name (the first slide\n * to use it), for giving another slide the very same place. */\nexport function storyPlaceChoices(doc: StoryDoc, exceptIndex?: number): Place[] {\n const byName = new Map<string, Place>();\n doc.slides.forEach((slide, i) => {\n const name = slide.place?.name?.trim();\n if (i !== exceptIndex && name && !byName.has(name)) byName.set(name, slide.place!);\n });\n return [...byName.values()];\n}\n\n/** A prepared image to add to a story (see optimizeImage). */\nexport interface NewImage {\n data: Uint8Array;\n mime: string;\n /** File extension, without the dot. */\n ext: string;\n width?: number;\n height?: number;\n}\n\nfunction sameBytes(a: Uint8Array | undefined, b: Uint8Array): boolean {\n if (!a || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** The media key whose file is exactly these bytes, if any: a photo\n * that's already in the story, chosen again. */\nexport function findMedia(doc: StoryDoc, files: Map<string, Uint8Array>, data: Uint8Array): string | undefined {\n for (const [key, item] of Object.entries(doc.media)) {\n if (sameBytes(files.get(item.src), data)) return key;\n }\n return undefined;\n}\n\n/** Adds an image to the story's media (not to any slide), or finds the\n * identical one already there, so the same photo is stored once. Returns\n * its media key. */\nexport function addImage(\n doc: StoryDoc, files: Map<string, Uint8Array>, image: NewImage, stem = \"photo\",\n): { doc: StoryDoc; files: Map<string, Uint8Array>; key: string } {\n const existing = findMedia(doc, files, image.data);\n if (existing) return { doc, files, key: existing };\n let n = 1;\n const taken = (key: string) => Object.prototype.hasOwnProperty.call(doc.media, key) || files.has(`media/${key}.${image.ext}`);\n while (taken(`${stem}-${n}`)) n += 1;\n const key = `${stem}-${n}`;\n const src = `media/${key}.${image.ext}`;\n const item: MediaItem = {\n src, mime: image.mime,\n ...(image.width ? { width: image.width } : {}),\n ...(image.height ? { height: image.height } : {}),\n };\n return {\n doc: { ...doc, media: { ...doc.media, [key]: item } },\n files: new Map(files).set(src, image.data),\n key,\n };\n}\n\n/** A slide's photo list; an empty one removes the field. */\nexport function setSlidePhotos(doc: StoryDoc, index: number, media: SlideMedia[]): StoryDoc {\n return updateSlide(doc, index, { media: media.length ? media : undefined });\n}\n\n/** Changes a media item itself (its description, shared by every slide\n * that shows it). */\nexport function updateMedia(doc: StoryDoc, key: string, patch: Partial<MediaItem>): StoryDoc {\n if (!Object.prototype.hasOwnProperty.call(doc.media, key)) return doc;\n return { ...doc, media: { ...doc.media, [key]: patched(doc.media[key], patch) } };\n}\n\n/** Every media key a slide or overlay refers to. */\nexport function usedMedia(doc: StoryDoc): Set<string> {\n const used = new Set<string>();\n for (const slide of doc.slides) {\n for (const m of slide.media ?? []) used.add(m.ref);\n for (const o of slide.place?.overlays ?? []) used.add(o.media);\n }\n return used;\n}\n\n/** The story as it should be saved: media nothing refers to any more left\n * out, and the files only those that are still used. */\nexport function pruneMedia(doc: StoryDoc, files: Map<string, Uint8Array>): { doc: StoryDoc; files: Map<string, Uint8Array> } {\n const used = usedMedia(doc);\n const media = Object.fromEntries(Object.entries(doc.media).filter(([key]) => used.has(key)));\n const srcs = new Set(Object.values(media).map((m) => m.src));\n return {\n doc: { ...doc, media },\n files: new Map([...files].filter(([path]) => srcs.has(path))),\n };\n}\n\n/** \"Josef Meyer\" -> \"Josef Meyer.story.zip\", minus characters some file\n * systems refuse. */\nexport function storyFileName(title: string): string {\n const safe = title.replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]+/g, \" \").replace(/\\s+/g, \" \").trim().slice(0, 120);\n return `${safe || \"story\"}.story.zip`;\n}\n\n/** Undo and redo over whole documents (a StoryDoc here; any value that's\n * replaced, never changed in place, works). Typing in one field makes one\n * step, not one per keystroke: a change with the same `key` within\n * COALESCE_MS of the last replaces it. */\nexport interface History<T = StoryDoc> {\n past: T[];\n present: T;\n future: T[];\n lastKey?: string;\n lastAt?: number;\n}\n\nexport const COALESCE_MS = 1500;\nconst MAX_STEPS = 200;\n\nexport function startHistory<T = StoryDoc>(doc: T): History<T> {\n return { past: [], present: doc, future: [] };\n}\n\nexport function record<T>(history: History<T>, next: T, key?: string, now = Date.now()): History<T> {\n if (next === history.present) return history;\n const coalesce = key !== undefined && key === history.lastKey && history.lastAt !== undefined && now - history.lastAt < COALESCE_MS;\n const past = coalesce ? history.past : [...history.past, history.present].slice(-MAX_STEPS);\n return { past, present: next, future: [], lastKey: key, lastAt: now };\n}\n\nexport function undo<T>(history: History<T>): History<T> {\n const previous = history.past[history.past.length - 1];\n if (!previous) return history;\n return { past: history.past.slice(0, -1), present: previous, future: [history.present, ...history.future] };\n}\n\nexport function redo<T>(history: History<T>): History<T> {\n const [next, ...future] = history.future;\n if (!next) return history;\n return { past: [...history.past, history.present], present: next, future };\n}\n", "// A slide's photos: add (pick, drop or paste -- pasting is the editor's),\n// replace, reorder and remove them, and write each one's caption, credit\n// and description. The files themselves are the editor's to prepare and\n// store; this only says what was chosen.\nimport { useEffect, useRef, useState, type DragEvent } from \"react\";\nimport { ActionIcon, Box, Button, Group, Loader, Stack, Text, TextInput, Tooltip } from \"@mantine/core\";\nimport type { MediaItem, SlideMedia } from \"../types\";\nimport type { EditorStrings } from \"./strings\";\n\nexport interface PhotosFieldProps {\n photos: SlideMedia[];\n media: Record<string, MediaItem>;\n /** A displayable URL for a media key. */\n urlFor: (key: string) => Promise<string | null>;\n strings: EditorStrings;\n /** True while chosen files are being prepared. */\n busy?: boolean;\n onChange: (photos: SlideMedia[], key: string) => void;\n /** Image files to add at the end, or to put in place of photo `replace`. */\n onFiles: (files: File[], replace?: number) => void;\n onDescription: (mediaKey: string, alt: string) => void;\n}\n\nconst imagesIn = (list: FileList | null | undefined) => [...(list ?? [])].filter((f) => f.type.startsWith(\"image/\"));\n\nfunction Preview({ mediaKey, urlFor }: { mediaKey: string; urlFor: PhotosFieldProps[\"urlFor\"] }) {\n const [url, setUrl] = useState<string | null>(null);\n useEffect(() => {\n let live = true;\n void urlFor(mediaKey).then((u) => { if (live) setUrl(u); });\n return () => { live = false; };\n }, [mediaKey, urlFor]);\n return (\n <Box w={96} h={96} style={{ flex: \"none\", borderRadius: 6, overflow: \"hidden\", background: \"var(--mantine-color-default-hover)\" }}>\n {url && <img src={url} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </Box>\n );\n}\n\nexport function PhotosField({ photos, media, urlFor, strings, busy, onChange, onFiles, onDescription }: PhotosFieldProps) {\n const input = useRef<HTMLInputElement>(null);\n const replacing = useRef<number | undefined>(undefined);\n const [dropping, setDropping] = useState(false);\n\n const pick = (replace?: number) => {\n replacing.current = replace;\n input.current?.click();\n };\n const set = (i: number, patch: Partial<SlideMedia>, field: string) => {\n const next = photos.map((p, j) => {\n if (j !== i) return p;\n const changed: Record<string, unknown> = { ...p, ...patch };\n for (const [k, v] of Object.entries(patch)) if (!v) delete changed[k];\n return changed as unknown as SlideMedia;\n });\n onChange(next, `photo:${i}:${field}`);\n };\n const move = (from: number, to: number) => {\n const next = [...photos];\n const [p] = next.splice(from, 1);\n next.splice(to, 0, p);\n onChange(next, \"photos\");\n };\n const onDrop = (e: DragEvent) => {\n e.preventDefault();\n setDropping(false);\n const files = imagesIn(e.dataTransfer.files);\n if (files.length) onFiles(files);\n };\n\n return (\n <Stack\n gap=\"sm\"\n onDragOver={(e) => { if ([...e.dataTransfer.types].includes(\"Files\")) { e.preventDefault(); setDropping(true); } }}\n onDragLeave={(e) => { if (e.currentTarget === e.target) setDropping(false); }}\n onDrop={onDrop}\n style={{\n borderRadius: 8, padding: dropping ? 8 : 0, margin: dropping ? -8 : 0,\n outline: dropping ? \"2px dashed var(--mantine-primary-color-filled)\" : undefined,\n }}\n >\n <Group justify=\"space-between\">\n <Text size=\"sm\" fw={500}>{strings.photos}</Text>\n <Group gap=\"xs\">\n {busy && <Loader size=\"xs\" />}\n <Button variant=\"default\" size=\"xs\" onClick={() => pick()} disabled={busy}>+ {strings.addPhoto}</Button>\n </Group>\n </Group>\n <input\n ref={input} type=\"file\" accept=\"image/*\" multiple hidden\n onChange={(e) => {\n const files = imagesIn(e.currentTarget.files);\n e.currentTarget.value = \"\";\n if (files.length) onFiles(replacing.current === undefined ? files : files.slice(0, 1), replacing.current);\n }}\n />\n {photos.length === 0 && <Text size=\"xs\" c=\"dimmed\">{strings.photosHint}</Text>}\n {photos.map((photo, i) => {\n const item = Object.prototype.hasOwnProperty.call(media, photo.ref) ? media[photo.ref] : undefined;\n return (\n <Group key={i} gap=\"sm\" align=\"flex-start\" wrap=\"nowrap\">\n <Stack gap={4} align=\"center\">\n <Preview mediaKey={photo.ref} urlFor={urlFor} />\n <Group gap={4}>\n <Tooltip label={strings.movePhotoUp}>\n <ActionIcon size=\"sm\" variant=\"default\" aria-label={strings.movePhotoUp} disabled={i === 0} onClick={() => move(i, i - 1)}>\u2191</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.movePhotoDown}>\n <ActionIcon size=\"sm\" variant=\"default\" aria-label={strings.movePhotoDown} disabled={i === photos.length - 1} onClick={() => move(i, i + 1)}>\u2193</ActionIcon>\n </Tooltip>\n </Group>\n </Stack>\n <Stack gap={6} style={{ flex: 1, minWidth: 0 }}>\n <TextInput size=\"xs\" label={strings.caption} value={photo.caption ?? \"\"} onChange={(e) => set(i, { caption: e.currentTarget.value }, \"caption\")} />\n <TextInput size=\"xs\" label={strings.credit} placeholder={strings.creditHint} value={photo.credit ?? \"\"} onChange={(e) => set(i, { credit: e.currentTarget.value }, \"credit\")} />\n {item && (\n <TextInput\n size=\"xs\" label={strings.description} description={strings.descriptionHint} value={item.alt ?? \"\"}\n onChange={(e) => onDescription(photo.ref, e.currentTarget.value)}\n />\n )}\n <Group gap=\"xs\">\n <Button variant=\"subtle\" size=\"compact-xs\" onClick={() => pick(i)} disabled={busy}>{strings.replacePhoto}</Button>\n <Button variant=\"subtle\" size=\"compact-xs\" color=\"red\" onClick={() => onChange(photos.filter((_, j) => j !== i), \"photos\")}>\n {strings.removePhoto}\n </Button>\n </Group>\n </Stack>\n </Group>\n );\n })}\n </Stack>\n );\n}\n", "// A slide's place: a name and a point. The point comes from clicking the\n// map, dragging the pin, typing coordinates, or a search by name (opt-in:\n// the one thing the editor sends anywhere). Picking one of the story's\n// other places gives this slide the very same place, overlays and all.\n// A place's shapes and old maps are edited full screen (onEditMap), and\n// always kept.\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Autocomplete, Button, Group, Loader, Stack, Text, TextInput, Tooltip, UnstyledButton } from \"@mantine/core\";\nimport type { Place } from \"../types\";\nimport type { Bounds } from \"../player/geo\";\nimport { formatLatLon, parseLatLon, patchPlace, roundDegrees } from \"./model\";\nimport { PlaceMap } from \"./PlaceMap\";\nimport type { PlaceSearch, PlaceSearchResult } from \"./placeSearch\";\nimport type { EditorStrings } from \"./strings\";\n\nexport type PlaceUpdate = (place: Place | undefined) => Place | undefined;\n\nexport interface PlaceFieldProps {\n place: Place | undefined;\n /** The story's other places, to reuse. */\n choices: Place[];\n /** Where the map looks while this place has no point. */\n around?: Bounds | null;\n /** The story's language: search results are named in it. */\n language?: string;\n /** Null hides the search. */\n search: PlaceSearch | null;\n dark?: boolean;\n strings: EditorStrings;\n /** A change, as a function of the place as it is by then. */\n onChange: (update: PlaceUpdate, key: string) => void;\n /** Opens the shapes-and-old-maps editor; without it, those are only\n * kept. */\n onEditMap?: () => void;\n}\n\ntype Found =\n | { state: \"idle\" }\n | { state: \"searching\" }\n | { state: \"results\"; results: PlaceSearchResult[] }\n | { state: \"message\"; message: string };\n\nexport function PlaceField({ place, choices, around, language, search, dark, strings, onChange, onEditMap }: PlaceFieldProps) {\n const lat = place?.lat;\n const lon = place?.lon;\n const point = lat !== undefined && lon !== undefined ? ([lon, lat] as [number, number]) : null;\n const name = place?.name ?? \"\";\n\n // The coordinates as typed, until they're a point; then as the point is.\n const [coords, setCoords] = useState(point ? formatLatLon(point[1], point[0]) : \"\");\n useEffect(() => {\n setCoords((typed) => {\n const parsed = parseLatLon(typed);\n if (lat === undefined || lon === undefined) return parsed ? \"\" : typed;\n return parsed && parsed.lat === lat && parsed.lon === lon ? typed : formatLatLon(lat, lon);\n });\n }, [lat, lon]);\n const coordsInvalid = coords.trim() !== \"\" && !parseLatLon(coords);\n\n const [found, setFound] = useState<Found>({ state: \"idle\" });\n const searching = useRef<AbortController | null>(null);\n useEffect(() => () => searching.current?.abort(), []);\n const find = async () => {\n if (!search || !name.trim()) return;\n searching.current?.abort();\n const controller = new AbortController();\n searching.current = controller;\n setFound({ state: \"searching\" });\n try {\n const results = await search.search(name.trim(), language, controller.signal);\n setFound(results.length ? { state: \"results\", results } : { state: \"message\", message: strings.findPlaceNone });\n } catch {\n if (!controller.signal.aborted) setFound({ state: \"message\", message: strings.findPlaceFailed });\n }\n };\n const choose = async (result: PlaceSearchResult) => {\n if (!search) return;\n searching.current?.abort();\n const controller = new AbortController();\n searching.current = controller;\n setFound({ state: \"searching\" });\n try {\n const at = await search.point(result, controller.signal);\n if (!at) {\n setFound({ state: \"message\", message: strings.findPlaceNoPoint(result.label) });\n return;\n }\n setFound({ state: \"idle\" });\n onChange((p) => patchPlace(p, { name: result.label, lat: roundDegrees(at.lat), lon: roundDegrees(at.lon) }), \"place\");\n } catch {\n if (!controller.signal.aborted) setFound({ state: \"message\", message: strings.findPlaceFailed });\n }\n };\n\n const byName = useMemo(() => new Map(choices.map((c) => [c.name!.trim(), c])), [choices]);\n const keeps = [\n place?.geometry ? strings.placeShape : null,\n place?.overlays?.length ? strings.placeOverlays(place.overlays.length) : null,\n ].filter(Boolean);\n\n return (\n <Stack gap=\"xs\">\n <Group justify=\"space-between\">\n <Text size=\"sm\" fw={500}>{strings.place}</Text>\n {place && (\n <Button variant=\"subtle\" size=\"compact-xs\" color=\"red\" onClick={() => { setFound({ state: \"idle\" }); onChange(() => undefined, \"place\"); }}>\n {strings.removePlace}\n </Button>\n )}\n </Group>\n <Group gap=\"xs\" align=\"flex-end\" wrap=\"nowrap\">\n <Autocomplete\n size=\"xs\" label={strings.placeName} style={{ flex: 1 }} value={name}\n data={[...byName.keys()]}\n comboboxProps={{ withinPortal: true }}\n onChange={(value) => onChange((p) => patchPlace(p, { name: value || undefined }), \"place:name\")}\n onOptionSubmit={(value) => {\n const chosen = byName.get(value);\n if (chosen) onChange(() => structuredClone(chosen), \"place\");\n }}\n />\n {search && (\n <Tooltip label={strings.findPlaceHint} multiline w={260}>\n <Button variant=\"default\" size=\"xs\" disabled={!name.trim() || found.state === \"searching\"} onClick={() => void find()}>\n {strings.findPlace}\n </Button>\n </Tooltip>\n )}\n </Group>\n {found.state === \"searching\" && <Loader size=\"xs\" />}\n {found.state === \"message\" && <Text size=\"xs\" c=\"dimmed\" role=\"status\">{found.message}</Text>}\n {found.state === \"results\" && (\n <Stack gap={2} role=\"list\" aria-label={strings.findPlace}>\n {found.results.map((result) => (\n <UnstyledButton\n key={result.id} role=\"listitem\" onClick={() => void choose(result)}\n style={{ padding: \"4px 8px\", borderRadius: 4, border: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Text size=\"sm\">{result.label}</Text>\n {result.description && <Text size=\"xs\" c=\"dimmed\">{result.description}</Text>}\n </UnstyledButton>\n ))}\n </Stack>\n )}\n <TextInput\n size=\"xs\" label={strings.coordinates} placeholder={strings.coordinatesHint} w={260} value={coords}\n error={coordsInvalid ? strings.coordinatesInvalid : undefined}\n onChange={(e) => {\n const text = e.currentTarget.value;\n setCoords(text);\n const parsed = parseLatLon(text);\n if (!text.trim()) onChange((p) => patchPlace(p, { lat: undefined, lon: undefined }), \"place:point\");\n else if (parsed) onChange((p) => patchPlace(p, parsed), \"place:point\");\n }}\n />\n <PlaceMap\n point={point} around={around} dark={dark} label={strings.placeMap}\n onPick={([pickedLon, pickedLat]) => onChange((p) => patchPlace(p, { lat: pickedLat, lon: pickedLon }), \"place:point\")}\n />\n <Text size=\"xs\" c=\"dimmed\">{strings.placeMapHint}</Text>\n {keeps.length > 0 && <Text size=\"xs\" c=\"dimmed\">{strings.placeKeeps(keeps.join(\", \"))}</Text>}\n {onEditMap && (\n <Group gap=\"sm\" wrap=\"nowrap\" align=\"center\">\n <Button variant=\"default\" size=\"xs\" style={{ flex: \"none\" }} onClick={onEditMap}>{strings.editMap}</Button>\n <Text size=\"xs\" c=\"dimmed\">{strings.editMapHint}</Text>\n </Group>\n )}\n </Stack>\n );\n}\n", "// A small map for setting a place's point: click to put the pin there,\n// drag the pin to move it. It starts at the point, or (with none yet) at\n// the story's other places, or the whole world.\nimport { useEffect, useRef } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from \"maplibre-gl\";\nimport type { LonLat } from \"../types\";\nimport type { Bounds } from \"../player/geo\";\nimport { mapStyleUrl } from \"../player/mapStyles\";\nimport { defaultColors, PIN_PATH_D } from \"../player/theme\";\nimport { roundDegrees } from \"./model\";\n\nexport interface PlaceMapProps {\n point: LonLat | null;\n /** Where to look when there's no point yet. */\n around?: Bounds | null;\n dark?: boolean;\n label: string;\n onPick: (point: LonLat) => void;\n}\n\nexport function PlaceMap({ point, around, dark = false, label, onPick }: PlaceMapProps) {\n const container = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markerRef = useRef<MapLibreMarker | null>(null);\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const pick = (lngLat: { lng: number; lat: number }) => onPickRef.current([roundDegrees(lngLat.lng), roundDegrees(lngLat.lat)]);\n // The first point and surroundings only: moving is the effect below.\n const start = useRef({ point, around });\n\n useEffect(() => {\n if (!container.current) return;\n const { point: first, around: box } = start.current;\n const map = new maplibregl.Map({\n container: container.current,\n style: mapStyleUrl(dark, null),\n ...(first ? { center: first, zoom: 9 } : box ? { bounds: box, fitBoundsOptions: { padding: 30, maxZoom: 9 } } : { center: [10, 30], zoom: 0.5 }),\n attributionControl: { compact: true },\n // Scrolling the form past the map shouldn't zoom it.\n cooperativeGestures: true,\n });\n map.addControl(new maplibregl.NavigationControl({ showCompass: false }), \"top-right\");\n map.getCanvas().style.cursor = \"crosshair\";\n map.on(\"click\", (e) => pick(e.lngLat));\n mapRef.current = map;\n return () => {\n markerRef.current?.remove();\n markerRef.current = null;\n map.remove();\n mapRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dark]);\n\n // The pin follows the point, however it changed; the view follows only\n // when the pin would be out of sight.\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n if (!point) {\n markerRef.current?.remove();\n markerRef.current = null;\n return;\n }\n if (!markerRef.current) {\n const el = document.createElement(\"div\");\n const c = defaultColors(dark);\n el.innerHTML = `<svg viewBox=\"0 0 24 24\" width=\"28\" height=\"28\" style=\"display:block;cursor:grab\">`\n + `<path d=\"${PIN_PATH_D}\" fill=\"${c.mark}\" stroke=\"${c.surface}\" stroke-width=\"1.5\" /></svg>`;\n const marker = new maplibregl.Marker({ element: el, anchor: \"bottom\", draggable: true }).setLngLat(point).addTo(map);\n marker.on(\"dragend\", () => pick(marker.getLngLat()));\n markerRef.current = marker;\n } else {\n markerRef.current.setLngLat(point);\n }\n if (!map.getBounds().contains(point)) map.easeTo({ center: point, zoom: Math.max(map.getZoom(), 8) });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [point?.[0], point?.[1], dark]);\n\n return (\n <div\n ref={container} role=\"application\" aria-label={label}\n style={{ height: 240, borderRadius: 6, overflow: \"hidden\", border: \"1px solid var(--mantine-color-default-border)\" }}\n />\n );\n}\n", "// A slide's map, full screen: the shapes under its pin (drawn, or imported\n// from a KML, GPX or GeoJSON file) and scanned old maps laid over it, each\n// with the years it shows. Works on a copy: Done hands the editor the\n// place and any images added, as one change; Cancel drops them.\nimport { useMemo, useRef, useState } from \"react\";\nimport { ActionIcon, Box, Button, Group, Modal, Stack, Text, TextInput, Tooltip } from \"@mantine/core\";\nimport type { MediaItem, Place, StoryDate, StoryDoc } from \"../types\";\nimport { optimizeImage } from \"../image\";\nimport { parseMapFile } from \"../mapEdit\";\nimport { storyPlaces } from \"../player/geo\";\nimport { edtfYearRange } from \"../player/dates\";\nimport type { DateTextParser } from \"./dates\";\nimport { MapEditor, MapEditorHelp, type MapEditorHandle } from \"./MapEditor\";\nimport type { MapEditorStrings } from \"./mapEditorStrings\";\nimport { addImage, slideDate, type NewImage } from \"./model\";\nimport { editorToPlace, placeToEditor } from \"./placeShapes\";\nimport type { EditorStrings } from \"./strings\";\n\nconst BAR_HEIGHT = 56;\n\n/** Where the map editor's English is Gramps Connect's (images come from\n * its media there), the story editor's own. */\nconst STORY_MAP_WORDS: Partial<MapEditorStrings> = {\n helpImage: \"Image: add a picture file, such as a scan of an old map -- see\",\n};\n\nexport interface PlaceMapDialogProps {\n place: Place | undefined;\n doc: StoryDoc;\n files: Map<string, Uint8Array>;\n dark?: boolean;\n parseDateText: DateTextParser;\n strings: EditorStrings;\n mapStrings?: Partial<MapEditorStrings>;\n onCancel: () => void;\n /** The place as edited, and the story's media and files with any images\n * added here. */\n onDone: (place: Place | undefined, media: Record<string, MediaItem>, files: Map<string, Uint8Array>) => void;\n}\n\n/** The default way an old map's scan is stored: 2048px, PNG when it has\n * transparency (see optimizeImage's \"overlay\" purpose). */\nasync function prepareOverlay(file: Blob): Promise<NewImage> {\n const image = await optimizeImage(file, { purpose: \"overlay\" });\n return { data: new Uint8Array(await image.blob.arrayBuffer()), mime: image.mime, ext: image.ext, width: image.width, height: image.height };\n}\n\n/** An overlay's years, as readers would write them; the precise form\n * follows. Narrow, for the map editor's side panel. */\nfunction OverlayDateField({ value, language, parse, strings, onChange }: {\n value: StoryDate | undefined;\n language: string | undefined;\n parse: DateTextParser;\n strings: EditorStrings;\n onChange: (date: StoryDate | undefined) => void;\n}) {\n const [text, setText] = useState(value?.text ?? \"\");\n const request = useRef(0);\n const edtf = value?.edtf;\n return (\n <Stack gap={2} maw={220}>\n <TextInput\n size=\"xs\" label={strings.overlayDate} description={strings.overlayDateHint} value={text}\n onChange={(e) => {\n const typed = e.currentTarget.value;\n setText(typed);\n const id = ++request.current;\n if (!typed.trim()) { onChange(undefined); return; }\n void parse(typed, language).then((parsed) => {\n if (id === request.current) onChange(slideDate(value, typed, parsed));\n });\n }}\n />\n {text.trim() && (\n <Text size=\"xs\" c={edtf && edtfYearRange(edtf) ? \"dimmed\" : \"red\"}>\n {edtf && edtfYearRange(edtf) ? `EDTF ${edtf}` : strings.preciseDateNotUnderstood}\n </Text>\n )}\n </Stack>\n );\n}\n\nexport function PlaceMapDialog({\n place, doc, files, dark, parseDateText, strings, mapStrings: mapStringOverrides, onCancel, onDone,\n}: PlaceMapDialogProps) {\n const mapStrings = { ...STORY_MAP_WORDS, ...mapStringOverrides };\n const editorRef = useRef<MapEditorHandle>(null);\n const initial = useMemo(() => placeToEditor(place), [place]);\n // The story's media and files with what's been added here.\n const [work, setWork] = useState({ doc, files });\n const workRef = useRef(work);\n workRef.current = work;\n // Each overlay's date by media key, once changed here.\n const [dates, setDates] = useState(() => new Map<string, StoryDate | undefined>());\n const [message, setMessage] = useState<string | null>(null);\n const [helpOpen, setHelpOpen] = useState(false);\n const imageInput = useRef<HTMLInputElement>(null);\n const shapesInput = useRef<HTMLInputElement>(null);\n\n // Where to look with nothing to frame: the pin, or the story's places.\n const initialView = useMemo(() => {\n if (place?.lat !== undefined && place.lon !== undefined) return { center: [place.lon, place.lat] as [number, number], zoom: 12 };\n const all = storyPlaces(doc.slides.map((s) => s.place));\n if (!all) return undefined;\n const [w, s, e, n] = all.bounds;\n return { center: [(w + e) / 2, (s + n) / 2] as [number, number], zoom: 5 };\n }, [place, doc]);\n\n const resolveImage = async (key: string) => {\n const item = Object.prototype.hasOwnProperty.call(workRef.current.doc.media, key) ? workRef.current.doc.media[key] : undefined;\n const data = item && workRef.current.files.get(item.src);\n if (!item || !data) throw new Error(strings.photoFailed(key));\n return URL.createObjectURL(new Blob([data as Uint8Array<ArrayBuffer>], { type: item.mime }));\n };\n\n const addImages = async (chosen: File[]) => {\n setMessage(null);\n for (const file of chosen) {\n let key: string;\n try {\n const added = addImage(workRef.current.doc, workRef.current.files, await prepareOverlay(file), \"map\");\n workRef.current = { doc: added.doc, files: added.files };\n setWork(workRef.current);\n key = added.key;\n } catch {\n setMessage(strings.photoFailed(file.name || \"the image\"));\n continue;\n }\n try {\n if (!(await editorRef.current?.addImage(key))) setMessage(strings.overlayAlready);\n } catch (err) {\n setMessage(err instanceof Error ? err.message : String(err));\n }\n }\n };\n\n const importShapes = async (chosen: File[]) => {\n setMessage(null);\n for (const file of chosen) {\n try {\n // A KML GroundOverlay's picture lives outside the file; only shapes\n // come in.\n const features = parseMapFile(await file.text()).filter((f) => f.properties?.[\"@geometry-type\"] !== \"groundoverlay\");\n if (features.length === 0) setMessage(strings.importNothing(file.name));\n else editorRef.current?.addFeatures(features);\n } catch {\n setMessage(strings.importFailed(file.name));\n }\n }\n };\n\n const done = () => {\n const editor = editorRef.current;\n if (!editor) return;\n onDone(editorToPlace(place, editor.getResult(), dates), workRef.current.doc.media, workRef.current.files);\n };\n\n const bar = dark ? \"rgba(20,20,20,0.85)\" : \"rgba(255,255,255,0.9)\";\n return (\n <Modal opened onClose={onCancel} fullScreen withCloseButton={false} closeOnEscape={false} padding={0}>\n <Box style={{ position: \"fixed\", inset: 0, overflow: \"hidden\" }}>\n <MapEditor\n ref={editorRef}\n initial={initial}\n initialView={initialView}\n resolveImage={resolveImage}\n releaseImage={(url) => URL.revokeObjectURL(url)}\n onAddImage={() => imageInput.current?.click()}\n onError={setMessage}\n dark={dark}\n toolbarTop={BAR_HEIGHT + 12}\n overlayNames={false}\n strings={mapStrings}\n renderOverlayOptions={(key) => (\n <OverlayDateField\n key={key}\n value={dates.has(key) ? dates.get(key) : place?.overlays?.find((o) => o.media === key)?.date}\n language={doc.language}\n parse={parseDateText}\n strings={strings}\n onChange={(date) => setDates((prev) => new Map(prev).set(key, date))}\n />\n )}\n />\n <Group\n justify=\"space-between\" wrap=\"nowrap\" px=\"md\" gap=\"sm\"\n style={{ position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3, background: bar }}\n >\n <Group gap={6} wrap=\"nowrap\" style={{ minWidth: 0 }}>\n <Text fw={600} truncate dir=\"auto\">{strings.mapDialogTitle(place?.name)}</Text>\n <Tooltip label={strings.mapHelp}>\n <ActionIcon variant=\"subtle\" radius=\"xl\" aria-label={strings.mapHelp} onClick={() => setHelpOpen(true)}>\u24D8</ActionIcon>\n </Tooltip>\n </Group>\n <Group gap=\"xs\" wrap=\"nowrap\">\n <Tooltip label={strings.importShapesHint} multiline w={280}>\n <Button variant=\"default\" size=\"sm\" onClick={() => shapesInput.current?.click()}>{strings.importShapes}</Button>\n </Tooltip>\n <Button variant=\"default\" size=\"sm\" onClick={onCancel}>{strings.cancel}</Button>\n <Button size=\"sm\" onClick={done}>{strings.done}</Button>\n </Group>\n </Group>\n {message && (\n <Text\n size=\"sm\" role=\"alert\"\n style={{\n position: \"absolute\", bottom: 12, left: 12, zIndex: 3, maxWidth: 480, padding: \"6px 10px\", borderRadius: 6,\n background: bar, color: \"var(--mantine-color-red-filled)\",\n }}\n >\n {message}\n </Text>\n )}\n <input\n ref={imageInput} type=\"file\" accept=\"image/*\" multiple hidden\n onChange={(e) => { const chosen = [...(e.currentTarget.files ?? [])]; e.currentTarget.value = \"\"; void addImages(chosen); }}\n />\n <input\n ref={shapesInput} type=\"file\" accept=\".kml,.gpx,.geojson,.json,application/vnd.google-earth.kml+xml,application/gpx+xml,application/geo+json\" multiple hidden\n onChange={(e) => { const chosen = [...(e.currentTarget.files ?? [])]; e.currentTarget.value = \"\"; void importShapes(chosen); }}\n />\n </Box>\n <Modal opened={helpOpen} onClose={() => setHelpOpen(false)} title={strings.mapHelp} size=\"md\" zIndex={1000}>\n <MapEditorHelp strings={mapStrings} />\n </Modal>\n </Modal>\n );\n}\n", "// Turning a map file's features into what the map editor's terra-draw\n// canvas can edit, and back into features to save (as GeoJSON, see\n// mapItemToGeoJson), with nothing dropped on the way. terra-draw only\n// knows single Points, LineStrings and Polygons with 2D, at-most-9-decimal\n// coordinates, and only keeps the few properties the editor itself sets\n// (name/color/opacity) --\n// while a KML, GeoJSON or GPX file can hold multi-part shapes, arbitrary\n// properties and a GPS track's per-point times. So:\n//\n// - a multi-part shape is split into single parts that share a group,\n// and rejoined on save (parts whose name/colour/opacity were changed\n// apart become separate shapes, since one KML Placemark has one style);\n// - every other property is set aside per part and put back on save;\n// - a track's times are kept only while its points are unchanged --\n// reshaped, it no longer matches the recording, so it saves as a plain\n// line;\n// - elevations are dropped (nothing here uses them);\n// - anything terra-draw still can't take (a polygon with holes, one that\n// crosses itself) is \"locked\": shown but not editable, and saved back\n// exactly as it was, rather than silently left out of the save.\nimport type { Feature, Geometry, LineString, Point, Polygon, Position } from \"geojson\";\n\n/** What the editor reads and writes on each terra-draw feature itself. */\nconst EDITOR_OWNED = new Set([\"name\", \"color\", \"opacity\"]);\n/** Parser bookkeeping with nothing worth saving: the per-point data that's\n * carried separately (coordinateProperties), @tmcw/togeojson's GPX type tag,\n * and a KML style reference whose <Style> doesn't come along. */\nconst DROPPED = new Set([\"coordinateProperties\", \"_gpxType\", \"styleUrl\", \"@geometry-type\"]);\n\nexport type EditableGeometry = Point | LineString | Polygon;\nexport type EditMode = \"point\" | \"linestring\" | \"polygon\";\n\n/** One single-geometry part, ready for terra-draw. `sourceKey` rides on the\n * terra-draw feature as a property so save can find what was set aside. */\nexport interface EditablePart {\n sourceKey: string;\n mode: EditMode;\n geometry: EditableGeometry;\n name?: string;\n color?: string;\n opacity?: number;\n}\n\ninterface PartSource {\n group: string;\n /** Position within its group, so rejoined parts keep their order. */\n index: number;\n extra: Record<string, unknown>;\n /** A track part's per-point times, and the (2D, rounded) points they\n * belong to -- kept only while the saved points still match. */\n times?: string[];\n coords?: Position[];\n}\n\nexport interface EditSession {\n parts: EditablePart[];\n sources: Map<string, PartSource>;\n /** Parts terra-draw wouldn't accept -- see lockPart. */\n locked: Map<string, EditablePart>;\n}\n\n/** terra-draw rejects coordinates with more than 9 decimal places (its\n * coordinatePrecision) -- well under a millimetre, so rounding loses\n * nothing real. Also drops a third (elevation) value. */\nfunction round2d(position: Position): Position {\n return [Number(position[0].toFixed(9)), Number(position[1].toFixed(9))];\n}\n\nfunction singleParts(geometry: Geometry): EditableGeometry[] {\n switch (geometry.type) {\n case \"Point\":\n return [{ type: \"Point\", coordinates: round2d(geometry.coordinates) }];\n case \"LineString\":\n return [{ type: \"LineString\", coordinates: geometry.coordinates.map(round2d) }];\n case \"Polygon\":\n return [{ type: \"Polygon\", coordinates: geometry.coordinates.map((ring) => ring.map(round2d)) }];\n case \"MultiPoint\":\n return geometry.coordinates.map((c) => ({ type: \"Point\", coordinates: round2d(c) }));\n case \"MultiLineString\":\n return geometry.coordinates.map((line) => ({ type: \"LineString\", coordinates: line.map(round2d) }));\n case \"MultiPolygon\":\n return geometry.coordinates.map((poly) => ({ type: \"Polygon\", coordinates: poly.map((ring) => ring.map(round2d)) }));\n case \"GeometryCollection\":\n return geometry.geometries.flatMap(singleParts);\n }\n}\n\nconst modeOf = (geometry: EditableGeometry): EditMode =>\n geometry.type === \"Point\" ? \"point\" : geometry.type === \"LineString\" ? \"linestring\" : \"polygon\";\n\n/** A feature's properties minus the editor's own and the parser's\n * bookkeeping -- kept as they are, nested values included. */\nfunction extraProperties(properties: Record<string, unknown>): Record<string, unknown> {\n const extra: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(properties)) {\n if (EDITOR_OWNED.has(key) || DROPPED.has(key) || value === undefined || value === null) continue;\n extra[key] = value;\n }\n return extra;\n}\n\n/** Each part's times, if the feature has them in @tmcw/togeojson's own\n * shape: string[] for a LineString, string[][] for a MultiLineString. */\nfunction partTimes(feature: Feature, partCount: number): (string[] | undefined)[] {\n const times = (feature.properties?.coordinateProperties as { times?: unknown } | undefined)?.times;\n if (!Array.isArray(times) || times.length === 0) return [];\n if (feature.geometry?.type === \"LineString\" && times.every((t) => typeof t === \"string\")) {\n return [times as string[]];\n }\n if (feature.geometry?.type === \"MultiLineString\" && times.length === partCount && times.every(Array.isArray)) {\n return times as string[][];\n }\n return [];\n}\n\n/** Splits a file's features (e.g. parseMapFile's) into\n * editable single parts. A polygon with holes is locked from the start:\n * terra-draw's polygon editing only knows an outer ring. */\nexport function prepareForEditing(features: Feature[], firstIndex = 0): EditSession {\n const session: EditSession = { parts: [], sources: new Map(), locked: new Map() };\n features.forEach((feature, i) => {\n const f = firstIndex + i;\n if (!feature.geometry) return;\n const properties = (feature.properties ?? {}) as Record<string, unknown>;\n const extra = extraProperties(properties);\n const geometries = singleParts(feature.geometry);\n const times = partTimes(feature, geometries.length);\n const opacityRaw = Number(properties.opacity);\n const opacity = Number.isFinite(opacityRaw) && opacityRaw >= 0 && opacityRaw <= 1 ? opacityRaw : undefined;\n geometries.forEach((geometry, index) => {\n const sourceKey = `f${f}p${index}`;\n const partTimesHere = times[index];\n const keepTimes = geometry.type === \"LineString\" && partTimesHere?.length === geometry.coordinates.length;\n session.sources.set(sourceKey, {\n group: `f${f}`, index, extra,\n ...(keepTimes ? { times: partTimesHere, coords: geometry.coordinates } : {}),\n });\n const part: EditablePart = {\n sourceKey, mode: modeOf(geometry), geometry,\n name: typeof properties.name === \"string\" ? properties.name : undefined,\n color: typeof properties.color === \"string\" ? properties.color : undefined,\n ...(geometry.type === \"Polygon\" ? { opacity } : {}),\n };\n if (geometry.type === \"Polygon\" && geometry.coordinates.length > 1) session.locked.set(sourceKey, part);\n else session.parts.push(part);\n });\n });\n return session;\n}\n\n/** Adds more features (a file imported while editing) after the session's\n * own, so they save after them too. Returns the session of just the new\n * ones, whose parts the canvas still has to take. */\nexport function addToSession(session: EditSession, features: Feature[]): EditSession {\n let next = 0;\n for (const source of session.sources.values()) next = Math.max(next, Number(source.group.slice(1)) + 1);\n const added = prepareForEditing(features, next);\n session.parts.push(...added.parts);\n for (const [key, source] of added.sources) session.sources.set(key, source);\n for (const [key, part] of added.locked) session.locked.set(key, part);\n return added;\n}\n\n/** Marks a part terra-draw refused to load (addFeatures' validation): it's\n * no longer editable, and assembleForSaving writes it back unchanged. */\nexport function lockPart(session: EditSession, sourceKey: string): void {\n const index = session.parts.findIndex((part) => part.sourceKey === sourceKey);\n if (index < 0) return;\n session.locked.set(sourceKey, session.parts[index]);\n session.parts.splice(index, 1);\n}\n\n/** A part as saved from the canvas: its (possibly edited) geometry and the\n * editor's own properties, plus the sourceKey it was loaded with -- absent\n * for a shape drawn new in this session. */\nexport interface SavedPart {\n sourceKey?: string;\n geometry: EditableGeometry;\n name?: string;\n color?: string;\n opacity?: number;\n}\n\nconst samePositions = (a: Position[], b: Position[]) =>\n a.length === b.length && a.every((p, i) => p[0] === b[i][0] && p[1] === b[i][1]);\n\n/** Joins single geometries back into one -- Multi* when they're all one\n * kind, a GeometryCollection when mixed (what a KML MultiGeometry is). */\nfunction joinGeometries(geometries: EditableGeometry[]): Geometry {\n if (geometries.length === 1) return geometries[0];\n const kinds = new Set(geometries.map((g) => g.type));\n if (kinds.size === 1) {\n if (kinds.has(\"Point\")) return { type: \"MultiPoint\", coordinates: geometries.map((g) => (g as Point).coordinates) };\n if (kinds.has(\"LineString\")) return { type: \"MultiLineString\", coordinates: geometries.map((g) => (g as LineString).coordinates) };\n return { type: \"MultiPolygon\", coordinates: geometries.map((g) => (g as Polygon).coordinates) };\n }\n return { type: \"GeometryCollection\", geometries };\n}\n\n/** Everything to save: the canvas's parts with their set-aside data put\n * back, multi-part shapes rejoined, and locked parts as they were loaded.\n * Features come out in their original file order, new shapes last. */\nexport function assembleForSaving(session: EditSession, saved: SavedPart[]): Feature[] {\n interface Entry { part: SavedPart; source?: PartSource }\n const entries: Entry[] = [\n ...saved.map((part) => ({ part, source: part.sourceKey ? session.sources.get(part.sourceKey) : undefined })),\n ...[...session.locked.values()].map((part) => ({ part, source: session.sources.get(part.sourceKey) })),\n ];\n // One bucket per original feature and style (a part restyled apart from\n // its siblings becomes its own shape), and one per new shape.\n const buckets = new Map<string, Entry[]>();\n let newCount = 0;\n for (const entry of entries) {\n const { part, source } = entry;\n const key = source\n ? `${source.group}|${part.name ?? \"\"}|${part.color ?? \"\"}|${part.opacity ?? \"\"}`\n : `new${newCount++}`;\n const bucket = buckets.get(key);\n if (bucket) bucket.push(entry);\n else buckets.set(key, [entry]);\n }\n const groupOrder = (key: string) => (key.startsWith(\"new\") ? Infinity : Number(key.slice(1, key.indexOf(\"|\"))));\n return [...buckets.entries()]\n .sort(([a], [b]) => groupOrder(a) - groupOrder(b))\n .map(([, bucket]) => {\n bucket.sort((a, b) => (a.source?.index ?? 0) - (b.source?.index ?? 0));\n const first = bucket[0];\n const geometry = joinGeometries(bucket.map((e) => e.part.geometry));\n // Times only when every line in the shape still has its own, on\n // unchanged points -- @tmcw/togeojson's own shape for them is all of\n // a track's segments timed or none.\n const times = bucket.map(({ part, source }) =>\n part.geometry.type === \"LineString\" && source?.times && source.coords\n && samePositions(part.geometry.coordinates, source.coords)\n ? source.times\n : undefined);\n const allTimed = bucket.every((e) => e.part.geometry.type === \"LineString\") && times.every(Boolean);\n return {\n type: \"Feature\",\n geometry,\n properties: {\n ...(first.source?.extra ?? {}),\n ...(first.part.color !== undefined ? { color: first.part.color } : {}),\n ...(first.part.name ? { name: first.part.name } : {}),\n ...(first.part.opacity !== undefined ? { opacity: first.part.opacity } : {}),\n ...(allTimed ? { coordinateProperties: { times: bucket.length === 1 ? times[0] : times } } : {}),\n },\n } as Feature;\n });\n}\n", "// Reading and writing map files: KML, GPX and GeoJSON in (read into GeoJSON\n// features, with each format's own colours where they're reliable), and\n// GeoJSON out, with image overlays as Polygon features marked\n// IMAGE_OVERLAY_PROPERTY. A GeoJSON overlay's `image` names its picture;\n// read back, it becomes the same feature @tmcw/togeojson makes of a KML\n// GroundOverlay, with the picture behind MEDIA_HANDLE_PREFIX. Moved here\n// from Gramps Connect (kmlMedia.ts and mapFileWrite.ts), which shares it\n// with the Story Editor. GPX and KML need a DOMParser (a browser, or jsdom).\n//\n// GeoJSON keeps every property as JSON and multi-part shapes as they are,\n// with no format translation to lose anything in; a GPS track's per-point\n// times ride along in `coordinateProperties.times`, the same place\n// @tmcw/togeojson's GPX/KML readers put them.\nimport type { Feature, FeatureCollection, GeoJsonObject, Geometry, Position } from \"geojson\";\nimport { gpx, kml } from \"@tmcw/togeojson\";\nimport type { OverlayCorners } from \"./geometry\";\n\n/** An image overlay's picture, as a Media handle behind this marker (not a\n * real URL: an app-internal reference, since a resolvable link would need\n * an expiring auth token baked in) -- in a KML GroundOverlay's href, and\n * what asGroundOverlay makes of a GeoJSON one's `image`. */\nexport const MEDIA_HANDLE_PREFIX = \"media-handle:\";\n\n/** A GeoJSON or GPX file's own colours, in the simplestyle convention\n * (`stroke`/`fill`/`fill-opacity`/`marker-color`, which both GeoJSON tools\n * and @tmcw/togeojson's gpx() use), copied onto the `color`/`opacity`\n * properties every map layer actually reads (see MapCanvas.tsx's\n * KML_FILL_LAYER). Fills only what's missing, so an explicit `color` wins.\n * Not applied to KML: Gramps Connect's own KML carries `color` already, and\n * leaving foreign KML alone keeps every existing overlay looking the same. */\nfunction applySimplestyle(feature: Feature): Feature {\n const props = feature.properties ?? {};\n const isRegion = feature.geometry?.type === \"Polygon\" || feature.geometry?.type === \"MultiPolygon\";\n const color = props.color ?? (isRegion ? props.fill ?? props.stroke : props.stroke ?? props[\"marker-color\"]);\n const opacity = props.opacity ?? (isRegion ? props[\"fill-opacity\"] : undefined);\n if (color === props.color && opacity === props.opacity) return feature;\n return { ...feature, properties: { ...props, color, opacity } };\n}\n\n/** A GeoJSON file's features: a FeatureCollection, a single Feature or a\n * bare Geometry are all valid GeoJSON documents. */\nfunction geoJsonFeatures(doc: GeoJsonObject): Feature<Geometry | null>[] {\n if (doc.type === \"FeatureCollection\") return (doc as { features?: Feature<Geometry | null>[] }).features ?? [];\n if (doc.type === \"Feature\") return [doc as Feature<Geometry | null>];\n return [{ type: \"Feature\", geometry: doc as Geometry, properties: {} }];\n}\n\n/** Gramps Connect's GeoJSON image overlay (see mapItemToGeoJson), turned into\n * the same feature @tmcw/togeojson makes of a KML <gx:LatLonQuad>\n * GroundOverlay -- so fetchAllKmlImageOverlays and everything that skips\n * overlays read both formats the same way. */\nfunction asGroundOverlay(feature: Feature): Feature {\n const props = feature.properties ?? {};\n if (props[IMAGE_OVERLAY_PROPERTY] !== true || typeof props.image !== \"string\") return feature;\n const { [IMAGE_OVERLAY_PROPERTY]: _marker, image, ...rest } = props;\n return {\n ...feature,\n properties: { ...rest, \"@geometry-type\": \"groundoverlay\", icon: `${MEDIA_HANDLE_PREFIX}${image}` },\n };\n}\n\n/** A map file's text, as GeoJSON features. The format is read off the\n * content (GeoJSON is JSON; GPX and KML differ by root element) rather\n * than the media object's stored mime, which a file attached by another\n * client may not have set to anything Gramps Connect recognizes. Throws on\n * unparseable text; features with no geometry are dropped -- a KML\n * Placemark without Point/LineString/Polygon (see @tmcw/togeojson's\n * KMLOptions.skipNullGeometry), or a GeoJSON Feature with `geometry: null`,\n * is of no use to a caller here, so dropped rather than threaded through\n * as `Feature<Geometry | null>` everywhere downstream. */\nexport function parseMapFile(text: string): Feature[] {\n const hasGeometry = (f: Feature<Geometry | null>): f is Feature => f.geometry != null;\n if (text.trimStart().startsWith(\"{\")) {\n return geoJsonFeatures(JSON.parse(text) as GeoJsonObject).filter(hasGeometry).map(asGroundOverlay).map(applySimplestyle);\n }\n const dom = new DOMParser().parseFromString(text, \"text/xml\");\n if (dom.documentElement.localName === \"gpx\") {\n return gpx(dom).features.filter(hasGeometry).map(applySimplestyle);\n }\n return kml(dom).features.filter(hasGeometry);\n}\n\n/** An overlay file's SOURCE_PROPERTY, if it's GeoJSON that has one. */\nexport function overlaySourceOfText(text: string): string | undefined {\n if (!text.trimStart().startsWith(\"{\")) return undefined;\n try {\n const source = (JSON.parse(text) as Record<string, unknown>)[SOURCE_PROPERTY];\n return typeof source === \"string\" ? source : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Every Polygon ring inside `feature` -- itself (a plain Polygon), or each\n * Polygon sub-geometry of a GeometryCollection. A country-level Wikidata/\n * Commons outline (e.g. the United States) is often a disjoint shape --\n * islands/territories a single Polygon ring can't express -- unlike a\n * state's simpler single-ring Polygon. A KML file stores one as a\n * <MultiGeometry> of several <Polygon>s, and @tmcw/togeojson reads *any* multi-child\n * Placemark geometry back as a GeometryCollection (never reconstituting\n * MultiPolygon) -- so that's the shape that actually reaches here, not\n * \"MultiPolygon\" itself (confirmed live, 2026-09-09, round-tripping a\n * synthetic MultiPolygon through both libraries). A non-Polygon sub-geometry\n * (there shouldn't be one -- Gramps Connect never writes anything else into a\n * region's own Placemark) is simply skipped rather than failing the whole\n * feature. `[]` for anything else (a Point, a bare LineString route, ...),\n * meaning \"not a region\" to every caller below. */\nexport function polygonRingsOf(feature: Feature): Position[][] {\n if (feature.geometry?.type === \"Polygon\") return [feature.geometry.coordinates[0]];\n if (feature.geometry?.type === \"GeometryCollection\") {\n return feature.geometry.geometries.filter((g) => g.type === \"Polygon\").map((g) => g.coordinates[0]);\n }\n return [];\n}\n\n/** True for a feature fetchAllKmlRegions/MapCanvas.tsx's own shapes effect\n * both treat as one drawable/controllable region -- see polygonRingsOf.\n * Exported so MapCanvas.tsx's key/hidden/opacity stamping can use the exact\n * same test fetchAllKmlRegions does: the two must never drift, or a row's\n * key stops matching the feature it's meant to control -- found live as a\n * place whose outline drew on the map (MapLibre's GeoJSON source splits a\n * GeometryCollection into one sub-feature per geometry before rendering,\n * each individually typed \"Polygon\") but never showed up in\n * OverlayLayersPanel.tsx's list. */\nexport function isKmlRegion(feature: Feature): boolean {\n return polygonRingsOf(feature).length > 0;\n}\n\n/** Every vertex of `feature` if it's a line: a LineString, a MultiLineString\n * (a GPX track with several segments) or a GeometryCollection of only\n * LineStrings (how @tmcw/togeojson reads a KML MultiGeometry -- see\n * polygonRingsOf). `[]` for anything else, meaning \"not a line\". */\nexport function lineCoordsOf(feature: Feature): Position[] {\n const geometry = feature.geometry;\n if (geometry?.type === \"LineString\") return geometry.coordinates;\n if (geometry?.type === \"MultiLineString\") return geometry.coordinates.flat();\n if (geometry?.type === \"GeometryCollection\" && geometry.geometries.length > 0\n && geometry.geometries.every((g) => g.type === \"LineString\")) {\n return geometry.geometries.flatMap((g) => (g.type === \"LineString\" ? g.coordinates : []));\n }\n return [];\n}\n\n/** True for a feature fetchAllKmlLines lists and MapCanvas.tsx's shapes\n * effect lets the panel hide/dim -- shared for the same reason as\n * isKmlRegion: the two must never drift apart. A region is never a line. */\nexport function isKmlLine(feature: Feature): boolean {\n return !isKmlRegion(feature) && lineCoordsOf(feature).length > 0;\n}\n\n/** An image overlay, as MapItemEditorDialog.tsx tracks one -- always 4\n * explicit world corners; see kmlMedia.ts's KmlImageOverlay, which this\n * mirrors on the write side. */\nexport interface ImageOverlay {\n handle: string;\n corners: OverlayCorners;\n name?: string;\n opacity?: number;\n order?: number;\n}\n\n/** The property marking a feature as an image overlay rather than a shape:\n * its Polygon is the image's 4 corners (top-left, top-right, bottom-right,\n * bottom-left, closed), and `image` is the picture's Media handle. This\n * app's own convention -- plain GeoJSON has no image overlays -- read back\n * by parseMapFile. */\nexport const IMAGE_OVERLAY_PROPERTY = \"gramps:image-overlay\";\n\nfunction overlayFeature(overlay: ImageOverlay): Feature {\n const ring = [...overlay.corners, overlay.corners[0]];\n return {\n type: \"Feature\",\n geometry: { type: \"Polygon\", coordinates: [ring] },\n properties: {\n [IMAGE_OVERLAY_PROPERTY]: true,\n image: overlay.handle,\n ...(overlay.name ? { name: overlay.name } : {}),\n ...(overlay.opacity !== undefined && overlay.opacity !== 1 ? { opacity: overlay.opacity } : {}),\n ...(overlay.order !== undefined ? { order: overlay.order } : {}),\n },\n };\n}\n\n/** Records which Media object an overlay was made from (mapOverlays.ts) --\n * a \"foreign member\" of the FeatureCollection, which GeoJSON allows. */\nexport const SOURCE_PROPERTY = \"gramps:source\";\n\n/** Every shape plus every image overlay, as one GeoJSON FeatureCollection.\n * Overlays go last: kmlMedia.ts's region/line row indexes count every\n * feature in the file but MapCanvas.tsx's leave overlays out, and the two\n * only agree while no overlay comes before a shape. */\nexport function mapItemToGeoJson(features: Feature[], overlays: ImageOverlay[] = [], source?: string): string {\n const collection: FeatureCollection & { [SOURCE_PROPERTY]?: string } = {\n type: \"FeatureCollection\",\n ...(source ? { [SOURCE_PROPERTY]: source } : {}),\n features: [...features, ...overlays.map(overlayFeature)],\n };\n return JSON.stringify(collection);\n}\n", "// Map geometry for shapes and image overlays, as plain math (no map\n// library): image overlay corners moved, scaled and rotated in Web Mercator\n// space so a rectangle stays one at any latitude, and bounding boxes over\n// features and overlays. Moved here from Gramps Connect (its kmlMedia.ts),\n// which shares it with the Story Editor; the \"kml\" in some names is from\n// there, where KML was the first map file format.\nimport type { Feature, Position } from \"geojson\";\n\n/** An overlay's 4 world corners, maplibre's own ImageSource `coordinates`\n * order (top-left, top-right, bottom-right, bottom-left) and type. */\nexport type OverlayCorners = [[number, number], [number, number], [number, number], [number, number]];\n\nconst DEG_TO_RAD = Math.PI / 180;\nconst RAD_TO_DEG = 180 / Math.PI;\n\n/** [lng,lat] -> normalized Web Mercator x/y (x east-positive, y\n * *south*-positive) -- the exact projection maplibre's own map.project()\n * uses internally, reimplemented here as plain math (no maplibre-gl\n * import) so this module stays free of that ~900KB dependency (see\n * MapItemEditorDialog.tsx's own doc comment on why maplibre-gl is always\n * behind a lazy import elsewhere in Gramps Connect). Unlike raw [lng,lat],\n * Mercator x/y is locally isotropic -- equal scale in both directions at\n * any given point, which is the whole point of the projection -- making it\n * the correct space to rotate a box in; see rotatePoint. */\nfunction mercatorFromLngLat([lng, lat]: [number, number]): [number, number] {\n const x = (180 + lng) / 360;\n const y = (180 - RAD_TO_DEG * Math.log(Math.tan(Math.PI / 4 + (lat * DEG_TO_RAD) / 2))) / 360;\n return [x, y];\n}\n\n/** mercatorFromLngLat's inverse. */\nfunction lngLatFromMercator([x, y]: [number, number]): [number, number] {\n const lng = x * 360 - 180;\n const lat = 90 - 2 * Math.atan(Math.exp((y * 360 - 180) * DEG_TO_RAD)) * RAD_TO_DEG;\n return [lng, lat];\n}\n\n/** Rotates one point by `rotationDeg` around `center` (positive =\n * counterclockwise, matching KML's own <LatLonBox><rotation> convention)\n * -- done in Mercator-projected space (see mercatorFromLngLat), not raw\n * [lng,lat], so a rectangle stays a rectangle (right angles preserved)\n * after rotating, regardless of latitude. A naive rotation directly on\n * [lng,lat] -- this function's original implementation -- shears instead,\n * since a degree of longitude and a degree of latitude aren't the same\n * ground (or screen) distance away from the equator (found live: a square\n * image's corners visibly stopped being 90 degrees once rotated away from\n * 0). Gramps Connect's own image overlays are never meant to be opened in an\n * external viewer (their picture is an app-internal Media reference), so diverging here\n * from what Google Earth's own <LatLonBox><rotation> would render is an\n * acceptable trade for Gramps Connect always rendering its own files correctly.\n * Pass a negative `rotationDeg` to go the other way (world -> local). */\nexport function rotatePoint(point: [number, number], center: [number, number], rotationDeg: number): [number, number] {\n const angle = rotationDeg * DEG_TO_RAD;\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n const [px, py] = mercatorFromLngLat(point);\n const [cx, cy] = mercatorFromLngLat(center);\n // Mercator y increases southward -- negated here so this rotation is\n // expressed in a conventional north-up, east-right plane (dx\n // east-positive, dy north-positive), keeping \"positive rotationDeg =\n // counterclockwise\" the same sense every caller already expects.\n const dx = px - cx;\n const dy = -(py - cy);\n const rx = dx * cos - dy * sin;\n const ry = dx * sin + dy * cos;\n return lngLatFromMercator([cx + rx, cy - ry]);\n}\n\n/** Scales the distance from `center` to `point` by `scale`, in the same\n * Mercator-projected space rotatePoint rotates in -- so scaling a\n * rectangle (or an already-warped quad) uniformly from its own center\n * preserves its exact shape/aspect ratio regardless of latitude, the same\n * way rotatePoint preserves angles. MapItemEditorDialog.tsx's resize\n * handle applies this to all 4 corners at once (see mountOverlay). */\nexport function scalePoint(point: [number, number], center: [number, number], scale: number): [number, number] {\n const [px, py] = mercatorFromLngLat(point);\n const [cx, cy] = mercatorFromLngLat(center);\n return lngLatFromMercator([cx + (px - cx) * scale, cy + (py - cy) * scale]);\n}\n\n/** The distance between `a` and `b` in the same Mercator-projected space\n * scalePoint scales in -- not a real-world distance (Mercator distorts\n * those away from the equator), just a consistent unit for computing a\n * resize handle's before/after scale ratio, which only ever needs to be\n * internally consistent with scalePoint's own projection, not physically\n * meaningful on its own. */\nexport function mercatorDistance(a: [number, number], b: [number, number]): number {\n const [ax, ay] = mercatorFromLngLat(a);\n const [bx, by] = mercatorFromLngLat(b);\n return Math.hypot(bx - ax, by - ay);\n}\n\n/** The angle (degrees, positive = counterclockwise, 0 = due east) from\n * `from` to `to` -- measured in the same Mercator-projected, north-up\n * plane rotatePoint itself rotates in, so a caller tracking \"how far has\n * the user dragged this handle around the center\" gets an angle that\n * matches how rotatePoint will then actually render it (unlike a plain\n * atan2 on raw [lng,lat], which suffers the same latitude-dependent skew\n * rotatePoint's own doc comment describes). */\nexport function mercatorBearing(from: [number, number], to: [number, number]): number {\n const [fx, fy] = mercatorFromLngLat(from);\n const [tx, ty] = mercatorFromLngLat(to);\n return Math.atan2(-(ty - fy), tx - fx) * RAD_TO_DEG;\n}\n\n/** An axis-aligned box plus a rotation about its own center's 4 world\n * corners -- KML's own <LatLonBox><rotation> model. Only ever needed to\n * interpret an *old* overlay saved before Gramps Connect always wrote\n * explicit corners (see its fetchAllKmlImageOverlays); the map editor\n * itself only ever deals with corners directly, never this box shape. */\nexport function cornersFromBox(\n box: { north: number; south: number; east: number; west: number; rotation: number },\n): OverlayCorners {\n const center: [number, number] = [(box.west + box.east) / 2, (box.north + box.south) / 2];\n const corners: [number, number][] = [\n [box.west, box.north], [box.east, box.north], [box.east, box.south], [box.west, box.south],\n ];\n return corners.map((p) => rotatePoint(p, center, box.rotation)) as OverlayCorners;\n}\n\nfunction visitCoordinates(coords: unknown, bounds: [number, number, number, number]): void {\n if (typeof (coords as Position)[0] === \"number\") {\n const [lng, lat] = coords as Position;\n if (lng < bounds[0]) bounds[0] = lng;\n if (lat < bounds[1]) bounds[1] = lat;\n if (lng > bounds[2]) bounds[2] = lng;\n if (lat > bounds[3]) bounds[3] = lat;\n return;\n }\n for (const c of coords as unknown[]) visitCoordinates(c, bounds);\n}\n\n/** Every coordinate's bounding box across a set of KML features, as\n * [west, south, east, north] -- maplibre's own LngLatBoundsLike corner\n * order, so a caller can hand this straight to fitBounds/cameraForBounds to\n * frame a field boundary or a route at whatever zoom actually fits it,\n * rather than guessing one. Null when the features carry no coordinates at\n * all (an empty file, or every fetch above failed). */\nexport function kmlBounds(features: Feature[]): [west: number, south: number, east: number, north: number] | null {\n const bounds: [number, number, number, number] = [Infinity, Infinity, -Infinity, -Infinity];\n for (const feature of features) {\n const geometry = feature.geometry;\n if (!geometry) continue;\n if (geometry.type === \"GeometryCollection\") {\n for (const g of geometry.geometries) if (\"coordinates\" in g) visitCoordinates(g.coordinates, bounds);\n continue;\n }\n visitCoordinates(geometry.coordinates, bounds);\n }\n return Number.isFinite(bounds[0]) ? bounds : null;\n}\n\n/** The center of kmlBounds -- a plain bbox center rather than an\n * area-weighted centroid, which is all a \"roughly where does this file sit\"\n * marker position needs. */\nexport function kmlCenter(features: Feature[]): [lat: number, long: number] | null {\n const bounds = kmlBounds(features);\n if (!bounds) return null;\n return [(bounds[1] + bounds[3]) / 2, (bounds[0] + bounds[2]) / 2];\n}\n\n/** Same bbox as kmlBounds, but over a set of image overlays' corners instead\n * of vector features -- overlays (GroundOverlay/region placemarks) carry no\n * Point/LineString/Polygon geometry for kmlBounds to find anything in, since\n * fetchAllKmlFeatures excludes them entirely. Lets a caller fit the camera to\n * an overlay-only KML attachment the same way it would a vector one. */\nexport function kmlOverlayBounds(\n overlays: { corners: OverlayCorners }[],\n): [west: number, south: number, east: number, north: number] | null {\n if (overlays.length === 0) return null;\n const bounds: [number, number, number, number] = [Infinity, Infinity, -Infinity, -Infinity];\n for (const overlay of overlays) {\n for (const [lng, lat] of overlay.corners) {\n if (lng < bounds[0]) bounds[0] = lng;\n if (lat < bounds[1]) bounds[1] = lat;\n if (lng > bounds[2]) bounds[2] = lng;\n if (lat > bounds[3]) bounds[3] = lat;\n }\n }\n return bounds;\n}\n\n/** Combines two nullable bboxes (as returned by kmlBounds/kmlOverlayBounds)\n * into the box that encloses both -- a place's KML attachment(s) can carry\n * vector shapes and image overlays side by side, and framing the camera to\n * just one kind would clip whichever the caller didn't ask for. Either side\n * missing (no shapes, or no overlays) just passes the other through; both\n * missing is null, same as either input alone would be. */\nexport function unionBounds(\n a: [west: number, south: number, east: number, north: number] | null,\n b: [west: number, south: number, east: number, north: number] | null,\n): [west: number, south: number, east: number, north: number] | null {\n if (!a) return b;\n if (!b) return a;\n return [Math.min(a[0], b[0]), Math.min(a[1], b[1]), Math.max(a[2], b[2]), Math.max(a[3], b[3])];\n}\n\n/** Same bbox-center guess as kmlCenter, but over a set of image overlays'\n * corners instead of vector features -- useVisualData.ts's fallback for a\n * PendingKmlPlace whose only KML attachment is a GroundOverlay (an\n * overlay-only file: no Point/LineString/Polygon placemark for kmlCenter to\n * find anything in, since fetchAllKmlFeatures excludes GroundOverlay\n * placemarks entirely). Without this, a place with only an image overlay\n * attached and no lat/long of its own never gets a derived position and so\n * never renders on the map until someone sets its coordinates by hand\n * (found live). */\nexport function kmlOverlayCenter(overlays: { corners: OverlayCorners }[]): [lat: number, long: number] | null {\n const bounds = kmlOverlayBounds(overlays);\n if (!bounds) return null;\n return [(bounds[1] + bounds[3]) / 2, (bounds[0] + bounds[2]) / 2];\n}\n", "// A full map for drawing and editing shapes (points, lines, polygons,\n// rectangles, with terra-draw) and placing image overlays such as scanned\n// old maps (move, resize, rotate, drag each corner, opacity, order). It\n// edits what it's given and hands it back when asked (MapEditorHandle);\n// loading and saving are the host's: Gramps Connect's MapItemEditorDialog\n// reads and writes a map file on the server, the Story Editor a slide's\n// place.\n//\n// Shapes go through map-edit's model (prepareForEditing/assembleForSaving),\n// so multi-part shapes, GPS track times and properties this editor doesn't\n// know survive an edit; anything terra-draw can't take is shown dashed\n// (\"locked\") and saved back exactly as it was.\n//\n// Needs Mantine (like the rest of the editor), maplibre-gl, terra-draw and\n// terra-draw-maplibre-gl-adapter.\nimport { forwardRef, useEffect, useImperativeHandle, useRef, useState, type ReactNode } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\n// maplibre's stylesheet comes with the player, which this entry includes\n// (an import of it here would end up in the published declarations).\nimport type { Map as MapLibreMap } from \"maplibre-gl\";\nimport {\n TerraDraw, TerraDrawLineStringMode, TerraDrawPointMode, TerraDrawPolygonMode, TerraDrawRectangleMode,\n TerraDrawSelectMode,\n} from \"terra-draw\";\nimport type { GeoJSONStoreFeatures, HexColor } from \"terra-draw\";\nimport { TerraDrawMapLibreGLAdapter } from \"terra-draw-maplibre-gl-adapter\";\nimport type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport {\n Alert, Box, Button, ColorInput, Divider, Group, Kbd, List, Loader, NumberInput, SegmentedControl, Slider, Stack, Text,\n TextInput,\n} from \"@mantine/core\";\nimport {\n addToSession, assembleForSaving, lockPart, mercatorBearing, mercatorDistance, prepareForEditing, rotatePoint, scalePoint,\n type EditableGeometry, type EditablePart, type EditSession, type OverlayCorners, type SavedPart,\n} from \"../mapEdit\";\nimport { mapStyleUrl } from \"../player/mapStyles\";\nimport { defaultColors } from \"../player/theme\";\nimport { MAP_EDITOR_ENGLISH, type MapEditorStrings } from \"./mapEditorStrings\";\n\ntype DrawMode = \"point\" | \"linestring\" | \"polygon\" | \"rectangle\" | \"select\";\n\nconst TOOLBAR: { mode: DrawMode; label: keyof MapEditorStrings }[] = [\n { mode: \"point\", label: \"point\" },\n { mode: \"linestring\", label: \"line\" },\n { mode: \"polygon\", label: \"polygon\" },\n { mode: \"rectangle\", label: \"rectangle\" },\n { mode: \"select\", label: \"select\" },\n];\n\n// A handful of preset swatches for the color picker -- ColorInput's own\n// popover still offers the full picker for anything else, this just saves\n// a trip there for the common case.\nconst COLOR_SWATCHES = [\n \"#2a78d6\", \"#d64545\", \"#3aa657\", \"#e0a325\", \"#8654c9\", \"#2aa7a0\", \"#e0678a\", \"#555555\",\n];\n\n/** A region's fill with no opacity of its own, as the maps and the story\n * player draw it; also a new region's starting opacity. */\nconst UNSET_OPACITY = 0.25;\nconst EMPTY_LABEL_PREVIEW: FeatureCollection = { type: \"FeatureCollection\", features: [] };\n\n/** An image overlay as the host gives and gets it: `image` is the host's\n * own name for the picture (a media handle, a story media key), turned\n * into something displayable by `resolveImage`. */\nexport interface MapEditorOverlay {\n image: string;\n /** Top-left, top-right, bottom-right, bottom-left, as [lng, lat]. */\n corners: OverlayCorners;\n name?: string;\n /** 0-1; undefined is fully opaque. */\n opacity?: number;\n /** Stacking rank; higher draws on top. */\n order?: number;\n}\n\n/** What's in the editor, for the host to save. */\nexport interface MapEditorResult {\n features: Feature[];\n overlays: MapEditorOverlay[];\n}\n\nexport interface MapEditorStatus {\n /** Anything drawn or placed (shapes or images). */\n hasDrawn: boolean;\n /** Anything to save at all: drawn, placed, or locked. */\n hasContent: boolean;\n}\n\nexport interface MapEditorHandle {\n /** Everything as it is now: shapes put back together (see map-edit's\n * assembleForSaving) and the image overlays. */\n getResult: () => MapEditorResult;\n /** The box around everything drawn and placed, [west, south, east,\n * north], or null with nothing there yet. */\n drawnBounds: () => [number, number, number, number] | null;\n /** Places an image in the middle of the current view, at its own aspect\n * ratio, and selects it. False if that image is already one of the\n * overlays. Throws if it can't be loaded. */\n addImage: (image: string) => Promise<boolean>;\n /** Adds shapes (an imported map file's, see parseMapFile) after what's\n * there, and frames them. */\n addFeatures: (features: Feature[]) => void;\n}\n\nexport interface MapEditorProps {\n /** What to edit: null while the host is still loading it (the map shows,\n * and fills in once this arrives). Read once; later changes are\n * ignored. */\n initial: { features: Feature[]; overlays: MapEditorOverlay[] } | null;\n /** Where to look when what's loaded has nothing to frame. */\n initialView?: { center: [number, number]; zoom: number };\n /** A displayable URL for an overlay's image. */\n resolveImage: (image: string) => Promise<string>;\n /** Called with a URL from resolveImage once the editor is done with it\n * (e.g. URL.revokeObjectURL). */\n releaseImage?: (url: string) => void;\n /** Shows an Image button; the host picks one and calls addImage. */\n onAddImage?: () => void;\n onStatus?: (status: MapEditorStatus) => void;\n /** A map that wouldn't load, or a terra-draw failure. */\n onError?: (message: string) => void;\n dark?: boolean;\n /** A new shape's color until another is picked. */\n defaultColor?: string;\n /** For point labels drawn on the map. */\n labelColors?: { text: string; surface: string };\n /** Room to leave above the tool panel for the host's own bars. */\n toolbarTop?: number;\n /** Whether an image overlay has a name to edit (default true). */\n overlayNames?: boolean;\n /** More fields for the selected image overlay, below its own. */\n renderOverlayOptions?: (image: string) => ReactNode;\n strings?: Partial<MapEditorStrings>;\n}\n\n/** One placed-and-sized image overlay in this editor -- always 4 explicit\n * world corners. `id` is a local key only (React list key + maplibre\n * source/layer id prefix), not persisted.\n *\n * There's deliberately no separate \"box\" (north/south/east/west/rotation)\n * representation: move/resize/rotate/corner-drag all transform these same\n * 4 points directly (see mountOverlay) -- resize scales all 4 uniformly\n * from their shared center, rotate spins all 4 uniformly around it, a\n * corner drag moves just the one point -- so a plain rectangle is simply\n * the case where the 4 points happen to describe one, and resize/rotate\n * stay exactly as meaningful (and aspect-preserving) on an already-warped\n * quad as on a rectangle. The free-transform control only ever shows or\n * hides the 4 individual corner-drag handles (see showCornerHandles further\n * down) -- it never touches `corners` itself. */\ninterface ImageOverlayDraft extends MapEditorOverlay {\n id: string;\n}\n\n/** What's tracked per mounted image overlay -- everything needed to move\n * it (imperatively, outside React) and tear it down again. `box.corners`\n * is the live, authoritative geometry during a drag; `overlays` state\n * (committed on drag end) only needs to be right when read back and on\n * remount.\n *\n * No mousedown listener of its own -- maplibre's layer-filtered events\n * (`map.on(type, layerId, listener)`) work by hit-testing via\n * queryRenderedFeatures, which only supports vector-ish layer types\n * (circle/fill/fill-extrusion/line/symbol); a `type: \"raster\"` layer (what\n * an image source renders as) never matches, so a per-layer listener here\n * would simply never fire (found live: this is why clicking an image did\n * nothing at all). `startMove` is called instead by the one map-wide\n * mousedown handler in the map-setup effect, which does its own point-in-\n * box hit test against every mount's `box`. */\ninterface OverlayMount {\n sourceId: string;\n box: { corners: OverlayCorners };\n deleteMarker: maplibregl.Marker;\n resizeMarker: maplibregl.Marker;\n rotateMarker: maplibregl.Marker;\n /** The 4 free-transform corner handles, maplibre's own `coordinates`\n * order -- shown only while this overlay's id is in `warpHandleIds` (see\n * the selection/visibility effect below); dragging one is the only way\n * to actually turn a rectangle into a non-rectangular quad. */\n cornerMarkers: [maplibregl.Marker, maplibregl.Marker, maplibregl.Marker, maplibregl.Marker];\n startMove: (e: maplibregl.MapMouseEvent) => void;\n /** Applies a new set of corners to `box` and the live map source in one\n * step -- shared by every drag handler (move/resize/rotate/corner-drag),\n * so there's exactly one place that keeps `box` and the rendered image\n * in sync. */\n setCorners: (next: OverlayCorners) => void;\n /** Snaps every handle back onto `box`'s current corners -- called after\n * every geometry change. */\n repositionHandles: () => void;\n /** From resolveImage, given back to releaseImage on unmount, not\n * before: maplibre's `image` source keeps reading from it for as long as\n * the layer exists. */\n imageUrl: string;\n}\n\n/** See the style.load handler's own doc comment on why every image\n * overlay's raster layer is inserted directly below this one layer,\n * rather than wherever addLayer's default \"on top of everything\" would\n * otherwise put it. */\nconst OVERLAY_ANCHOR_LAYER = \"image-overlay-anchor\";\n\n/** terra-draw-maplibre-gl-adapter's own fixed layer ids (its default\n * `prefixId` is \"td\", never overridden here -- see the `TerraDraw`\n * constructor below) -- every one of these is always created by its\n * `register()` (called via `draw.start()`), regardless of which drawing\n * modes are actually used, so this list is safe to `queryRenderedFeatures`\n * against unconditionally once `ready` is true. Used by the map's own\n * mousedown handler to tell whether a click landed on an actual drawn\n * shape before falling through to the image-overlay hit test below it. */\nconst TERRA_DRAW_LAYERS = [\"td-polygon\", \"td-polygon-outline\", \"td-linestring\", \"td-point\", \"td-point-marker\"];\n\n/** Shapes loaded that terra-draw can't edit (see map-edit's lockPart) --\n * drawn dashed underneath, so they're still visible, and saved back\n * exactly as they were. */\nconst LOCKED_SOURCE = \"locked-shapes\";\nconst LOCKED_FILL_LAYER = \"locked-shapes-fill\";\nconst LOCKED_LINE_LAYER = \"locked-shapes-line\";\n\n/** terra-draw's own point mode has no text-label styling (see the\n * label-preview effect below), so a labeled point's text is drawn by this\n * separate, independent geojson source/layer stacked on top of\n * terra-draw's own -- purely visual, never read back from directly\n * (getResult reads terra-draw's own snapshot, this is a mirror of it). */\nconst LABEL_PREVIEW_SOURCE = \"label-preview\";\nconst LABEL_PREVIEW_LAYER = \"label-preview-text\";\n\n/** The tool panel sits over the map; its own background and the gaps\n * between controls let clicks through to the map below (a shape corner or\n * overlay handle that ends up under the panel's empty space would\n * otherwise be dead), the way maplibre's own control containers do. */\nconst TOOLBAR_CLASS = \"gc-map-editor-toolbar\";\nconst TOOLBAR_CSS = `.${TOOLBAR_CLASS} { pointer-events: none; } .${TOOLBAR_CLASS} > * { pointer-events: auto; }`;\n\n/** The average of `corners` -- a plain centroid, not an area-weighted one,\n * which is all a resize/rotate pivot or a delete-handle position needs.\n * Corner indices are tracked by identity (index 0 is always \"whichever\n * point started as top-left\", however far move/resize/rotate/warp has\n * since carried it), so this stays a stable, sensible center throughout. */\nfunction overlayCenter(corners: OverlayCorners): [number, number] {\n let lng = 0, lat = 0;\n for (const [x, y] of corners) { lng += x; lat += y; }\n return [lng / 4, lat / 4];\n}\n\n/** The rotate handle's own resting position -- beyond the midpoint of the\n * corners[0]-corners[1] edge (this overlay's \"top\" edge, by index, however\n * it's currently oriented), extended further out from `center` so the\n * handle doesn't crowd that edge. Since this is recomputed from the\n * *current* corners every time (not from a persisted rotation angle), it\n * naturally orbits the shape as move/resize/rotate/corner-drag change it,\n * the standard \"stalk above a selected object\" rotate-handle convention --\n * with no separate \"unrotated\" reference frame needed. */\nfunction rotateHandleAnchor(corners: OverlayCorners, center: [number, number]): [number, number] {\n const [topLeft, topRight] = corners;\n const topMid: [number, number] = [(topLeft[0] + topRight[0]) / 2, (topLeft[1] + topRight[1]) / 2];\n return [center[0] + (topMid[0] - center[0]) * 1.5, center[1] + (topMid[1] - center[1]) * 1.5];\n}\n\n/** Whether `point` (screen pixels) falls inside the convex quad described\n * by `corners` (in order around the shape) -- a plain same-side-of-every-\n * edge cross-product test, since a rotated overlay's screen footprint\n * isn't an axis-aligned rectangle a simple min/max bounds check could\n * handle anymore. */\nfunction pointInQuad(point: { x: number; y: number }, corners: { x: number; y: number }[]): boolean {\n let sign = 0;\n for (let i = 0; i < corners.length; i++) {\n const a = corners[i];\n const b = corners[(i + 1) % corners.length];\n const cross = (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x);\n if (cross === 0) continue;\n const s = cross > 0 ? 1 : -1;\n if (sign === 0) sign = s;\n else if (s !== sign) return false;\n }\n return true;\n}\n\n// How see-through a dragged overlay image gets, so whatever's underneath\n// (other images, map features) is visible for positioning it precisely.\nconst OVERLAY_DRAG_OPACITY = 0.5;\n\n// zIndex above the floating left toolbar's own 3 (see its `Stack` style\n// further down) -- that toolbar is positioned absolutely over the map\n// itself and grows taller once an overlay is selected (its \"Edit Options\"\n// section), so a handle whose current corner happens to land underneath\n// it would otherwise be unclickable: the toolbar, not the handle, receives\n// the click. Found live: rotating an overlay a little was enough to swing\n// its resize handle under that panel. Plain maplibre markers have no\n// z-index of their own (auto), so this alone is enough to always win.\nconst OVERLAY_HANDLE_STYLE = {\n width: \"20px\", height: \"20px\", borderRadius: \"50%\", background: \"white\",\n border: \"2px solid #333\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\",\n fontSize: \"12px\", fontWeight: \"700\", color: \"#333\", cursor: \"pointer\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.4)\", userSelect: \"none\", zIndex: 4,\n} as const;\n\nfunction loadImageElement(src: string, failed: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(failed));\n img.src = src;\n });\n}\n\nfunction extendBounds(bounds: maplibregl.LngLatBounds, geometry: Geometry): void {\n if (geometry.type === \"Point\") {\n bounds.extend(geometry.coordinates as [number, number]);\n } else if (geometry.type === \"LineString\") {\n for (const c of geometry.coordinates) bounds.extend(c as [number, number]);\n } else if (geometry.type === \"Polygon\") {\n for (const ring of geometry.coordinates) for (const c of ring) bounds.extend(c as [number, number]);\n }\n}\n\nexport const MapEditor = forwardRef<MapEditorHandle, MapEditorProps>(function MapEditor({\n initial, initialView, resolveImage, releaseImage, onAddImage, onStatus, onError, dark = false, defaultColor, labelColors,\n toolbarTop = 12, overlayNames = true, renderOverlayOptions, strings: stringOverrides,\n}, ref) {\n const strings = { ...MAP_EDITOR_ENGLISH, ...stringOverrides };\n // Callbacks and words the once-per-map listeners below read, kept live.\n const live = useRef({ strings, resolveImage, releaseImage, onError });\n live.current = { strings, resolveImage, releaseImage, onError };\n const fail = (message: string) => live.current.onError?.(message);\n const release = (url: string) => live.current.releaseImage?.(url);\n\n // A callback ref surfaced as state, not a plain useRef -- a host may put\n // this inside a Mantine Modal, whose own children aren't necessarily\n // committed to the DOM in the same pass as this component's first render\n // (found live: a plain `useRef` read inside a `[]`-effect saw `null`\n // every time, so the map/draw setup below never ran at all). Assigning\n // the DOM node to state instead means the effect below (keyed on\n // `containerEl`) reliably fires once it's actually mounted.\n const [containerEl, setContainerEl] = useState<HTMLDivElement | null>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const drawRef = useRef<TerraDraw | null>(null);\n // Image overlays live outside terra-draw entirely (see ImageOverlayDraft's\n // own doc comment) -- this is their bookkeeping, keyed by\n // ImageOverlayDraft.id, imperative like drawRef itself.\n const overlayMountsRef = useRef<Map<string, OverlayMount>>(new Map());\n const [mode, setMode] = useState<DrawMode>(\"select\");\n // Mirrors `mode` state for the finish listener set up once below (same\n // reasoning as colorRef just under this) -- lets it tell a just-finished\n // region (polygon/rectangle) apart from a point/line, since it's\n // registered once per map rather than fresh on every `mode` change.\n const modeRef = useRef(mode);\n modeRef.current = mode;\n const [ready, setReady] = useState(false);\n // The color a newly-finished shape takes (draw.on(\"finish\") below), and\n // -- when a shape is currently selected -- what changing this recolors\n // in place.\n const [color, setColor] = useState(() => defaultColor ?? defaultColors(dark).mark);\n // Mirrors `color` state for the terra-draw styling functions/listeners\n // set up once (keyed on `containerEl`, see that effect) below -- they\n // close over this ref instead of `color` itself so a later color change\n // doesn't need the whole map/draw instance rebuilt to see it.\n const colorRef = useRef(color);\n colorRef.current = color;\n // A region's (polygon/rectangle) fill opacity, same pattern as `color`:\n // both a newly-finished region's own opacity and, while one is selected,\n // what changing this edits in place. 0.25 matches Gramps Connect's map\n // view default, so an untouched region renders the same there.\n const [opacity, setOpacity] = useState(UNSET_OPACITY);\n const opacityRef = useRef(opacity);\n opacityRef.current = opacity;\n // How a loaded shape with no color of its own is drawn: as the maps draw\n // it (their mark color), not in whatever the toolbar's color is now --\n // and it's saved still without one.\n const unsetColorRef = useRef(defaultColor ?? defaultColors(dark).mark);\n unsetColorRef.current = defaultColor ?? defaultColors(dark).mark;\n // The selected point/region's own `name` (a point's label text, or a\n // region's purely-descriptive name), mirroring `color`'s own pattern --\n // NOT derived from getSnapshot() on every render, since\n // updateFeatureProperties (called on every keystroke below) doesn't\n // itself trigger a re-render, which would leave a derived value stuck\n // showing whatever it read on the last unrelated render. Seeded/cleared\n // by the select/deselect listeners below instead.\n const [labelText, setLabelText] = useState(\"\");\n // Populated fresh every render by the effect below -- lets the map-setup\n // effect's own terra-draw listeners (registered once, see colorRef's own\n // doc comment on this pattern) call the latest refreshLabelPreview\n // without closing over a stale `labelText`.\n const refreshLabelPreviewRef = useRef<(() => void) | null>(null);\n // terra-draw's own select mode only ever has zero or one feature\n // selected at a time (see TOOLBAR's \"select\" mode) -- this mirrors that\n // via draw.on(\"select\"/\"deselect\") so the color picker knows whether a\n // change should recolor something instead of just setting the next\n // shape's color.\n const [selectedId, setSelectedId] = useState<string | null>(null);\n // Mirrors `selectedId` for the canvas keydown listener set up once\n // below (Backspace-deletes-the-selection), same reasoning as colorRef.\n const selectedIdRef = useRef(selectedId);\n selectedIdRef.current = selectedId;\n const labelColorsRef = useRef(labelColors ?? defaultColors(dark));\n labelColorsRef.current = labelColors ?? defaultColors(dark);\n // Keeps LABEL_PREVIEW_SOURCE (the editor's own text-rendering layer,\n // added in the style.load handler below since terra-draw's point mode\n // can't render text itself) in sync with every named point -- including,\n // for the currently selected feature only, `labelText` itself rather\n // than its last-saved `name` property, so a keystroke shows up\n // immediately instead of only once the point is deselected (terra-draw's\n // updateFeatureProperties, called on every keystroke by the text field\n // below, doesn't reliably fire draw's own \"change\" event).\n useEffect(() => {\n const draw = drawRef.current;\n const map = mapRef.current;\n const source = map?.getSource(LABEL_PREVIEW_SOURCE) as maplibregl.GeoJSONSource | undefined;\n const refresh = () => {\n const currentDraw = drawRef.current;\n const currentSource = mapRef.current?.getSource(LABEL_PREVIEW_SOURCE) as maplibregl.GeoJSONSource | undefined;\n if (!currentDraw || !currentSource) return;\n const features: Feature[] = [];\n for (const f of currentDraw.getSnapshot()) {\n if (f.geometry?.type !== \"Point\") continue;\n const isSelected = String(f.id) === selectedId;\n const name = (isSelected ? labelText : (f.properties?.name as string | undefined))?.trim();\n if (!name) continue;\n features.push({\n type: \"Feature\", geometry: f.geometry,\n properties: { name, color: f.properties?.color as string | undefined },\n });\n }\n currentSource.setData({ type: \"FeatureCollection\", features });\n };\n refreshLabelPreviewRef.current = refresh;\n if (draw && source) refresh();\n }, [labelText, selectedId]);\n // Every placed image overlay -- a wholly separate system from terra-draw\n // (which has no image geometry type), see the block of effects/handlers\n // below this component's map-setup effect.\n const [overlays, setOverlays] = useState<ImageOverlayDraft[]>([]);\n // Mirrors `overlays` for startMove's onUp (below), set up once per mount\n // and so unable to see a later opacity edit via closure alone -- same\n // colorRef/selectedIdRef pattern as elsewhere in this file.\n const overlaysRef = useRef(overlays);\n overlaysRef.current = overlays;\n // Which overlay's move/resize/delete handles are currently showing --\n // set on mousedown over that overlay's image (see mountOverlay), cleared\n // by clicking anywhere else on the map (see the map-setup effect's own\n // mousedown handler) or by deleting the selected overlay itself.\n const [selectedOverlayId, setSelectedOverlayId] = useState<string | null>(null);\n // Which overlays currently show their 4 free-transform corner handles\n // (in addition to the always-available delete/resize/rotate) -- purely a\n // display preference, never touched by geometry (see\n // setCornerHandlesVisible's own doc comment), so it lives here rather\n // than on ImageOverlayDraft/`overlays` state.\n const [warpHandleIds, setWarpHandleIds] = useState<Set<string>>(new Set());\n // Whether terra-draw currently holds any shape.\n const [hasFeatures, setHasFeatures] = useState(false);\n // What was set aside when loading (map-edit's model) -- the properties,\n // multi-part groups and track times terra-draw doesn't keep, put back by\n // getResult. Null with nothing loaded.\n const sessionRef = useRef<EditSession | null>(null);\n // How many of the loaded shapes terra-draw couldn't take, shown locked.\n const [lockedCount, setLockedCount] = useState(0);\n const [lockedNoticeDismissed, setLockedNoticeDismissed] = useState(false);\n\n const hasDrawn = hasFeatures || overlays.length > 0;\n const hasContent = hasDrawn || lockedCount > 0;\n const onStatusRef = useRef(onStatus);\n onStatusRef.current = onStatus;\n useEffect(() => { onStatusRef.current?.({ hasDrawn, hasContent }); }, [hasDrawn, hasContent]);\n\n useEffect(() => {\n if (!containerEl) return;\n const map = new maplibregl.Map({\n container: containerEl,\n style: mapStyleUrl(dark, null),\n center: [0, 20],\n zoom: 1.5,\n attributionControl: { compact: true },\n });\n mapRef.current = map;\n map.addControl(new maplibregl.NavigationControl({ showCompass: false }), \"top-right\");\n // maplibre's own default: holding Ctrl and dragging (or a two-finger\n // touch twist) rotates/pitches the *camera*, which collides directly\n // with terra-draw's own rotate gesture for rotating a *selected shape*\n // (see the select mode's `rotateable` flag below) -- found live,\n // holding the rotate key and dragging a vertex was spinning the whole\n // map instead of the shape. This editor has no use for a tilted/\n // rotated basemap anyway, so the camera's own rotate/pitch is disabled\n // outright rather than trying to make the two coexist.\n map.dragRotate.disable();\n map.touchZoomRotate.disableRotation();\n map.keyboard.disableRotation();\n\n // Every drawing mode's color comes from the feature's own `color`\n // property, not a fixed style -- colorRef (above) is what the styling\n // functions actually read, kept live via a ref rather than closing\n // over `color` state directly, since these mode instances are built\n // once per map (this effect is keyed on `containerEl`, not `color`)\n // and terra-draw calls a styling function fresh on every render, not\n // just at construction time.\n const readColor = (feature: GeoJSONStoreFeatures): HexColor =>\n (feature.properties.color as HexColor | undefined) ?? (unsetColorRef.current as HexColor);\n // Same pattern as readColor, for a region's own `opacity` property --\n // only polygon/rectangle modes take a `fillOpacity` style at all (point/\n // line have nothing to fill).\n const readOpacity = (feature: GeoJSONStoreFeatures): number =>\n (feature.properties.opacity as number | undefined) ?? UNSET_OPACITY;\n\n const draw = new TerraDraw({\n adapter: new TerraDrawMapLibreGLAdapter({ map }),\n modes: [\n new TerraDrawPointMode({ styles: { pointColor: readColor } }),\n new TerraDrawLineStringMode({ styles: { lineStringColor: readColor } }),\n new TerraDrawPolygonMode({ styles: { fillColor: readColor, fillOpacity: readOpacity, outlineColor: readColor } }),\n new TerraDrawRectangleMode({ styles: { fillColor: readColor, fillOpacity: readOpacity, outlineColor: readColor } }),\n // Dragging (both a whole feature and its individual vertices) and\n // deletion (terra-draw's own default keybinding, Delete/Backspace\n // on the current selection) are what this editor needs from\n // Select for every mode; `rotateable` additionally turns on\n // terra-draw's own built-in rotate gesture (hold R while dragging\n // a selected shape's vertex) for anything 2D enough for \"rotate\"\n // to mean something -- not `point`, a single vertex has nothing to\n // rotate around.\n new TerraDrawSelectMode({\n // While a feature is selected, terra-draw renders it through\n // *this* mode's own styling, not the drawing mode that created it\n // (see TerraDraw's own per-feature style dispatch: only the\n // selected feature goes through TerraDrawSelectMode.styleFeature;\n // every other feature keeps using its own mode's, which is why an\n // unselected shape's color/opacity already reflects its own\n // properties fine). Without these, the selected-state styling\n // falls back to terra-draw's fixed defaults regardless of\n // `feature.properties` -- so dragging the opacity slider (or\n // recoloring) while a shape is actively selected had no visible\n // effect until it was deselected. Found live.\n styles: {\n selectedPointColor: readColor,\n selectedLineStringColor: readColor,\n selectedPolygonColor: readColor,\n selectedPolygonOutlineColor: readColor,\n selectedPolygonFillOpacity: readOpacity,\n },\n // Half terra-draw's own default (40px) -- with labels sitting\n // right next to their point (see LABEL_PREVIEW_LAYER's\n // text-offset below) and vertices sometimes placed close\n // together, the default hit-test radius made clicking one point\n // too likely to grab a neighboring one instead. Found live.\n pointerDistance: 20,\n // Every field restated (terra-draw's own type doesn't allow a\n // partial override), only `rotate` actually changed from its\n // default -- plain \"r\" instead of the default Ctrl+R, an\n // awkward two-handed chord to hold through an entire drag. Bare\n // \"r\" is safe here the same way Backspace-delete is (see the\n // canvas keydown listener below): terra-draw's own keydown\n // listener is bound to the map canvas specifically, so it never\n // fires while typing \"r\" into a text field.\n keyEvents: { deselect: \"Escape\", delete: \"Delete\", rotate: [\"r\"], scale: [\"Control\", \"s\"] },\n flags: {\n point: { feature: { draggable: true } },\n linestring: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n polygon: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n rectangle: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n },\n }),\n ],\n });\n drawRef.current = draw;\n draw.on(\"change\", () => {\n // Same guidance-point exclusion as getResult's own filter below --\n // otherwise a shape's selection handles alone (nothing actually\n // drawn) would count as \"has features\".\n setHasFeatures(\n draw.getSnapshot().some((f) => f.geometry != null && !f.properties?.selectionPoint && !f.properties?.midPoint),\n );\n refreshLabelPreviewRef.current?.();\n });\n // Shared by the \"select\" listener below and the finish handler just\n // under it: selecting an existing feature and just having finished\n // drawing a new one both need the color/opacity/label widgets to catch\n // up to *that* feature's own properties, not whatever the toolbar was\n // last left showing. `id` null means deselected -- nothing to edit, so\n // the widgets themselves go away entirely (see selectedFeature/\n // selectedIsRegion in the render body below).\n function syncSelection(id: string | null) {\n setSelectedId(id);\n const feature = id ? draw.getSnapshot().find((f) => String(f.id) === id) : undefined;\n setLabelText((feature?.properties?.name as string | undefined) ?? \"\");\n if (feature) {\n // An uncolored shape shows the color it's drawn in.\n setColor((feature.properties?.color as string | undefined) ?? unsetColorRef.current);\n setOpacity((feature.properties?.opacity as number | undefined) ?? UNSET_OPACITY);\n // Mirrors the overlay mousedown handler's own deselectFeature call\n // -- an image overlay and a drawn shape are mutually exclusive\n // selections, so a shape becoming selected clears any overlay\n // selection the same way.\n setSelectedOverlayId(null);\n }\n }\n // A shape takes the toolbar's current color (and, for a region, opacity)\n // the moment it's finished drawing -- colorRef/opacityRef (not `color`/\n // `opacity` state) since this listener, like the mode instances above,\n // is registered once per map. Opacity only for polygon/rectangle (both\n // land here as \"polygon\"/\"rectangle\" -- see modeRef): a point or line\n // has no fill for it to mean anything on.\n draw.on(\"finish\", (id) => {\n const isRegion = modeRef.current === \"polygon\" || modeRef.current === \"rectangle\";\n draw.updateFeatureProperties(\n id,\n isRegion ? { color: colorRef.current, opacity: opacityRef.current } : { color: colorRef.current },\n );\n // Every finished shape drops straight into Select mode with itself\n // selected -- lets someone place a boundary, say, and immediately\n // see/adjust its color and opacity without an extra click to the\n // Select tool and back onto the shape it just placed.\n draw.setMode(\"select\");\n setMode(\"select\");\n draw.selectFeature(id);\n syncSelection(String(id));\n });\n draw.on(\"select\", (id) => syncSelection(String(id)));\n draw.on(\"deselect\", () => syncSelection(null));\n\n // terra-draw's own delete keybinding only recognizes the literal\n // \"Delete\" key (terra-draw-maplibre-gl-adapter's default keyEvents) --\n // on a Mac laptop keyboard, the key labelled \"delete\" actually sends\n // \"Backspace\" (only Fn+Delete sends \"Delete\"), so without this a Mac\n // user's most natural keypress would silently do nothing. Bound to\n // the same canvas element terra-draw's own keydown listener uses\n // (getMapEventElement() in that adapter), so -- like terra-draw's own\n // handler -- this only fires while the map canvas has focus, never\n // while typing in a text field.\n const canvas = map.getCanvas();\n const onCanvasKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Backspace\" || !selectedIdRef.current) return;\n try {\n draw.removeFeatures([selectedIdRef.current]);\n } catch {\n // Selection may already be stale (e.g. removed some other way) --\n // nothing more to do.\n }\n setSelectedId(null);\n };\n canvas.addEventListener(\"keydown\", onCanvasKeyDown);\n\n // Some WebKit-based environments (found live: a desktop build's native\n // window) never dispatch PointerEvents for mouse input, even though\n // ordinary MouseEvents work fine there -- map pan/zoom and the\n // image-overlay drag below both ride on mousedown/mousemove/mouseup and\n // both work. terra-draw's own Select mode listens *exclusively* for\n // pointerdown/pointermove/pointerup on the map canvas (see\n // TerraDrawBaseAdapter), so without a bridge, selecting a shape to drag\n // it silently does nothing on such a platform while every other\n // gesture in this editor keeps working. Detected once at runtime -- a\n // \"mousedown\" on the canvas not followed by a real \"pointerdown\" within\n // a frame means this environment isn't dispatching pointer events for\n // mouse input at all, so from then on every mouse event on the canvas\n // is re-dispatched as the equivalent pointer event. terra-draw's own\n // listeners only read clientX/clientY/button/isPrimary/target, none of\n // which require an actual PointerEvent instance -- a MouseEvent with\n // `isPrimary` patched on satisfies them exactly the same.\n let sawNativePointerdown = false;\n let pointerBridgeActive = false;\n let pendingFirstMouseDown: MouseEvent | null = null;\n const onNativePointerDown = () => { sawNativePointerdown = true; };\n canvas.addEventListener(\"pointerdown\", onNativePointerDown, { once: true });\n const dispatchAsPointerEvent = (type: string, e: MouseEvent) => {\n const synthetic = new MouseEvent(type, {\n bubbles: true, cancelable: true, view: window,\n clientX: e.clientX, clientY: e.clientY, button: e.button, buttons: e.buttons,\n });\n Object.defineProperty(synthetic, \"isPrimary\", { value: true });\n canvas.dispatchEvent(synthetic);\n };\n const onMouseDownBridge = (e: MouseEvent) => {\n if (pointerBridgeActive) { dispatchAsPointerEvent(\"pointerdown\", e); return; }\n if (sawNativePointerdown) return;\n pendingFirstMouseDown = e;\n requestAnimationFrame(() => {\n if (sawNativePointerdown || !pendingFirstMouseDown) return;\n pointerBridgeActive = true;\n dispatchAsPointerEvent(\"pointerdown\", pendingFirstMouseDown);\n pendingFirstMouseDown = null;\n });\n };\n const onMouseMoveBridge = (e: MouseEvent) => { if (pointerBridgeActive) dispatchAsPointerEvent(\"pointermove\", e); };\n const onMouseUpBridge = (e: MouseEvent) => { if (pointerBridgeActive) dispatchAsPointerEvent(\"pointerup\", e); };\n canvas.addEventListener(\"mousedown\", onMouseDownBridge);\n canvas.addEventListener(\"mousemove\", onMouseMoveBridge);\n canvas.addEventListener(\"mouseup\", onMouseUpBridge);\n\n // Selects whichever image overlay (if any) was clicked, deselects\n // otherwise, and kicks off that overlay's move-drag -- all in one\n // map-wide handler rather than a per-overlay one, since raster/image\n // layers can't be hit-tested via maplibre's layer-filtered events (see\n // OverlayMount's own doc comment). Does its own point-in-quad check\n // (a rotated overlay's screen footprint isn't axis-aligned) against\n // every mounted overlay's live geometry, topmost (last-added) first,\n // mirroring how they're actually layered on screen.\n map.on(\"mousedown\", (e) => {\n // Marker handles (delete/resize/rotate/corner) are DOM elements\n // appended into maplibre's own canvas container, not the canvas\n // itself -- they still receive this same \"mousedown\" event, so\n // without this check a click that landed on one would also match the\n // point-in-quad test below (a handle sits right at or near the box's\n // own edge) and start a move, fighting the marker's own native drag\n // (found live: dragging the resize handle just moved the image\n // instead of resizing it -- the same bug recurred for the 4 warp-\n // mode corner handles until they were added to this same check).\n // Bail out entirely for a click on any handle and let its own\n // listener (Marker's built-in drag, or the delete element's own\n // click handler) run uncontested.\n const target = e.originalEvent.target;\n if (target instanceof Node) {\n for (const mount of overlayMountsRef.current.values()) {\n if (\n mount.deleteMarker.getElement().contains(target)\n || mount.resizeMarker.getElement().contains(target)\n || mount.rotateMarker.getElement().contains(target)\n || mount.cornerMarkers.some((marker) => marker.getElement().contains(target))\n ) return;\n }\n }\n // A drawn shape (point/line/region) always renders above every image\n // overlay in this editor (see OVERLAY_ANCHOR_LAYER's own doc\n // comment), but the point-in-quad test below has no notion of that --\n // it only asks \"is this pixel inside some overlay's bounds\", so a\n // shape drawn on top of (or overlapping) an image used to have its\n // clicks hijacked into moving that image out from under it instead of\n // ever reaching terra-draw's own selection. Found live: a rectangle\n // sitting over an image overlay was simply unclickable. Checking what\n // maplibre actually rendered at this pixel first -- rather than\n // reimplementing terra-draw's own per-geometry-type hit testing here\n // -- defers to terra-draw whenever a shape is really the topmost\n // thing at this point, same as a sighted user would expect from what\n // they're looking at.\n if (map.queryRenderedFeatures(e.point, { layers: TERRA_DRAW_LAYERS }).length > 0) return;\n const mounts = [...overlayMountsRef.current.entries()].reverse();\n for (const [id, mount] of mounts) {\n const corners = mount.box.corners.map((c) => map.project(c));\n if (pointInQuad(e.point, corners)) {\n // An image overlay and a drawn shape are mutually exclusive\n // selections -- deselect any terra-draw feature first, or its\n // own color/name/opacity controls would keep showing alongside\n // this overlay's, none of them meaningful for the other's kind\n // of item. Found live.\n if (selectedIdRef.current) draw.deselectFeature(selectedIdRef.current);\n setSelectedOverlayId(id);\n mount.startMove(e);\n return;\n }\n }\n setSelectedOverlayId(null);\n });\n\n // A failed style/tile fetch is the one thing that can leave this view\n // blank for a reason the user can't guess.\n map.on(\"error\", (e) => {\n const message = (e.error as Error | undefined)?.message ?? \"\";\n if (/style|sprite|tile|fetch|network|Failed/i.test(message)) fail(message || live.current.strings.basemapFailed);\n });\n\n map.on(\"style.load\", () => {\n // draw.start() registers terra-draw's own sources/layers on the map,\n // which maplibre only allows once the style has actually finished\n // loading -- wrapped so a failure here (a version mismatch, a mode\n // misconfiguration, ...) surfaces as a visible error instead of\n // leaving `ready` false forever.\n try {\n // A permanent, invisible layer added before draw.start() -- image\n // overlays (mountOverlay below) always insert themselves directly\n // below this anchor, so they stay under terra-draw's own shape\n // layers (added next, appended above everything as normal) no\n // matter what order shapes/images actually get added in during the\n // session: images first, geometries on top, matching how a photo\n // of an old map should sit relative to pins/routes drawn over it.\n map.addLayer({ id: OVERLAY_ANCHOR_LAYER, type: \"background\", paint: { \"background-opacity\": 0 } });\n map.addSource(LOCKED_SOURCE, { type: \"geojson\", data: { type: \"FeatureCollection\", features: [] } });\n map.addLayer({\n id: LOCKED_FILL_LAYER, type: \"fill\", source: LOCKED_SOURCE,\n filter: [\"==\", [\"geometry-type\"], \"Polygon\"],\n paint: { \"fill-color\": [\"coalesce\", [\"get\", \"color\"], \"#888888\"], \"fill-opacity\": 0.15 },\n });\n map.addLayer({\n id: LOCKED_LINE_LAYER, type: \"line\", source: LOCKED_SOURCE,\n filter: [\"any\", [\"==\", [\"geometry-type\"], \"Polygon\"], [\"==\", [\"geometry-type\"], \"LineString\"]],\n paint: { \"line-color\": [\"coalesce\", [\"get\", \"color\"], \"#888888\"], \"line-width\": 2, \"line-dasharray\": [2, 2] },\n });\n draw.start();\n draw.setMode(\"select\");\n // Added after draw.start() so it stacks above terra-draw's own\n // point layer -- see LABEL_PREVIEW_SOURCE's own doc comment on why\n // this mirror exists at all. refreshLabelPreviewRef is populated by\n // the effect above; called once here too, in case any features\n // were already loaded before this handler ran.\n const colors = labelColorsRef.current;\n map.addSource(LABEL_PREVIEW_SOURCE, { type: \"geojson\", data: EMPTY_LABEL_PREVIEW });\n map.addLayer({\n id: LABEL_PREVIEW_LAYER,\n type: \"symbol\",\n source: LABEL_PREVIEW_SOURCE,\n layout: {\n \"text-field\": [\"get\", \"name\"],\n \"text-size\": 12,\n \"text-font\": [\"Noto Sans Regular\"],\n // Offset right rather than centered on the point -- centered\n // text sat directly on top of the point, making it hard to see\n // (and, in the real map views, click) the point itself.\n \"text-anchor\": \"left\",\n \"text-offset\": [0.6, 0],\n },\n paint: {\n \"text-color\": [\"coalesce\", [\"get\", \"color\"], colors.text],\n \"text-halo-color\": colors.surface,\n \"text-halo-width\": 1.5,\n },\n });\n refreshLabelPreviewRef.current?.();\n } catch (err) {\n fail(err instanceof Error ? err.message : String(err));\n } finally {\n setReady(true);\n }\n });\n\n return () => {\n draw.stop();\n canvas.removeEventListener(\"keydown\", onCanvasKeyDown);\n canvas.removeEventListener(\"pointerdown\", onNativePointerDown);\n canvas.removeEventListener(\"mousedown\", onMouseDownBridge);\n canvas.removeEventListener(\"mousemove\", onMouseMoveBridge);\n canvas.removeEventListener(\"mouseup\", onMouseUpBridge);\n // Markers aren't part of the map's own style/source tree -- map.remove()\n // below doesn't clean these up on its own.\n for (const mount of overlayMountsRef.current.values()) {\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n release(mount.imageUrl);\n }\n overlayMountsRef.current.clear();\n map.remove();\n mapRef.current = null;\n drawRef.current = null;\n };\n // `dark` only matters for the very first style URL -- a scheme flip\n // while this editor happens to be open isn't worth a style reload.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [containerEl]);\n\n // Mounts one image overlay onto the live map: a maplibre `image` source +\n // `raster` layer (created once, then moved/resized via setCoordinates\n // rather than recreated) plus its handles and a whole-image move\n // gesture. Called both when a new image is added and when the initial\n // overlays are loaded in (the effect below).\n async function mountOverlay(overlay: ImageOverlayDraft) {\n const map = mapRef.current;\n if (!map) return;\n const sourceId = `img-${overlay.id}`;\n const box: { corners: OverlayCorners } = { corners: overlay.corners };\n const imageUrl = await live.current.resolveImage(overlay.image);\n map.addSource(sourceId, { type: \"image\", url: imageUrl, coordinates: box.corners });\n // beforeId keeps this under terra-draw's own shape layers -- see\n // OVERLAY_ANCHOR_LAYER's own doc comment.\n map.addLayer({ id: sourceId, type: \"raster\", source: sourceId }, OVERLAY_ANCHOR_LAYER);\n map.setPaintProperty(sourceId, \"raster-opacity\", overlay.opacity ?? 1);\n\n // The live geometry during a drag -- `overlays` state (below) is only\n // synced at gesture end, both for perf (no re-render per drag frame)\n // and because it's only read back at the end, not mid-drag.\n const setCorners = (next: OverlayCorners) => {\n box.corners = next;\n (map.getSource(sourceId) as maplibregl.ImageSource | undefined)?.setCoordinates(box.corners);\n };\n const commit = () => {\n setOverlays((prev) => prev.map((o) => (o.id === overlay.id ? { ...o, corners: box.corners } : o)));\n };\n\n // Not added to the map yet -- all handles are selection-gated (see the\n // sync effect below), same as terra-draw's own vertex handles only\n // showing up once a shape is actually selected, rather than cluttering\n // every image on screen with several more controls all the time.\n const words = live.current.strings;\n const deleteEl = document.createElement(\"div\");\n deleteEl.textContent = \"\u00D7\";\n deleteEl.title = words.removeImage;\n Object.assign(deleteEl.style, OVERLAY_HANDLE_STYLE);\n const deleteMarker = new maplibregl.Marker({ element: deleteEl, anchor: \"center\" });\n deleteEl.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n unmountOverlay(overlay.id);\n setOverlays((prev) => prev.filter((o) => o.id !== overlay.id));\n setSelectedOverlayId((current) => (current === overlay.id ? null : current));\n });\n\n const resizeEl = document.createElement(\"div\");\n resizeEl.textContent = \"\u2198\";\n resizeEl.title = words.resizeImage;\n Object.assign(resizeEl.style, OVERLAY_HANDLE_STYLE);\n const resizeMarker = new maplibregl.Marker({ element: resizeEl, anchor: \"center\", draggable: true });\n // Captured at the start of each drag: the corners and the handle's own\n // distance from their shared center right then, so every subsequent\n // \"drag\" frame computes one clean scale factor relative to the drag's\n // own start (distance-now / distance-then) rather than compounding a\n // per-frame ratio, which would drift.\n let resizeStartCorners: OverlayCorners = box.corners;\n let resizeStartDist = 1;\n resizeMarker.on(\"dragstart\", () => {\n resizeStartCorners = box.corners;\n const center = overlayCenter(resizeStartCorners);\n const p = resizeMarker.getLngLat();\n resizeStartDist = Math.max(1e-9, mercatorDistance(center, [p.lng, p.lat]));\n });\n resizeMarker.on(\"drag\", () => {\n // Scales every corner's distance from their shared center by the\n // same factor (in Mercator-projected space -- see scalePoint's own\n // doc comment), so this works identically whether the current\n // corners describe a plain rectangle or an already-warped quad: the\n // exact shape is preserved either way, just bigger or smaller. No\n // separate \"aspect ratio\" to track at all -- a uniform scale from\n // center can't distort it.\n const center = overlayCenter(resizeStartCorners);\n const p = resizeMarker.getLngLat();\n const scale = Math.max(0.02, mercatorDistance(center, [p.lng, p.lat]) / resizeStartDist);\n setCorners(resizeStartCorners.map((c) => scalePoint(c, center, scale)) as OverlayCorners);\n repositionHandles();\n });\n resizeMarker.on(\"dragend\", commit);\n\n const rotateEl = document.createElement(\"div\");\n rotateEl.textContent = \"\u21BB\";\n rotateEl.title = words.rotateImage;\n Object.assign(rotateEl.style, OVERLAY_HANDLE_STYLE);\n const rotateMarker = new maplibregl.Marker({ element: rotateEl, anchor: \"center\", draggable: true });\n // Same start-of-drag capture as resize, but for an angle instead of a\n // distance: every \"drag\" frame rotates the *start* corners by\n // (current handle bearing - start handle bearing), an incremental\n // delta from center rather than an absolute angle -- there's no\n // persisted \"rotation\" field to be absolute relative to anymore (see\n // rotateHandleAnchor's own doc comment on why that's fine).\n let rotateStartCorners: OverlayCorners = box.corners;\n let rotateStartAngle = 0;\n rotateMarker.on(\"dragstart\", () => {\n rotateStartCorners = box.corners;\n const center = overlayCenter(rotateStartCorners);\n const p = rotateMarker.getLngLat();\n rotateStartAngle = mercatorBearing(center, [p.lng, p.lat]);\n });\n rotateMarker.on(\"drag\", () => {\n const center = overlayCenter(rotateStartCorners);\n const p = rotateMarker.getLngLat();\n const delta = mercatorBearing(center, [p.lng, p.lat]) - rotateStartAngle;\n setCorners(rotateStartCorners.map((c) => rotatePoint(c, center, delta)) as OverlayCorners);\n repositionHandles();\n });\n rotateMarker.on(\"dragend\", commit);\n\n // Free-transform's 4 independent corner handles -- one per index of\n // maplibre's own `coordinates` order (top-left, top-right,\n // bottom-right, bottom-left). Each drag writes only its own corner,\n // leaving the other 3 exactly where they were -- the actual \"rubber\n // sheet\" warp, as opposed to resize/rotate's whole-shape transforms.\n const cornerMarkers = [0, 1, 2, 3].map((i) => {\n const el = document.createElement(\"div\");\n el.title = words.warpCorner;\n Object.assign(el.style, OVERLAY_HANDLE_STYLE);\n const marker = new maplibregl.Marker({ element: el, anchor: \"center\", draggable: true });\n marker.on(\"drag\", () => {\n const corners = [...box.corners] as OverlayCorners;\n const p = marker.getLngLat();\n corners[i] = [p.lng, p.lat];\n setCorners(corners);\n repositionHandles();\n });\n marker.on(\"dragend\", commit);\n return marker;\n }) as [maplibregl.Marker, maplibregl.Marker, maplibregl.Marker, maplibregl.Marker];\n\n // Snaps every handle back onto the box's current corners -- called\n // after every geometry change (move, resize, rotate, corner drag) so\n // they stay glued to the image instead of drifting back to a stale\n // position. Delete/resize/rotate always track the actual corners (no\n // separate \"rect\" representation to fall back to); the 4 corner\n // handles are additionally repositioned here too, since a resize or\n // rotate gesture moves them right along with everything else.\n const repositionHandles = () => {\n const [topLeft, topRight, bottomRight, bottomLeft] = box.corners;\n const center = overlayCenter(box.corners);\n deleteMarker.setLngLat(center);\n resizeMarker.setLngLat(bottomRight);\n rotateMarker.setLngLat(rotateHandleAnchor(box.corners, center));\n cornerMarkers[0].setLngLat(topLeft);\n cornerMarkers[1].setLngLat(topRight);\n cornerMarkers[2].setLngLat(bottomRight);\n cornerMarkers[3].setLngLat(bottomLeft);\n };\n\n // Move -- dragging anywhere on the image itself (not a small handle;\n // the image can be much bigger than one). Called by the map-wide\n // mousedown handler in the map-setup effect once its own point-in-box\n // test picks this overlay out (see OverlayMount's own doc comment on\n // why that test exists instead of a listener here). Tracked via plain\n // document listeners rather than map-scoped ones so a fast drag that\n // leaves the map div doesn't get stuck without a mouseup.\n const startMove = (e: maplibregl.MapMouseEvent) => {\n e.preventDefault();\n map.dragPan.disable();\n // Nearly-transparent while being dragged so whatever's underneath\n // (other images, the base map) stays visible for positioning --\n // restored on mouseup.\n map.setPaintProperty(sourceId, \"raster-opacity\", OVERLAY_DRAG_OPACITY);\n // In screen pixels, not raw lng/lat degrees -- a fixed degree offset\n // covers a different on-screen distance depending on latitude (Web\n // Mercator isn't uniformly scaled north-south), so translating this\n // way visibly grew/shrank the image as it crossed latitudes mid-drag,\n // even though its own lat/lng span never actually changed. Found\n // live. Projecting each corner once up front, shifting all of them by\n // the same pixel delta the cursor has moved, and unprojecting back\n // keeps the dragged image's on-screen size constant -- the same\n // \"work in projected space, not raw degrees\" fix rotatePoint/\n // scalePoint already apply to rotate/resize (see their own doc\n // comments), just via maplibre's own project/unproject here, since\n // screen pixels (not zoom-independent normalized Mercator units) are\n // exactly what a mouse drag is measured in.\n const startPoint = e.point;\n const startScreenCorners = box.corners.map((corner) => map.project(corner));\n const container = map.getContainer();\n const onMove = (moveEvent: MouseEvent) => {\n const rect = container.getBoundingClientRect();\n const dx = moveEvent.clientX - rect.left - startPoint.x;\n const dy = moveEvent.clientY - rect.top - startPoint.y;\n const newCorners = startScreenCorners.map((screenCorner) => {\n const lngLat = map.unproject([screenCorner.x + dx, screenCorner.y + dy]);\n return [lngLat.lng, lngLat.lat] as [number, number];\n });\n setCorners(newCorners as OverlayCorners);\n repositionHandles();\n };\n const onUp = () => {\n document.removeEventListener(\"mousemove\", onMove);\n document.removeEventListener(\"mouseup\", onUp);\n map.dragPan.enable();\n // Restores this overlay's own opacity (not necessarily fully\n // opaque) -- overlaysRef, not the `overlay` param captured at\n // mount time, so an opacity edit made since this overlay was\n // mounted is still honored.\n const current = overlaysRef.current.find((o) => o.id === overlay.id);\n map.setPaintProperty(sourceId, \"raster-opacity\", current?.opacity ?? 1);\n commit();\n };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n };\n\n repositionHandles();\n overlayMountsRef.current.set(overlay.id, {\n sourceId, box, deleteMarker, resizeMarker, rotateMarker, cornerMarkers, startMove, setCorners, repositionHandles, imageUrl,\n });\n }\n\n function unmountOverlay(id: string) {\n const map = mapRef.current;\n const mount = overlayMountsRef.current.get(id);\n if (!map || !mount) return;\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n if (map.getLayer(mount.sourceId)) map.removeLayer(mount.sourceId);\n if (map.getSource(mount.sourceId)) map.removeSource(mount.sourceId);\n release(mount.imageUrl);\n overlayMountsRef.current.delete(id);\n }\n\n /** Shows or hides one overlay's 4 free-transform corner handles -- the\n * \"Scale\" / \"Transform\" SegmentedControl's onChange. Purely a display\n * preference (see warpHandleIds' own doc comment): move/resize/rotate/\n * delete always work the same way regardless of this, uniformly\n * transforming whatever the current corners are (see mountOverlay), so\n * picking either option never touches geometry at all. */\n function setCornerHandlesVisible(id: string, visible: boolean) {\n setWarpHandleIds((prev) => {\n const next = new Set(prev);\n if (visible) next.add(id); else next.delete(id);\n return next;\n });\n }\n\n // Shows the selected overlay's delete/resize/rotate handles (always) and\n // its 4 free-transform corner handles (only while its id is in\n // warpHandleIds), hides every other overlay's -- mountOverlay creates\n // every marker detached (not added to the map), so a freshly-added or\n // freshly-loaded overlay correctly starts with nothing showing until\n // it's actually clicked.\n const showCornerHandles = selectedOverlayId !== null && warpHandleIds.has(selectedOverlayId);\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n for (const [id, mount] of overlayMountsRef.current) {\n if (id !== selectedOverlayId) {\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n continue;\n }\n mount.deleteMarker.addTo(map);\n mount.resizeMarker.addTo(map);\n mount.rotateMarker.addTo(map);\n for (const marker of mount.cornerMarkers) (showCornerHandles ? marker.addTo(map) : marker.remove());\n }\n }, [selectedOverlayId, showCornerHandles]);\n\n const selectedOverlay = overlays.find((o) => o.id === selectedOverlayId) ?? null;\n\n /** Patches the selected overlay's name/opacity/order in `overlays` state\n * -- and, for opacity, also pushes the change straight onto the live\n * mounted layer for immediate visual feedback, the same way color\n * changes update terra-draw's own selected feature in place. No-op with\n * nothing selected. */\n function updateSelectedOverlay(patch: Partial<Pick<ImageOverlayDraft, \"name\" | \"opacity\" | \"order\">>) {\n if (!selectedOverlayId) return;\n setOverlays((prev) => prev.map((o) => (o.id === selectedOverlayId ? { ...o, ...patch } : o)));\n if (patch.opacity !== undefined) {\n const mount = overlayMountsRef.current.get(selectedOverlayId);\n if (mount) mapRef.current?.setPaintProperty(mount.sourceId, \"raster-opacity\", patch.opacity);\n }\n }\n\n // Loads what's to be edited once the map/draw instance is ready and the\n // host has it, then frames it -- shapes and image overlays together (an\n // overlay-only item has no shape to frame), or the host's initialView\n // when there's nothing to frame.\n const loaded = useRef(false);\n useEffect(() => {\n if (!ready || !initial || loaded.current) return;\n const draw = drawRef.current;\n const map = mapRef.current;\n if (!draw || !map) return;\n loaded.current = true;\n const bounds = new maplibregl.LngLatBounds();\n if (initial.features.length > 0) {\n const session = prepareForEditing(initial.features);\n sessionRef.current = session;\n for (const geometry of showShapes(session, session)) extendBounds(bounds, geometry);\n }\n const drafts = initial.overlays.map((overlay): ImageOverlayDraft => ({ ...overlay, id: crypto.randomUUID() }));\n setOverlays(drafts);\n for (const draft of drafts) {\n // One image that won't load shouldn't keep the rest from editing.\n mountOverlay(draft).catch(() => {});\n for (const corner of draft.corners) bounds.extend(corner);\n }\n if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: 60, maxZoom: 17, duration: 0 });\n else if (initialView) map.jumpTo(initialView);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ready, initial]);\n\n /** Puts a session's parts on the canvas -- `added`, the ones new to it\n * (all of them on load, an import's after) -- locking any terra-draw\n * refuses (a polygon that crosses itself, say) so the save keeps it.\n * Returns every new part's geometry, for framing. */\n function showShapes(session: EditSession, added: EditSession): Geometry[] {\n const draw = drawRef.current;\n const map = mapRef.current;\n if (!draw || !map) return [];\n // Split into single, 2D parts with everything terra-draw won't keep\n // set aside (map-edit's model), so a multi-part shape, a GPS track or\n // a property this editor doesn't know survives the save.\n const parts: EditablePart[] = [...added.parts];\n const results = draw.addFeatures(parts.map((part) => ({\n type: \"Feature\" as const,\n geometry: part.geometry,\n properties: {\n mode: part.mode, sourceKey: part.sourceKey, color: part.color, name: part.name,\n ...(part.mode === \"polygon\" ? { opacity: part.opacity } : {}),\n },\n })) as GeoJSONStoreFeatures[]);\n results.forEach((result, i) => {\n if (!result.valid) lockPart(session, parts[i].sourceKey);\n });\n const locked = [...session.locked.values()];\n setLockedCount(locked.length);\n (map.getSource(LOCKED_SOURCE) as maplibregl.GeoJSONSource | undefined)?.setData({\n type: \"FeatureCollection\",\n features: locked.map((part) => ({ type: \"Feature\", geometry: part.geometry, properties: { color: part.color } })),\n });\n return [...parts, ...added.locked.values()].map((part) => part.geometry);\n }\n\n function handleModeChange(next: DrawMode) {\n // Guarded, not just disabled on the button below: terra-draw's own\n // setMode() throws (\"Terra Draw is not enabled\") until draw.start() has\n // actually run (the style.load handler above), and a click landing in\n // that window before `ready` flips would otherwise be an uncaught\n // exception -- found live.\n if (!ready) return;\n setMode(next);\n // Switching drawing tools while an image overlay is selected leaves it\n // selected otherwise -- the overlay mousedown handler and syncSelection\n // (map-setup effect above) only clear it from the *other* direction\n // (a shape getting selected), not a mere tool change with nothing\n // clicked yet.\n setSelectedOverlayId(null);\n drawRef.current?.setMode(next);\n }\n\n useImperativeHandle(ref, () => ({\n getResult() {\n // Geometry plus the editor's own color/name (and, for a region,\n // opacity) and the part's sourceKey -- terra-draw's other bookkeeping\n // properties (mode, id, ...) mean nothing outside the editor.\n // Everything set aside when loading is put back by assembleForSaving.\n //\n // Also excluded: terra-draw's own selection-mode guidance points --\n // the small vertex/midpoint handle dots it draws on a shape's corners\n // and edges while selected. Select mode stores those as ordinary\n // Point features in the same snapshot (tagged `selectionPoint`/\n // `midPoint`), so saving mid-selection without this filter wrote them\n // into the file as if they were real map-item points. Found live.\n const savedParts: SavedPart[] = (drawRef.current?.getSnapshot() ?? [])\n .filter((f) => f.geometry != null && !f.properties?.selectionPoint && !f.properties?.midPoint)\n .map((f) => {\n // Trimmed, and omitted entirely rather than written as \"\" -- a\n // label point placed but never typed into should round-trip as a\n // plain, nameless point (the presence of `name` is itself what\n // marks a point as a label), not an invisible label with empty\n // text.\n const name = (f.properties?.name as string | undefined)?.trim();\n // Opacity only for a region (Polygon) -- meaningless on a point/\n // line, which have nothing to fill (see readOpacity/opacityRef).\n // Color and opacity only as the shape has them: a drawn shape got\n // both when finished, and one loaded without them stays that way.\n const regionOpacity = f.geometry.type === \"Polygon\"\n ? f.properties?.opacity as number | undefined\n : undefined;\n const color = f.properties?.color as string | undefined;\n const sourceKey = f.properties?.sourceKey;\n return {\n ...(typeof sourceKey === \"string\" ? { sourceKey } : {}),\n geometry: f.geometry as EditableGeometry,\n ...(color !== undefined ? { color } : {}),\n ...(name ? { name } : {}),\n ...(regionOpacity !== undefined ? { opacity: regionOpacity } : {}),\n };\n });\n const session = sessionRef.current ?? { parts: [], sources: new Map(), locked: new Map() };\n return {\n features: assembleForSaving(session, savedParts),\n overlays: overlaysRef.current.map(({ image, corners, name, opacity, order }) => ({ image, corners, name, opacity, order })),\n };\n },\n drawnBounds() {\n const bounds = new maplibregl.LngLatBounds();\n for (const f of drawRef.current?.getSnapshot() ?? []) {\n if (f.geometry == null || f.properties?.selectionPoint || f.properties?.midPoint) continue;\n extendBounds(bounds, f.geometry as Geometry);\n }\n for (const overlay of overlaysRef.current) for (const corner of overlay.corners) bounds.extend(corner);\n return bounds.isEmpty() ? null : (bounds.toArray().flat() as [number, number, number, number]);\n },\n async addImage(image: string) {\n // The same image placed twice has no use: in Gramps Connect an\n // overlay's dates are its place's, so a second copy couldn't even be\n // given a different era -- it would just always show (or not) in\n // lockstep with the first.\n if (overlaysRef.current.some((o) => o.image === image)) return false;\n const map = mapRef.current;\n if (!map) return false;\n // Only to measure the image's own pixel dimensions: mountOverlay\n // asks for it again for its persistent `image` source.\n const url = await live.current.resolveImage(image);\n const element = await loadImageElement(url, live.current.strings.imageFailed).finally(() => release(url));\n const aspect = element.naturalWidth / element.naturalHeight;\n const centerScreen = map.project(map.getCenter());\n const halfWidthPx = 130;\n const halfHeightPx = halfWidthPx / aspect;\n const topLeft = map.unproject([centerScreen.x - halfWidthPx, centerScreen.y - halfHeightPx]);\n const bottomRight = map.unproject([centerScreen.x + halfWidthPx, centerScreen.y + halfHeightPx]);\n const draft: ImageOverlayDraft = {\n id: crypto.randomUUID(),\n image,\n corners: [\n [topLeft.lng, topLeft.lat], [bottomRight.lng, topLeft.lat],\n [bottomRight.lng, bottomRight.lat], [topLeft.lng, bottomRight.lat],\n ],\n // Leaves room to insert between existing overlays later without\n // renumbering.\n order: overlaysRef.current.length * 10,\n };\n setOverlays((prev) => [...prev, draft]);\n // Awaited so the overlay's mount exists before selecting it --\n // selecting one before it's mounted would have nothing for the\n // handle-visibility effect above to find. Auto-selected so its\n // resize/move handles are immediately visible: the initial placement\n // is only ever an approximation.\n await mountOverlay(draft);\n setSelectedOverlayId(draft.id);\n return true;\n },\n addFeatures(features: Feature[]) {\n const map = mapRef.current;\n if (!map || features.length === 0) return;\n const session = sessionRef.current ?? { parts: [], sources: new Map(), locked: new Map() };\n sessionRef.current = session;\n const bounds = new maplibregl.LngLatBounds();\n for (const geometry of showShapes(session, addToSession(session, features))) extendBounds(bounds, geometry);\n if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: 60, maxZoom: 17 });\n },\n // mountOverlay and friends read only refs: a fresh handle each render\n // is fine.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }));\n\n // Cheap to recompute on every render (getSnapshot() is just an array\n // read) rather than mirrored into its own state -- selectedId already\n // triggers a re-render via draw.on(\"select\"/\"deselect\") above, so this\n // stays in sync for free.\n const selectedFeature = selectedId ? drawRef.current?.getSnapshot().find((f) => String(f.id) === selectedId) : undefined;\n const selectedIsPoint = selectedFeature?.geometry?.type === \"Point\";\n // Covers both polygon and rectangle tools -- a rectangle is stored as a\n // Polygon feature under the hood.\n const selectedIsRegion = selectedFeature?.geometry?.type === \"Polygon\";\n\n function renderModeButton(entry: { mode: DrawMode; label: keyof MapEditorStrings }) {\n return (\n <Button\n key={entry.mode}\n size=\"xs\"\n variant={mode === entry.mode ? \"filled\" : \"default\"}\n disabled={!ready}\n onClick={() => handleModeChange(entry.mode)}\n >\n {strings[entry.label] as string}\n </Button>\n );\n }\n\n return (\n <Box style={{ position: \"absolute\", inset: 0, overflow: \"hidden\" }}>\n <style>{TOOLBAR_CSS}</style>\n <div ref={setContainerEl} style={{ position: \"absolute\", inset: 0 }} />\n\n {/* Left toolbar: which terra-draw mode is active, then the selected\n item's own options. */}\n <Stack\n gap={4}\n p={6}\n className={TOOLBAR_CLASS}\n style={{\n position: \"absolute\", top: toolbarTop, left: 12, zIndex: 3, borderRadius: 8,\n background: dark ? \"rgba(20,20,20,0.75)\" : \"rgba(255,255,255,0.85)\",\n }}\n >\n {/* Point/Line/Polygon/Rectangle -- the terra-draw creation tools,\n TOOLBAR's own order minus its trailing \"select\" entry, which\n renders last below. */}\n {TOOLBAR.filter((entry) => entry.mode !== \"select\").map(renderModeButton)}\n {/* Not a terra-draw mode (there's no drawing gesture for it, just\n the host's picker), so it never shows as \"active\" the way the\n others do -- but it's one more kind of thing to add, same as\n Point/Line/Rectangle, and more than one image is supported. */}\n {onAddImage && (\n <Button size=\"xs\" variant=\"default\" disabled={!ready} onClick={onAddImage}>\n {strings.image}\n </Button>\n )}\n {TOOLBAR.filter((entry) => entry.mode === \"select\").map(renderModeButton)}\n\n <Divider my={2} />\n <Text size=\"xs\" fw={600} c=\"dimmed\">{strings.editOptions}</Text>\n\n {/* Only a selected drawn shape (point/line/region) offers this --\n hidden, not just disabled, the rest of the time: a picker with\n nothing to recolor is more confusing left sitting there than\n gone. */}\n {selectedFeature && (\n <ColorInput\n size=\"xs\"\n value={color}\n onChange={(next) => {\n setColor(next);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { color: next });\n }}\n swatches={COLOR_SWATCHES}\n disabled={!ready}\n popoverProps={{ withinPortal: true, zIndex: 1000 }}\n />\n )}\n {/* A point's `name` places a text label on the map -- a label is\n always its own point. A region's `name` is purely descriptive,\n the same as an image overlay's own. */}\n {(selectedIsPoint || selectedIsRegion) && (\n <TextInput\n size=\"xs\"\n placeholder={selectedIsPoint ? strings.labelText : strings.regionName}\n value={labelText}\n onChange={(e) => {\n setLabelText(e.currentTarget.value);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { name: e.currentTarget.value });\n }}\n disabled={!ready}\n />\n )}\n {/* Only a selected region (polygon/rectangle) offers this, same\n reasoning as the color picker above. */}\n {selectedIsRegion && (\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\">{strings.fillOpacity}</Text>\n <Slider\n size=\"xs\"\n min={0.1}\n max={1}\n step={0.05}\n label={(v) => `${Math.round(v * 100)}%`}\n value={opacity}\n onChange={(v) => {\n setOpacity(v);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { opacity: v });\n }}\n disabled={!ready}\n />\n </Stack>\n )}\n {/* Only a selected image overlay offers this -- purely shows or\n hides the 4 corner-drag handles (see setCornerHandlesVisible's\n own doc comment). */}\n {selectedOverlayId && (\n <SegmentedControl\n size=\"xs\"\n value={showCornerHandles ? \"transform\" : \"scale\"}\n onChange={(value) => setCornerHandlesVisible(selectedOverlayId, value === \"transform\")}\n disabled={!ready}\n data={[\n { label: strings.scale, value: \"scale\" },\n { label: strings.transform, value: \"transform\" },\n ]}\n />\n )}\n {/* The selected image overlay's own name/opacity/order. Opacity\n applies live (see updateSelectedOverlay). */}\n {selectedOverlay && (\n <>\n {overlayNames && (\n <TextInput\n size=\"xs\"\n placeholder={strings.overlayName}\n value={selectedOverlay.name ?? \"\"}\n onChange={(e) => updateSelectedOverlay({ name: e.currentTarget.value })}\n disabled={!ready}\n />\n )}\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\">{strings.opacity}</Text>\n <Slider\n size=\"xs\"\n min={0.1}\n max={1}\n step={0.05}\n label={(v) => `${Math.round(v * 100)}%`}\n value={selectedOverlay.opacity ?? 1}\n onChange={(v) => updateSelectedOverlay({ opacity: v })}\n disabled={!ready}\n />\n </Stack>\n <NumberInput\n size=\"xs\"\n label={strings.stackingOrder}\n hideControls={false}\n value={selectedOverlay.order ?? 0}\n onChange={(v) => updateSelectedOverlay({ order: Number(v) || 0 })}\n disabled={!ready}\n />\n {renderOverlayOptions?.(selectedOverlay.image)}\n </>\n )}\n </Stack>\n\n {!ready && (\n <Group justify=\"center\" align=\"center\" style={{ position: \"absolute\", inset: 0, zIndex: 2 }}>\n <Loader size=\"sm\" />\n </Group>\n )}\n\n {lockedCount > 0 && !lockedNoticeDismissed && (\n <Alert\n color=\"yellow\"\n title={lockedCount === 1 ? strings.lockedOne : strings.lockedMany(lockedCount)}\n withCloseButton\n onClose={() => setLockedNoticeDismissed(true)}\n style={{ position: \"absolute\", bottom: 12, right: 12, zIndex: 3, maxWidth: 360 }}\n >\n {strings.lockedExplain}\n </Alert>\n )}\n </Box>\n );\n});\n\n/** How to use the map editor, for the host to show where it likes (Gramps\n * Connect: an info button's modal). */\nexport function MapEditorHelp({ strings: stringOverrides, images = true }: { strings?: Partial<MapEditorStrings>; images?: boolean }) {\n const strings = { ...MAP_EDITOR_ENGLISH, ...stringOverrides };\n return (\n <Stack gap=\"md\">\n <Text size=\"sm\" fw={600}>{strings.helpDrawing}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpPoint}</List.Item>\n <List.Item>\n {strings.helpLine}{\" \"}\n <Kbd>Enter</Kbd> {strings.helpEnterFinishes} <Kbd>Esc</Kbd> {strings.helpEscCancels}\n </List.Item>\n <List.Item>{strings.helpRectangle}</List.Item>\n {images && (\n <List.Item>{strings.helpImage} <Text span fw={600}>{strings.helpImages}</Text>{\" \"}\n {strings.helpBelow}\n </List.Item>\n )}\n </List>\n <Text size=\"sm\" fw={600}>{strings.helpEditing}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpSelect}</List.Item>\n <List.Item>{strings.helpVertex}</List.Item>\n <List.Item>{strings.helpColor}</List.Item>\n <List.Item>\n {strings.helpDelete} <Kbd>Delete</Kbd> {strings.helpOr} <Kbd>Backspace</Kbd>.\n </List.Item>\n <List.Item>\n {strings.helpRotate} <Kbd>R</Kbd>{\" \"}\n {strings.helpRotateHandle}\n </List.Item>\n </List>\n {images && (\n <>\n <Text size=\"sm\" fw={600}>{strings.helpImages}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpImageMove}</List.Item>\n <List.Item>{strings.helpImageResize}</List.Item>\n <List.Item>{strings.helpImageRotate}</List.Item>\n <List.Item>{strings.helpImageTransform}</List.Item>\n <List.Item>{strings.helpImageRemove}</List.Item>\n </List>\n </>\n )}\n </Stack>\n );\n}\n", "// The map editor's words. English here; Gramps Connect passes its own\n// translations (its t() is keyed by these same English texts).\n\nexport interface MapEditorStrings {\n point: string;\n line: string;\n polygon: string;\n rectangle: string;\n select: string;\n image: string;\n editOptions: string;\n labelText: string;\n regionName: string;\n fillOpacity: string;\n scale: string;\n transform: string;\n overlayName: string;\n opacity: string;\n stackingOrder: string;\n removeImage: string;\n resizeImage: string;\n rotateImage: string;\n warpCorner: string;\n basemapFailed: string;\n imageFailed: string;\n lockedOne: string;\n lockedMany: (count: number) => string;\n lockedExplain: string;\n // The help (MapEditorHelp), in the pieces it's put together from.\n helpTitle: string;\n helpDrawing: string;\n helpPoint: string;\n helpLine: string;\n helpEnterFinishes: string;\n helpEscCancels: string;\n helpRectangle: string;\n helpImage: string;\n helpImages: string;\n helpBelow: string;\n helpEditing: string;\n helpSelect: string;\n helpVertex: string;\n helpColor: string;\n helpDelete: string;\n helpOr: string;\n helpRotate: string;\n helpRotateHandle: string;\n helpImageMove: string;\n helpImageResize: string;\n helpImageRotate: string;\n helpImageTransform: string;\n helpImageRemove: string;\n}\n\nexport const MAP_EDITOR_ENGLISH: MapEditorStrings = {\n point: \"Point\",\n line: \"Line\",\n polygon: \"Polygon\",\n rectangle: \"Rectangle\",\n select: \"Select\",\n image: \"Image\",\n editOptions: \"Edit Options\",\n labelText: \"Label text\",\n regionName: \"Region name (optional)\",\n fillOpacity: \"Fill opacity\",\n scale: \"Scale\",\n transform: \"Transform\",\n overlayName: \"Overlay name (optional)\",\n opacity: \"Opacity\",\n stackingOrder: \"Stacking order\",\n removeImage: \"Remove this image\",\n resizeImage: \"Drag to resize (keeps its exact shape, warped or not)\",\n rotateImage: \"Drag to rotate\",\n warpCorner: \"Drag to warp this corner\",\n basemapFailed: \"The basemap could not be loaded.\",\n imageFailed: \"The image failed to load.\",\n lockedOne: \"1 shape can't be edited here\",\n lockedMany: (count) => `${count} shapes can't be edited here`,\n lockedExplain: \"For example, a region with a hole in it, or one whose outline crosses itself. It's drawn dashed, and saved exactly as it was.\",\n helpTitle: \"How to use this editor\",\n helpDrawing: \"Drawing\",\n helpPoint: \"Point: click once to place it.\",\n helpLine: \"Line, Polygon: click to place each point, then click that first point's own marker again to \"\n + \"finish -- it's styled differently once there's enough points to close the shape. Pressing\",\n helpEnterFinishes: \"finishes it too;\",\n helpEscCancels: \"cancels it.\",\n helpRectangle: \"Rectangle: click and drag from one corner to the opposite corner.\",\n helpImage: \"Image: pick a media object to overlay -- see\",\n helpImages: \"Images\",\n helpBelow: \"below.\",\n helpEditing: \"Editing a shape\",\n helpSelect: \"Select: click a shape to select it, then drag it or one of its handles.\",\n helpVertex: \"Drag a vertex to move it. To add a new point on a Line, Polygon, or Rectangle, drag the small \"\n + \"midpoint marker between two existing vertices outward.\",\n helpColor: \"The color swatch sets the next shape's color -- or, with a shape selected, changes its color.\",\n helpDelete: \"Delete a selected shape or image with\",\n helpOr: \"or\",\n helpRotate: \"Rotate a selected Polygon, Rectangle, or Line: hold\",\n helpRotateHandle: \"while dragging one of its handles.\",\n helpImageMove: \"Drag anywhere on an image to move it.\",\n helpImageResize: \"Drag its \u2198 handle to resize it -- grows or shrinks from its own center, \"\n + \"keeping its exact shape (works the same on a warped image, too).\",\n helpImageRotate: \"Drag its \u21BB handle to rotate it -- handy for aligning a scanned old map.\",\n helpImageTransform: \"Switch to \\\"Transform\\\" to also show 4 corner handles you can drag independently \"\n + \"(rubber-sheeting) -- for a scanned map that isn't printed at a uniform scale/orientation. \"\n + \"Switching back to \\\"Scale\\\" just hides those 4 handles again; move/resize/rotate keep \"\n + \"working on the image's exact current shape either way.\",\n helpImageRemove: \"Click its \u00D7 handle to remove it.\",\n};\n", "// A slide's place as the map editor sees it, and back: the place's\n// `geometry` (a FeatureCollection, a Feature or a bare geometry) as\n// features, and its `overlays` as image overlays keyed by media. Whatever\n// the editor doesn't edit -- an overlay's date, fields this version\n// doesn't know, a FeatureCollection's own members -- is carried over from\n// the place as it was.\nimport type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport type { Overlay, Place, StoryDate } from \"../types\";\nimport type { MapEditorOverlay, MapEditorResult } from \"./MapEditor\";\nimport { patchPlace } from \"./model\";\n\n/** The features in a place's `geometry`, whichever form it takes. */\nexport function placeFeatures(place: Place | undefined): Feature[] {\n const geometry = place?.geometry as { type: string; features?: unknown[] } | undefined;\n if (!geometry) return [];\n if (geometry.type === \"FeatureCollection\") {\n return ((geometry.features ?? []) as Feature[]).filter((f) => f && f.geometry);\n }\n if (geometry.type === \"Feature\") return (geometry as unknown as Feature).geometry ? [geometry as unknown as Feature] : [];\n return [{ type: \"Feature\", properties: {}, geometry: geometry as unknown as Geometry }];\n}\n\n/** What the map editor opens with for a place. */\nexport function placeToEditor(place: Place | undefined): { features: Feature[]; overlays: MapEditorOverlay[] } {\n return {\n features: placeFeatures(place),\n overlays: (place?.overlays ?? []).map((o) => ({\n image: o.media, corners: o.corners,\n ...(o.opacity !== undefined ? { opacity: o.opacity } : {}),\n ...(o.order !== undefined ? { order: o.order } : {}),\n })),\n };\n}\n\n/** The place with what the map editor ended with. `dates` holds each\n * overlay's date by media key, as edited beside the editor. */\nexport function editorToPlace(\n place: Place | undefined, result: MapEditorResult, dates: Map<string, StoryDate | undefined>,\n): Place | undefined {\n const before = place?.geometry as (FeatureCollection & Record<string, unknown>) | undefined;\n const geometry = result.features.length === 0\n ? undefined\n // A FeatureCollection keeps its own other members; anything else\n // becomes one.\n : { ...(before?.type === \"FeatureCollection\" ? before : {}), type: \"FeatureCollection\", features: result.features };\n const previous = new Map((place?.overlays ?? []).map((o) => [o.media, o]));\n const overlays = result.overlays.map((o): Overlay => {\n const { opacity: _o, order: _r, date: _d, ...kept } = previous.get(o.image) ?? ({} as Partial<Overlay>);\n const date = dates.has(o.image) ? dates.get(o.image) : previous.get(o.image)?.date;\n return {\n ...kept,\n media: o.image,\n corners: o.corners,\n ...(o.opacity !== undefined && o.opacity !== 1 ? { opacity: o.opacity } : {}),\n ...(o.order !== undefined ? { order: Math.round(o.order) } : {}),\n ...(date ? { date } : {}),\n };\n });\n return patchPlace(place, {\n geometry: geometry as Place[\"geometry\"],\n overlays: overlays.length ? overlays : undefined,\n });\n}\n", "// Finding a place by name, for the place field's opt-in search: Wikidata's\n// own search, then the chosen item's coordinates (P625). Both endpoints\n// allow any origin and need no key. This is the only thing the editor\n// sends anywhere, and only when asked to: it sends the name typed.\n// (Gramps Connect's place lookup walks the same API further, up the\n// \"located in\" chain, to build a place hierarchy; a story place is just a\n// name and a point.)\n\nconst WIKIDATA_API = \"https://www.wikidata.org/w/api.php\";\nconst WIKIDATA_ENTITY_DATA = \"https://www.wikidata.org/wiki/Special:EntityData\";\n\nexport interface PlaceSearchResult {\n /** The Wikidata item, e.g. \"Q72\". */\n id: string;\n label: string;\n /** Usually names the region and country, which tells same-named places\n * apart. */\n description?: string;\n}\n\nexport interface PlaceSearch {\n search: (term: string, language: string | undefined, signal?: AbortSignal) => Promise<PlaceSearchResult[]>;\n /** The result's position, or null when it has none. */\n point: (result: PlaceSearchResult, signal?: AbortSignal) => Promise<{ lat: number; lon: number } | null>;\n}\n\n/** \"fr_CA\" or \"fr-CA\" -> \"fr-ca\", Wikidata's form. */\nfunction wikidataLanguage(language: string | undefined): string {\n return (language ?? \"\").trim().toLowerCase().replace(/_/g, \"-\") || \"en\";\n}\n\nexport async function searchWikidataPlaces(term: string, language?: string, signal?: AbortSignal): Promise<PlaceSearchResult[]> {\n const code = wikidataLanguage(language);\n const params = new URLSearchParams({\n action: \"wbsearchentities\", search: term, language: code, uselang: code, format: \"json\", limit: \"7\",\n origin: \"*\", // what makes an anonymous api.php GET answer cross-origin\n });\n const res = await fetch(`${WIKIDATA_API}?${params}`, { signal });\n if (!res.ok) throw new Error(`Wikidata search failed (${res.status})`);\n const data = (await res.json()) as { search?: { id: string; label?: string; description?: string }[] };\n return (data.search ?? []).map((hit) => ({\n id: hit.id,\n label: hit.label ?? hit.id,\n ...(hit.description ? { description: hit.description } : {}),\n }));\n}\n\nexport async function wikidataPoint(result: PlaceSearchResult, signal?: AbortSignal): Promise<{ lat: number; lon: number } | null> {\n const res = await fetch(`${WIKIDATA_ENTITY_DATA}/${encodeURIComponent(result.id)}.json`, { signal });\n if (!res.ok) throw new Error(`Wikidata fetch failed for ${result.id} (${res.status})`);\n const data = (await res.json()) as {\n entities?: Record<string, { claims?: Record<string, { mainsnak?: { datavalue?: { value?: unknown } } }[]> }>;\n };\n // A redirected item comes back under its new id: take whichever is there.\n const entity = data.entities?.[result.id] ?? Object.values(data.entities ?? {})[0];\n const value = entity?.claims?.P625?.[0]?.mainsnak?.datavalue?.value as { latitude?: number; longitude?: number } | undefined;\n if (typeof value?.latitude !== \"number\" || typeof value.longitude !== \"number\") return null;\n return { lat: value.latitude, lon: value.longitude };\n}\n\nexport const WIKIDATA_PLACE_SEARCH: PlaceSearch = { search: searchWikidataPlaces, point: wikidataPoint };\n", "// A list of slides to pick from and reorder by dragging -- generic over\n// what a slide is, so any story editor can use it with its own rows.\nimport { useState, type ReactNode } from \"react\";\nimport { Stack, UnstyledButton } from \"@mantine/core\";\n\nexport interface SlideListProps<T> {\n items: T[];\n selected: number;\n onSelect: (index: number) => void;\n /** Called when a row is dropped somewhere else. */\n onMove: (from: number, to: number) => void;\n getKey: (item: T, index: number) => string;\n renderItem: (item: T, index: number) => ReactNode;\n label?: string;\n}\n\nexport function SlideList<T>({ items, selected, onSelect, onMove, getKey, renderItem, label }: SlideListProps<T>) {\n const [dragging, setDragging] = useState<number | null>(null);\n const [over, setOver] = useState<number | null>(null);\n const end = () => { setDragging(null); setOver(null); };\n\n return (\n <Stack gap={4} role=\"listbox\" aria-label={label}>\n {items.map((item, i) => {\n const isSelected = i === selected;\n // A line on the side the row will land: below when moving down.\n const dropLine = over === i && dragging !== null && dragging !== i\n ? (dragging < i ? { borderBottom: \"2px solid var(--mantine-primary-color-filled)\" } : { borderTop: \"2px solid var(--mantine-primary-color-filled)\" })\n : {};\n return (\n <UnstyledButton\n key={getKey(item, i)}\n role=\"option\"\n aria-selected={isSelected}\n draggable\n onClick={() => onSelect(i)}\n onDragStart={(e) => { setDragging(i); e.dataTransfer.effectAllowed = \"move\"; e.dataTransfer.setData(\"text/plain\", String(i)); }}\n onDragOver={(e) => { if (dragging === null) return; e.preventDefault(); setOver(i); }}\n onDrop={(e) => { e.preventDefault(); if (dragging !== null && dragging !== i) onMove(dragging, i); end(); }}\n onDragEnd={end}\n style={{\n display: \"block\", width: \"100%\", padding: \"6px 8px\", borderRadius: 6,\n background: isSelected ? \"var(--mantine-primary-color-light)\" : undefined,\n opacity: dragging === i ? 0.5 : 1,\n ...dropLine,\n }}\n >\n {renderItem(item, i)}\n </UnstyledButton>\n );\n })}\n </Stack>\n );\n}\n", "// A plain Textarea plus Bold/Italic buttons that wrap the selection in the\n// story format's `**`/`*` markers -- the only formatting a slide's text has\n// (parseStoryText is the matching reader), so no rich-text editor.\nimport { useRef } from \"react\";\nimport { Button, Group, Stack, Text, Textarea } from \"@mantine/core\";\n\n/** Wraps the textarea's selection in `marker` (or unwraps it, if the\n * selection is already exactly `marker\u2026marker`); with nothing selected,\n * inserts an empty pair and leaves the cursor between them. */\nfunction applyMarker(el: HTMLTextAreaElement, marker: string, value: string, onChange: (v: string) => void) {\n const start = el.selectionStart ?? value.length;\n const end = el.selectionEnd ?? value.length;\n if (start === end) {\n onChange(value.slice(0, start) + marker + marker + value.slice(end));\n requestAnimationFrame(() => {\n el.focus();\n el.setSelectionRange(start + marker.length, start + marker.length);\n });\n return;\n }\n const selected = value.slice(start, end);\n const alreadyWrapped = selected.length > marker.length * 2 && selected.startsWith(marker) && selected.endsWith(marker);\n const replacement = alreadyWrapped ? selected.slice(marker.length, selected.length - marker.length) : `${marker}${selected}${marker}`;\n onChange(value.slice(0, start) + replacement + value.slice(end));\n}\n\nexport interface StoryTextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n boldLabel?: string;\n italicLabel?: string;\n minRows?: number;\n}\n\nexport function StoryTextField({ label, value, onChange, boldLabel = \"Bold\", italicLabel = \"Italic\", minRows = 3 }: StoryTextFieldProps) {\n const ref = useRef<HTMLTextAreaElement>(null);\n return (\n <Stack gap={4}>\n <Group gap=\"xs\">\n <Text size=\"sm\" fw={500}>{label}</Text>\n <Button\n variant=\"default\" size=\"compact-xs\" fw={700} aria-label={boldLabel} title={boldLabel}\n onClick={() => ref.current && applyMarker(ref.current, \"**\", value, onChange)}\n >\n B\n </Button>\n <Button\n variant=\"default\" size=\"compact-xs\" fs=\"italic\" aria-label={italicLabel} title={italicLabel}\n onClick={() => ref.current && applyMarker(ref.current, \"*\", value, onChange)}\n >\n i\n </Button>\n </Group>\n <Textarea\n ref={ref} aria-label={label} autosize minRows={minRows} maxRows={14} value={value}\n onChange={(e) => onChange(e.currentTarget.value)}\n />\n </Stack>\n );\n}\n", "// The editor's own words. English here; a host with its own translations\n// (Gramps Connect) passes StoryEditor's `strings` instead.\n\nexport interface EditorStrings {\n story: string;\n storySettings: string;\n title: string;\n language: string;\n languageHint: string;\n map: string;\n mapStandard: string;\n mapHistorical: string;\n mapAuto: string;\n mapNone: string;\n slides: string;\n untitledSlide: string;\n addSlide: string;\n duplicateSlide: string;\n deleteSlide: string;\n moveUp: string;\n moveDown: string;\n slideTitle: string;\n text: string;\n bold: string;\n italic: string;\n date: string;\n dateHint: string;\n preciseDate: string;\n preciseDateHint: string;\n preciseDateFollows: string;\n preciseDateNotUnderstood: string;\n matchDateAsWritten: string;\n noPreciseDate: string;\n place: string;\n placeName: string;\n removePlace: string;\n findPlace: string;\n findPlaceHint: string;\n findPlaceNone: string;\n findPlaceFailed: string;\n findPlaceNoPoint: (name: string) => string;\n coordinates: string;\n coordinatesHint: string;\n coordinatesInvalid: string;\n placeMap: string;\n placeMapHint: string;\n placeShape: string;\n placeOverlays: (count: number) => string;\n placeKeeps: (what: string) => string;\n editMap: string;\n editMapHint: string;\n mapDialogTitle: (placeName: string | undefined) => string;\n mapHelp: string;\n importShapes: string;\n importShapesHint: string;\n importFailed: (fileName: string) => string;\n importNothing: (fileName: string) => string;\n overlayAlready: string;\n overlayDate: string;\n overlayDateHint: string;\n cancel: string;\n done: string;\n photos: string;\n photosHint: string;\n addPhoto: string;\n replacePhoto: string;\n movePhotoUp: string;\n movePhotoDown: string;\n removePhoto: string;\n caption: string;\n credit: string;\n creditHint: string;\n description: string;\n descriptionHint: string;\n photoFailed: (name: string) => string;\n undo: string;\n redo: string;\n present: string;\n preview: string;\n problems: (count: number) => string;\n openingSlide: string;\n}\n\nexport const EDITOR_ENGLISH: EditorStrings = {\n story: \"Story\",\n storySettings: \"Title, language and map\",\n title: \"Title\",\n language: \"Language\",\n languageHint: \"The language the story is written in, e.g. en, de or fr-CA. Dates are read in it.\",\n map: \"Map\",\n mapStandard: \"Today's map\",\n mapHistorical: \"Historical maps for each slide's year\",\n mapAuto: \"Viewer's choice\",\n mapNone: \"No map\",\n slides: \"Slides\",\n untitledSlide: \"Untitled slide\",\n addSlide: \"Add slide\",\n duplicateSlide: \"Duplicate\",\n deleteSlide: \"Delete\",\n moveUp: \"Move up\",\n moveDown: \"Move down\",\n slideTitle: \"Title\",\n text: \"Text\",\n bold: \"Bold\",\n italic: \"Italic\",\n date: \"Date\",\n dateHint: \"As readers should see it, e.g. about 1850, 3 May 1850, between 1850 and 1860.\",\n preciseDate: \"Precise date (EDTF)\",\n preciseDateHint: \"Places the slide on the timeline and picks historical maps.\",\n preciseDateFollows: \"Worked out from the date as written.\",\n preciseDateNotUnderstood: \"Not a date the timeline can use.\",\n matchDateAsWritten: \"Work it out from the date\",\n noPreciseDate: \"None: this slide stays off the timeline.\",\n place: \"Place\",\n placeName: \"Name\",\n removePlace: \"Remove place\",\n findPlace: \"Find on Wikidata\",\n findPlaceHint: \"Looks the name up on Wikidata, to put the pin there. The name is all that's sent, and only when you ask.\",\n findPlaceNone: \"Wikidata has no place by that name.\",\n findPlaceFailed: \"Couldn't reach Wikidata.\",\n findPlaceNoPoint: (name) => `Wikidata has no map position for ${name}.`,\n coordinates: \"Latitude, longitude\",\n coordinatesHint: \"e.g. 47.3769, 8.5417\",\n coordinatesInvalid: \"Two numbers: latitude (-90 to 90), then longitude (-180 to 180).\",\n placeMap: \"Map: click to put the pin\",\n placeMapHint: \"Click the map to put the pin there, or drag the pin.\",\n placeShape: \"a shape\",\n placeOverlays: (count) => (count === 1 ? \"a map overlay\" : `${count} map overlays`),\n placeKeeps: (what) => `This place also has ${what}.`,\n editMap: \"Edit map\",\n editMapHint: \"Shapes under the pin (a parish, a route) and scans of old maps laid over it.\",\n mapDialogTitle: (placeName) => (placeName ? `Map: ${placeName}` : \"Map\"),\n mapHelp: \"How to use this editor\",\n importShapes: \"Import shapes\",\n importShapesHint: \"Adds the points, lines and areas in a KML, GPX or GeoJSON file to this map.\",\n importFailed: (fileName) => `Couldn't read ${fileName} as a KML, GPX or GeoJSON file.`,\n importNothing: (fileName) => `${fileName} has no shapes in it.`,\n overlayAlready: \"That image is already on this map.\",\n overlayDate: \"Years it shows\",\n overlayDateHint: \"e.g. 1850, or 1850 to 1880. With historical maps, it's hidden on slides outside them.\",\n cancel: \"Cancel\",\n done: \"Done\",\n photos: \"Photos\",\n photosHint: \"Add, drop or paste a photo. It's resized for the screen, and hidden details like camera and location are left out.\",\n addPhoto: \"Add photo\",\n replacePhoto: \"Replace\",\n movePhotoUp: \"Move photo up\",\n movePhotoDown: \"Move photo down\",\n removePhoto: \"Remove\",\n caption: \"Caption\",\n credit: \"Credit\",\n creditHint: \"Who took it, or where it's from\",\n description: \"Description\",\n descriptionHint: \"What the photo shows, for anyone who can't see it.\",\n photoFailed: (name) => `Couldn't use ${name}: this browser can't read it as an image.`,\n undo: \"Undo\",\n redo: \"Redo\",\n present: \"Present\",\n preview: \"Preview\",\n problems: (count) => (count === 1 ? \"1 problem to fix before saving\" : `${count} problems to fix before saving`),\n openingSlide: \"Opening slide\",\n};\n"],
5
- "mappings": "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",
6
- "names": ["useEffect", "useMemo", "useRef", "useState", "ActionIcon", "Box", "Button", "Divider", "Group", "Modal", "Stack", "Text", "TextInput", "Tooltip", "UnstyledButton", "blob", "validate", "usedMedia", "useEffect", "useRef", "useState", "jsx", "useEffect", "useRef", "useState", "jsx", "jsxs", "useRef", "useState", "useEffect", "jsx", "jsxs", "useState", "useEffect", "useRef", "useEffect", "useRef", "useState", "key", "jsx", "jsxs", "useState", "useRef", "useEffect", "edtf", "useEffect", "useRef", "useState", "Group", "Stack", "Text", "TextInput", "jsx", "jsxs", "useEffect", "useMemo", "useRef", "useState", "Button", "Group", "Loader", "Stack", "Text", "TextInput", "Tooltip", "useEffect", "useRef", "maplibregl", "jsx", "useRef", "useEffect", "jsx", "jsxs", "useState", "useEffect", "useRef", "useMemo", "Stack", "Group", "Text", "Button", "Tooltip", "Loader", "TextInput", "useMemo", "useRef", "useState", "ActionIcon", "Box", "Button", "Group", "Stack", "Text", "TextInput", "Tooltip", "useEffect", "useRef", "useState", "maplibregl", "Box", "Button", "Group", "Loader", "Stack", "Text", "TextInput", "Fragment", "jsx", "jsxs", "MapEditor", "useRef", "useState", "useEffect", "color", "opacity", "Button", "Box", "Stack", "Text", "TextInput", "Group", "Loader", "jsx", "jsxs", "BAR_HEIGHT", "useState", "useRef", "Stack", "TextInput", "Text", "useMemo", "s", "Box", "Group", "Tooltip", "ActionIcon", "Button", "useState", "Stack", "UnstyledButton", "jsx", "useRef", "Button", "Group", "Stack", "Text", "jsx", "jsxs", "jsx", "jsxs", "BAR_HEIGHT", "useState", "useEffect", "Box", "useMemo", "useRef", "slideId", "validate", "Group", "Tooltip", "ActionIcon", "Button", "Stack", "Text", "TextInput", "UnstyledButton", "Divider", "Modal"]
3
+ "sources": ["../src/editor/StoryEditor.tsx", "../src/image.ts", "../spec/1.0/story.schema.json", "../src/generated/schemaValidator.js", "../src/version.ts", "../src/validate.ts", "../src/player/geo.ts", "../src/player/StoryPlayer.tsx", "../src/player/dates.ts", "../src/player/MapBackground.tsx", "../src/player/mapStyles.ts", "../src/player/theme.ts", "../src/player/MapModeControl.tsx", "../src/player/text.ts", "../src/player/strings.ts", "../src/player/TimelineStrip.tsx", "../src/player/timelineLayout.ts", "../src/editor/dates.ts", "../src/editor/DateField.tsx", "../src/editor/model.ts", "../src/editor/PhotosField.tsx", "../src/editor/PlaceField.tsx", "../src/editor/PlaceMap.tsx", "../src/editor/PlaceMapDialog.tsx", "../src/mapEdit/model.ts", "../src/mapEdit/mapFile.ts", "../src/mapEdit/geometry.ts", "../src/editor/MapEditor.tsx", "../src/editor/translations/de.ts", "../src/editor/translations/es.ts", "../src/editor/translations/fr.ts", "../src/editor/translations/nl.ts", "../src/editor/translations/index.ts", "../src/editor/strings.ts", "../src/editor/mapEditorStrings.ts", "../src/editor/placeShapes.ts", "../src/editor/placeSearch.ts", "../src/editor/SlideList.tsx", "../src/editor/StoryTextField.tsx"],
4
+ "sourcesContent": ["// Edits a story document: a list of slides on the left, the selected\n// slide's (or the story's own) fields in the middle, and the real player\n// on the right showing that slide as it's changed. Works on the document\n// only -- opening and saving files is the host's (the viewer site's editor\n// page does it with the File System Access API or a download).\n//\n// Needs Mantine: wrap it in a MantineProvider and load @mantine/core's\n// stylesheet, as with any Mantine component.\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n ActionIcon, Badge, Box, Button, Divider, Group, Modal, Popover, Select, Stack, Text, TextInput, Tooltip, UnstyledButton,\n} from \"@mantine/core\";\nimport { useMediaQuery } from \"@mantine/hooks\";\nimport type { MediaItem, Slide, SlideMedia, StoryDoc } from \"../types\";\nimport { optimizeImage } from \"../image\";\nimport { validate, type StoryIssue } from \"../validate\";\nimport { storyPlaces } from \"../player/geo\";\nimport { StoryPlayer } from \"../player/StoryPlayer\";\nimport type { PlayerStrings } from \"../player/strings\";\nimport { suggestEdtf, type DateTextParser } from \"./dates\";\nimport { DateField } from \"./DateField\";\nimport {\n addImage, addSlide, deleteSlide, findMedia, duplicateSlide, moveSlide, record, redo, setSlidePhotos, startHistory, storyPlaceChoices,\n undo, updateMedia, updateSlide, updateStory, type History, type NewImage,\n} from \"./model\";\nimport { PhotosField } from \"./PhotosField\";\nimport { PlaceField, type PlaceUpdate } from \"./PlaceField\";\nimport { PlaceMapDialog } from \"./PlaceMapDialog\";\nimport type { MapEditorStrings } from \"./mapEditorStrings\";\nimport { WIKIDATA_PLACE_SEARCH, type PlaceSearch } from \"./placeSearch\";\nimport { SlideList } from \"./SlideList\";\nimport { StoryTextField } from \"./StoryTextField\";\nimport { browserLanguages, editorStringsFor, type EditorStrings } from \"./strings\";\nimport { mapEditorStringsFor } from \"./mapEditorStrings\";\n\nconst BAR_HEIGHT = 56;\n/** The story's own settings, in place of a slide index. */\nconst STORY = -1;\n\nexport interface StoryEditorProps {\n /** The story to start from, and its files (paths as in media `src`).\n * Changing these later has no effect: remount (a new `key`) to edit\n * another story. */\n initialStory: StoryDoc;\n initialFiles?: Map<string, Uint8Array>;\n /** Called with the document and its files after every change, undo and\n * redo included. The files only grow while editing (an undone photo's\n * file stays); pruneMedia leaves out what nothing uses when saving. */\n onChange?: (doc: StoryDoc, files: Map<string, Uint8Array>) => void;\n /** Turns a chosen image file into what's stored. By default\n * optimizeImage: 1600px WebP (JPEG where the browser can't), with the\n * original's metadata left behind. */\n prepareImage?: (file: Blob) => Promise<NewImage>;\n /** The host's own buttons (Open, Save, ...), at the right of the top bar. */\n toolbar?: ReactNode;\n /** Shown first in the top bar, e.g. ViewerBrand. */\n brand?: ReactNode;\n dark?: boolean;\n strings?: Partial<EditorStrings>;\n playerStrings?: Partial<PlayerStrings>;\n /** Date text -> EDTF. By default gramps-date, in the story's language. */\n parseDateText?: DateTextParser;\n /** Finding a place by name. By default Wikidata, and only when the\n * person asks; null leaves the search out. */\n placeSearch?: PlaceSearch | null;\n /** The map editor's words (Edit map), over its English. */\n mapStrings?: Partial<MapEditorStrings>;\n}\n\n/** The slide an issue's JSON Pointer is about, or STORY. */\nfunction issueSlide(issue: StoryIssue): number {\n const match = /^\\/slides\\/(\\d+)/.exec(issue.path);\n return match ? Number(match[1]) : STORY;\n}\n\ntype Resolve = (key: string, item: MediaItem) => Promise<string | null>;\n\n/** The default prepareImage. */\nexport async function prepareImage(file: Blob): Promise<NewImage> {\n const image = await optimizeImage(file);\n return { data: new Uint8Array(await image.blob.arrayBuffer()), mime: image.mime, ext: image.ext, width: image.width, height: image.height };\n}\n\nfunction Thumb({ doc, slide, resolveMedia }: { doc: StoryDoc; slide: Slide; resolveMedia: Resolve }) {\n const ref = slide.media?.[0]?.ref;\n const item = ref && Object.prototype.hasOwnProperty.call(doc.media, ref) ? doc.media[ref] : undefined;\n const [url, setUrl] = useState<string | null>(null);\n useEffect(() => {\n let live = true;\n setUrl(null);\n if (ref && item) void resolveMedia(ref, item).then((u) => { if (live) setUrl(u); });\n return () => { live = false; };\n }, [ref, item, resolveMedia]);\n return (\n <Box\n w={40} h={40}\n style={{ flex: \"none\", borderRadius: 4, background: \"var(--mantine-color-default-hover)\", overflow: \"hidden\" }}\n >\n {url && <img src={url} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </Box>\n );\n}\n\nexport function StoryEditor({\n initialStory, initialFiles, onChange, prepareImage: prepare = prepareImage, toolbar, brand, dark = false,\n strings: stringOverrides, playerStrings, parseDateText = suggestEdtf, placeSearch = WIKIDATA_PLACE_SEARCH, mapStrings: mapStringOverrides,\n}: StoryEditorProps) {\n // In the browser's language where there's a translation, over English.\n const strings = useMemo(() => ({ ...editorStringsFor(...browserLanguages()), ...stringOverrides }), [stringOverrides]);\n const mapStrings = useMemo(\n () => ({ ...mapEditorStringsFor(...browserLanguages()), helpImage: strings.mapHelpImage, ...mapStringOverrides }),\n [strings, mapStringOverrides],\n );\n const [history, setHistory] = useState<History>(() => startHistory(initialStory));\n const [selected, setSelected] = useState(0);\n const [presenting, setPresenting] = useState(false);\n const [problemsOpen, setProblemsOpen] = useState(false);\n const wide = useMediaQuery(\"(min-width: 1000px)\", true);\n const doc = history.present;\n const [files, setFiles] = useState(() => new Map(initialFiles ?? []));\n const [busy, setBusy] = useState(false);\n const [photoError, setPhotoError] = useState<string | null>(null);\n // The latest of each, for work that finishes after a render (photos).\n const docRef = useRef(doc);\n docRef.current = doc;\n const filesRef = useRef(files);\n filesRef.current = files;\n\n // A blob: URL per stored file, made once and released with the editor.\n const urls = useRef(new Map<string, string>());\n useEffect(() => () => {\n for (const url of urls.current.values()) URL.revokeObjectURL(url);\n }, []);\n const resolveMedia = useCallback<Resolve>(async (_key, item) => {\n const cached = urls.current.get(item.src);\n if (cached) return cached;\n const data = filesRef.current.get(item.src);\n if (!data) return null;\n const url = URL.createObjectURL(new Blob([data as Uint8Array<ArrayBuffer>], { type: item.mime }));\n urls.current.set(item.src, url);\n return url;\n }, []);\n const urlFor = useCallback((key: string) => {\n const item = Object.prototype.hasOwnProperty.call(docRef.current.media, key) ? docRef.current.media[key] : undefined;\n return item ? resolveMedia(key, item) : Promise.resolve(null);\n }, [resolveMedia]);\n\n // Every change goes through here (and so into history and to the host).\n const apply = useCallback((next: StoryDoc, key?: string) => {\n setHistory((h) => record(h, next, key));\n }, []);\n useEffect(() => { onChange?.(doc, files); }, [doc, files, onChange]);\n\n const index = selected === STORY ? STORY : Math.min(selected, doc.slides.length - 1);\n const slide = index === STORY ? undefined : doc.slides[index];\n const setSlide = (patch: Partial<Slide>, key: string) => {\n if (index !== STORY) apply(updateSlide(history.present, index, patch), `${slide!.id}:${key}`);\n };\n\n // A place change applies to the slide as it is by then: a name typed and\n // a place picked in the same moment both land.\n const setPlace = (slideId: string, update: PlaceUpdate, key: string) => {\n setHistory((h) => {\n const at = h.present.slides.findIndex((s) => s.id === slideId);\n if (at < 0) return h;\n const before = h.present.slides[at].place;\n const after = update(before);\n return after === before ? h : record(h, updateSlide(h.present, at, { place: after }), `${slideId}:${key}`);\n });\n };\n // The slide whose map (shapes, old maps) is open full screen.\n const [mapSlideId, setMapSlideId] = useState<string | null>(null);\n const mapSlide = mapSlideId ? doc.slides.find((s) => s.id === mapSlideId) : undefined;\n const placeChoices = useMemo(() => storyPlaceChoices(doc, index), [doc, index]);\n const around = useMemo(() => storyPlaces(doc.slides.map((s) => s.place))?.bounds ?? null, [doc.slides]);\n\n const issues = useMemo(() => validate(doc, files).errors, [doc, files]);\n\n /** Prepares image files and puts them on a slide: added at the end, or\n * in place of photo `replace` (keeping its caption and credit). */\n const addPhotos = useCallback(async (chosen: File[], slideId: string, replace?: number) => {\n setBusy(true);\n setPhotoError(null);\n // A file already in the story (chosen again) is used as it is;\n // anything else is prepared first.\n const chosenImages: (NewImage | string)[] = [];\n for (const file of chosen) {\n try {\n const known = findMedia(docRef.current, filesRef.current, new Uint8Array(await file.arrayBuffer()));\n chosenImages.push(known ?? await prepare(file));\n } catch {\n setPhotoError(strings.photoFailed(file.name || \"the image\"));\n }\n }\n setBusy(false);\n if (!chosenImages.length) return;\n let next = docRef.current;\n let nextFiles = filesRef.current;\n const keys: string[] = [];\n for (const image of chosenImages) {\n if (typeof image === \"string\") {\n keys.push(image);\n continue;\n }\n const added = addImage(next, nextFiles, image);\n next = added.doc;\n nextFiles = added.files;\n keys.push(added.key);\n }\n const at = next.slides.findIndex((s) => s.id === slideId);\n if (at < 0) return;\n const photos: SlideMedia[] = [...(next.slides[at].media ?? [])];\n if (replace !== undefined && photos[replace]) photos[replace] = { ...photos[replace], ref: keys[0] };\n else photos.push(...keys.map((ref) => ({ ref })));\n setFiles(nextFiles);\n apply(setSlidePhotos(next, at, photos));\n }, [apply, prepare, strings]);\n\n // Pasting an image (outside a text field) adds it to the slide.\n const slideId = slide?.id;\n useEffect(() => {\n if (!slideId) return;\n const onPaste = (e: ClipboardEvent) => {\n if ((e.target as HTMLElement | null)?.closest(\"input, textarea, [contenteditable=true]\")) return;\n const images = [...(e.clipboardData?.files ?? [])].filter((f) => f.type.startsWith(\"image/\"));\n if (!images.length) return;\n e.preventDefault();\n void addPhotos(images, slideId);\n };\n window.addEventListener(\"paste\", onPaste);\n return () => window.removeEventListener(\"paste\", onPaste);\n }, [slideId, addPhotos]);\n\n // Undo/redo from the keyboard, except where a text field has its own.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (!(e.ctrlKey || e.metaKey) || e.altKey) return;\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"input, textarea, [contenteditable=true]\")) return;\n const key = e.key.toLowerCase();\n if (key === \"z\" && !e.shiftKey) { e.preventDefault(); setHistory(undo); }\n else if ((key === \"z\" && e.shiftKey) || key === \"y\") { e.preventDefault(); setHistory(redo); }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, []);\n\n const slideActions = slide && (\n <Group gap={6}>\n <Tooltip label={strings.moveUp}>\n <ActionIcon variant=\"default\" aria-label={strings.moveUp} disabled={index === 0}\n onClick={() => { apply(moveSlide(doc, index, index - 1)); setSelected(index - 1); }}>\u2191</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.moveDown}>\n <ActionIcon variant=\"default\" aria-label={strings.moveDown} disabled={index === doc.slides.length - 1}\n onClick={() => { apply(moveSlide(doc, index, index + 1)); setSelected(index + 1); }}>\u2193</ActionIcon>\n </Tooltip>\n <Button variant=\"default\" size=\"xs\" onClick={() => { const r = duplicateSlide(doc, index); apply(r.doc); setSelected(r.index); }}>\n {strings.duplicateSlide}\n </Button>\n <Button variant=\"default\" size=\"xs\" color=\"red\" disabled={doc.slides.length <= 1}\n onClick={() => { const r = deleteSlide(doc, index); apply(r.doc); setSelected(r.index); }}>\n {strings.deleteSlide}\n </Button>\n </Group>\n );\n\n const storyForm = (\n <Stack gap=\"md\">\n <Text fw={600} size=\"lg\">{strings.story}</Text>\n <TextInput\n label={strings.title} required value={doc.title}\n onChange={(e) => apply(updateStory(doc, { title: e.currentTarget.value }), \"story:title\")}\n />\n <TextInput\n label={strings.language} description={strings.languageHint} w={260} value={doc.language ?? \"\"}\n onChange={(e) => apply(updateStory(doc, { language: e.currentTarget.value.trim() || undefined }), \"story:language\")}\n />\n <Select\n label={strings.map} description={strings.mapHint} w={320} allowDeselect={false}\n data={[\n { value: \"auto\", label: strings.mapAuto },\n { value: \"standard\", label: strings.mapStandard },\n { value: \"historical\", label: strings.mapHistorical },\n { value: \"none\", label: strings.mapNone },\n ]}\n value={doc.presentation?.basemap ?? \"auto\"}\n onChange={(value) => value && apply(updateStory(doc, {\n presentation: { ...doc.presentation, basemap: value as NonNullable<StoryDoc[\"presentation\"]>[\"basemap\"] },\n }))}\n />\n </Stack>\n );\n\n const slideForm = slide && (\n <Stack gap=\"md\" key={slide.id}>\n <Group justify=\"space-between\" wrap=\"wrap\" gap=\"xs\">\n <Text fw={600} size=\"lg\">{index === 0 ? strings.openingSlide : `${index + 1} / ${doc.slides.length}`}</Text>\n {slideActions}\n </Group>\n <TextInput\n label={strings.slideTitle} value={slide.title ?? \"\"}\n onChange={(e) => setSlide({ title: e.currentTarget.value || undefined }, \"title\")}\n />\n <DateField\n value={slide.date} language={doc.language} parse={parseDateText} strings={strings}\n onChange={(date) => setSlide({ date }, \"date\")}\n />\n <StoryTextField\n label={strings.text} value={slide.text ?? \"\"} boldLabel={strings.bold} italicLabel={strings.italic} minRows={5}\n onChange={(text) => setSlide({ text: text || undefined }, \"text\")}\n />\n <PlaceField\n place={slide.place} choices={placeChoices} around={around} language={doc.language} search={placeSearch} dark={dark} strings={strings}\n onChange={(update, key) => setPlace(slide.id, update, key)}\n onEditMap={() => setMapSlideId(slide.id)}\n />\n <PhotosField\n photos={slide.media ?? []} media={doc.media} urlFor={urlFor} strings={strings} busy={busy}\n onChange={(photos, key) => apply(setSlidePhotos(doc, index, photos), `${slide.id}:${key}`)}\n onFiles={(chosen, replace) => void addPhotos(chosen, slide.id, replace)}\n onDescription={(key, alt) => apply(updateMedia(doc, key, { alt: alt || undefined }), `media:${key}:alt`)}\n />\n {photoError && <Text size=\"xs\" c=\"red\" role=\"alert\">{photoError}</Text>}\n </Stack>\n );\n\n const list = (\n <Stack gap=\"xs\">\n <UnstyledButton\n onClick={() => setSelected(STORY)}\n style={{ padding: \"8px\", borderRadius: 6, background: index === STORY ? \"var(--mantine-primary-color-light)\" : undefined }}\n >\n <Text fw={600} size=\"sm\">{strings.story}</Text>\n <Text size=\"xs\" c=\"dimmed\">{strings.storySettings}</Text>\n </UnstyledButton>\n <Divider label={strings.slides} labelPosition=\"left\" />\n <SlideList\n label={strings.slides}\n items={doc.slides}\n selected={index}\n onSelect={setSelected}\n onMove={(from, to) => { apply(moveSlide(doc, from, to)); setSelected(to); }}\n getKey={(s) => s.id}\n renderItem={(s, i) => (\n <Group gap=\"sm\" wrap=\"nowrap\">\n <Thumb doc={doc} slide={s} resolveMedia={resolveMedia} />\n <Box style={{ minWidth: 0 }}>\n <Text size=\"sm\" fw={500} truncate dir=\"auto\" c={s.title ? undefined : \"dimmed\"}>\n {s.title || strings.untitledSlide}\n </Text>\n <Text size=\"xs\" c=\"dimmed\" truncate>{i === 0 ? strings.openingSlide : s.date?.text ?? \"\"}</Text>\n </Box>\n </Group>\n )}\n />\n <Button\n variant=\"light\" size=\"xs\" mt={4}\n onClick={() => { const r = addSlide(doc, index === STORY ? doc.slides.length - 1 : index); apply(r.doc); setSelected(r.index); }}\n >\n + {strings.addSlide}\n </Button>\n </Stack>\n );\n\n const preview = (\n <Box style={{ position: \"relative\", height: wide ? \"100%\" : 460, borderRadius: 8, overflow: \"hidden\", border: \"1px solid var(--mantine-color-default-border)\" }}>\n <StoryPlayer\n story={doc} resolveMedia={resolveMedia} dark={dark} strings={playerStrings}\n keyboard={false} initialSlide={index === STORY ? 0 : index}\n onSlideChange={(i) => { if (i !== index && index !== STORY) setSelected(i); }}\n />\n </Box>\n );\n\n const column = (children: ReactNode, width?: number | string) => (\n <Box\n style={{\n width, flex: width ? \"none\" : 1, minWidth: 0, padding: 16,\n overflowY: wide ? \"auto\" : undefined, height: wide ? \"100%\" : undefined,\n }}\n >\n {children}\n </Box>\n );\n\n return (\n <Box style={{ height: \"100%\", display: \"flex\", flexDirection: \"column\" }}>\n <Group\n h={BAR_HEIGHT} px=\"md\" gap=\"sm\" wrap=\"nowrap\" justify=\"space-between\"\n style={{ flex: \"none\", borderBottom: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Group gap=\"sm\" wrap=\"nowrap\" style={{ minWidth: 0 }}>\n {brand}\n <Text fw={600} truncate dir=\"auto\">{doc.title}</Text>\n </Group>\n <Group gap=\"xs\" wrap=\"nowrap\">\n {issues.length > 0 && (\n <Popover opened={problemsOpen} onChange={setProblemsOpen} width={360} position=\"bottom-end\" withArrow>\n <Popover.Target>\n <Badge color=\"red\" variant=\"light\" style={{ cursor: \"pointer\" }} onClick={() => setProblemsOpen((o) => !o)}>\n {strings.problems(issues.length)}\n </Badge>\n </Popover.Target>\n <Popover.Dropdown>\n <Stack gap={6}>\n {issues.map((issue, i) => {\n const at = issueSlide(issue);\n return (\n <UnstyledButton key={i} onClick={() => { setSelected(at); setProblemsOpen(false); }}>\n <Text size=\"sm\" fw={500}>{at === STORY ? strings.story : (doc.slides[at]?.title || `${strings.untitledSlide} ${at + 1}`)}</Text>\n <Text size=\"xs\" c=\"dimmed\">{issue.path} {issue.message}</Text>\n </UnstyledButton>\n );\n })}\n </Stack>\n </Popover.Dropdown>\n </Popover>\n )}\n <Tooltip label={strings.undo}>\n <ActionIcon variant=\"default\" size=\"lg\" aria-label={strings.undo} disabled={history.past.length === 0} onClick={() => setHistory(undo)}>\u21B6</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.redo}>\n <ActionIcon variant=\"default\" size=\"lg\" aria-label={strings.redo} disabled={history.future.length === 0} onClick={() => setHistory(redo)}>\u21B7</ActionIcon>\n </Tooltip>\n <Button variant=\"default\" onClick={() => setPresenting(true)}>{strings.present}</Button>\n {toolbar}\n </Group>\n </Group>\n <Box\n style={{\n flex: 1, minHeight: 0, display: \"flex\", flexDirection: wide ? \"row\" : \"column\",\n overflowY: wide ? undefined : \"auto\",\n }}\n >\n {column(list, wide ? 280 : undefined)}\n {column(index === STORY ? storyForm : slideForm, wide ? \"min(520px, 36%)\" : undefined)}\n {column(preview)}\n </Box>\n {mapSlide && (\n <PlaceMapDialog\n place={mapSlide.place} doc={doc} files={files} dark={dark} parseDateText={parseDateText}\n strings={strings} mapStrings={mapStrings}\n onCancel={() => setMapSlideId(null)}\n onDone={(place, media, nextFiles) => {\n const at = doc.slides.findIndex((s) => s.id === mapSlide.id);\n setMapSlideId(null);\n if (at < 0) return;\n setFiles(nextFiles);\n // One step for undo: the map's images and the place together.\n apply(updateSlide({ ...doc, media }, at, { place }));\n }}\n />\n )}\n <Modal opened={presenting} onClose={() => setPresenting(false)} fullScreen withCloseButton={false} padding={0}>\n <Box style={{ position: \"fixed\", inset: 0 }}>\n <StoryPlayer\n story={doc} resolveMedia={resolveMedia} dark={dark} strings={playerStrings}\n initialSlide={index === STORY ? 0 : index} onClose={() => setPresenting(false)}\n />\n </Box>\n </Modal>\n </Box>\n );\n}\n", "// Re-encodes an image for presentation (spec/1.0/README.md section 5):\n// scaled to fit a long-edge limit and written through a canvas, which also\n// drops every bit of EXIF/GPS metadata the original carried. Browser-only\n// (createImageBitmap + OffscreenCanvas); the sizing and format decisions are\n// split out as plain functions so they can be tested anywhere.\n\nexport type ImagePurpose = \"photo\" | \"overlay\";\n\nexport interface OptimizeOptions {\n /** \"photo\" (default): slide pictures, 1600px, WebP. \"overlay\": map\n * overlays, 2048px, PNG when they have transparency. */\n purpose?: ImagePurpose;\n /** Overrides the purpose's long-edge limit. Never scales up. */\n maxEdge?: number;\n /** Lossy quality, 0-1. Default 0.82. */\n quality?: number;\n}\n\nexport interface OptimizedImage {\n blob: Blob;\n mime: \"image/webp\" | \"image/jpeg\" | \"image/png\";\n /** File extension without the dot, matching `mime`. */\n ext: \"webp\" | \"jpg\" | \"png\";\n width: number;\n height: number;\n}\n\nexport const DEFAULT_MAX_EDGE: Record<ImagePurpose, number> = { photo: 1600, overlay: 2048 };\n\n/** Scales (width, height) down to fit within maxEdge on the longer side,\n * keeping the aspect ratio; never scales up. */\nexport function fitWithin(width: number, height: number, maxEdge: number): { width: number; height: number } {\n const longEdge = Math.max(width, height);\n if (longEdge <= maxEdge) return { width, height };\n const scale = maxEdge / longEdge;\n return { width: Math.max(1, Math.round(width * scale)), height: Math.max(1, Math.round(height * scale)) };\n}\n\n/** Which encodings to try, best first. An overlay with transparency must\n * keep its alpha channel, and lossless PNG keeps hard map edges clean;\n * everything else goes lossy. JPEG is the fallback for a browser that\n * can't encode WebP (convertToBlob silently returns PNG then). */\nexport function encodingCandidates(purpose: ImagePurpose, hasAlpha: boolean): OptimizedImage[\"mime\"][] {\n if (hasAlpha) return purpose === \"overlay\" ? [\"image/png\"] : [\"image/webp\", \"image/png\"];\n return [\"image/webp\", \"image/jpeg\"];\n}\n\nconst EXT: Record<OptimizedImage[\"mime\"], OptimizedImage[\"ext\"]> = {\n \"image/webp\": \"webp\",\n \"image/jpeg\": \"jpg\",\n \"image/png\": \"png\",\n};\n\n/** Any pixel not fully opaque. Checked on the already-scaled canvas, so the\n * cost is bounded by maxEdge, not by the original's size. */\nfunction canvasHasAlpha(ctx: OffscreenCanvasRenderingContext2D, width: number, height: number): boolean {\n const data = ctx.getImageData(0, 0, width, height).data;\n for (let i = 3; i < data.length; i += 4) {\n if (data[i] < 255) return true;\n }\n return false;\n}\n\nexport async function optimizeImage(input: Blob, options: OptimizeOptions = {}): Promise<OptimizedImage> {\n const purpose = options.purpose ?? \"photo\";\n const maxEdge = options.maxEdge ?? DEFAULT_MAX_EDGE[purpose];\n const quality = options.quality ?? 0.82;\n\n // imageOrientation \"from-image\" applies the EXIF rotation before the\n // metadata is lost, so a sideways phone photo stays upright.\n const bitmap = await createImageBitmap(input, { imageOrientation: \"from-image\" });\n try {\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxEdge);\n const canvas = new OffscreenCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"No 2D canvas context available.\");\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(bitmap, 0, 0, width, height);\n const hasAlpha = canvasHasAlpha(ctx, width, height);\n\n for (const mime of encodingCandidates(purpose, hasAlpha)) {\n const blob = await canvas.convertToBlob({ type: mime, quality });\n if (blob.type === mime) return { blob, mime, ext: EXT[mime], width, height };\n }\n // Every browser can encode PNG; it's convertToBlob's own fallback.\n const blob = await canvas.convertToBlob({ type: \"image/png\" });\n return { blob, mime: \"image/png\", ext: \"png\", width, height };\n } finally {\n bitmap.close();\n }\n}\n", "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\",\n \"title\": \"Gramps Connect Story, format 1.0\",\n \"description\": \"The story.json at the root of a .story.zip. See spec/1.0/README.md for the rules this schema can't express (every ref resolves, every src exists in the zip, unknown fields are ignored).\",\n \"type\": \"object\",\n \"required\": [\"format\", \"version\", \"title\", \"slides\", \"media\"],\n \"properties\": {\n \"$schema\": { \"type\": \"string\" },\n \"format\": { \"const\": \"gramps-connect-story\" },\n \"version\": {\n \"description\": \"MAJOR.MINOR. This schema validates any 1.x file: newer minor versions only add optional fields.\",\n \"type\": \"string\",\n \"pattern\": \"^1\\\\.(0|[1-9][0-9]*)$\"\n },\n \"title\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"language\": {\n \"description\": \"BCP 47 language tag of the story's text, e.g. \\\"en\\\", \\\"de-CH\\\".\",\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"\n },\n \"created\": {\n \"description\": \"When the file was written, as an RFC 3339 date-time.\",\n \"type\": \"string\",\n \"pattern\": \"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"\n },\n \"generator\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"version\": { \"type\": \"string\" },\n \"url\": { \"type\": \"string\" }\n }\n },\n \"authors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"url\": { \"type\": \"string\" }\n }\n }\n },\n \"license\": {\n \"description\": \"License of the story's content (text and media), as an SPDX identifier or free text.\",\n \"type\": \"string\"\n },\n \"presentation\": {\n \"type\": \"object\",\n \"properties\": {\n \"basemap\": { \"enum\": [\"standard\", \"historical\", \"auto\", \"none\"] }\n }\n },\n \"slides\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/$defs/slide\" }\n },\n \"media\": {\n \"description\": \"Every media file in the story, keyed by an id that slides and overlays refer to.\",\n \"type\": \"object\",\n \"propertyNames\": { \"$ref\": \"#/$defs/id\" },\n \"additionalProperties\": { \"$ref\": \"#/$defs/mediaItem\" }\n },\n \"extensions\": {\n \"description\": \"Producer-specific data, keyed by namespace. Viewers ignore it.\",\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"object\" }\n }\n },\n \"$defs\": {\n \"id\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Za-z0-9_-]{1,64}$\"\n },\n \"storyDate\": {\n \"type\": \"object\",\n \"required\": [\"text\"],\n \"properties\": {\n \"text\": {\n \"description\": \"The date as it should be shown, in the story's language.\",\n \"type\": \"string\",\n \"pattern\": \"\\\\S\"\n },\n \"edtf\": {\n \"description\": \"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\n \"type\": \"string\",\n \"pattern\": \"\\\\S\"\n },\n \"sortYear\": {\n \"description\": \"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\n \"type\": \"integer\"\n }\n }\n },\n \"slide\": {\n \"type\": \"object\",\n \"required\": [\"id\"],\n \"properties\": {\n \"id\": { \"$ref\": \"#/$defs/id\" },\n \"title\": { \"type\": \"string\" },\n \"text\": {\n \"description\": \"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\n \"type\": \"string\"\n },\n \"date\": { \"$ref\": \"#/$defs/storyDate\" },\n \"place\": { \"$ref\": \"#/$defs/place\" },\n \"media\": {\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/slideMedia\" }\n },\n \"people\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"name\"],\n \"properties\": {\n \"name\": { \"type\": \"string\", \"pattern\": \"\\\\S\" },\n \"role\": { \"type\": \"string\" }\n }\n }\n }\n }\n },\n \"slideMedia\": {\n \"type\": \"object\",\n \"required\": [\"ref\"],\n \"properties\": {\n \"ref\": { \"$ref\": \"#/$defs/id\" },\n \"caption\": { \"type\": \"string\" },\n \"credit\": { \"type\": \"string\" }\n }\n },\n \"place\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": { \"type\": \"string\" },\n \"lat\": { \"type\": \"number\", \"minimum\": -90, \"maximum\": 90 },\n \"lon\": { \"type\": \"number\", \"minimum\": -180, \"maximum\": 180 },\n \"geometry\": {\n \"description\": \"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\n \"type\": \"object\",\n \"required\": [\"type\"],\n \"properties\": { \"type\": { \"type\": \"string\" } },\n \"additionalProperties\": true\n },\n \"overlays\": {\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/overlay\" }\n }\n },\n \"dependentRequired\": {\n \"lat\": [\"lon\"],\n \"lon\": [\"lat\"]\n }\n },\n \"lonLat\": {\n \"type\": \"array\",\n \"prefixItems\": [\n { \"type\": \"number\", \"minimum\": -180, \"maximum\": 180 },\n { \"type\": \"number\", \"minimum\": -90, \"maximum\": 90 }\n ],\n \"minItems\": 2,\n \"maxItems\": 2\n },\n \"overlay\": {\n \"type\": \"object\",\n \"required\": [\"media\", \"corners\"],\n \"properties\": {\n \"media\": { \"$ref\": \"#/$defs/id\" },\n \"corners\": {\n \"description\": \"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\n \"type\": \"array\",\n \"items\": { \"$ref\": \"#/$defs/lonLat\" },\n \"minItems\": 4,\n \"maxItems\": 4\n },\n \"opacity\": { \"type\": \"number\", \"minimum\": 0, \"maximum\": 1 },\n \"order\": {\n \"description\": \"Stacking order among a slide's overlays; lower is drawn first.\",\n \"type\": \"integer\"\n },\n \"date\": { \"$ref\": \"#/$defs/storyDate\" }\n }\n },\n \"mediaItem\": {\n \"type\": \"object\",\n \"required\": [\"src\", \"mime\"],\n \"properties\": {\n \"src\": {\n \"description\": \"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\n \"type\": \"string\",\n \"pattern\": \"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"\n },\n \"mime\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-z]+/[A-Za-z0-9.+-]+$\"\n },\n \"width\": { \"type\": \"integer\", \"minimum\": 1 },\n \"height\": { \"type\": \"integer\", \"minimum\": 1 },\n \"alt\": { \"type\": \"string\" }\n }\n }\n }\n}\n", "// GENERATED by scripts/generate-validator.mjs from spec/1.0/story.schema.json -- do not edit.\n// @ts-nocheck\n\"use strict\";export const validate = validate20;export default validate20;const schema31 = {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\",\"title\":\"Gramps Connect Story, format 1.0\",\"description\":\"The story.json at the root of a .story.zip. See spec/1.0/README.md for the rules this schema can't express (every ref resolves, every src exists in the zip, unknown fields are ignored).\",\"type\":\"object\",\"required\":[\"format\",\"version\",\"title\",\"slides\",\"media\"],\"properties\":{\"$schema\":{\"type\":\"string\"},\"format\":{\"const\":\"gramps-connect-story\"},\"version\":{\"description\":\"MAJOR.MINOR. This schema validates any 1.x file: newer minor versions only add optional fields.\",\"type\":\"string\",\"pattern\":\"^1\\\\.(0|[1-9][0-9]*)$\"},\"title\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"language\":{\"description\":\"BCP 47 language tag of the story's text, e.g. \\\"en\\\", \\\"de-CH\\\".\",\"type\":\"string\",\"pattern\":\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"},\"created\":{\"description\":\"When the file was written, as an RFC 3339 date-time.\",\"type\":\"string\",\"pattern\":\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"},\"generator\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"version\":{\"type\":\"string\"},\"url\":{\"type\":\"string\"}}},\"authors\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"url\":{\"type\":\"string\"}}}},\"license\":{\"description\":\"License of the story's content (text and media), as an SPDX identifier or free text.\",\"type\":\"string\"},\"presentation\":{\"type\":\"object\",\"properties\":{\"basemap\":{\"enum\":[\"standard\",\"historical\",\"auto\",\"none\"]}}},\"slides\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/$defs/slide\"}},\"media\":{\"description\":\"Every media file in the story, keyed by an id that slides and overlays refer to.\",\"type\":\"object\",\"propertyNames\":{\"$ref\":\"#/$defs/id\"},\"additionalProperties\":{\"$ref\":\"#/$defs/mediaItem\"}},\"extensions\":{\"description\":\"Producer-specific data, keyed by namespace. Viewers ignore it.\",\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"$defs\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[A-Za-z0-9_-]{1,64}$\"},\"storyDate\":{\"type\":\"object\",\"required\":[\"text\"],\"properties\":{\"text\":{\"description\":\"The date as it should be shown, in the story's language.\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"edtf\":{\"description\":\"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"sortYear\":{\"description\":\"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\"type\":\"integer\"}}},\"slide\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"$ref\":\"#/$defs/id\"},\"title\":{\"type\":\"string\"},\"text\":{\"description\":\"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\"type\":\"string\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"},\"place\":{\"$ref\":\"#/$defs/place\"},\"media\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/slideMedia\"}},\"people\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"role\":{\"type\":\"string\"}}}}}},\"slideMedia\":{\"type\":\"object\",\"required\":[\"ref\"],\"properties\":{\"ref\":{\"$ref\":\"#/$defs/id\"},\"caption\":{\"type\":\"string\"},\"credit\":{\"type\":\"string\"}}},\"place\":{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"},\"lat\":{\"type\":\"number\",\"minimum\":-90,\"maximum\":90},\"lon\":{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},\"geometry\":{\"description\":\"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\"type\":\"object\",\"required\":[\"type\"],\"properties\":{\"type\":{\"type\":\"string\"}},\"additionalProperties\":true},\"overlays\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/overlay\"}}},\"dependentRequired\":{\"lat\":[\"lon\"],\"lon\":[\"lat\"]}},\"lonLat\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},{\"type\":\"number\",\"minimum\":-90,\"maximum\":90}],\"minItems\":2,\"maxItems\":2},\"overlay\":{\"type\":\"object\",\"required\":[\"media\",\"corners\"],\"properties\":{\"media\":{\"$ref\":\"#/$defs/id\"},\"corners\":{\"description\":\"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/lonLat\"},\"minItems\":4,\"maxItems\":4},\"opacity\":{\"type\":\"number\",\"minimum\":0,\"maximum\":1},\"order\":{\"description\":\"Stacking order among a slide's overlays; lower is drawn first.\",\"type\":\"integer\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"}}},\"mediaItem\":{\"type\":\"object\",\"required\":[\"src\",\"mime\"],\"properties\":{\"src\":{\"description\":\"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\"type\":\"string\",\"pattern\":\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},\"mime\":{\"type\":\"string\",\"pattern\":\"^[a-z]+/[A-Za-z0-9.+-]+$\"},\"width\":{\"type\":\"integer\",\"minimum\":1},\"height\":{\"type\":\"integer\",\"minimum\":1},\"alt\":{\"type\":\"string\"}}}}};const schema33 = {\"type\":\"string\",\"pattern\":\"^[A-Za-z0-9_-]{1,64}$\"};const schema43 = {\"type\":\"object\",\"required\":[\"src\",\"mime\"],\"properties\":{\"src\":{\"description\":\"Path of the file inside the zip, relative to its root. No leading slash, no \\\"..\\\" segments.\",\"type\":\"string\",\"pattern\":\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},\"mime\":{\"type\":\"string\",\"pattern\":\"^[a-z]+/[A-Za-z0-9.+-]+$\"},\"width\":{\"type\":\"integer\",\"minimum\":1},\"height\":{\"type\":\"integer\",\"minimum\":1},\"alt\":{\"type\":\"string\"}}};const pattern4 = new RegExp(\"^1\\\\.(0|[1-9][0-9]*)$\", \"u\");const pattern5 = new RegExp(\"\\\\S\", \"u\");const pattern6 = new RegExp(\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\", \"u\");const pattern7 = new RegExp(\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\", \"u\");const pattern10 = new RegExp(\"^[A-Za-z0-9_-]{1,64}$\", \"u\");const pattern19 = new RegExp(\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\", \"u\");const pattern20 = new RegExp(\"^[a-z]+/[A-Za-z0-9.+-]+$\", \"u\");const schema32 = {\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"$ref\":\"#/$defs/id\"},\"title\":{\"type\":\"string\"},\"text\":{\"description\":\"Body text. Markup: **bold**, *italic*, line breaks. Nothing else is interpreted.\",\"type\":\"string\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"},\"place\":{\"$ref\":\"#/$defs/place\"},\"media\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/slideMedia\"}},\"people\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"name\"],\"properties\":{\"name\":{\"type\":\"string\",\"pattern\":\"\\\\S\"},\"role\":{\"type\":\"string\"}}}}}};const schema34 = {\"type\":\"object\",\"required\":[\"text\"],\"properties\":{\"text\":{\"description\":\"The date as it should be shown, in the story's language.\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"edtf\":{\"description\":\"Optional machine-readable form, in Extended Date/Time Format (ISO 8601-2).\",\"type\":\"string\",\"pattern\":\"\\\\S\"},\"sortYear\":{\"description\":\"Optional year (proleptic Gregorian) that places the slide on the timeline.\",\"type\":\"integer\"}}};const schema35 = {\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"},\"lat\":{\"type\":\"number\",\"minimum\":-90,\"maximum\":90},\"lon\":{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},\"geometry\":{\"description\":\"Optional GeoJSON (RFC 7946) object drawn under the slide's pin: a FeatureCollection, Feature, or bare geometry.\",\"type\":\"object\",\"required\":[\"type\"],\"properties\":{\"type\":{\"type\":\"string\"}},\"additionalProperties\":true},\"overlays\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/overlay\"}}},\"dependentRequired\":{\"lat\":[\"lon\"],\"lon\":[\"lat\"]}};const schema36 = {\"type\":\"object\",\"required\":[\"media\",\"corners\"],\"properties\":{\"media\":{\"$ref\":\"#/$defs/id\"},\"corners\":{\"description\":\"[lon, lat] of the image's top-left, top-right, bottom-right and bottom-left corners.\",\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/lonLat\"},\"minItems\":4,\"maxItems\":4},\"opacity\":{\"type\":\"number\",\"minimum\":0,\"maximum\":1},\"order\":{\"description\":\"Stacking order among a slide's overlays; lower is drawn first.\",\"type\":\"integer\"},\"date\":{\"$ref\":\"#/$defs/storyDate\"}}};const schema38 = {\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\",\"minimum\":-180,\"maximum\":180},{\"type\":\"number\",\"minimum\":-90,\"maximum\":90}],\"minItems\":2,\"maxItems\":2};function validate23(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate23.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.media === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"media\"},message:\"must have required property '\"+\"media\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.corners === undefined){const err1 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"corners\"},message:\"must have required property '\"+\"corners\"+\"'\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.media !== undefined){let data0 = data.media;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err2 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}else {const err3 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.corners !== undefined){let data1 = data.corners;if(Array.isArray(data1)){if(data1.length > 4){const err4 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/maxItems\",keyword:\"maxItems\",params:{limit: 4},message:\"must NOT have more than 4 items\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data1.length < 4){const err5 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/minItems\",keyword:\"minItems\",params:{limit: 4},message:\"must NOT have fewer than 4 items\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}const len0 = data1.length;for(let i0=0; i0<len0; i0++){let data2 = data1[i0];if(Array.isArray(data2)){if(data2.length > 2){const err6 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/maxItems\",keyword:\"maxItems\",params:{limit: 2},message:\"must NOT have more than 2 items\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(data2.length < 2){const err7 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/minItems\",keyword:\"minItems\",params:{limit: 2},message:\"must NOT have fewer than 2 items\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}const len1 = data2.length;if(len1 > 0){let data3 = data2[0];if((typeof data3 == \"number\") && (isFinite(data3))){if(data3 > 180 || isNaN(data3)){const err8 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 180},message:\"must be <= 180\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}if(data3 < -180 || isNaN(data3)){const err9 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -180},message:\"must be >= -180\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+\"/corners/\" + i0+\"/0\",schemaPath:\"#/$defs/lonLat/prefixItems/0/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(len1 > 1){let data4 = data2[1];if((typeof data4 == \"number\") && (isFinite(data4))){if(data4 > 90 || isNaN(data4)){const err11 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 90},message:\"must be <= 90\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}if(data4 < -90 || isNaN(data4)){const err12 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -90},message:\"must be >= -90\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+\"/corners/\" + i0+\"/1\",schemaPath:\"#/$defs/lonLat/prefixItems/1/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}}else {const err14 = {instancePath:instancePath+\"/corners/\" + i0,schemaPath:\"#/$defs/lonLat/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}}else {const err15 = {instancePath:instancePath+\"/corners\",schemaPath:\"#/properties/corners/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.opacity !== undefined){let data5 = data.opacity;if((typeof data5 == \"number\") && (isFinite(data5))){if(data5 > 1 || isNaN(data5)){const err16 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 1},message:\"must be <= 1\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}if(data5 < 0 || isNaN(data5)){const err17 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 0},message:\"must be >= 0\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}else {const err18 = {instancePath:instancePath+\"/opacity\",schemaPath:\"#/properties/opacity/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}if(data.order !== undefined){let data6 = data.order;if(!(((typeof data6 == \"number\") && (!(data6 % 1) && !isNaN(data6))) && (isFinite(data6)))){const err19 = {instancePath:instancePath+\"/order\",schemaPath:\"#/properties/order/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}if(data.date !== undefined){let data7 = data.date;if(data7 && typeof data7 == \"object\" && !Array.isArray(data7)){if(data7.text === undefined){const err20 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/required\",keyword:\"required\",params:{missingProperty: \"text\"},message:\"must have required property '\"+\"text\"+\"'\"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data7.text !== undefined){let data8 = data7.text;if(typeof data8 === \"string\"){if(!pattern5.test(data8)){const err21 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}else {const err22 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data7.edtf !== undefined){let data9 = data7.edtf;if(typeof data9 === \"string\"){if(!pattern5.test(data9)){const err23 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}else {const err24 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data7.sortYear !== undefined){let data10 = data7.sortYear;if(!(((typeof data10 == \"number\") && (!(data10 % 1) && !isNaN(data10))) && (isFinite(data10)))){const err25 = {instancePath:instancePath+\"/date/sortYear\",schemaPath:\"#/$defs/storyDate/properties/sortYear/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}else {const err26 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}validate23.errors = vErrors;return errors === 0;}validate23.evaluated = {\"props\":{\"media\":true,\"corners\":true,\"opacity\":true,\"order\":true,\"date\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate22(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate22.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.name !== undefined){if(typeof data.name !== \"string\"){const err0 = {instancePath:instancePath+\"/name\",schemaPath:\"#/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}}if(data.lat !== undefined){let data1 = data.lat;if((typeof data1 == \"number\") && (isFinite(data1))){if(data1 > 90 || isNaN(data1)){const err1 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 90},message:\"must be <= 90\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data1 < -90 || isNaN(data1)){const err2 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -90},message:\"must be >= -90\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}else {const err3 = {instancePath:instancePath+\"/lat\",schemaPath:\"#/properties/lat/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.lon !== undefined){let data2 = data.lon;if((typeof data2 == \"number\") && (isFinite(data2))){if(data2 > 180 || isNaN(data2)){const err4 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/maximum\",keyword:\"maximum\",params:{comparison: \"<=\", limit: 180},message:\"must be <= 180\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data2 < -180 || isNaN(data2)){const err5 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: -180},message:\"must be >= -180\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}else {const err6 = {instancePath:instancePath+\"/lon\",schemaPath:\"#/properties/lon/type\",keyword:\"type\",params:{type: \"number\"},message:\"must be number\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.geometry !== undefined){let data3 = data.geometry;if(data3 && typeof data3 == \"object\" && !Array.isArray(data3)){if(data3.type === undefined){const err7 = {instancePath:instancePath+\"/geometry\",schemaPath:\"#/properties/geometry/required\",keyword:\"required\",params:{missingProperty: \"type\"},message:\"must have required property '\"+\"type\"+\"'\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}if(data3.type !== undefined){if(typeof data3.type !== \"string\"){const err8 = {instancePath:instancePath+\"/geometry/type\",schemaPath:\"#/properties/geometry/properties/type/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}else {const err9 = {instancePath:instancePath+\"/geometry\",schemaPath:\"#/properties/geometry/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.overlays !== undefined){let data5 = data.overlays;if(Array.isArray(data5)){const len0 = data5.length;for(let i0=0; i0<len0; i0++){if(!(validate23(data5[i0], {instancePath:instancePath+\"/overlays/\" + i0,parentData:data5,parentDataProperty:i0,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}}}else {const err10 = {instancePath:instancePath+\"/overlays\",schemaPath:\"#/properties/overlays/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.lat !== undefined){if(data.lon === undefined){const err11 = {instancePath,schemaPath:\"#/dependentRequired\",keyword:\"dependentRequired\",params:{property: \"lat\",\n missingProperty: \"lon\",\n depsCount: 1,\n deps: \"lon\"},message:\"must have property lon when property lat is present\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.lon !== undefined){if(data.lat === undefined){const err12 = {instancePath,schemaPath:\"#/dependentRequired\",keyword:\"dependentRequired\",params:{property: \"lon\",\n missingProperty: \"lat\",\n depsCount: 1,\n deps: \"lat\"},message:\"must have property lat when property lon is present\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}}else {const err13 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}validate22.errors = vErrors;return errors === 0;}validate22.evaluated = {\"props\":{\"name\":true,\"lat\":true,\"lon\":true,\"geometry\":true,\"overlays\":true},\"dynamicProps\":false,\"dynamicItems\":false};const schema40 = {\"type\":\"object\",\"required\":[\"ref\"],\"properties\":{\"ref\":{\"$ref\":\"#/$defs/id\"},\"caption\":{\"type\":\"string\"},\"credit\":{\"type\":\"string\"}}};function validate26(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate26.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.ref === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"ref\"},message:\"must have required property '\"+\"ref\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.ref !== undefined){let data0 = data.ref;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err1 = {instancePath:instancePath+\"/ref\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}else {const err2 = {instancePath:instancePath+\"/ref\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.caption !== undefined){if(typeof data.caption !== \"string\"){const err3 = {instancePath:instancePath+\"/caption\",schemaPath:\"#/properties/caption/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.credit !== undefined){if(typeof data.credit !== \"string\"){const err4 = {instancePath:instancePath+\"/credit\",schemaPath:\"#/properties/credit/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}validate26.errors = vErrors;return errors === 0;}validate26.evaluated = {\"props\":{\"ref\":true,\"caption\":true,\"credit\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate21(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate21.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.id === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"id\"},message:\"must have required property '\"+\"id\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.id !== undefined){let data0 = data.id;if(typeof data0 === \"string\"){if(!pattern10.test(data0)){const err1 = {instancePath:instancePath+\"/id\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}else {const err2 = {instancePath:instancePath+\"/id\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.title !== undefined){if(typeof data.title !== \"string\"){const err3 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.text !== undefined){if(typeof data.text !== \"string\"){const err4 = {instancePath:instancePath+\"/text\",schemaPath:\"#/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.date !== undefined){let data3 = data.date;if(data3 && typeof data3 == \"object\" && !Array.isArray(data3)){if(data3.text === undefined){const err5 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/required\",keyword:\"required\",params:{missingProperty: \"text\"},message:\"must have required property '\"+\"text\"+\"'\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}if(data3.text !== undefined){let data4 = data3.text;if(typeof data4 === \"string\"){if(!pattern5.test(data4)){const err6 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}else {const err7 = {instancePath:instancePath+\"/date/text\",schemaPath:\"#/$defs/storyDate/properties/text/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data3.edtf !== undefined){let data5 = data3.edtf;if(typeof data5 === \"string\"){if(!pattern5.test(data5)){const err8 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}else {const err9 = {instancePath:instancePath+\"/date/edtf\",schemaPath:\"#/$defs/storyDate/properties/edtf/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data3.sortYear !== undefined){let data6 = data3.sortYear;if(!(((typeof data6 == \"number\") && (!(data6 % 1) && !isNaN(data6))) && (isFinite(data6)))){const err10 = {instancePath:instancePath+\"/date/sortYear\",schemaPath:\"#/$defs/storyDate/properties/sortYear/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}else {const err11 = {instancePath:instancePath+\"/date\",schemaPath:\"#/$defs/storyDate/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.place !== undefined){if(!(validate22(data.place, {instancePath:instancePath+\"/place\",parentData:data,parentDataProperty:\"place\",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate22.errors : vErrors.concat(validate22.errors);errors = vErrors.length;}}if(data.media !== undefined){let data8 = data.media;if(Array.isArray(data8)){const len0 = data8.length;for(let i0=0; i0<len0; i0++){if(!(validate26(data8[i0], {instancePath:instancePath+\"/media/\" + i0,parentData:data8,parentDataProperty:i0,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate26.errors : vErrors.concat(validate26.errors);errors = vErrors.length;}}}else {const err12 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.people !== undefined){let data10 = data.people;if(Array.isArray(data10)){const len1 = data10.length;for(let i1=0; i1<len1; i1++){let data11 = data10[i1];if(data11 && typeof data11 == \"object\" && !Array.isArray(data11)){if(data11.name === undefined){const err13 = {instancePath:instancePath+\"/people/\" + i1,schemaPath:\"#/properties/people/items/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}if(data11.name !== undefined){let data12 = data11.name;if(typeof data12 === \"string\"){if(!pattern5.test(data12)){const err14 = {instancePath:instancePath+\"/people/\" + i1+\"/name\",schemaPath:\"#/properties/people/items/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}else {const err15 = {instancePath:instancePath+\"/people/\" + i1+\"/name\",schemaPath:\"#/properties/people/items/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data11.role !== undefined){if(typeof data11.role !== \"string\"){const err16 = {instancePath:instancePath+\"/people/\" + i1+\"/role\",schemaPath:\"#/properties/people/items/properties/role/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath:instancePath+\"/people/\" + i1,schemaPath:\"#/properties/people/items/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}}else {const err18 = {instancePath:instancePath+\"/people\",schemaPath:\"#/properties/people/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}}else {const err19 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}validate21.errors = vErrors;return errors === 0;}validate21.evaluated = {\"props\":{\"id\":true,\"title\":true,\"text\":true,\"date\":true,\"place\":true,\"media\":true,\"people\":true},\"dynamicProps\":false,\"dynamicItems\":false};function validate20(data, {instancePath=\"\", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL=\"https://dsblank.github.io/gramps-connect-stories/spec/1.0/story.schema.json\" */;let vErrors = null;let errors = 0;const evaluated0 = validate20.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == \"object\" && !Array.isArray(data)){if(data.format === undefined){const err0 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"format\"},message:\"must have required property '\"+\"format\"+\"'\"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.version === undefined){const err1 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"version\"},message:\"must have required property '\"+\"version\"+\"'\"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.title === undefined){const err2 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"title\"},message:\"must have required property '\"+\"title\"+\"'\"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.slides === undefined){const err3 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"slides\"},message:\"must have required property '\"+\"slides\"+\"'\"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(data.media === undefined){const err4 = {instancePath,schemaPath:\"#/required\",keyword:\"required\",params:{missingProperty: \"media\"},message:\"must have required property '\"+\"media\"+\"'\"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data.$schema !== undefined){if(typeof data.$schema !== \"string\"){const err5 = {instancePath:instancePath+\"/$schema\",schemaPath:\"#/properties/%24schema/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.format !== undefined){if(\"gramps-connect-story\" !== data.format){const err6 = {instancePath:instancePath+\"/format\",schemaPath:\"#/properties/format/const\",keyword:\"const\",params:{allowedValue: \"gramps-connect-story\"},message:\"must be equal to constant\"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.version !== undefined){let data2 = data.version;if(typeof data2 === \"string\"){if(!pattern4.test(data2)){const err7 = {instancePath:instancePath+\"/version\",schemaPath:\"#/properties/version/pattern\",keyword:\"pattern\",params:{pattern: \"^1\\\\.(0|[1-9][0-9]*)$\"},message:\"must match pattern \\\"\"+\"^1\\\\.(0|[1-9][0-9]*)$\"+\"\\\"\"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}else {const err8 = {instancePath:instancePath+\"/version\",schemaPath:\"#/properties/version/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.title !== undefined){let data3 = data.title;if(typeof data3 === \"string\"){if(!pattern5.test(data3)){const err9 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+\"/title\",schemaPath:\"#/properties/title/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.language !== undefined){let data4 = data.language;if(typeof data4 === \"string\"){if(!pattern6.test(data4)){const err11 = {instancePath:instancePath+\"/language\",schemaPath:\"#/properties/language/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\"+\"\\\"\"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}else {const err12 = {instancePath:instancePath+\"/language\",schemaPath:\"#/properties/language/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.created !== undefined){let data5 = data.created;if(typeof data5 === \"string\"){if(!pattern7.test(data5)){const err13 = {instancePath:instancePath+\"/created\",schemaPath:\"#/properties/created/pattern\",keyword:\"pattern\",params:{pattern: \"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"},message:\"must match pattern \\\"\"+\"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$\"+\"\\\"\"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}else {const err14 = {instancePath:instancePath+\"/created\",schemaPath:\"#/properties/created/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.generator !== undefined){let data6 = data.generator;if(data6 && typeof data6 == \"object\" && !Array.isArray(data6)){if(data6.name === undefined){const err15 = {instancePath:instancePath+\"/generator\",schemaPath:\"#/properties/generator/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}if(data6.name !== undefined){let data7 = data6.name;if(typeof data7 === \"string\"){if(!pattern5.test(data7)){const err16 = {instancePath:instancePath+\"/generator/name\",schemaPath:\"#/properties/generator/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}else {const err17 = {instancePath:instancePath+\"/generator/name\",schemaPath:\"#/properties/generator/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data6.version !== undefined){if(typeof data6.version !== \"string\"){const err18 = {instancePath:instancePath+\"/generator/version\",schemaPath:\"#/properties/generator/properties/version/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}if(data6.url !== undefined){if(typeof data6.url !== \"string\"){const err19 = {instancePath:instancePath+\"/generator/url\",schemaPath:\"#/properties/generator/properties/url/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}}else {const err20 = {instancePath:instancePath+\"/generator\",schemaPath:\"#/properties/generator/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}if(data.authors !== undefined){let data10 = data.authors;if(Array.isArray(data10)){const len0 = data10.length;for(let i0=0; i0<len0; i0++){let data11 = data10[i0];if(data11 && typeof data11 == \"object\" && !Array.isArray(data11)){if(data11.name === undefined){const err21 = {instancePath:instancePath+\"/authors/\" + i0,schemaPath:\"#/properties/authors/items/required\",keyword:\"required\",params:{missingProperty: \"name\"},message:\"must have required property '\"+\"name\"+\"'\"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}if(data11.name !== undefined){let data12 = data11.name;if(typeof data12 === \"string\"){if(!pattern5.test(data12)){const err22 = {instancePath:instancePath+\"/authors/\" + i0+\"/name\",schemaPath:\"#/properties/authors/items/properties/name/pattern\",keyword:\"pattern\",params:{pattern: \"\\\\S\"},message:\"must match pattern \\\"\"+\"\\\\S\"+\"\\\"\"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}else {const err23 = {instancePath:instancePath+\"/authors/\" + i0+\"/name\",schemaPath:\"#/properties/authors/items/properties/name/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data11.url !== undefined){if(typeof data11.url !== \"string\"){const err24 = {instancePath:instancePath+\"/authors/\" + i0+\"/url\",schemaPath:\"#/properties/authors/items/properties/url/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}}else {const err25 = {instancePath:instancePath+\"/authors/\" + i0,schemaPath:\"#/properties/authors/items/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}else {const err26 = {instancePath:instancePath+\"/authors\",schemaPath:\"#/properties/authors/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}if(data.license !== undefined){if(typeof data.license !== \"string\"){const err27 = {instancePath:instancePath+\"/license\",schemaPath:\"#/properties/license/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}}if(data.presentation !== undefined){let data15 = data.presentation;if(data15 && typeof data15 == \"object\" && !Array.isArray(data15)){if(data15.basemap !== undefined){let data16 = data15.basemap;if(!((((data16 === \"standard\") || (data16 === \"historical\")) || (data16 === \"auto\")) || (data16 === \"none\"))){const err28 = {instancePath:instancePath+\"/presentation/basemap\",schemaPath:\"#/properties/presentation/properties/basemap/enum\",keyword:\"enum\",params:{allowedValues: schema31.properties.presentation.properties.basemap.enum},message:\"must be equal to one of the allowed values\"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}}}else {const err29 = {instancePath:instancePath+\"/presentation\",schemaPath:\"#/properties/presentation/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}}if(data.slides !== undefined){let data17 = data.slides;if(Array.isArray(data17)){if(data17.length < 1){const err30 = {instancePath:instancePath+\"/slides\",schemaPath:\"#/properties/slides/minItems\",keyword:\"minItems\",params:{limit: 1},message:\"must NOT have fewer than 1 items\"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}const len1 = data17.length;for(let i1=0; i1<len1; i1++){if(!(validate21(data17[i1], {instancePath:instancePath+\"/slides/\" + i1,parentData:data17,parentDataProperty:i1,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate21.errors : vErrors.concat(validate21.errors);errors = vErrors.length;}}}else {const err31 = {instancePath:instancePath+\"/slides\",schemaPath:\"#/properties/slides/type\",keyword:\"type\",params:{type: \"array\"},message:\"must be array\"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}if(data.media !== undefined){let data19 = data.media;if(data19 && typeof data19 == \"object\" && !Array.isArray(data19)){for(const key0 in data19){const _errs38 = errors;if(typeof key0 === \"string\"){if(!pattern10.test(key0)){const err32 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/pattern\",keyword:\"pattern\",params:{pattern: \"^[A-Za-z0-9_-]{1,64}$\"},message:\"must match pattern \\\"\"+\"^[A-Za-z0-9_-]{1,64}$\"+\"\\\"\",propertyName:key0};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}}else {const err33 = {instancePath:instancePath+\"/media\",schemaPath:\"#/$defs/id/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\",propertyName:key0};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}var valid8 = _errs38 === errors;if(!valid8){const err34 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/propertyNames\",keyword:\"propertyNames\",params:{propertyName: key0},message:\"property name must be valid\"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}for(const key1 in data19){let data20 = data19[key1];if(data20 && typeof data20 == \"object\" && !Array.isArray(data20)){if(data20.src === undefined){const err35 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/required\",keyword:\"required\",params:{missingProperty: \"src\"},message:\"must have required property '\"+\"src\"+\"'\"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}if(data20.mime === undefined){const err36 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/required\",keyword:\"required\",params:{missingProperty: \"mime\"},message:\"must have required property '\"+\"mime\"+\"'\"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}if(data20.src !== undefined){let data21 = data20.src;if(typeof data21 === \"string\"){if(!pattern19.test(data21)){const err37 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/src\",schemaPath:\"#/$defs/mediaItem/properties/src/pattern\",keyword:\"pattern\",params:{pattern: \"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"},message:\"must match pattern \\\"\"+\"^(?!/)(?!.*(^|/)\\\\.\\\\.?(/|$))[^\\\\\\\\]+$\"+\"\\\"\"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}}else {const err38 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/src\",schemaPath:\"#/$defs/mediaItem/properties/src/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}}if(data20.mime !== undefined){let data22 = data20.mime;if(typeof data22 === \"string\"){if(!pattern20.test(data22)){const err39 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/mime\",schemaPath:\"#/$defs/mediaItem/properties/mime/pattern\",keyword:\"pattern\",params:{pattern: \"^[a-z]+/[A-Za-z0-9.+-]+$\"},message:\"must match pattern \\\"\"+\"^[a-z]+/[A-Za-z0-9.+-]+$\"+\"\\\"\"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}else {const err40 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/mime\",schemaPath:\"#/$defs/mediaItem/properties/mime/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}}if(data20.width !== undefined){let data23 = data20.width;if(!(((typeof data23 == \"number\") && (!(data23 % 1) && !isNaN(data23))) && (isFinite(data23)))){const err41 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/width\",schemaPath:\"#/$defs/mediaItem/properties/width/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}if((typeof data23 == \"number\") && (isFinite(data23))){if(data23 < 1 || isNaN(data23)){const err42 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/width\",schemaPath:\"#/$defs/mediaItem/properties/width/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 1},message:\"must be >= 1\"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}}if(data20.height !== undefined){let data24 = data20.height;if(!(((typeof data24 == \"number\") && (!(data24 % 1) && !isNaN(data24))) && (isFinite(data24)))){const err43 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/height\",schemaPath:\"#/$defs/mediaItem/properties/height/type\",keyword:\"type\",params:{type: \"integer\"},message:\"must be integer\"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}if((typeof data24 == \"number\") && (isFinite(data24))){if(data24 < 1 || isNaN(data24)){const err44 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/height\",schemaPath:\"#/$defs/mediaItem/properties/height/minimum\",keyword:\"minimum\",params:{comparison: \">=\", limit: 1},message:\"must be >= 1\"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}}}if(data20.alt !== undefined){if(typeof data20.alt !== \"string\"){const err45 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")+\"/alt\",schemaPath:\"#/$defs/mediaItem/properties/alt/type\",keyword:\"type\",params:{type: \"string\"},message:\"must be string\"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}}}else {const err46 = {instancePath:instancePath+\"/media/\" + key1.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/$defs/mediaItem/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}}else {const err47 = {instancePath:instancePath+\"/media\",schemaPath:\"#/properties/media/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.extensions !== undefined){let data26 = data.extensions;if(data26 && typeof data26 == \"object\" && !Array.isArray(data26)){for(const key2 in data26){let data27 = data26[key2];if(!(data27 && typeof data27 == \"object\" && !Array.isArray(data27))){const err48 = {instancePath:instancePath+\"/extensions/\" + key2.replace(/~/g, \"~0\").replace(/\\//g, \"~1\"),schemaPath:\"#/properties/extensions/additionalProperties/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}}}else {const err49 = {instancePath:instancePath+\"/extensions\",schemaPath:\"#/properties/extensions/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}}}else {const err50 = {instancePath,schemaPath:\"#/type\",keyword:\"type\",params:{type: \"object\"},message:\"must be object\"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}validate20.errors = vErrors;return errors === 0;}validate20.evaluated = {\"props\":{\"$schema\":true,\"format\":true,\"version\":true,\"title\":true,\"language\":true,\"created\":true,\"generator\":true,\"authors\":true,\"license\":true,\"presentation\":true,\"slides\":true,\"media\":true,\"extensions\":true},\"dynamicProps\":false,\"dynamicItems\":false};\n", "// Format identity and versioning (spec/1.0/README.md section 2), and the\n// chain of upgraders that lets this package keep opening every older major\n// version of the format.\nimport type { StoryDoc } from \"./types\";\n\nexport const FORMAT_ID = \"gramps-connect-story\";\n\n/** The version this package writes. */\nexport const FORMAT_VERSION = \"1.0\";\n\nexport const CURRENT_MAJOR = 1;\n\n/** Upgraders, keyed by the major version they upgrade *from*: UPGRADERS[1]\n * turns a 1.x document into a 2.0 one, and so on. Never remove one -- each\n * is the only thing that keeps old files opening -- and give each a fixture\n * from its source version under examples/. Empty while 1 is the only major.\n * Each receives a document that already passed its own version's checks. */\nconst UPGRADERS: Record<number, (doc: Record<string, unknown>) => Record<string, unknown>> = {};\n\n/** Every major version upgradeStory() can open. */\nexport const SUPPORTED_FORMAT_MAJORS: readonly number[] = Object.freeze(\n Array.from({ length: CURRENT_MAJOR }, (_, i) => i + 1).filter(\n (major) => major === CURRENT_MAJOR || UPGRADERS[major] !== undefined,\n ),\n);\n\nexport type StoryErrorCode =\n | \"not-a-zip\"\n | \"no-story-json\"\n | \"bad-json\"\n | \"not-a-story\"\n | \"bad-version\"\n | \"newer-version\"\n | \"too-large\"\n | \"invalid\";\n\nexport class StoryFormatError extends Error {\n readonly code: StoryErrorCode;\n constructor(code: StoryErrorCode, message: string) {\n super(message);\n this.name = \"StoryFormatError\";\n this.code = code;\n }\n}\n\nexport interface ParsedVersion {\n major: number;\n minor: number;\n}\n\nexport function parseVersion(version: unknown): ParsedVersion | null {\n if (typeof version !== \"string\") return null;\n const match = /^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$/.exec(version);\n if (!match) return null;\n return { major: Number(match[1]), minor: Number(match[2]) };\n}\n\n/** Checks `raw` is a story at all and brings it up to CURRENT_MAJOR.\n * Doesn't validate the result -- see validate.ts -- only what it needs to\n * pick upgraders: `format` and `version`. Throws StoryFormatError. */\nexport function upgradeStory(raw: unknown): StoryDoc {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new StoryFormatError(\"not-a-story\", \"story.json is not a JSON object.\");\n }\n let doc = raw as Record<string, unknown>;\n if (doc.format !== FORMAT_ID) {\n throw new StoryFormatError(\"not-a-story\", `story.json's \"format\" is not \"${FORMAT_ID}\".`);\n }\n const parsed = parseVersion(doc.version);\n if (!parsed || parsed.major < 1) {\n throw new StoryFormatError(\"bad-version\", `story.json's \"version\" (${JSON.stringify(doc.version)}) is not a valid MAJOR.MINOR version.`);\n }\n if (parsed.major > CURRENT_MAJOR) {\n throw new StoryFormatError(\n \"newer-version\",\n `This story uses format version ${doc.version}, which is newer than this viewer supports (up to ${CURRENT_MAJOR}.x). A newer viewer is needed to open it.`,\n );\n }\n for (let major = parsed.major; major < CURRENT_MAJOR; major++) {\n const upgrade = UPGRADERS[major];\n if (!upgrade) {\n throw new StoryFormatError(\"bad-version\", `No upgrade path from format version ${major}.x.`);\n }\n doc = upgrade(doc);\n }\n return doc as unknown as StoryDoc;\n}\n", "// Everything that makes a story.json valid: the JSON Schema (compiled ahead\n// of time into generated/schemaValidator.js -- see\n// scripts/generate-validator.mjs for why) plus the cross-references the\n// schema can't express (spec/1.0/README.md section 8).\nimport schema from \"../spec/1.0/story.schema.json\" with { type: \"json\" };\nimport { validate as schemaValidate } from \"./generated/schemaValidator.js\";\nimport { CURRENT_MAJOR, parseVersion } from \"./version\";\nimport type { StoryDoc } from \"./types\";\n\n/** Minor version of the schema bundled here: unknown fields in a file of\n * this minor version or older are probably typos, not newer features. */\nconst SCHEMA_MINOR = 0;\n\nexport interface StoryIssue {\n /** JSON Pointer into story.json (\"\" for the root), e.g. \"/slides/2/media/0/ref\". */\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: StoryIssue[];\n /** Not wrong, but probably not intended: unknown fields in a file that\n * claims a version this package fully knows, media nothing uses. */\n warnings: StoryIssue[];\n}\n\n/** Checks a story document. `files`, when given, is the set of paths in the\n * zip (relative to its story root), so every media `src` can be checked\n * too; without it only story.json itself is checked. */\nexport function validate(doc: unknown, files?: { has(path: string): boolean }): ValidationResult {\n const errors: StoryIssue[] = [];\n const warnings: StoryIssue[] = [];\n\n if (!schemaValidate(doc)) {\n for (const err of schemaValidate.errors ?? []) {\n errors.push({ path: err.instancePath, message: describeSchemaError(err) });\n }\n // Cross-reference checks below assume the basic shape is right.\n return { valid: false, errors, warnings };\n }\n const story = doc as StoryDoc;\n\n const slideIds = new Set<string>();\n const usedMedia = new Set<string>();\n const checkRef = (key: string, path: string) => {\n usedMedia.add(key);\n if (!Object.prototype.hasOwnProperty.call(story.media, key)) {\n errors.push({ path, message: `refers to media \"${key}\", which isn't in \"media\".` });\n }\n };\n story.slides.forEach((slide, i) => {\n if (slideIds.has(slide.id)) {\n errors.push({ path: `/slides/${i}/id`, message: `duplicate slide id \"${slide.id}\".` });\n }\n slideIds.add(slide.id);\n slide.media?.forEach((m, j) => checkRef(m.ref, `/slides/${i}/media/${j}/ref`));\n slide.place?.overlays?.forEach((o, j) => checkRef(o.media, `/slides/${i}/place/overlays/${j}/media`));\n });\n\n for (const [key, item] of Object.entries(story.media)) {\n const path = `/media/${escapePointer(key)}`;\n if (files && !files.has(item.src)) {\n errors.push({ path: `${path}/src`, message: `file \"${item.src}\" is not in the zip.` });\n }\n if (!usedMedia.has(key)) {\n warnings.push({ path, message: `media \"${key}\" isn't used by any slide or overlay.` });\n }\n }\n\n const version = parseVersion(story.version);\n if (version && version.major === CURRENT_MAJOR && version.minor <= SCHEMA_MINOR) {\n findUnknownFields(story, schema as unknown as SchemaNode, \"\", warnings);\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\ninterface AjvError {\n instancePath: string;\n keyword: string;\n params: Record<string, unknown>;\n message?: string;\n}\n\nfunction describeSchemaError(err: AjvError): string {\n if (err.keyword === \"pattern\" && err.params.pattern === \"\\\\S\") return \"must not be empty.\";\n if (err.keyword === \"required\") return `is missing required field \"${String(err.params.missingProperty)}\".`;\n if (err.keyword === \"const\") return `must be ${JSON.stringify(err.params.allowedValue)}.`;\n if (err.keyword === \"enum\") return `must be one of ${(err.params.allowedValues as unknown[]).map((v) => JSON.stringify(v)).join(\", \")}.`;\n return `${err.message ?? \"is invalid\"}.`;\n}\n\nfunction escapePointer(key: string): string {\n return key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n}\n\ntype SchemaNode = {\n $ref?: string;\n properties?: Record<string, SchemaNode>;\n additionalProperties?: SchemaNode | boolean;\n items?: SchemaNode;\n prefixItems?: SchemaNode[];\n};\n\nfunction resolveRef(node: SchemaNode, root: Record<string, unknown>): SchemaNode {\n if (!node.$ref) return node;\n const name = node.$ref.replace(/^#\\/\\$defs\\//, \"\");\n return (root.$defs as Record<string, SchemaNode>)[name];\n}\n\n/** Walks the document alongside the schema, warning about any key an\n * object's schema doesn't name. An object whose schema says\n * `additionalProperties: true` (GeoJSON) or gives a schema for extra keys\n * (`media`, `extensions`) is open, not a typo trap. */\nfunction findUnknownFields(value: unknown, node: SchemaNode, path: string, warnings: StoryIssue[], root = schema as unknown as Record<string, unknown>) {\n node = resolveRef(node, root);\n if (Array.isArray(value)) {\n value.forEach((item, i) => {\n const itemNode = node.prefixItems?.[i] ?? node.items;\n if (itemNode) findUnknownFields(item, itemNode, `${path}/${i}`, warnings, root);\n });\n return;\n }\n if (typeof value !== \"object\" || value === null) return;\n for (const [key, child] of Object.entries(value)) {\n const childPath = `${path}/${escapePointer(key)}`;\n const known = node.properties?.[key];\n if (known) {\n findUnknownFields(child, known, childPath, warnings, root);\n } else if (typeof node.additionalProperties === \"object\") {\n findUnknownFields(child, node.additionalProperties, childPath, warnings, root);\n } else if (node.properties && node.additionalProperties !== true) {\n warnings.push({ path: childPath, message: `unknown field \"${key}\" (ignored).` });\n }\n }\n}\n", "// Where a slide is on the map: its point, or the box around its shape and\n// overlays -- pure geometry, no map library.\nimport type { LonLat, Place } from \"../types\";\n\nexport type Bounds = [west: number, south: number, east: number, north: number];\n\nfunction visit(coords: unknown, bounds: Bounds): void {\n if (!Array.isArray(coords)) return;\n if (coords.length >= 2 && typeof coords[0] === \"number\" && typeof coords[1] === \"number\") {\n const [lon, lat] = coords as number[];\n bounds[0] = Math.min(bounds[0], lon);\n bounds[1] = Math.min(bounds[1], lat);\n bounds[2] = Math.max(bounds[2], lon);\n bounds[3] = Math.max(bounds[3], lat);\n return;\n }\n for (const child of coords) visit(child, bounds);\n}\n\n/** Every coordinate in a GeoJSON object, whatever its nesting. */\nfunction visitGeoJson(node: unknown, bounds: Bounds): void {\n if (!node || typeof node !== \"object\") return;\n const obj = node as { type?: string; coordinates?: unknown; geometry?: unknown; geometries?: unknown[]; features?: unknown[] };\n if (obj.coordinates !== undefined) visit(obj.coordinates, bounds);\n if (obj.geometry) visitGeoJson(obj.geometry, bounds);\n for (const g of obj.geometries ?? []) visitGeoJson(g, bounds);\n for (const f of obj.features ?? []) visitGeoJson(f, bounds);\n}\n\n/** The box around a place's shape and overlays, or null when it has\n * neither (or they hold no coordinates). */\nexport function placeBounds(place: Place | undefined): Bounds | null {\n if (!place) return null;\n const bounds: Bounds = [Infinity, Infinity, -Infinity, -Infinity];\n visitGeoJson(place.geometry, bounds);\n for (const overlay of place.overlays ?? []) visit(overlay.corners as LonLat[], bounds);\n return Number.isFinite(bounds[0]) ? bounds : null;\n}\n\n/** Where to put the pin: the place's own point, else the middle of its\n * shape and overlays. Null for a slide with no position at all. */\nexport function placeCenter(place: Place | undefined): LonLat | null {\n if (place?.lat !== undefined && place.lon !== undefined) return [place.lon, place.lat];\n const bounds = placeBounds(place);\n return bounds ? [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2] : null;\n}\n\nexport interface StoryPlaces {\n points: LonLat[];\n bounds: Bounds;\n}\n\n/** Every place in the story at once, for its opening view: one point per\n * distinct place, and the box around all of them, shapes and overlays\n * included. Null when no slide has a position. */\nexport function storyPlaces(places: (Place | undefined)[]): StoryPlaces | null {\n const bounds: Bounds = [Infinity, Infinity, -Infinity, -Infinity];\n const points = new Map<string, LonLat>();\n for (const place of places) {\n const center = placeCenter(place);\n if (!center) continue;\n points.set(`${center[0].toFixed(5)},${center[1].toFixed(5)}`, center);\n visit(center, bounds);\n const box = placeBounds(place);\n if (box) visit([[box[0], box[1]], [box[2], box[3]]], bounds);\n }\n return points.size ? { points: [...points.values()], bounds } : null;\n}\n", "// Presents a story: one slide at a time, with a full-bleed map behind the\n// slides when any of them has a place (modeled on a Knight Lab StoryMapJS\n// slide), or a plain centered card when none does, plus a timeline strip\n// when two or more slides are dated. Fills its container; the host decides\n// whether that's a fullscreen modal, a page, or a box on a blog.\nimport { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type TouchEvent } from \"react\";\nimport type { MediaItem, Slide, StoryDoc } from \"../types\";\nimport { timelineYear } from \"./dates\";\nimport { placeCenter, storyPlaces } from \"./geo\";\nimport { MapBackground, type MapSlide } from \"./MapBackground\";\nimport { MapModeControl, type MapMode, type MapModeControlProps } from \"./MapModeControl\";\nimport { parseStoryText } from \"./text\";\nimport { stringsFor, type PlayerStrings } from \"./strings\";\nimport { defaultColors, type PlayerColors } from \"./theme\";\nimport { TIMELINE_HEIGHT, TimelineStrip, type TimelinePoint } from \"./TimelineStrip\";\n\n/** How much of the width the slide panel takes over a map; the map\n * centers each point in what's left. */\nconst PANEL_FRACTION = 0.62;\nconst BAR_HEIGHT = 56;\n\nexport interface StoryPlayerProps {\n story: StoryDoc;\n /** A URL the browser can load for a media key: a blob: URL for a file\n * out of a zip, or anything else the host serves. The host owns these\n * URLs (and revoking them); the player may ask for the same key again.\n * Null when it can't be had: the slide shows without it. */\n resolveMedia: (key: string, item: MediaItem) => Promise<string | null>;\n dark?: boolean;\n colors?: Partial<PlayerColors>;\n /** The player's own words. By default, the built-in table for the\n * story's language, else the browser's, else English (strings.ts). */\n strings?: Partial<PlayerStrings>;\n /** Shows a close button that calls this. */\n onClose?: () => void;\n /** Arrow keys move between slides: true listens on the whole window (a\n * fullscreen presentation), \"focus\" only while the player has focus (one\n * of several on a page), false not at all. Default true. */\n keyboard?: boolean | \"focus\";\n /** Called with the new index whenever the slide changes. */\n onSlideChange?: (index: number) => void;\n /** Replaces the built-in map-mode control, e.g. with one from the host's\n * own UI kit. */\n renderMapModeControl?: (props: MapModeControlProps) => ReactNode;\n /** Shown before the title, e.g. ViewerBrand on a standalone page. */\n brand?: ReactNode;\n /** The host's own buttons, at the right of the title bar (before the\n * close button), e.g. the viewer site's Edit. */\n actions?: ReactNode;\n initialSlide?: number;\n}\n\n/** The story's basemap hint (spec section 6) as the control's starting mode:\n * \"historical\" -- a map of each slide's era -- is what the control calls\n * Auto; \"auto\" (viewer's choice) starts on the standard map. */\nfunction initialMapMode(story: StoryDoc): MapMode {\n return story.presentation?.basemap === \"historical\" ? \"auto\" : \"standard\";\n}\n\nfunction SlideText({ text, colors }: { text: string; colors: PlayerColors }) {\n return (\n <>\n {parseStoryText(text).map((lines, p) => (\n <p key={p} dir=\"auto\" style={{ margin: \"0 0 0.6em\", color: colors.text, lineHeight: 1.55 }}>\n {lines.map((spans, l) => (\n <span key={l}>\n {l > 0 && <br />}\n {spans.map((span, s) => {\n if (span.bold) return <b key={s}>{span.text}</b>;\n if (span.italic) return <i key={s}>{span.text}</i>;\n return <span key={s}>{span.text}</span>;\n })}\n </span>\n ))}\n </p>\n ))}\n </>\n );\n}\n\nfunction SlidePhoto({ mediaKey, item, caption, credit, resolveMedia, colors }: {\n mediaKey: string;\n item: MediaItem;\n caption?: string;\n credit?: string;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n}) {\n const [src, setSrc] = useState<string | null>(null);\n useEffect(() => {\n setSrc(null);\n let cancelled = false;\n resolveMedia(mediaKey, item).then((url) => { if (!cancelled) setSrc(url); }, () => {});\n return () => {\n cancelled = true;\n };\n }, [mediaKey, item, resolveMedia]);\n if (!src) return null;\n return (\n <figure style={{ margin: 0, display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n <img\n src={src}\n alt={item.alt ?? \"\"}\n width={item.width}\n height={item.height}\n style={{ maxHeight: \"42vh\", maxWidth: \"100%\", width: \"auto\", height: \"auto\", objectFit: \"contain\", borderRadius: 4 }}\n />\n {(caption || credit) && (\n <figcaption style={{ fontSize: 13, color: colors.muted }}>\n {[caption, credit && `\u00A9 ${credit}`].filter(Boolean).join(\" \u00B7 \")}\n </figcaption>\n )}\n </figure>\n );\n}\n\n/** A small button showing one of a slide's photos. */\nfunction PhotoThumb({ mediaKey, item, label, selected, onSelect, resolveMedia, colors }: {\n mediaKey: string;\n item: MediaItem;\n label: string;\n selected: boolean;\n onSelect: () => void;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n}) {\n const [src, setSrc] = useState<string | null>(null);\n useEffect(() => {\n let cancelled = false;\n resolveMedia(mediaKey, item).then((url) => { if (!cancelled) setSrc(url); }, () => {});\n return () => { cancelled = true; };\n }, [mediaKey, item, resolveMedia]);\n return (\n <button\n type=\"button\" aria-label={label} title={label} aria-pressed={selected} onClick={onSelect}\n style={{\n width: 44, height: 44, padding: 0, borderRadius: 4, overflow: \"hidden\", cursor: \"pointer\",\n border: `2px solid ${selected ? colors.mark : \"transparent\"}`, background: colors.border,\n opacity: selected ? 1 : 0.7,\n }}\n >\n {src && <img src={src} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </button>\n );\n}\n\nfunction SlideContent({ slide, story, resolveMedia, colors, strings }: {\n slide: Slide | undefined;\n story: StoryDoc;\n resolveMedia: StoryPlayerProps[\"resolveMedia\"];\n colors: PlayerColors;\n strings: PlayerStrings;\n}) {\n // Every photo whose media exists; with several, thumbnails pick which\n // one is shown. Keyed by slide in the caller, so each slide starts on\n // its first photo.\n const photos = (slide?.media ?? []).filter((m) => Object.prototype.hasOwnProperty.call(story.media, m.ref));\n const [shown, setShown] = useState(0);\n const photo = photos[Math.min(shown, photos.length - 1)];\n const eyebrow = [slide?.date?.text, slide?.place?.name].filter(Boolean).join(\" \u00B7 \");\n return (\n <>\n {photo && (\n <SlidePhoto\n mediaKey={photo.ref}\n item={story.media[photo.ref]}\n caption={photo.caption}\n credit={photo.credit}\n resolveMedia={resolveMedia}\n colors={colors}\n />\n )}\n {photos.length > 1 && (\n <div style={{ display: \"flex\", gap: 6, flexWrap: \"wrap\", justifyContent: \"center\" }}>\n {photos.map((m, i) => (\n <PhotoThumb\n key={`${i}:${m.ref}`}\n mediaKey={m.ref}\n item={story.media[m.ref]}\n label={strings.photoOf(i + 1, photos.length)}\n selected={photo === m}\n onSelect={() => setShown(i)}\n resolveMedia={resolveMedia}\n colors={colors}\n />\n ))}\n </div>\n )}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 4, alignItems: \"center\", maxWidth: 640, textAlign: \"center\" }}>\n {eyebrow && <div dir=\"auto\" style={{ fontSize: 14, color: colors.muted }}>{eyebrow}</div>}\n {slide?.title && <div dir=\"auto\" style={{ fontSize: 20, fontWeight: 700, color: colors.text }}>{slide.title}</div>}\n {slide?.text && <div><SlideText text={slide.text} colors={colors} /></div>}\n </div>\n </>\n );\n}\n\nfunction RoundButton({ label, onClick, disabled, size, children, style }: {\n label: string;\n onClick: () => void;\n disabled?: boolean;\n size: number;\n children: ReactNode;\n style?: CSSProperties;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n onClick={onClick}\n disabled={disabled}\n style={{\n width: size, height: size, borderRadius: \"50%\", border: \"none\",\n background: \"#25262b\", color: \"#ffffff\", fontSize: size >= 48 ? 22 : 18,\n cursor: disabled ? \"default\" : \"pointer\", opacity: disabled ? 0.35 : 0.8,\n display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, fontFamily: \"inherit\",\n ...style,\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction NavArrows({ index, total, onPrev, onNext, variant, strings, colors }: {\n index: number;\n total: number;\n onPrev: () => void;\n onNext: () => void;\n /** \"edge\": large buttons at the screen edges, dark so they stay legible\n * over any map. \"inline\": small buttons and an \"n / N\" counter. */\n variant: \"inline\" | \"edge\";\n strings: PlayerStrings;\n colors: PlayerColors;\n}) {\n if (variant === \"edge\") {\n const edge: CSSProperties = { position: \"absolute\", top: \"50%\", transform: \"translateY(-50%)\", zIndex: 2 };\n return (\n <>\n <RoundButton label={strings.previous} size={56} disabled={index === 0} onClick={onPrev} style={{ ...edge, left: 24 }}>\u2190</RoundButton>\n <RoundButton label={strings.next} size={56} disabled={index === total - 1} onClick={onNext} style={{ ...edge, right: 24 }}>\u2192</RoundButton>\n </>\n );\n }\n return (\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"center\", gap: 16, marginTop: 16 }}>\n <RoundButton label={strings.previous} size={34} disabled={index === 0} onClick={onPrev}>\u2190</RoundButton>\n <span style={{ fontSize: 14, color: colors.muted }}>{index + 1} / {total}</span>\n <RoundButton label={strings.next} size={34} disabled={index === total - 1} onClick={onNext}>\u2192</RoundButton>\n </div>\n );\n}\n\nexport function StoryPlayer({\n story, resolveMedia, dark = false, colors: colorOverrides, strings: stringOverrides, onClose,\n keyboard = true, onSlideChange, renderMapModeControl, brand, actions, initialSlide = 0,\n}: StoryPlayerProps) {\n const colors = useMemo(() => ({ ...defaultColors(dark), ...colorOverrides }), [dark, colorOverrides]);\n const strings = useMemo(\n () => ({\n ...stringsFor(story.language, typeof navigator === \"undefined\" ? undefined : navigator.language),\n ...stringOverrides,\n }),\n [story.language, stringOverrides],\n );\n const rootRef = useRef<HTMLDivElement>(null);\n const slides = story.slides;\n const [index, setIndex] = useState(initialSlide);\n const slide = slides[index];\n\n useEffect(() => {\n setIndex(Math.min(Math.max(initialSlide, 0), Math.max(slides.length - 1, 0)));\n }, [story, initialSlide, slides.length]);\n\n const datedSlides = useMemo(() => {\n const points: TimelinePoint[] = [];\n slides.forEach((s, i) => {\n const year = timelineYear(s.date);\n if (year !== null) points.push({ index: i, year });\n });\n return points;\n }, [slides]);\n const showTimeline = datedSlides.length >= 2;\n\n // Map modes: \"auto\" follows the current slide's year as the story moves.\n const [mapMode, setMapMode] = useState<MapMode>(() => initialMapMode(story));\n const [historicalYear, setHistoricalYear] = useState(() => new Date().getFullYear());\n const currentYear = timelineYear(slide?.date);\n const autoYear = currentYear !== null ? Math.floor(currentYear) : null;\n const yearBounds = useMemo<[number, number]>(() => {\n if (datedSlides.length === 0) {\n const thisYear = new Date().getFullYear();\n return [thisYear - 200, thisYear];\n }\n const years = datedSlides.map((d) => d.year);\n return [Math.floor(Math.min(...years)), Math.ceil(Math.max(...years))];\n }, [datedSlides]);\n // Entering Historical starts the slider on this slide's year.\n const wasHistoricalRef = useRef(false);\n useEffect(() => {\n if (mapMode === \"historical\" && !wasHistoricalRef.current) setHistoricalYear(autoYear ?? yearBounds[1]);\n wasHistoricalRef.current = mapMode === \"historical\";\n }, [mapMode, autoYear, yearBounds]);\n const ohmYear = mapMode === \"standard\" ? null : mapMode === \"auto\" ? autoYear : historicalYear;\n\n const goPrev = () => setIndex((i) => Math.max(i - 1, 0));\n const goNext = () => setIndex((i) => Math.min(i + 1, slides.length - 1));\n\n const onSlideChangeRef = useRef(onSlideChange);\n onSlideChangeRef.current = onSlideChange;\n useEffect(() => {\n onSlideChangeRef.current?.(index);\n }, [index]);\n\n useEffect(() => {\n if (!keyboard) return;\n const target: HTMLElement | Window | null = keyboard === \"focus\" ? rootRef.current : window;\n if (!target) return;\n function onKey(e: Event) {\n const key = (e as KeyboardEvent).key;\n const from = e.target as HTMLElement | null;\n // Not while typing a year into the map control.\n if (from && (from.tagName === \"INPUT\" || from.tagName === \"TEXTAREA\" || from.isContentEditable)) return;\n if (key === \"ArrowRight\") setIndex((i) => Math.min(i + 1, slides.length - 1));\n if (key === \"ArrowLeft\") setIndex((i) => Math.max(i - 1, 0));\n }\n target.addEventListener(\"keydown\", onKey);\n return () => target.removeEventListener(\"keydown\", onKey);\n }, [keyboard, slides.length]);\n\n // A horizontal swipe on the slide (not the map, which a drag pans)\n // moves between slides.\n const swipeStart = useRef<{ x: number; y: number } | null>(null);\n const swipeHandlers = {\n onTouchStart: (e: TouchEvent) => {\n const t = e.touches[0];\n swipeStart.current = e.touches.length === 1 ? { x: t.clientX, y: t.clientY } : null;\n },\n onTouchEnd: (e: TouchEvent) => {\n const start = swipeStart.current;\n swipeStart.current = null;\n const t = e.changedTouches[0];\n if (!start || !t) return;\n const dx = t.clientX - start.x;\n const dy = t.clientY - start.y;\n if (Math.abs(dx) < 50 || Math.abs(dx) < Math.abs(dy) * 1.5) return;\n if (dx < 0) goNext();\n else goPrev();\n },\n };\n\n // Stable per slide, so a re-render for an unrelated reason (a map-mode\n // click) never looks like a new slide to the map's camera.\n const places = useMemo(() => storyPlaces(slides.map((s) => s.place)), [slides]);\n const mapSlide = useMemo<MapSlide>(() => ({\n key: slide?.id ?? String(index),\n place: slide?.place,\n // The opening card, with no place of its own, shows where the story goes.\n overview: index === 0 && !placeCenter(slide?.place) ? places : null,\n }), [slide, index, places]);\n const firstCenter = useMemo(() => {\n if (story.presentation?.basemap === \"none\") return null;\n for (const s of slides) {\n const center = placeCenter(s.place);\n if (center) return center;\n }\n return null;\n }, [story, slides]);\n\n const modeControlProps: MapModeControlProps = {\n mode: mapMode, onModeChange: setMapMode, autoYear, year: historicalYear, onYearChange: setHistoricalYear, yearBounds,\n };\n const mediaResolver = useMemo(() => (key: string) => {\n const item = Object.prototype.hasOwnProperty.call(story.media, key) ? story.media[key] : undefined;\n return item ? resolveMedia(key, item) : Promise.resolve(null);\n }, [story, resolveMedia]);\n\n const content = (\n <SlideContent key={slide?.id ?? index} slide={slide} story={story} resolveMedia={resolveMedia} colors={colors} strings={strings} />\n );\n const timeline = showTimeline && (\n <TimelineStrip points={datedSlides} currentIndex={index} onSelect={setIndex} colors={colors} />\n );\n\n return (\n <div\n ref={rootRef}\n lang={story.language}\n tabIndex={keyboard === \"focus\" ? 0 : undefined}\n style={{\n position: \"relative\", width: \"100%\", height: \"100%\", overflow: \"hidden\",\n background: colors.surface, color: colors.text,\n }}\n >\n {/* Title bar: translucent, so it reads over the map too. */}\n <div\n style={{\n position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3,\n background: dark ? \"rgba(20,20,20,0.55)\" : \"rgba(255,255,255,0.55)\",\n }}\n />\n <div\n dir=\"auto\"\n style={{\n position: \"absolute\", top: 0, left: 20, height: BAR_HEIGHT, maxWidth: \"26%\", zIndex: 3,\n display: \"flex\", alignItems: \"center\", gap: 10, fontWeight: 600,\n }}\n >\n {brand && <span style={{ flex: \"none\", display: \"flex\" }}>{brand}</span>}\n <span style={{ whiteSpace: \"nowrap\", overflow: \"hidden\", textOverflow: \"ellipsis\" }}>{story.title}</span>\n </div>\n {/* Centered on the whole bar, as a toolbar for the presentation; the\n full-width wrapper lets clicks through to anything under it. */}\n {firstCenter && (\n <div\n style={{\n position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3,\n display: \"flex\", alignItems: \"center\", justifyContent: \"center\", pointerEvents: \"none\",\n }}\n >\n <div style={{ pointerEvents: \"auto\" }}>\n {renderMapModeControl\n ? renderMapModeControl(modeControlProps)\n : <MapModeControl {...modeControlProps} strings={strings} colors={colors} />}\n </div>\n </div>\n )}\n {actions && (\n <div\n style={{\n position: \"absolute\", top: 0, right: onClose ? 60 : 12, height: BAR_HEIGHT, zIndex: 3,\n display: \"flex\", alignItems: \"center\", gap: 8,\n }}\n >\n {actions}\n </div>\n )}\n {onClose && (\n <RoundButton\n label={strings.close} size={36} onClick={onClose}\n style={{ position: \"absolute\", top: 10, right: 12, zIndex: 3 }}\n >\n \u00D7\n </RoundButton>\n )}\n\n {firstCenter ? (\n <div style={{ position: \"absolute\", inset: 0 }}>\n <MapBackground\n initialCenter={firstCenter}\n current={mapSlide}\n dark={dark}\n colors={colors}\n panelFraction={PANEL_FRACTION}\n ohmYear={ohmYear}\n resolveMedia={mediaResolver}\n />\n <div\n style={{\n position: \"absolute\", top: 0, bottom: 0, right: 0, width: `${PANEL_FRACTION * 100}%`, zIndex: 1,\n padding: `${BAR_HEIGHT}px 32px ${showTimeline ? TIMELINE_HEIGHT : 32}px`, boxSizing: \"border-box\",\n display: \"flex\", flexDirection: \"column\", justifyContent: \"center\", alignItems: \"center\", gap: 16,\n overflowY: \"auto\",\n // Transparent where the panel starts, mid-screen, and solid\n // well before the centered content, so text never sits on map.\n background: `linear-gradient(to right, transparent 0%, ${colors.panel} 22%)`,\n }}\n {...swipeHandlers}\n >\n {content}\n </div>\n <NavArrows index={index} total={slides.length} onPrev={goPrev} onNext={goNext} variant=\"edge\" strings={strings} colors={colors} />\n {timeline}\n </div>\n ) : (\n <div\n style={{\n position: \"absolute\", inset: 0, overflowY: \"auto\", boxSizing: \"border-box\",\n padding: `${BAR_HEIGHT + 16}px 24px ${showTimeline ? TIMELINE_HEIGHT + 16 : 24}px`,\n display: \"flex\", flexDirection: \"column\", alignItems: \"center\", justifyContent: \"center\", gap: 16,\n }}\n {...swipeHandlers}\n >\n {content}\n <NavArrows index={index} total={slides.length} onPrev={goPrev} onNext={goNext} variant=\"inline\" strings={strings} colors={colors} />\n {timeline}\n </div>\n )}\n </div>\n );\n}\n", "// What the player needs from a story's dates: which years an EDTF value\n// covers (to show a historical map overlay only in its own era), and a\n// position on the timeline finer than a whole year when the date allows.\nimport type { StoryDate } from \"../types\";\n\nexport interface YearRange {\n /** Undefined for an open start (\"../1850\"). */\n min?: number;\n /** Undefined for an open end (\"1850/..\"). */\n max?: number;\n}\n\nconst DATE = /^(-?\\d{4})(?:-(\\d{2}|XX))?(?:-(\\d{2}|XX))?[~?%]?$/;\n\nfunction yearOf(part: string): number | null {\n const match = DATE.exec(part.trim());\n return match ? Number(match[1]) : null;\n}\n\n/** The years an EDTF date covers, or null when it can't be read (which\n * callers treat the same as having no date). Handles single dates\n * (\"1850\", \"1850-03-12\", \"1850~\"), intervals (\"1850/1860\", \"../1850\",\n * \"1850/..\") and one-of sets (\"[1850..1860]\"). */\nexport function edtfYearRange(edtf: string | undefined): YearRange | null {\n if (!edtf) return null;\n const value = edtf.trim();\n const set = /^\\[(.+)\\.\\.(.+)\\]$/.exec(value);\n if (set) {\n const min = yearOf(set[1]);\n const max = yearOf(set[2]);\n return min !== null && max !== null ? { min: Math.min(min, max), max: Math.max(min, max) } : null;\n }\n if (value.includes(\"/\")) {\n const [startText, endText] = value.split(\"/\");\n const openStart = startText === \"..\" || startText === \"\";\n const openEnd = endText === \"..\" || endText === \"\";\n const start = openStart ? undefined : yearOf(startText);\n const end = openEnd ? undefined : yearOf(endText);\n if (start === null || end === null) return null;\n if (start === undefined && end === undefined) return null;\n if (start !== undefined && end !== undefined) return { min: Math.min(start, end), max: Math.max(start, end) };\n return { min: start, max: end };\n }\n const year = yearOf(value);\n return year === null ? null : { min: year, max: year };\n}\n\n/** Whether something dated `date` belongs on a map of `year`. No date, an\n * unreadable one, or no year to compare against (a standard, non-historical\n * map) all mean visible: an undated overlay is never hidden. */\nexport function dateCoversYear(date: StoryDate | undefined, year: number | null): boolean {\n if (!date || year === null) return true;\n const range = edtfYearRange(date.edtf);\n if (!range) return true;\n if (range.min !== undefined && year < range.min) return false;\n if (range.max !== undefined && year > range.max) return false;\n return true;\n}\n\n/** A slide's position on the timeline, as a fractional year: its\n * `sortYear`, nudged within the year by the EDTF month and day when they\n * agree with it -- so two events in the same year don't land on the exact\n * same spot. Null for a slide that isn't on the timeline. */\nexport function timelineYear(date: StoryDate | undefined): number | null {\n if (!date) return null;\n const match = date.edtf ? DATE.exec(date.edtf.trim()) : null;\n const sortYear = date.sortYear ?? (match ? Number(match[1]) : undefined);\n if (sortYear === undefined) return null;\n if (!match || Number(match[1]) !== sortYear) return sortYear;\n const month = match[2] && match[2] !== \"XX\" ? Number(match[2]) : 0;\n const day = match[3] && match[3] !== \"XX\" ? Number(match[3]) : 0;\n if (!month) return sortYear;\n return sortYear + (month - 1) / 12 + (day ? (day - 1) / 365 : 0);\n}\n", "// The full-bleed map behind a located story's slides: flies to the current\n// slide's place (or frames its shape and overlays), draws that shape and\n// those overlays, and holds still -- marker dimmed -- on a slide with no\n// place. Its own small maplibre instance; the host page loads no map of\n// its own for this.\nimport { useEffect, useRef, useState } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\n// Positions the marker and styles the attribution control; without it the\n// pin sits in normal flow at the top left instead of on its coordinate.\nimport \"maplibre-gl/dist/maplibre-gl.css\";\nimport type { GeoJSONSource, Map as MapLibreMap, Marker as MapLibreMarker } from \"maplibre-gl\";\nimport type { FeatureCollection, GeoJSON } from \"geojson\";\nimport type { Overlay, Place } from \"../types\";\nimport { dateCoversYear } from \"./dates\";\nimport { placeBounds, placeCenter, type StoryPlaces } from \"./geo\";\nimport { applyOhmYear, crossfadeStyleSwap, mapStyleKey, mapStyleUrl } from \"./mapStyles\";\nimport { PIN_PATH_D, type PlayerColors } from \"./theme\";\n\nconst SHAPE_SOURCE = \"story-shape\";\nconst FILL_LAYER = \"story-shape-fill\";\nconst LINE_LAYER = \"story-shape-line\";\nconst POINT_LAYER = \"story-shape-points\";\nconst LABEL_LAYER = \"story-shape-labels\";\nconst OVERLAY_PREFIX = \"story-overlay-\";\nconst PLACES_SOURCE = \"story-places\";\nconst PLACES_LAYER = \"story-places-dots\";\n// Room around the outermost dots of the opening view, inside the part of\n// the map the slide panel leaves free.\nconst OVERVIEW_PADDING = 60;\nconst EMPTY: FeatureCollection = { type: \"FeatureCollection\", features: [] };\n\n/** The current slide, as far as the map cares. `key` is the slide id:\n * what tells \"a new slide\" from \"the same slide, re-rendered\". */\nexport interface MapSlide {\n key: string;\n place: Place | undefined;\n /** Every place in the story, on an opening slide with no place of its\n * own: framed together, a dot each, instead of the pin. */\n overview: StoryPlaces | null;\n}\n\n/** Frame the story's places for an overview; else the place's shape or\n * overlays (usually a field, a route or an old map, far tighter than a\n * town-level zoom); else fly to its point. */\nfunction moveCamera(map: MapLibreMap, slide: MapSlide, duration: number) {\n if (slide.overview) {\n const [west, south, east, north] = slide.overview.bounds;\n map.fitBounds([[west, south], [east, north]], { maxZoom: 9, padding: OVERVIEW_PADDING, duration });\n return;\n }\n const place = slide.place;\n const bounds = placeBounds(place);\n if (bounds) {\n map.fitBounds([[bounds[0], bounds[1]], [bounds[2], bounds[3]]], { maxZoom: 17, duration });\n return;\n }\n const center = placeCenter(place);\n if (center) map.flyTo({ center, zoom: 9, essential: true, duration });\n}\n\n/** The pin on the place; hidden for an overview (the dots stand in for\n * it), else held where it was, dimmed, for a slide with no place. */\nfunction placeMarker(marker: MapLibreMarker | null, slide: MapSlide) {\n if (!marker) return;\n const center = placeCenter(slide.place);\n if (center) marker.setLngLat(center);\n // Through the marker, not its element's style: maplibre rewrites that\n // from the marker's own opacity every frame.\n marker.setOpacity(slide.overview ? 0 : center ? 1 : 0.4);\n}\n\nconst placeDots = (overview: StoryPlaces | null): FeatureCollection => ({\n type: \"FeatureCollection\",\n features: (overview?.points ?? []).map((coordinates) => ({\n type: \"Feature\", properties: {}, geometry: { type: \"Point\", coordinates },\n })),\n});\n\nexport function MapBackground({ initialCenter, current, dark, colors, panelFraction, ohmYear, resolveMedia }: {\n initialCenter: [number, number];\n current: MapSlide;\n dark: boolean;\n colors: PlayerColors;\n /** How much of the right side the slide panel covers: a point is\n * centered in the remaining left part, not the whole width. */\n panelFraction: number;\n /** Non-null switches to OpenHistoricalMap filtered to this year. */\n ohmYear: number | null;\n resolveMedia: (key: string) => Promise<string | null>;\n}) {\n // A callback ref (via state), not useRef: a host that mounts the player\n // inside a modal may not have it in the DOM on the first render, and a\n // plain ref would leave the create-effect below nothing to re-run on.\n const [containerEl, setContainerEl] = useState<HTMLDivElement | null>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markerRef = useRef<MapLibreMarker | null>(null);\n // True after each \"style.load\" (initial load, and again after every\n // style swap, which wipes the layers this component adds).\n const [ready, setReady] = useState(false);\n\n const darkRef = useRef(dark);\n darkRef.current = dark;\n const ohmYearRef = useRef(ohmYear);\n ohmYearRef.current = ohmYear;\n const colorsRef = useRef(colors);\n colorsRef.current = colors;\n // overlay layer id -> its date, for re-checking visibility on a year change.\n const overlayDatesRef = useRef<Map<string, Overlay[\"date\"]>>(new Map());\n // What the map was built or last swapped with, so a re-render with the\n // same effective style never triggers a reload.\n const appliedStyleKeyRef = useRef(mapStyleKey(dark, ohmYear));\n const currentRef = useRef(current);\n currentRef.current = current;\n\n useEffect(() => {\n if (!containerEl) return;\n setReady(false);\n appliedStyleKeyRef.current = mapStyleKey(darkRef.current, ohmYearRef.current);\n const map = new maplibregl.Map({\n container: containerEl,\n style: mapStyleUrl(darkRef.current, ohmYearRef.current),\n zoom: 5,\n attributionControl: { compact: true },\n // So crossfadeStyleSwap's snapshot has the last frame in it.\n canvasContextAttributes: { preserveDrawingBuffer: true },\n });\n mapRef.current = map;\n map.on(\"style.load\", () => setReady(true));\n // Center points in the part of the map the slide panel doesn't cover.\n map.setPadding({ top: 0, bottom: 0, left: 0, right: containerEl.clientWidth * panelFraction });\n // Straight to the opening slide's place, unanimated. The camera effect\n // below ran for it before this map existed (the container arrives a\n // render late), so a story opened partway through starts there too.\n const start = currentRef.current;\n map.jumpTo({ center: placeCenter(start.place) ?? initialCenter });\n moveCamera(map, start, 0);\n map.on(\"load\", () => {\n const c = colorsRef.current;\n const el = document.createElement(\"div\");\n el.style.width = \"26px\";\n el.style.height = \"26px\";\n el.style.transition = \"opacity 300ms\";\n el.innerHTML = `<svg viewBox=\"0 0 24 24\" width=\"26\" height=\"26\">`\n + `<path d=\"${PIN_PATH_D}\" fill=\"${c.mark}\" stroke=\"${c.surface}\" stroke-width=\"1.5\" />`\n + `</svg>`;\n // The pin's tip, not its middle, sits on the coordinate.\n markerRef.current = new maplibregl.Marker({ element: el, anchor: \"bottom\" }).setLngLat(initialCenter).addTo(map);\n placeMarker(markerRef.current, currentRef.current);\n });\n return () => {\n markerRef.current?.remove();\n markerRef.current = null;\n map.remove();\n mapRef.current = null;\n };\n // initialCenter is only the first frame; moving is the effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [containerEl]);\n\n useEffect(() => {\n const map = mapRef.current;\n const key = mapStyleKey(dark, ohmYear);\n if (!map || appliedStyleKeyRef.current === key) return;\n appliedStyleKeyRef.current = key;\n crossfadeStyleSwap(map, mapStyleUrl(dark, ohmYear), () => setReady(false));\n }, [dark, ohmYear]);\n\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready || ohmYear == null) return;\n applyOhmYear(map, ohmYear);\n }, [ready, ohmYear]);\n\n // The shape layers, (re-)added after every style load, under the marker.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready || map.getSource(SHAPE_SOURCE)) return;\n const c = colorsRef.current;\n map.addSource(SHAPE_SOURCE, { type: \"geojson\", data: EMPTY });\n // A feature's own `color` property (simplestyle-ish) wins over the mark color.\n const color = [\"coalesce\", [\"get\", \"color\"], c.mark] as maplibregl.ExpressionSpecification;\n map.addLayer({\n id: FILL_LAYER, type: \"fill\", source: SHAPE_SOURCE,\n filter: [\"==\", [\"geometry-type\"], \"Polygon\"],\n // And its own `opacity` (what the map editor sets on an area) over\n // a light default.\n paint: { \"fill-color\": color, \"fill-opacity\": [\"coalesce\", [\"to-number\", [\"get\", \"opacity\"], 0.25], 0.25] },\n });\n map.addLayer({\n id: LINE_LAYER, type: \"line\", source: SHAPE_SOURCE,\n filter: [\"any\", [\"==\", [\"geometry-type\"], \"Polygon\"], [\"==\", [\"geometry-type\"], \"LineString\"]],\n paint: { \"line-color\": color, \"line-width\": 2 },\n });\n map.addLayer({\n id: POINT_LAYER, type: \"circle\", source: SHAPE_SOURCE,\n // A named point is a label (next layer), drawn as text only.\n filter: [\"all\", [\"==\", [\"geometry-type\"], \"Point\"], [\"!\", [\"has\", \"name\"]]],\n paint: { \"circle-radius\": 5, \"circle-color\": color, \"circle-stroke-width\": 1, \"circle-stroke-color\": c.surface },\n });\n map.addLayer({\n id: LABEL_LAYER, type: \"symbol\", source: SHAPE_SOURCE,\n filter: [\"all\", [\"==\", [\"geometry-type\"], \"Point\"], [\"has\", \"name\"]],\n layout: {\n \"text-field\": [\"get\", \"name\"],\n \"text-size\": 12,\n \"text-font\": [\"Noto Sans Regular\"],\n \"text-anchor\": \"left\",\n \"text-offset\": [0.6, 0],\n },\n paint: {\n \"text-color\": [\"coalesce\", [\"get\", \"color\"], c.text],\n \"text-halo-color\": c.surface,\n \"text-halo-width\": 1.5,\n },\n });\n map.addSource(PLACES_SOURCE, { type: \"geojson\", data: EMPTY });\n map.addLayer({\n id: PLACES_LAYER, type: \"circle\", source: PLACES_SOURCE,\n paint: { \"circle-radius\": 6, \"circle-color\": c.mark, \"circle-stroke-width\": 2, \"circle-stroke-color\": c.surface },\n });\n }, [ready]);\n\n const place = current.place;\n\n // The current slide's shape, or the overview's dots. Re-supplied after each style load, since a\n // swap empties the source.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n const source = map.getSource(SHAPE_SOURCE) as GeoJSONSource | undefined;\n source?.setData((place?.geometry as GeoJSON | undefined) ?? EMPTY);\n const dots = map.getSource(PLACES_SOURCE) as GeoJSONSource | undefined;\n dots?.setData(placeDots(current.overview));\n }, [ready, current.key, place, current.overview]);\n\n // Camera: once per slide (see moveCamera). Keyed to the slide, not to `ready`, so a\n // map-mode switch never yanks the view back from wherever the viewer\n // has since panned.\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n placeMarker(markerRef.current, current);\n // No place and no overview: the camera stays put.\n moveCamera(map, current, 900);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [current.key]);\n\n // Image overlays: one image source + raster layer each, under the shape\n // layers, lowest `order` first so the highest ends up on top. Keyed by\n // the overlays themselves, so consecutive slides at the same place keep\n // theirs instead of reloading them.\n const overlayKey = JSON.stringify(place?.overlays ?? []);\n useEffect(() => {\n const map = mapRef.current;\n const overlays = place?.overlays ?? [];\n if (!map || !ready || overlays.length === 0) return;\n let cancelled = false;\n const added: string[] = [];\n (async () => {\n const sorted = overlays\n .map((overlay, i) => ({ overlay, i }))\n .sort((a, b) => (a.overlay.order ?? a.i) - (b.overlay.order ?? b.i));\n for (const { overlay, i } of sorted) {\n const url = await resolveMedia(overlay.media);\n if (cancelled) return;\n if (!url) continue;\n const id = `${OVERLAY_PREFIX}${i}`;\n if (map.getSource(id)) continue;\n map.addSource(id, { type: \"image\", url, coordinates: overlay.corners });\n map.addLayer({ id, type: \"raster\", source: id }, FILL_LAYER);\n map.setPaintProperty(id, \"raster-opacity\", overlay.opacity ?? 1);\n overlayDatesRef.current.set(id, overlay.date);\n map.setLayoutProperty(id, \"visibility\", dateCoversYear(overlay.date, ohmYearRef.current) ? \"visible\" : \"none\");\n added.push(id);\n }\n })();\n return () => {\n cancelled = true;\n for (const id of added) {\n overlayDatesRef.current.delete(id);\n if (map.getLayer(id)) map.removeLayer(id);\n if (map.getSource(id)) map.removeSource(id);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [overlayKey, ready]);\n\n // A new map year alone: re-check each overlay's era.\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n for (const [id, date] of overlayDatesRef.current) {\n if (!map.getLayer(id)) continue;\n map.setLayoutProperty(id, \"visibility\", dateCoversYear(date, ohmYear) ? \"visible\" : \"none\");\n }\n }, [ohmYear, ready]);\n\n return <div ref={setContainerEl} style={{ position: \"absolute\", inset: 0 }} />;\n}\n", "// Basemaps for the story map: OpenFreeMap (light), CARTO Dark Matter (dark)\n// and OpenHistoricalMap (historical, filtered to a year), plus the\n// crossfade used when switching between them. Gramps Connect's own map\n// view uses these too (its visuals/mapStyles.ts re-exports them), so the\n// app and the story player can't drift into two versions of the same three\n// map modes.\nimport type { Map as MapLibreMap } from \"maplibre-gl\";\n// A CJS module with no browser global to patch onto (it only self-attaches\n// to `window.maplibregl`, which our namespace import never creates) -- the\n// named export below is what its `module.exports` branch actually produces,\n// and it's what both callers use directly rather than the `map.filterByDate`\n// method the plugin's own README shows for a script-tag install.\nimport { filterByDate } from \"@openhistoricalmap/maplibre-gl-dates\";\n\n/** The same OpenFreeMap \"liberty\" style gramps-web uses for its light\n * basemap, so the two clients' maps look like the same product in light\n * mode. Free, key-less, and hosted -- which does mean a map (unlike every\n * other view in this app) needs the network even though its *data* is\n * local. */\nexport const STYLE_LIGHT = \"https://tiles.openfreemap.org/styles/liberty\";\n/** OpenFreeMap's own \"dark\" style renders every layer, including water, in\n * the same near-zero-saturation gray (confirmed against their own demo at\n * openfreemap.org) -- there's no hue anywhere to tell land from water at a\n * glance. CARTO's Dark Matter style is the free, key-less alternative with\n * an actual (if muted) blue-gray palette -- water and major roads read as\n * distinct from background and from each other. */\nexport const STYLE_DARK = \"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json\";\n\n/** OHM's own vector style -- one cartography regardless of light/dark,\n * matching gramps-web's choice. */\nexport const OHM_STYLE = \"https://www.openhistoricalmap.org/map-styles/main/main.json\";\n\n/** The three selectable modes wherever a historical map is shown. \"auto\" and\n * \"historical\" both render OHM tiles filtered to a year -- they differ only\n * in where that year comes from (context vs. a user-dragged slider), which\n * is why both map components take a single `ohmYear: number | null` rather\n * than the mode itself: \"standard\" and an \"auto\" with nothing to derive a\n * year from look identical to the map, and are meant to. */\nexport type MapMode = \"auto\" | \"standard\" | \"historical\";\n\n/** A stable key for \"would setStyle() actually change anything\" -- swapping\n * light/dark never matters once OHM is showing (its cartography doesn't\n * have a dark variant), so a slider drag that changes `ohmYear`'s value\n * without leaving historical/auto mode must not trip a style reload. */\nexport function mapStyleKey(dark: boolean, ohmYear: number | null): string {\n return ohmYear != null ? \"ohm\" : dark ? \"dark\" : \"light\";\n}\n\nexport function mapStyleUrl(dark: boolean, ohmYear: number | null): string {\n return ohmYear != null ? OHM_STYLE : dark ? STYLE_DARK : STYLE_LIGHT;\n}\n\n/** Swaps a map's style as a true crossfade -- the old and new basemaps\n * dissolving into each other, not one fading out before the other fades in.\n * A single WebGL map can only ever show one style at a time, so this fakes\n * it: a snapshot of the *old* style (a plain `<img>`, frozen) is overlaid\n * over the live map at full opacity, the live map underneath is swapped to\n * the new style immediately and left to load, and once it's actually\n * finished drawing (`idle`, not `style.load` -- that fires before a single\n * tile of the new style has painted) the snapshot dissolves away, revealing\n * the new style continuously as it goes rather than snapping to it. This\n * also means the old map stays on screen, fully intact, for however long\n * the new style's tiles take to fetch -- no blank/loading gap either way,\n * unlike fading through transparent would give.\n *\n * Requires `preserveDrawingBuffer: true` on the map (see both callers'\n * constructors) -- without it, `toDataURL()` on the canvas can come back\n * blank depending on exactly when the browser clears the drawing buffer\n * after compositing. Falls back to an instant, unfaded swap if the snapshot\n * can't be taken at all (a tainted canvas, or a browser that disallows it) --\n * a plain setStyle() rather than no swap.\n *\n * `beforeSwap` runs at the same moment as setStyle(), so a caller's own\n * `setReady(false)` -- which gates its layer re-add effect -- flips exactly\n * when setStyle() actually discards those layers. */\nexport function crossfadeStyleSwap(map: MapLibreMap, styleUrl: string, beforeSwap: () => void, duration = 300): void {\n const container = map.getContainer();\n // The container is `position: absolute` but neither caller gives it its\n // own `z-index` -- which means it *doesn't* establish a stacking context\n // of its own, and the overlay's z-index below would then be compared not\n // just against the container's own children but against the container's\n // own siblings elsewhere on the page (StoryView.tsx's content panel,\n // MapView.tsx's PlaceCard popup, both positioned with their own z-index).\n // Found live: the overlay ended up painting over the story's content\n // panel instead of staying confined beneath it. Setting a z-index here\n // (any value; 0 keeps this box in the same paint bucket it was already\n // in) traps the overlay inside this container instead.\n if (!container.style.zIndex) container.style.zIndex = \"0\";\n let snapshotUrl: string | null = null;\n try {\n snapshotUrl = map.getCanvas().toDataURL(\"image/png\");\n } catch {\n // Tainted canvas or an unsupported browser -- no crossfade, just swap.\n }\n\n beforeSwap();\n map.setStyle(styleUrl);\n if (!snapshotUrl) return;\n\n const overlay = document.createElement(\"img\");\n overlay.src = snapshotUrl;\n overlay.alt = \"\";\n Object.assign(overlay.style, {\n position: \"absolute\", inset: \"0\", width: \"100%\", height: \"100%\",\n zIndex: \"5\", pointerEvents: \"none\", transition: `opacity ${duration}ms ease`,\n });\n container.appendChild(overlay);\n map.once(\"idle\", () => {\n // rAF, not set on the same tick as append -- a transition needs the\n // browser to have painted the starting opacity (1, the element's\n // default) at least once before a change to it will animate rather\n // than just jumping straight to the end state.\n requestAnimationFrame(() => { overlay.style.opacity = \"0\"; });\n window.setTimeout(() => overlay.remove(), duration + 50);\n });\n}\n\n/** Filters an OHM style's own vector layers to a year. A no-op on any layer\n * without a `source-layer` -- which is every layer either map component\n * adds itself (GeoJSON place markers, clusters, the story's pin) -- and\n * idempotent to call again on every year change: the plugin rewrites a\n * `let`-bound variable in place rather than re-wrapping each layer's filter,\n * so a slider drag never needs a style reload to take effect. */\nexport function applyOhmYear(map: MapLibreMap, year: number): void {\n filterByDate(map, String(Math.round(year)));\n}\n", "// The player's look, as plain values a host can override (a host app\n// passes its own theme's colors, so the story matches it). Its words are\n// in strings.ts.\n\nexport interface PlayerColors {\n /** Page and strip background. */\n surface: string;\n text: string;\n muted: string;\n border: string;\n /** The pin, timeline dots and default shape color. */\n mark: string;\n /** The slide panel's solid color, fading in over the map. */\n panel: string;\n}\n\n/** The marks' blue clears 3:1 against both surfaces. */\nexport function defaultColors(dark: boolean): PlayerColors {\n return dark\n ? { surface: \"#242424\", text: \"#c9c9c9\", muted: \"#828282\", border: \"#424242\", mark: \"#3987e5\", panel: \"rgb(20,20,20)\" }\n : { surface: \"#ffffff\", text: \"#000000\", muted: \"#868e96\", border: \"#dee2e6\", mark: \"#2a78d6\", panel: \"rgb(255,255,255)\" };\n}\n\n/** A map pin (round top, point at the bottom) in a 24x24 box with its tip\n * at (12, 24): the map marker and the current timeline dot share it, and\n * every use aligns that tip to the point it marks. */\nexport const PIN_PATH_D = \"M12 0C7.03 0 3 4.03 3 9c0 6.25 9 15 9 15s9-8.75 9-15c0-4.97-4.03-9-9-9z\";\n", "// The Auto / Standard / Historical map picker, in plain HTML. A host app\n// with its own UI kit can supply its own control instead (StoryPlayer's\n// renderMapModeControl), taking the same props.\nimport type { PlayerStrings } from \"./strings\";\nimport type { PlayerColors } from \"./theme\";\n\n/** \"standard\" is today's map; \"historical\" a map of the year the viewer\n * picks; \"auto\" a map of each slide's own year as the story moves. */\nexport type MapMode = \"auto\" | \"standard\" | \"historical\";\n\nexport interface MapModeControlProps {\n mode: MapMode;\n onModeChange: (mode: MapMode) => void;\n /** What Auto resolves to on this slide, or null with no date to use. */\n autoYear: number | null;\n /** The viewer's own pick, live while mode is \"historical\". */\n year: number;\n onYearChange: (year: number) => void;\n yearBounds: [number, number];\n}\n\nexport function MapModeControl({ mode, onModeChange, autoYear, year, onYearChange, yearBounds, strings, colors }:\n MapModeControlProps & { strings: PlayerStrings; colors: PlayerColors }) {\n const modes: [MapMode, string][] = [[\"auto\", strings.auto], [\"standard\", strings.standard], [\"historical\", strings.historical]];\n const font = { fontSize: 12, fontFamily: \"inherit\" };\n return (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, whiteSpace: \"nowrap\" }}>\n <div role=\"radiogroup\" aria-label={strings.mapMode} style={{ display: \"flex\", border: `1px solid ${colors.border}`, borderRadius: 6, overflow: \"hidden\", background: colors.surface }}>\n {modes.map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={mode === value}\n onClick={() => onModeChange(value)}\n style={{\n ...font, padding: \"4px 10px\", border: \"none\", cursor: \"pointer\",\n background: mode === value ? colors.mark : \"transparent\",\n color: mode === value ? \"#ffffff\" : colors.text,\n }}\n >\n {label}\n </button>\n ))}\n </div>\n {mode === \"auto\" && (\n <span style={{ ...font, color: colors.muted }}>\n {autoYear != null ? strings.historicalMapYear(autoYear) : strings.noDateStandardMap}\n </span>\n )}\n {mode === \"historical\" && (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <input\n type=\"range\"\n min={yearBounds[0]}\n max={yearBounds[1]}\n step={1}\n value={year}\n onChange={(e) => onYearChange(Number(e.currentTarget.value))}\n aria-label={strings.historicalYear}\n style={{ width: 150, accentColor: colors.mark }}\n />\n <input\n type=\"number\"\n min={yearBounds[0]}\n max={yearBounds[1]}\n step={1}\n value={year}\n onChange={(e) => {\n const value = Number(e.currentTarget.value);\n if (Number.isFinite(value) && e.currentTarget.value !== \"\") onYearChange(Math.round(value));\n }}\n aria-label={strings.historicalYear}\n style={{ ...font, width: 70, padding: \"3px 4px\", border: `1px solid ${colors.border}`, borderRadius: 4, background: colors.surface, color: colors.text }}\n />\n </span>\n )}\n </div>\n );\n}\n", "// Slide text markup (spec/1.0/README.md section 4): **bold**, *italic*,\n// line breaks, and blank lines between paragraphs -- nothing else. Parsed\n// into plain data rather than HTML, so a viewer can never be tricked into\n// rendering markup a story file smuggles in.\n\nexport interface TextSpan {\n text: string;\n bold?: boolean;\n italic?: boolean;\n}\n\n/** Paragraphs of lines of spans. */\nexport type ParsedText = TextSpan[][][];\n\n// Bold before italic, so a bold span's own ** pair isn't read as two empty\n// italic spans. Neither crosses a line break.\nconst MARKERS = /\\*\\*([^\\n]+?)\\*\\*|\\*([^\\n]+?)\\*/g;\n\nfunction parseLine(line: string): TextSpan[] {\n const spans: TextSpan[] = [];\n let last = 0;\n for (const match of line.matchAll(MARKERS)) {\n const index = match.index ?? 0;\n if (index > last) spans.push({ text: line.slice(last, index) });\n if (match[1] !== undefined) spans.push({ text: match[1], bold: true });\n else spans.push({ text: match[2], italic: true });\n last = index + match[0].length;\n }\n if (last < line.length) spans.push({ text: line.slice(last) });\n return spans;\n}\n\nexport function parseStoryText(text: string): ParsedText {\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(/\\n[ \\t]*\\n+/)\n .map((paragraph) => paragraph.replace(/^\\n+|\\n+$/g, \"\"))\n .filter((paragraph) => paragraph.length > 0)\n .map((paragraph) => paragraph.split(\"\\n\").map(parseLine));\n}\n", "// The player's own words -- the few on its buttons and map control, never\n// the story's -- in a handful of languages, chosen by the story's language\n// and then the browser's. A host with its own translations passes\n// StoryPlayer's `strings` instead.\n\nexport interface PlayerStrings {\n previous: string;\n next: string;\n close: string;\n mapMode: string;\n auto: string;\n standard: string;\n historical: string;\n /** The Auto mode's readout. */\n historicalMapYear: (year: number) => string;\n noDateStandardMap: string;\n historicalYear: string;\n /** A photo's thumbnail button, on a slide with several. */\n photoOf: (n: number, total: number) => string;\n}\n\nexport const ENGLISH: PlayerStrings = {\n previous: \"Previous\",\n next: \"Next\",\n close: \"Close\",\n mapMode: \"Map\",\n auto: \"Auto\",\n standard: \"Standard\",\n historical: \"Historical\",\n historicalMapYear: (year) => `Historical map, ${year}`,\n noDateStandardMap: \"No date here \u2014 standard map\",\n historicalYear: \"Historical map year\",\n photoOf: (n, total) => `Photo ${n} of ${total}`,\n};\n\nconst TABLE: Record<string, PlayerStrings> = {\n en: ENGLISH,\n de: {\n previous: \"Zur\u00FCck\",\n next: \"Weiter\",\n close: \"Schlie\u00DFen\",\n mapMode: \"Karte\",\n auto: \"Automatisch\",\n standard: \"Standard\",\n historical: \"Historisch\",\n historicalMapYear: (year) => `Historische Karte, ${year}`,\n noDateStandardMap: \"Kein Datum hier \u2014 Standardkarte\",\n historicalYear: \"Jahr der historischen Karte\",\n photoOf: (n, total) => `Foto ${n} von ${total}`,\n },\n es: {\n previous: \"Anterior\",\n next: \"Siguiente\",\n close: \"Cerrar\",\n mapMode: \"Mapa\",\n auto: \"Autom\u00E1tico\",\n standard: \"Est\u00E1ndar\",\n historical: \"Hist\u00F3rico\",\n historicalMapYear: (year) => `Mapa hist\u00F3rico, ${year}`,\n noDateStandardMap: \"Sin fecha aqu\u00ED \u2014 mapa est\u00E1ndar\",\n historicalYear: \"A\u00F1o del mapa hist\u00F3rico\",\n photoOf: (n, total) => `Foto ${n} de ${total}`,\n },\n fr: {\n previous: \"Pr\u00E9c\u00E9dent\",\n next: \"Suivant\",\n close: \"Fermer\",\n mapMode: \"Carte\",\n auto: \"Auto\",\n standard: \"Standard\",\n historical: \"Historique\",\n historicalMapYear: (year) => `Carte historique, ${year}`,\n noDateStandardMap: \"Pas de date ici \u2014 carte standard\",\n historicalYear: \"Ann\u00E9e de la carte historique\",\n photoOf: (n, total) => `Photo ${n} sur ${total}`,\n },\n nl: {\n previous: \"Vorige\",\n next: \"Volgende\",\n close: \"Sluiten\",\n mapMode: \"Kaart\",\n auto: \"Automatisch\",\n standard: \"Standaard\",\n historical: \"Historisch\",\n historicalMapYear: (year) => `Historische kaart, ${year}`,\n noDateStandardMap: \"Geen datum hier \u2014 standaardkaart\",\n historicalYear: \"Jaar van de historische kaart\",\n photoOf: (n, total) => `Foto ${n} van ${total}`,\n },\n};\n\n/** The best table for a list of BCP 47 tags, most preferred first:\n * \"de-CH\" matches \"de\"; English when nothing does. */\nexport function stringsFor(...languages: (string | undefined)[]): PlayerStrings {\n for (const tag of languages) {\n const base = tag?.toLowerCase().split(/[-_]/)[0];\n if (base && TABLE[base]) return TABLE[base];\n }\n return ENGLISH;\n}\n\n/** Languages with a built-in table. */\nexport const PLAYER_LANGUAGES = Object.keys(TABLE);\n", "// \"A line with years on it, and a dot\": where the current slide sits among\n// the story's dated slides, with click-to-jump per dot. SVG, since a story\n// has at most a few dozen dated slides and SVG rescales for free.\nimport { useEffect, useRef, useState } from \"react\";\nimport { axisTicks, storyDomain, tickLabel, xForYear } from \"./timelineLayout\";\nimport { PIN_PATH_D, type PlayerColors } from \"./theme\";\n\nexport const TIMELINE_HEIGHT = 70;\nconst MARGIN = 28;\n/** Where each pin's tip touches the axis. */\nconst AXIS_Y = 42;\nconst LABEL_Y = 62;\nconst CURRENT_SCALE = 0.95;\n\nexport interface TimelinePoint {\n index: number;\n year: number;\n}\n\nexport function TimelineStrip({ points, currentIndex, onSelect, colors }: {\n points: TimelinePoint[];\n currentIndex: number;\n onSelect: (index: number) => void;\n colors: PlayerColors;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const plotWidth = Math.max(0, width - MARGIN * 2);\n const domain = storyDomain(points.map((p) => p.year));\n const ticks = plotWidth > 0 ? axisTicks(domain, plotWidth) : [];\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"absolute\", left: 0, right: 0, bottom: 0, height: TIMELINE_HEIGHT, background: colors.surface,\n // Above the slide panel, whose fading background would otherwise\n // wash out any dot beneath it.\n zIndex: 2,\n }}\n >\n {width > 0 && (\n <svg width={width} height={TIMELINE_HEIGHT} style={{ display: \"block\", overflow: \"visible\" }}>\n <line x1={MARGIN} y1={AXIS_Y} x2={width - MARGIN} y2={AXIS_Y} stroke={colors.border} strokeWidth={1} />\n {ticks.map((tick) => (\n <text key={tick.x} x={MARGIN + tick.x} y={LABEL_Y} fontSize={15} fill={colors.muted} textAnchor=\"middle\">\n {tick.label}\n </text>\n ))}\n {points.map((point) => {\n const cx = MARGIN + xForYear(point.year, domain, plotWidth);\n const current = point.index === currentIndex;\n return current ? (\n <path\n key={point.index}\n d={PIN_PATH_D}\n transform={`translate(${cx - 12 * CURRENT_SCALE} ${AXIS_Y - 24 * CURRENT_SCALE}) scale(${CURRENT_SCALE})`}\n fill={colors.mark}\n stroke={colors.text}\n strokeWidth={1.5}\n style={{ cursor: \"pointer\" }}\n onClick={() => onSelect(point.index)}\n >\n <title>{tickLabel(point.year)}</title>\n </path>\n ) : (\n <circle\n key={point.index}\n cx={cx}\n cy={AXIS_Y}\n r={3.5}\n fill={colors.mark}\n stroke={colors.surface}\n strokeWidth={1.5}\n style={{ cursor: \"pointer\" }}\n onClick={() => onSelect(point.index)}\n >\n <title>{tickLabel(point.year)}</title>\n </circle>\n );\n })}\n </svg>\n )}\n </div>\n );\n}\n", "// Layout math for the timeline strip along the bottom of a story -- pure\n// numbers, no DOM.\n\n/** The year range the strip covers, with a little padding, so a lone dot\n * (or two dots in the same year) still sits on a real span. */\nexport function storyDomain(years: number[]): [number, number] {\n const min = Math.min(...years);\n const max = Math.max(...years);\n if (max - min < 1) return [min - 5, min + 5];\n const padding = (max - min) * 0.05;\n return [min - padding, max + padding];\n}\n\n/** Where a year lands across a `width`-px strip for `domain`. */\nexport function xForYear(year: number, domain: [number, number], width: number): number {\n const [start, end] = domain;\n const span = end - start;\n if (!(span > 0)) return width / 2;\n return ((year - start) / span) * width;\n}\n\nexport interface AxisTick {\n x: number;\n label: string;\n}\n\n/** Candidate tick spacings in years, coarse to fine. */\nconst TICK_STEPS = [1000, 500, 250, 100, 50, 25, 10, 5, 2, 1];\n/** Aim for roughly this many labelled ticks. */\nconst TARGET_TICKS = 8;\n\nexport function axisTicks(domain: [number, number], width: number): AxisTick[] {\n const [start, end] = domain;\n const span = end - start;\n if (!(span > 0) || width <= 0) return [];\n const step = TICK_STEPS.find((candidate) => span / candidate >= TARGET_TICKS) ?? 1;\n const ticks: AxisTick[] = [];\n for (let year = Math.ceil(start / step) * step; year < end; year += step) {\n ticks.push({ x: ((year - start) / span) * width, label: tickLabel(year) });\n }\n return ticks;\n}\n\n/** Negative years are BC: genealogical calendars have no year 0. */\nexport function tickLabel(year: number): string {\n const whole = Math.floor(year);\n return whole < 0 ? `${-whole} BC` : String(whole);\n}\n", "// A date as typed (\"about 1850\", \"um 1850\") to its precise form (EDTF),\n// read the way Gramps reads dates, in the story's language: the player\n// needs the precise form for the timeline and for picking historical maps.\nimport { loadLocale, parseDate, resolveLocaleCode, toEdtf } from \"@gramps-connect/gramps-date\";\n\n/** Turns date text into EDTF, or undefined when the text isn't a date\n * that has one (\"spring 1850\", a non-Gregorian date). */\nexport type DateTextParser = (text: string, language: string | undefined) => Promise<string | undefined>;\n\n/** The default parser: gramps-date in the story's language (loaded on first\n * use), English when the story has none or gramps-date doesn't know it. */\nexport const suggestEdtf: DateTextParser = async (text, language) => {\n if (!text.trim()) return undefined;\n const code = (language && resolveLocaleCode(language.replace(/-/g, \"_\"))) || \"en\";\n if (code !== \"en\" && !(await loadLocale(code))) return undefined;\n try {\n return toEdtf(parseDate(text, { locale: code }));\n } catch {\n return undefined;\n }\n};\n", "// A slide's date: the text readers see, and its precise form (EDTF), which\n// follows the text as it's typed until someone changes it by hand.\nimport { useEffect, useRef, useState } from \"react\";\nimport { Anchor, Group, Stack, Text, TextInput } from \"@mantine/core\";\nimport type { StoryDate } from \"../types\";\nimport { edtfYearRange } from \"../player/dates\";\nimport type { DateTextParser } from \"./dates\";\nimport { slideDate } from \"./model\";\nimport type { EditorStrings } from \"./strings\";\n\nexport interface DateFieldProps {\n value: StoryDate | undefined;\n language: string | undefined;\n parse: DateTextParser;\n strings: EditorStrings;\n onChange: (date: StoryDate | undefined) => void;\n}\n\n/** Keyed by slide in the parent, so `following` starts over per slide. */\nexport function DateField({ value, language, parse, strings, onChange }: DateFieldProps) {\n // Whether the precise form is worked out from the text. Unknown (null)\n // until the stored one has been compared with what the text gives.\n const [following, setFollowing] = useState<boolean | null>(value?.edtf ? null : true);\n const latest = useRef(value);\n latest.current = value;\n const request = useRef(0);\n\n useEffect(() => {\n if (following !== null) return;\n let live = true;\n void parse(value?.text ?? \"\", language).then((edtf) => {\n if (live) setFollowing(edtf === value?.edtf);\n });\n return () => { live = false; };\n // Once, for the stored date.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const follow = (text: string) => {\n const id = ++request.current;\n void parse(text, language).then((edtf) => {\n // Only the latest text's answer, and only onto the date as it is now.\n if (id !== request.current || latest.current?.text !== text) return;\n onChange(slideDate(latest.current, text, edtf));\n });\n };\n\n const onText = (text: string) => {\n onChange(slideDate(latest.current, text, latest.current?.edtf));\n if (following !== false) follow(text);\n };\n\n const edtf = value?.edtf ?? \"\";\n const understood = !edtf || edtfYearRange(edtf) !== null;\n let note: string;\n if (edtf && !understood) note = strings.preciseDateNotUnderstood;\n else if (!edtf) note = strings.noPreciseDate;\n else if (following) note = strings.preciseDateFollows;\n else note = strings.preciseDateHint;\n\n return (\n <Stack gap={6}>\n <TextInput\n label={strings.date}\n description={strings.dateHint}\n value={value?.text ?? \"\"}\n onChange={(e) => onText(e.currentTarget.value)}\n />\n {value?.text && (\n <Group gap=\"sm\" align=\"flex-end\" wrap=\"nowrap\">\n <TextInput\n label={strings.preciseDate}\n size=\"xs\"\n w={200}\n value={edtf}\n error={!understood}\n styles={{ input: { fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\" } }}\n onChange={(e) => {\n setFollowing(false);\n onChange(slideDate(latest.current, latest.current?.text ?? \"\", e.currentTarget.value.trim() || undefined));\n }}\n />\n <Stack gap={0} pb={4}>\n <Text size=\"xs\" c={understood ? \"dimmed\" : \"red\"}>{note}</Text>\n {following === false && (\n <Anchor component=\"button\" type=\"button\" size=\"xs\" onClick={() => { setFollowing(true); follow(value.text); }}>\n {strings.matchDateAsWritten}\n </Anchor>\n )}\n </Stack>\n </Group>\n )}\n </Stack>\n );\n}\n", "// The editor's changes to a story, as pure functions from one StoryDoc to\n// the next -- never mutating, so undo is just keeping the old ones. Every\n// change spreads the object it touches, so fields this version doesn't\n// know (a newer minor version's, an extension's) ride along untouched:\n// opening and saving a story must never lose anything.\nimport { FORMAT_ID, FORMAT_VERSION } from \"../version\";\nimport type { MediaItem, Place, Slide, SlideMedia, StoryDate, StoryDoc } from \"../types\";\n\n/** A story with one empty slide: the smallest valid one. */\nexport function blankStory(title: string, language?: string): StoryDoc {\n return {\n format: FORMAT_ID,\n version: FORMAT_VERSION,\n title,\n ...(language ? { language } : {}),\n slides: [{ id: \"s0\", title }],\n media: {},\n };\n}\n\n/** \"s<n>\" past every id already of that form, so it's unique however the\n * story's other ids were made. */\nexport function nextSlideId(doc: StoryDoc): string {\n let max = -1;\n for (const slide of doc.slides) {\n const match = /^s(\\d+)$/.exec(slide.id);\n if (match) max = Math.max(max, Number(match[1]));\n }\n let n = max + 1;\n const ids = new Set(doc.slides.map((s) => s.id));\n while (ids.has(`s${n}`)) n += 1;\n return `s${n}`;\n}\n\nfunction withSlides(doc: StoryDoc, slides: Slide[]): StoryDoc {\n return { ...doc, slides };\n}\n\n/** A new empty slide after `index`; returns the story and the new slide's\n * index. */\nexport function addSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n const slides = [...doc.slides];\n const at = Math.min(Math.max(index + 1, 0), slides.length);\n slides.splice(at, 0, { id: nextSlideId(doc) });\n return { doc: withSlides(doc, slides), index: at };\n}\n\n/** A copy of the slide right after it, with its own id. */\nexport function duplicateSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n const slides = [...doc.slides];\n const copy = structuredClone(slides[index]);\n copy.id = nextSlideId(doc);\n slides.splice(index + 1, 0, copy);\n return { doc: withSlides(doc, slides), index: index + 1 };\n}\n\n/** Removes a slide, unless it's the only one (a story has at least one). */\nexport function deleteSlide(doc: StoryDoc, index: number): { doc: StoryDoc; index: number } {\n if (doc.slides.length <= 1) return { doc, index };\n const slides = doc.slides.filter((_, i) => i !== index);\n return { doc: withSlides(doc, slides), index: Math.min(index, slides.length - 1) };\n}\n\nexport function moveSlide(doc: StoryDoc, from: number, to: number): StoryDoc {\n if (from === to || to < 0 || to >= doc.slides.length) return doc;\n const slides = [...doc.slides];\n const [slide] = slides.splice(from, 1);\n slides.splice(to, 0, slide);\n return withSlides(doc, slides);\n}\n\n/** Sets fields on an object; an undefined value removes the field, so\n * cleared text doesn't linger as \"\". */\nfunction patched<T extends object>(base: T, patch: Partial<T>): T {\n const next = { ...base } as Record<string, unknown>;\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) delete next[key];\n else next[key] = value;\n }\n return next as T;\n}\n\nexport function updateSlide(doc: StoryDoc, index: number, patch: Partial<Slide>): StoryDoc {\n const slides = [...doc.slides];\n slides[index] = patched(slides[index], patch);\n return withSlides(doc, slides);\n}\n\nexport function updateStory(doc: StoryDoc, patch: Partial<Omit<StoryDoc, \"slides\" | \"media\">>): StoryDoc {\n return patched(doc, patch as Partial<StoryDoc>);\n}\n\n/** A slide date from what was typed and its precise form. Empty text is no\n * date at all. A new precise form drops a `sortYear` it would contradict\n * (the timeline reads sortYear first); the date's other fields stay. */\nexport function slideDate(previous: StoryDate | undefined, text: string, edtf: string | undefined): StoryDate | undefined {\n if (!text.trim()) return undefined;\n const next = patched(previous ?? { text }, { text, edtf: edtf || undefined });\n if (next.edtf !== previous?.edtf) delete next.sortYear;\n return next;\n}\n\n/** A place with some fields set or (undefined) removed; one left with\n * nothing in it is no place at all. Its shape and overlays, and any field\n * this version doesn't know, stay as they were. */\nexport function patchPlace(place: Place | undefined, patch: Partial<Place>): Place | undefined {\n if (place && Object.entries(patch).every(([key, value]) => place[key as keyof Place] === value)) return place;\n const next = patched(place ?? {}, patch);\n return Object.keys(next).length ? next : undefined;\n}\n\n/** Degrees to 5 decimals: about a metre, and no float noise. */\nexport const roundDegrees = (value: number) => Math.round(value * 1e5) / 1e5;\n\n/** \"47.3769, 8.5417\" (or with a space or semicolon between) -> a point;\n * null when that's not two numbers in range. */\nexport function parseLatLon(text: string): { lat: number; lon: number } | null {\n const parts = text.trim().split(/\\s*[,;\\s]\\s*/);\n if (parts.length !== 2 || parts.some((p) => !/^[-+]?(\\d+\\.?\\d*|\\.\\d+)$/.test(p))) return null;\n const [lat, lon] = parts.map(Number);\n if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return null;\n return { lat, lon };\n}\n\nexport function formatLatLon(lat: number, lon: number): string {\n return `${roundDegrees(lat)}, ${roundDegrees(lon)}`;\n}\n\n/** The places of the story's other slides, one per name (the first slide\n * to use it), for giving another slide the very same place. */\nexport function storyPlaceChoices(doc: StoryDoc, exceptIndex?: number): Place[] {\n const byName = new Map<string, Place>();\n doc.slides.forEach((slide, i) => {\n const name = slide.place?.name?.trim();\n if (i !== exceptIndex && name && !byName.has(name)) byName.set(name, slide.place!);\n });\n return [...byName.values()];\n}\n\n/** A prepared image to add to a story (see optimizeImage). */\nexport interface NewImage {\n data: Uint8Array;\n mime: string;\n /** File extension, without the dot. */\n ext: string;\n width?: number;\n height?: number;\n}\n\nfunction sameBytes(a: Uint8Array | undefined, b: Uint8Array): boolean {\n if (!a || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** The media key whose file is exactly these bytes, if any: a photo\n * that's already in the story, chosen again. */\nexport function findMedia(doc: StoryDoc, files: Map<string, Uint8Array>, data: Uint8Array): string | undefined {\n for (const [key, item] of Object.entries(doc.media)) {\n if (sameBytes(files.get(item.src), data)) return key;\n }\n return undefined;\n}\n\n/** Adds an image to the story's media (not to any slide), or finds the\n * identical one already there, so the same photo is stored once. Returns\n * its media key. */\nexport function addImage(\n doc: StoryDoc, files: Map<string, Uint8Array>, image: NewImage, stem = \"photo\",\n): { doc: StoryDoc; files: Map<string, Uint8Array>; key: string } {\n const existing = findMedia(doc, files, image.data);\n if (existing) return { doc, files, key: existing };\n let n = 1;\n const taken = (key: string) => Object.prototype.hasOwnProperty.call(doc.media, key) || files.has(`media/${key}.${image.ext}`);\n while (taken(`${stem}-${n}`)) n += 1;\n const key = `${stem}-${n}`;\n const src = `media/${key}.${image.ext}`;\n const item: MediaItem = {\n src, mime: image.mime,\n ...(image.width ? { width: image.width } : {}),\n ...(image.height ? { height: image.height } : {}),\n };\n return {\n doc: { ...doc, media: { ...doc.media, [key]: item } },\n files: new Map(files).set(src, image.data),\n key,\n };\n}\n\n/** A slide's photo list; an empty one removes the field. */\nexport function setSlidePhotos(doc: StoryDoc, index: number, media: SlideMedia[]): StoryDoc {\n return updateSlide(doc, index, { media: media.length ? media : undefined });\n}\n\n/** Changes a media item itself (its description, shared by every slide\n * that shows it). */\nexport function updateMedia(doc: StoryDoc, key: string, patch: Partial<MediaItem>): StoryDoc {\n if (!Object.prototype.hasOwnProperty.call(doc.media, key)) return doc;\n return { ...doc, media: { ...doc.media, [key]: patched(doc.media[key], patch) } };\n}\n\n/** Every media key a slide or overlay refers to. */\nexport function usedMedia(doc: StoryDoc): Set<string> {\n const used = new Set<string>();\n for (const slide of doc.slides) {\n for (const m of slide.media ?? []) used.add(m.ref);\n for (const o of slide.place?.overlays ?? []) used.add(o.media);\n }\n return used;\n}\n\n/** The story as it should be saved: media nothing refers to any more left\n * out, and the files only those that are still used. */\nexport function pruneMedia(doc: StoryDoc, files: Map<string, Uint8Array>): { doc: StoryDoc; files: Map<string, Uint8Array> } {\n const used = usedMedia(doc);\n const media = Object.fromEntries(Object.entries(doc.media).filter(([key]) => used.has(key)));\n const srcs = new Set(Object.values(media).map((m) => m.src));\n return {\n doc: { ...doc, media },\n files: new Map([...files].filter(([path]) => srcs.has(path))),\n };\n}\n\n/** \"Josef Meyer\" -> \"Josef Meyer.story.zip\", minus characters some file\n * systems refuse. */\nexport function storyFileName(title: string): string {\n const safe = title.replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]+/g, \" \").replace(/\\s+/g, \" \").trim().slice(0, 120);\n return `${safe || \"story\"}.story.zip`;\n}\n\n/** Undo and redo over whole documents (a StoryDoc here; any value that's\n * replaced, never changed in place, works). Typing in one field makes one\n * step, not one per keystroke: a change with the same `key` within\n * COALESCE_MS of the last replaces it. */\nexport interface History<T = StoryDoc> {\n past: T[];\n present: T;\n future: T[];\n lastKey?: string;\n lastAt?: number;\n}\n\nexport const COALESCE_MS = 1500;\nconst MAX_STEPS = 200;\n\nexport function startHistory<T = StoryDoc>(doc: T): History<T> {\n return { past: [], present: doc, future: [] };\n}\n\nexport function record<T>(history: History<T>, next: T, key?: string, now = Date.now()): History<T> {\n if (next === history.present) return history;\n const coalesce = key !== undefined && key === history.lastKey && history.lastAt !== undefined && now - history.lastAt < COALESCE_MS;\n const past = coalesce ? history.past : [...history.past, history.present].slice(-MAX_STEPS);\n return { past, present: next, future: [], lastKey: key, lastAt: now };\n}\n\nexport function undo<T>(history: History<T>): History<T> {\n const previous = history.past[history.past.length - 1];\n if (!previous) return history;\n return { past: history.past.slice(0, -1), present: previous, future: [history.present, ...history.future] };\n}\n\nexport function redo<T>(history: History<T>): History<T> {\n const [next, ...future] = history.future;\n if (!next) return history;\n return { past: [...history.past, history.present], present: next, future };\n}\n", "// A slide's photos: add (pick, drop or paste -- pasting is the editor's),\n// replace, reorder and remove them, and write each one's caption, credit\n// and description. The files themselves are the editor's to prepare and\n// store; this only says what was chosen.\nimport { useEffect, useRef, useState, type DragEvent } from \"react\";\nimport { ActionIcon, Box, Button, Group, Loader, Stack, Text, TextInput, Tooltip } from \"@mantine/core\";\nimport type { MediaItem, SlideMedia } from \"../types\";\nimport type { EditorStrings } from \"./strings\";\n\nexport interface PhotosFieldProps {\n photos: SlideMedia[];\n media: Record<string, MediaItem>;\n /** A displayable URL for a media key. */\n urlFor: (key: string) => Promise<string | null>;\n strings: EditorStrings;\n /** True while chosen files are being prepared. */\n busy?: boolean;\n onChange: (photos: SlideMedia[], key: string) => void;\n /** Image files to add at the end, or to put in place of photo `replace`. */\n onFiles: (files: File[], replace?: number) => void;\n onDescription: (mediaKey: string, alt: string) => void;\n}\n\nconst imagesIn = (list: FileList | null | undefined) => [...(list ?? [])].filter((f) => f.type.startsWith(\"image/\"));\n\nfunction Preview({ mediaKey, urlFor }: { mediaKey: string; urlFor: PhotosFieldProps[\"urlFor\"] }) {\n const [url, setUrl] = useState<string | null>(null);\n useEffect(() => {\n let live = true;\n void urlFor(mediaKey).then((u) => { if (live) setUrl(u); });\n return () => { live = false; };\n }, [mediaKey, urlFor]);\n return (\n <Box w={96} h={96} style={{ flex: \"none\", borderRadius: 6, overflow: \"hidden\", background: \"var(--mantine-color-default-hover)\" }}>\n {url && <img src={url} alt=\"\" style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }} />}\n </Box>\n );\n}\n\nexport function PhotosField({ photos, media, urlFor, strings, busy, onChange, onFiles, onDescription }: PhotosFieldProps) {\n const input = useRef<HTMLInputElement>(null);\n const replacing = useRef<number | undefined>(undefined);\n const [dropping, setDropping] = useState(false);\n\n const pick = (replace?: number) => {\n replacing.current = replace;\n input.current?.click();\n };\n const set = (i: number, patch: Partial<SlideMedia>, field: string) => {\n const next = photos.map((p, j) => {\n if (j !== i) return p;\n const changed: Record<string, unknown> = { ...p, ...patch };\n for (const [k, v] of Object.entries(patch)) if (!v) delete changed[k];\n return changed as unknown as SlideMedia;\n });\n onChange(next, `photo:${i}:${field}`);\n };\n const move = (from: number, to: number) => {\n const next = [...photos];\n const [p] = next.splice(from, 1);\n next.splice(to, 0, p);\n onChange(next, \"photos\");\n };\n const onDrop = (e: DragEvent) => {\n e.preventDefault();\n setDropping(false);\n const files = imagesIn(e.dataTransfer.files);\n if (files.length) onFiles(files);\n };\n\n return (\n <Stack\n gap=\"sm\"\n onDragOver={(e) => { if ([...e.dataTransfer.types].includes(\"Files\")) { e.preventDefault(); setDropping(true); } }}\n onDragLeave={(e) => { if (e.currentTarget === e.target) setDropping(false); }}\n onDrop={onDrop}\n style={{\n borderRadius: 8, padding: dropping ? 8 : 0, margin: dropping ? -8 : 0,\n outline: dropping ? \"2px dashed var(--mantine-primary-color-filled)\" : undefined,\n }}\n >\n <Group justify=\"space-between\">\n <Text size=\"sm\" fw={500}>{strings.photos}</Text>\n <Group gap=\"xs\">\n {busy && <Loader size=\"xs\" />}\n <Button variant=\"default\" size=\"xs\" onClick={() => pick()} disabled={busy}>+ {strings.addPhoto}</Button>\n </Group>\n </Group>\n <input\n ref={input} type=\"file\" accept=\"image/*\" multiple hidden\n onChange={(e) => {\n const files = imagesIn(e.currentTarget.files);\n e.currentTarget.value = \"\";\n if (files.length) onFiles(replacing.current === undefined ? files : files.slice(0, 1), replacing.current);\n }}\n />\n {photos.length === 0 && <Text size=\"xs\" c=\"dimmed\">{strings.photosHint}</Text>}\n {photos.map((photo, i) => {\n const item = Object.prototype.hasOwnProperty.call(media, photo.ref) ? media[photo.ref] : undefined;\n return (\n <Group key={i} gap=\"sm\" align=\"flex-start\" wrap=\"nowrap\">\n <Stack gap={4} align=\"center\">\n <Preview mediaKey={photo.ref} urlFor={urlFor} />\n <Group gap={4}>\n <Tooltip label={strings.movePhotoUp}>\n <ActionIcon size=\"sm\" variant=\"default\" aria-label={strings.movePhotoUp} disabled={i === 0} onClick={() => move(i, i - 1)}>\u2191</ActionIcon>\n </Tooltip>\n <Tooltip label={strings.movePhotoDown}>\n <ActionIcon size=\"sm\" variant=\"default\" aria-label={strings.movePhotoDown} disabled={i === photos.length - 1} onClick={() => move(i, i + 1)}>\u2193</ActionIcon>\n </Tooltip>\n </Group>\n </Stack>\n <Stack gap={6} style={{ flex: 1, minWidth: 0 }}>\n <TextInput size=\"xs\" label={strings.caption} value={photo.caption ?? \"\"} onChange={(e) => set(i, { caption: e.currentTarget.value }, \"caption\")} />\n <TextInput size=\"xs\" label={strings.credit} placeholder={strings.creditHint} value={photo.credit ?? \"\"} onChange={(e) => set(i, { credit: e.currentTarget.value }, \"credit\")} />\n {item && (\n <TextInput\n size=\"xs\" label={strings.description} description={strings.descriptionHint} value={item.alt ?? \"\"}\n onChange={(e) => onDescription(photo.ref, e.currentTarget.value)}\n />\n )}\n <Group gap=\"xs\">\n <Button variant=\"subtle\" size=\"compact-xs\" onClick={() => pick(i)} disabled={busy}>{strings.replacePhoto}</Button>\n <Button variant=\"subtle\" size=\"compact-xs\" color=\"red\" onClick={() => onChange(photos.filter((_, j) => j !== i), \"photos\")}>\n {strings.removePhoto}\n </Button>\n </Group>\n </Stack>\n </Group>\n );\n })}\n </Stack>\n );\n}\n", "// A slide's place: a name and a point. The point comes from clicking the\n// map, dragging the pin, typing coordinates, or a search by name (opt-in:\n// the one thing the editor sends anywhere). Picking one of the story's\n// other places gives this slide the very same place, overlays and all.\n// A place's shapes and old maps are edited full screen (onEditMap), and\n// always kept.\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Autocomplete, Button, Group, Loader, Stack, Text, TextInput, Tooltip, UnstyledButton } from \"@mantine/core\";\nimport type { Place } from \"../types\";\nimport type { Bounds } from \"../player/geo\";\nimport { formatLatLon, parseLatLon, patchPlace, roundDegrees } from \"./model\";\nimport { PlaceMap } from \"./PlaceMap\";\nimport type { PlaceSearch, PlaceSearchResult } from \"./placeSearch\";\nimport type { EditorStrings } from \"./strings\";\n\nexport type PlaceUpdate = (place: Place | undefined) => Place | undefined;\n\nexport interface PlaceFieldProps {\n place: Place | undefined;\n /** The story's other places, to reuse. */\n choices: Place[];\n /** Where the map looks while this place has no point. */\n around?: Bounds | null;\n /** The story's language: search results are named in it. */\n language?: string;\n /** Null hides the search. */\n search: PlaceSearch | null;\n dark?: boolean;\n strings: EditorStrings;\n /** A change, as a function of the place as it is by then. */\n onChange: (update: PlaceUpdate, key: string) => void;\n /** Opens the shapes-and-old-maps editor; without it, those are only\n * kept. */\n onEditMap?: () => void;\n}\n\ntype Found =\n | { state: \"idle\" }\n | { state: \"searching\" }\n | { state: \"results\"; results: PlaceSearchResult[] }\n | { state: \"message\"; message: string };\n\nexport function PlaceField({ place, choices, around, language, search, dark, strings, onChange, onEditMap }: PlaceFieldProps) {\n const lat = place?.lat;\n const lon = place?.lon;\n const point = lat !== undefined && lon !== undefined ? ([lon, lat] as [number, number]) : null;\n const name = place?.name ?? \"\";\n\n // The coordinates as typed, until they're a point; then as the point is.\n const [coords, setCoords] = useState(point ? formatLatLon(point[1], point[0]) : \"\");\n useEffect(() => {\n setCoords((typed) => {\n const parsed = parseLatLon(typed);\n if (lat === undefined || lon === undefined) return parsed ? \"\" : typed;\n return parsed && parsed.lat === lat && parsed.lon === lon ? typed : formatLatLon(lat, lon);\n });\n }, [lat, lon]);\n const coordsInvalid = coords.trim() !== \"\" && !parseLatLon(coords);\n\n const [found, setFound] = useState<Found>({ state: \"idle\" });\n const searching = useRef<AbortController | null>(null);\n useEffect(() => () => searching.current?.abort(), []);\n const find = async () => {\n if (!search || !name.trim()) return;\n searching.current?.abort();\n const controller = new AbortController();\n searching.current = controller;\n setFound({ state: \"searching\" });\n try {\n const results = await search.search(name.trim(), language, controller.signal);\n setFound(results.length ? { state: \"results\", results } : { state: \"message\", message: strings.findPlaceNone });\n } catch {\n if (!controller.signal.aborted) setFound({ state: \"message\", message: strings.findPlaceFailed });\n }\n };\n const choose = async (result: PlaceSearchResult) => {\n if (!search) return;\n searching.current?.abort();\n const controller = new AbortController();\n searching.current = controller;\n setFound({ state: \"searching\" });\n try {\n const at = await search.point(result, controller.signal);\n if (!at) {\n setFound({ state: \"message\", message: strings.findPlaceNoPoint(result.label) });\n return;\n }\n setFound({ state: \"idle\" });\n onChange((p) => patchPlace(p, { name: result.label, lat: roundDegrees(at.lat), lon: roundDegrees(at.lon) }), \"place\");\n } catch {\n if (!controller.signal.aborted) setFound({ state: \"message\", message: strings.findPlaceFailed });\n }\n };\n\n const byName = useMemo(() => new Map(choices.map((c) => [c.name!.trim(), c])), [choices]);\n const keeps = [\n place?.geometry ? strings.placeShape : null,\n place?.overlays?.length ? strings.placeOverlays(place.overlays.length) : null,\n ].filter(Boolean);\n\n return (\n <Stack gap=\"xs\">\n <Group justify=\"space-between\">\n <Text size=\"sm\" fw={500}>{strings.place}</Text>\n {place && (\n <Button variant=\"subtle\" size=\"compact-xs\" color=\"red\" onClick={() => { setFound({ state: \"idle\" }); onChange(() => undefined, \"place\"); }}>\n {strings.removePlace}\n </Button>\n )}\n </Group>\n <Group gap=\"xs\" align=\"flex-end\" wrap=\"nowrap\">\n <Autocomplete\n size=\"xs\" label={strings.placeName} style={{ flex: 1 }} value={name}\n data={[...byName.keys()]}\n comboboxProps={{ withinPortal: true }}\n onChange={(value) => onChange((p) => patchPlace(p, { name: value || undefined }), \"place:name\")}\n onOptionSubmit={(value) => {\n const chosen = byName.get(value);\n if (chosen) onChange(() => structuredClone(chosen), \"place\");\n }}\n />\n {search && (\n <Tooltip label={strings.findPlaceHint} multiline w={260}>\n <Button variant=\"default\" size=\"xs\" disabled={!name.trim() || found.state === \"searching\"} onClick={() => void find()}>\n {strings.findPlace}\n </Button>\n </Tooltip>\n )}\n </Group>\n {found.state === \"searching\" && <Loader size=\"xs\" />}\n {found.state === \"message\" && <Text size=\"xs\" c=\"dimmed\" role=\"status\">{found.message}</Text>}\n {found.state === \"results\" && (\n <Stack gap={2} role=\"list\" aria-label={strings.findPlace}>\n {found.results.map((result) => (\n <UnstyledButton\n key={result.id} role=\"listitem\" onClick={() => void choose(result)}\n style={{ padding: \"4px 8px\", borderRadius: 4, border: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Text size=\"sm\">{result.label}</Text>\n {result.description && <Text size=\"xs\" c=\"dimmed\">{result.description}</Text>}\n </UnstyledButton>\n ))}\n </Stack>\n )}\n <TextInput\n size=\"xs\" label={strings.coordinates} placeholder={strings.coordinatesHint} w={260} value={coords}\n error={coordsInvalid ? strings.coordinatesInvalid : undefined}\n onChange={(e) => {\n const text = e.currentTarget.value;\n setCoords(text);\n const parsed = parseLatLon(text);\n if (!text.trim()) onChange((p) => patchPlace(p, { lat: undefined, lon: undefined }), \"place:point\");\n else if (parsed) onChange((p) => patchPlace(p, parsed), \"place:point\");\n }}\n />\n <PlaceMap\n point={point} around={around} dark={dark} label={strings.placeMap}\n onPick={([pickedLon, pickedLat]) => onChange((p) => patchPlace(p, { lat: pickedLat, lon: pickedLon }), \"place:point\")}\n />\n <Text size=\"xs\" c=\"dimmed\">{strings.placeMapHint}</Text>\n {keeps.length > 0 && <Text size=\"xs\" c=\"dimmed\">{strings.placeKeeps(keeps.join(\", \"))}</Text>}\n {onEditMap && (\n <Group gap=\"sm\" wrap=\"nowrap\" align=\"center\">\n <Button variant=\"default\" size=\"xs\" style={{ flex: \"none\" }} onClick={onEditMap}>{strings.editMap}</Button>\n <Text size=\"xs\" c=\"dimmed\">{strings.editMapHint}</Text>\n </Group>\n )}\n </Stack>\n );\n}\n", "// A small map for setting a place's point: click to put the pin there,\n// drag the pin to move it. It starts at the point, or (with none yet) at\n// the story's other places, or the whole world.\nimport { useEffect, useRef } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from \"maplibre-gl\";\nimport type { LonLat } from \"../types\";\nimport type { Bounds } from \"../player/geo\";\nimport { mapStyleUrl } from \"../player/mapStyles\";\nimport { defaultColors, PIN_PATH_D } from \"../player/theme\";\nimport { roundDegrees } from \"./model\";\n\nexport interface PlaceMapProps {\n point: LonLat | null;\n /** Where to look when there's no point yet. */\n around?: Bounds | null;\n dark?: boolean;\n label: string;\n onPick: (point: LonLat) => void;\n}\n\nexport function PlaceMap({ point, around, dark = false, label, onPick }: PlaceMapProps) {\n const container = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markerRef = useRef<MapLibreMarker | null>(null);\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const pick = (lngLat: { lng: number; lat: number }) => onPickRef.current([roundDegrees(lngLat.lng), roundDegrees(lngLat.lat)]);\n // The first point and surroundings only: moving is the effect below.\n const start = useRef({ point, around });\n\n useEffect(() => {\n if (!container.current) return;\n const { point: first, around: box } = start.current;\n const map = new maplibregl.Map({\n container: container.current,\n style: mapStyleUrl(dark, null),\n ...(first ? { center: first, zoom: 9 } : box ? { bounds: box, fitBoundsOptions: { padding: 30, maxZoom: 9 } } : { center: [10, 30], zoom: 0.5 }),\n attributionControl: { compact: true },\n // Scrolling the form past the map shouldn't zoom it.\n cooperativeGestures: true,\n });\n map.addControl(new maplibregl.NavigationControl({ showCompass: false }), \"top-right\");\n map.getCanvas().style.cursor = \"crosshair\";\n map.on(\"click\", (e) => pick(e.lngLat));\n mapRef.current = map;\n return () => {\n markerRef.current?.remove();\n markerRef.current = null;\n map.remove();\n mapRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dark]);\n\n // The pin follows the point, however it changed; the view follows only\n // when the pin would be out of sight.\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n if (!point) {\n markerRef.current?.remove();\n markerRef.current = null;\n return;\n }\n if (!markerRef.current) {\n const el = document.createElement(\"div\");\n const c = defaultColors(dark);\n el.innerHTML = `<svg viewBox=\"0 0 24 24\" width=\"28\" height=\"28\" style=\"display:block;cursor:grab\">`\n + `<path d=\"${PIN_PATH_D}\" fill=\"${c.mark}\" stroke=\"${c.surface}\" stroke-width=\"1.5\" /></svg>`;\n const marker = new maplibregl.Marker({ element: el, anchor: \"bottom\", draggable: true }).setLngLat(point).addTo(map);\n marker.on(\"dragend\", () => pick(marker.getLngLat()));\n markerRef.current = marker;\n } else {\n markerRef.current.setLngLat(point);\n }\n if (!map.getBounds().contains(point)) map.easeTo({ center: point, zoom: Math.max(map.getZoom(), 8) });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [point?.[0], point?.[1], dark]);\n\n return (\n <div\n ref={container} role=\"application\" aria-label={label}\n style={{ height: 240, borderRadius: 6, overflow: \"hidden\", border: \"1px solid var(--mantine-color-default-border)\" }}\n />\n );\n}\n", "// A slide's map, full screen: the shapes under its pin (drawn, or imported\n// from a KML, GPX or GeoJSON file) and scanned old maps laid over it, each\n// with the years it shows. Works on a copy: Done hands the editor the\n// place and any images added, as one change; Cancel drops them.\nimport { useMemo, useRef, useState } from \"react\";\nimport { ActionIcon, Box, Button, Group, Modal, Stack, Text, TextInput, Tooltip } from \"@mantine/core\";\nimport type { MediaItem, Place, StoryDate, StoryDoc } from \"../types\";\nimport { optimizeImage } from \"../image\";\nimport { parseMapFile } from \"../mapEdit\";\nimport { storyPlaces } from \"../player/geo\";\nimport { edtfYearRange } from \"../player/dates\";\nimport type { DateTextParser } from \"./dates\";\nimport { MapEditor, MapEditorHelp, type MapEditorHandle } from \"./MapEditor\";\nimport type { MapEditorStrings } from \"./mapEditorStrings\";\nimport { addImage, slideDate, type NewImage } from \"./model\";\nimport { editorToPlace, placeToEditor } from \"./placeShapes\";\nimport type { EditorStrings } from \"./strings\";\n\nconst BAR_HEIGHT = 56;\n\nexport interface PlaceMapDialogProps {\n place: Place | undefined;\n doc: StoryDoc;\n files: Map<string, Uint8Array>;\n dark?: boolean;\n parseDateText: DateTextParser;\n strings: EditorStrings;\n mapStrings?: Partial<MapEditorStrings>;\n onCancel: () => void;\n /** The place as edited, and the story's media and files with any images\n * added here. */\n onDone: (place: Place | undefined, media: Record<string, MediaItem>, files: Map<string, Uint8Array>) => void;\n}\n\n/** The default way an old map's scan is stored: 2048px, PNG when it has\n * transparency (see optimizeImage's \"overlay\" purpose). */\nasync function prepareOverlay(file: Blob): Promise<NewImage> {\n const image = await optimizeImage(file, { purpose: \"overlay\" });\n return { data: new Uint8Array(await image.blob.arrayBuffer()), mime: image.mime, ext: image.ext, width: image.width, height: image.height };\n}\n\n/** An overlay's years, as readers would write them; the precise form\n * follows. Narrow, for the map editor's side panel. */\nfunction OverlayDateField({ value, language, parse, strings, onChange }: {\n value: StoryDate | undefined;\n language: string | undefined;\n parse: DateTextParser;\n strings: EditorStrings;\n onChange: (date: StoryDate | undefined) => void;\n}) {\n const [text, setText] = useState(value?.text ?? \"\");\n const request = useRef(0);\n const edtf = value?.edtf;\n return (\n <Stack gap={2} maw={220}>\n <TextInput\n size=\"xs\" label={strings.overlayDate} description={strings.overlayDateHint} value={text}\n onChange={(e) => {\n const typed = e.currentTarget.value;\n setText(typed);\n const id = ++request.current;\n if (!typed.trim()) { onChange(undefined); return; }\n void parse(typed, language).then((parsed) => {\n if (id === request.current) onChange(slideDate(value, typed, parsed));\n });\n }}\n />\n {text.trim() && (\n <Text size=\"xs\" c={edtf && edtfYearRange(edtf) ? \"dimmed\" : \"red\"}>\n {edtf && edtfYearRange(edtf) ? `EDTF ${edtf}` : strings.preciseDateNotUnderstood}\n </Text>\n )}\n </Stack>\n );\n}\n\nexport function PlaceMapDialog({\n place, doc, files, dark, parseDateText, strings, mapStrings: mapStringOverrides, onCancel, onDone,\n}: PlaceMapDialogProps) {\n // The map editor's help on images is Gramps Connect's (images come from\n // its media there); here they're files.\n const mapStrings = { helpImage: strings.mapHelpImage, ...mapStringOverrides };\n const editorRef = useRef<MapEditorHandle>(null);\n const initial = useMemo(() => placeToEditor(place), [place]);\n // The story's media and files with what's been added here.\n const [work, setWork] = useState({ doc, files });\n const workRef = useRef(work);\n workRef.current = work;\n // Each overlay's date by media key, once changed here.\n const [dates, setDates] = useState(() => new Map<string, StoryDate | undefined>());\n const [message, setMessage] = useState<string | null>(null);\n const [helpOpen, setHelpOpen] = useState(false);\n const imageInput = useRef<HTMLInputElement>(null);\n const shapesInput = useRef<HTMLInputElement>(null);\n\n // Where to look with nothing to frame: the pin, or the story's places.\n const initialView = useMemo(() => {\n if (place?.lat !== undefined && place.lon !== undefined) return { center: [place.lon, place.lat] as [number, number], zoom: 12 };\n const all = storyPlaces(doc.slides.map((s) => s.place));\n if (!all) return undefined;\n const [w, s, e, n] = all.bounds;\n return { center: [(w + e) / 2, (s + n) / 2] as [number, number], zoom: 5 };\n }, [place, doc]);\n\n const resolveImage = async (key: string) => {\n const item = Object.prototype.hasOwnProperty.call(workRef.current.doc.media, key) ? workRef.current.doc.media[key] : undefined;\n const data = item && workRef.current.files.get(item.src);\n if (!item || !data) throw new Error(strings.photoFailed(key));\n return URL.createObjectURL(new Blob([data as Uint8Array<ArrayBuffer>], { type: item.mime }));\n };\n\n const addImages = async (chosen: File[]) => {\n setMessage(null);\n for (const file of chosen) {\n let key: string;\n try {\n const added = addImage(workRef.current.doc, workRef.current.files, await prepareOverlay(file), \"map\");\n workRef.current = { doc: added.doc, files: added.files };\n setWork(workRef.current);\n key = added.key;\n } catch {\n setMessage(strings.photoFailed(file.name || \"the image\"));\n continue;\n }\n try {\n if (!(await editorRef.current?.addImage(key))) setMessage(strings.overlayAlready);\n } catch (err) {\n setMessage(err instanceof Error ? err.message : String(err));\n }\n }\n };\n\n const importShapes = async (chosen: File[]) => {\n setMessage(null);\n for (const file of chosen) {\n try {\n // A KML GroundOverlay's picture lives outside the file; only shapes\n // come in.\n const features = parseMapFile(await file.text()).filter((f) => f.properties?.[\"@geometry-type\"] !== \"groundoverlay\");\n if (features.length === 0) setMessage(strings.importNothing(file.name));\n else editorRef.current?.addFeatures(features);\n } catch {\n setMessage(strings.importFailed(file.name));\n }\n }\n };\n\n const done = () => {\n const editor = editorRef.current;\n if (!editor) return;\n onDone(editorToPlace(place, editor.getResult(), dates), workRef.current.doc.media, workRef.current.files);\n };\n\n const bar = dark ? \"rgba(20,20,20,0.85)\" : \"rgba(255,255,255,0.9)\";\n return (\n <Modal opened onClose={onCancel} fullScreen withCloseButton={false} closeOnEscape={false} padding={0}>\n <Box style={{ position: \"fixed\", inset: 0, overflow: \"hidden\" }}>\n <MapEditor\n ref={editorRef}\n initial={initial}\n initialView={initialView}\n resolveImage={resolveImage}\n releaseImage={(url) => URL.revokeObjectURL(url)}\n onAddImage={() => imageInput.current?.click()}\n onError={setMessage}\n dark={dark}\n toolbarTop={BAR_HEIGHT + 12}\n overlayNames={false}\n strings={mapStrings}\n renderOverlayOptions={(key) => (\n <OverlayDateField\n key={key}\n value={dates.has(key) ? dates.get(key) : place?.overlays?.find((o) => o.media === key)?.date}\n language={doc.language}\n parse={parseDateText}\n strings={strings}\n onChange={(date) => setDates((prev) => new Map(prev).set(key, date))}\n />\n )}\n />\n <Group\n justify=\"space-between\" wrap=\"nowrap\" px=\"md\" gap=\"sm\"\n style={{ position: \"absolute\", top: 0, left: 0, right: 0, height: BAR_HEIGHT, zIndex: 3, background: bar }}\n >\n <Group gap={6} wrap=\"nowrap\" style={{ minWidth: 0 }}>\n <Text fw={600} truncate dir=\"auto\">{strings.mapDialogTitle(place?.name)}</Text>\n <Tooltip label={strings.mapHelp}>\n <ActionIcon variant=\"subtle\" radius=\"xl\" aria-label={strings.mapHelp} onClick={() => setHelpOpen(true)}>\u24D8</ActionIcon>\n </Tooltip>\n </Group>\n <Group gap=\"xs\" wrap=\"nowrap\">\n <Tooltip label={strings.importShapesHint} multiline w={280}>\n <Button variant=\"default\" size=\"sm\" onClick={() => shapesInput.current?.click()}>{strings.importShapes}</Button>\n </Tooltip>\n <Button variant=\"default\" size=\"sm\" onClick={onCancel}>{strings.cancel}</Button>\n <Button size=\"sm\" onClick={done}>{strings.done}</Button>\n </Group>\n </Group>\n {message && (\n <Text\n size=\"sm\" role=\"alert\"\n style={{\n position: \"absolute\", bottom: 12, left: 12, zIndex: 3, maxWidth: 480, padding: \"6px 10px\", borderRadius: 6,\n background: bar, color: \"var(--mantine-color-red-filled)\",\n }}\n >\n {message}\n </Text>\n )}\n <input\n ref={imageInput} type=\"file\" accept=\"image/*\" multiple hidden\n onChange={(e) => { const chosen = [...(e.currentTarget.files ?? [])]; e.currentTarget.value = \"\"; void addImages(chosen); }}\n />\n <input\n ref={shapesInput} type=\"file\" accept=\".kml,.gpx,.geojson,.json,application/vnd.google-earth.kml+xml,application/gpx+xml,application/geo+json\" multiple hidden\n onChange={(e) => { const chosen = [...(e.currentTarget.files ?? [])]; e.currentTarget.value = \"\"; void importShapes(chosen); }}\n />\n </Box>\n <Modal opened={helpOpen} onClose={() => setHelpOpen(false)} title={strings.mapHelp} size=\"md\" zIndex={1000}>\n <MapEditorHelp strings={mapStrings} />\n </Modal>\n </Modal>\n );\n}\n", "// Turning a map file's features into what the map editor's terra-draw\n// canvas can edit, and back into features to save (as GeoJSON, see\n// mapItemToGeoJson), with nothing dropped on the way. terra-draw only\n// knows single Points, LineStrings and Polygons with 2D, at-most-9-decimal\n// coordinates, and only keeps the few properties the editor itself sets\n// (name/color/opacity) --\n// while a KML, GeoJSON or GPX file can hold multi-part shapes, arbitrary\n// properties and a GPS track's per-point times. So:\n//\n// - a multi-part shape is split into single parts that share a group,\n// and rejoined on save (parts whose name/colour/opacity were changed\n// apart become separate shapes, since one KML Placemark has one style);\n// - every other property is set aside per part and put back on save;\n// - a track's times are kept only while its points are unchanged --\n// reshaped, it no longer matches the recording, so it saves as a plain\n// line;\n// - elevations are dropped (nothing here uses them);\n// - anything terra-draw still can't take (a polygon with holes, one that\n// crosses itself) is \"locked\": shown but not editable, and saved back\n// exactly as it was, rather than silently left out of the save.\nimport type { Feature, Geometry, LineString, Point, Polygon, Position } from \"geojson\";\n\n/** What the editor reads and writes on each terra-draw feature itself. */\nconst EDITOR_OWNED = new Set([\"name\", \"color\", \"opacity\"]);\n/** Parser bookkeeping with nothing worth saving: the per-point data that's\n * carried separately (coordinateProperties), @tmcw/togeojson's GPX type tag,\n * and a KML style reference whose <Style> doesn't come along. */\nconst DROPPED = new Set([\"coordinateProperties\", \"_gpxType\", \"styleUrl\", \"@geometry-type\"]);\n\nexport type EditableGeometry = Point | LineString | Polygon;\nexport type EditMode = \"point\" | \"linestring\" | \"polygon\";\n\n/** One single-geometry part, ready for terra-draw. `sourceKey` rides on the\n * terra-draw feature as a property so save can find what was set aside. */\nexport interface EditablePart {\n sourceKey: string;\n mode: EditMode;\n geometry: EditableGeometry;\n name?: string;\n color?: string;\n opacity?: number;\n}\n\ninterface PartSource {\n group: string;\n /** Position within its group, so rejoined parts keep their order. */\n index: number;\n extra: Record<string, unknown>;\n /** A track part's per-point times, and the (2D, rounded) points they\n * belong to -- kept only while the saved points still match. */\n times?: string[];\n coords?: Position[];\n}\n\nexport interface EditSession {\n parts: EditablePart[];\n sources: Map<string, PartSource>;\n /** Parts terra-draw wouldn't accept -- see lockPart. */\n locked: Map<string, EditablePart>;\n}\n\n/** terra-draw rejects coordinates with more than 9 decimal places (its\n * coordinatePrecision) -- well under a millimetre, so rounding loses\n * nothing real. Also drops a third (elevation) value. */\nfunction round2d(position: Position): Position {\n return [Number(position[0].toFixed(9)), Number(position[1].toFixed(9))];\n}\n\nfunction singleParts(geometry: Geometry): EditableGeometry[] {\n switch (geometry.type) {\n case \"Point\":\n return [{ type: \"Point\", coordinates: round2d(geometry.coordinates) }];\n case \"LineString\":\n return [{ type: \"LineString\", coordinates: geometry.coordinates.map(round2d) }];\n case \"Polygon\":\n return [{ type: \"Polygon\", coordinates: geometry.coordinates.map((ring) => ring.map(round2d)) }];\n case \"MultiPoint\":\n return geometry.coordinates.map((c) => ({ type: \"Point\", coordinates: round2d(c) }));\n case \"MultiLineString\":\n return geometry.coordinates.map((line) => ({ type: \"LineString\", coordinates: line.map(round2d) }));\n case \"MultiPolygon\":\n return geometry.coordinates.map((poly) => ({ type: \"Polygon\", coordinates: poly.map((ring) => ring.map(round2d)) }));\n case \"GeometryCollection\":\n return geometry.geometries.flatMap(singleParts);\n }\n}\n\nconst modeOf = (geometry: EditableGeometry): EditMode =>\n geometry.type === \"Point\" ? \"point\" : geometry.type === \"LineString\" ? \"linestring\" : \"polygon\";\n\n/** A feature's properties minus the editor's own and the parser's\n * bookkeeping -- kept as they are, nested values included. */\nfunction extraProperties(properties: Record<string, unknown>): Record<string, unknown> {\n const extra: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(properties)) {\n if (EDITOR_OWNED.has(key) || DROPPED.has(key) || value === undefined || value === null) continue;\n extra[key] = value;\n }\n return extra;\n}\n\n/** Each part's times, if the feature has them in @tmcw/togeojson's own\n * shape: string[] for a LineString, string[][] for a MultiLineString. */\nfunction partTimes(feature: Feature, partCount: number): (string[] | undefined)[] {\n const times = (feature.properties?.coordinateProperties as { times?: unknown } | undefined)?.times;\n if (!Array.isArray(times) || times.length === 0) return [];\n if (feature.geometry?.type === \"LineString\" && times.every((t) => typeof t === \"string\")) {\n return [times as string[]];\n }\n if (feature.geometry?.type === \"MultiLineString\" && times.length === partCount && times.every(Array.isArray)) {\n return times as string[][];\n }\n return [];\n}\n\n/** Splits a file's features (e.g. parseMapFile's) into\n * editable single parts. A polygon with holes is locked from the start:\n * terra-draw's polygon editing only knows an outer ring. */\nexport function prepareForEditing(features: Feature[], firstIndex = 0): EditSession {\n const session: EditSession = { parts: [], sources: new Map(), locked: new Map() };\n features.forEach((feature, i) => {\n const f = firstIndex + i;\n if (!feature.geometry) return;\n const properties = (feature.properties ?? {}) as Record<string, unknown>;\n const extra = extraProperties(properties);\n const geometries = singleParts(feature.geometry);\n const times = partTimes(feature, geometries.length);\n const opacityRaw = Number(properties.opacity);\n const opacity = Number.isFinite(opacityRaw) && opacityRaw >= 0 && opacityRaw <= 1 ? opacityRaw : undefined;\n geometries.forEach((geometry, index) => {\n const sourceKey = `f${f}p${index}`;\n const partTimesHere = times[index];\n const keepTimes = geometry.type === \"LineString\" && partTimesHere?.length === geometry.coordinates.length;\n session.sources.set(sourceKey, {\n group: `f${f}`, index, extra,\n ...(keepTimes ? { times: partTimesHere, coords: geometry.coordinates } : {}),\n });\n const part: EditablePart = {\n sourceKey, mode: modeOf(geometry), geometry,\n name: typeof properties.name === \"string\" ? properties.name : undefined,\n color: typeof properties.color === \"string\" ? properties.color : undefined,\n ...(geometry.type === \"Polygon\" ? { opacity } : {}),\n };\n if (geometry.type === \"Polygon\" && geometry.coordinates.length > 1) session.locked.set(sourceKey, part);\n else session.parts.push(part);\n });\n });\n return session;\n}\n\n/** Adds more features (a file imported while editing) after the session's\n * own, so they save after them too. Returns the session of just the new\n * ones, whose parts the canvas still has to take. */\nexport function addToSession(session: EditSession, features: Feature[]): EditSession {\n let next = 0;\n for (const source of session.sources.values()) next = Math.max(next, Number(source.group.slice(1)) + 1);\n const added = prepareForEditing(features, next);\n session.parts.push(...added.parts);\n for (const [key, source] of added.sources) session.sources.set(key, source);\n for (const [key, part] of added.locked) session.locked.set(key, part);\n return added;\n}\n\n/** Marks a part terra-draw refused to load (addFeatures' validation): it's\n * no longer editable, and assembleForSaving writes it back unchanged. */\nexport function lockPart(session: EditSession, sourceKey: string): void {\n const index = session.parts.findIndex((part) => part.sourceKey === sourceKey);\n if (index < 0) return;\n session.locked.set(sourceKey, session.parts[index]);\n session.parts.splice(index, 1);\n}\n\n/** A part as saved from the canvas: its (possibly edited) geometry and the\n * editor's own properties, plus the sourceKey it was loaded with -- absent\n * for a shape drawn new in this session. */\nexport interface SavedPart {\n sourceKey?: string;\n geometry: EditableGeometry;\n name?: string;\n color?: string;\n opacity?: number;\n}\n\nconst samePositions = (a: Position[], b: Position[]) =>\n a.length === b.length && a.every((p, i) => p[0] === b[i][0] && p[1] === b[i][1]);\n\n/** Joins single geometries back into one -- Multi* when they're all one\n * kind, a GeometryCollection when mixed (what a KML MultiGeometry is). */\nfunction joinGeometries(geometries: EditableGeometry[]): Geometry {\n if (geometries.length === 1) return geometries[0];\n const kinds = new Set(geometries.map((g) => g.type));\n if (kinds.size === 1) {\n if (kinds.has(\"Point\")) return { type: \"MultiPoint\", coordinates: geometries.map((g) => (g as Point).coordinates) };\n if (kinds.has(\"LineString\")) return { type: \"MultiLineString\", coordinates: geometries.map((g) => (g as LineString).coordinates) };\n return { type: \"MultiPolygon\", coordinates: geometries.map((g) => (g as Polygon).coordinates) };\n }\n return { type: \"GeometryCollection\", geometries };\n}\n\n/** Everything to save: the canvas's parts with their set-aside data put\n * back, multi-part shapes rejoined, and locked parts as they were loaded.\n * Features come out in their original file order, new shapes last. */\nexport function assembleForSaving(session: EditSession, saved: SavedPart[]): Feature[] {\n interface Entry { part: SavedPart; source?: PartSource }\n const entries: Entry[] = [\n ...saved.map((part) => ({ part, source: part.sourceKey ? session.sources.get(part.sourceKey) : undefined })),\n ...[...session.locked.values()].map((part) => ({ part, source: session.sources.get(part.sourceKey) })),\n ];\n // One bucket per original feature and style (a part restyled apart from\n // its siblings becomes its own shape), and one per new shape.\n const buckets = new Map<string, Entry[]>();\n let newCount = 0;\n for (const entry of entries) {\n const { part, source } = entry;\n const key = source\n ? `${source.group}|${part.name ?? \"\"}|${part.color ?? \"\"}|${part.opacity ?? \"\"}`\n : `new${newCount++}`;\n const bucket = buckets.get(key);\n if (bucket) bucket.push(entry);\n else buckets.set(key, [entry]);\n }\n const groupOrder = (key: string) => (key.startsWith(\"new\") ? Infinity : Number(key.slice(1, key.indexOf(\"|\"))));\n return [...buckets.entries()]\n .sort(([a], [b]) => groupOrder(a) - groupOrder(b))\n .map(([, bucket]) => {\n bucket.sort((a, b) => (a.source?.index ?? 0) - (b.source?.index ?? 0));\n const first = bucket[0];\n const geometry = joinGeometries(bucket.map((e) => e.part.geometry));\n // Times only when every line in the shape still has its own, on\n // unchanged points -- @tmcw/togeojson's own shape for them is all of\n // a track's segments timed or none.\n const times = bucket.map(({ part, source }) =>\n part.geometry.type === \"LineString\" && source?.times && source.coords\n && samePositions(part.geometry.coordinates, source.coords)\n ? source.times\n : undefined);\n const allTimed = bucket.every((e) => e.part.geometry.type === \"LineString\") && times.every(Boolean);\n return {\n type: \"Feature\",\n geometry,\n properties: {\n ...(first.source?.extra ?? {}),\n ...(first.part.color !== undefined ? { color: first.part.color } : {}),\n ...(first.part.name ? { name: first.part.name } : {}),\n ...(first.part.opacity !== undefined ? { opacity: first.part.opacity } : {}),\n ...(allTimed ? { coordinateProperties: { times: bucket.length === 1 ? times[0] : times } } : {}),\n },\n } as Feature;\n });\n}\n", "// Reading and writing map files: KML, GPX and GeoJSON in (read into GeoJSON\n// features, with each format's own colours where they're reliable), and\n// GeoJSON out, with image overlays as Polygon features marked\n// IMAGE_OVERLAY_PROPERTY. A GeoJSON overlay's `image` names its picture;\n// read back, it becomes the same feature @tmcw/togeojson makes of a KML\n// GroundOverlay, with the picture behind MEDIA_HANDLE_PREFIX. Moved here\n// from Gramps Connect (kmlMedia.ts and mapFileWrite.ts), which shares it\n// with the Story Editor. GPX and KML need a DOMParser (a browser, or jsdom).\n//\n// GeoJSON keeps every property as JSON and multi-part shapes as they are,\n// with no format translation to lose anything in; a GPS track's per-point\n// times ride along in `coordinateProperties.times`, the same place\n// @tmcw/togeojson's GPX/KML readers put them.\nimport type { Feature, FeatureCollection, GeoJsonObject, Geometry, Position } from \"geojson\";\nimport { gpx, kml } from \"@tmcw/togeojson\";\nimport type { OverlayCorners } from \"./geometry\";\n\n/** An image overlay's picture, as a Media handle behind this marker (not a\n * real URL: an app-internal reference, since a resolvable link would need\n * an expiring auth token baked in) -- in a KML GroundOverlay's href, and\n * what asGroundOverlay makes of a GeoJSON one's `image`. */\nexport const MEDIA_HANDLE_PREFIX = \"media-handle:\";\n\n/** A GeoJSON or GPX file's own colours, in the simplestyle convention\n * (`stroke`/`fill`/`fill-opacity`/`marker-color`, which both GeoJSON tools\n * and @tmcw/togeojson's gpx() use), copied onto the `color`/`opacity`\n * properties every map layer actually reads (see MapCanvas.tsx's\n * KML_FILL_LAYER). Fills only what's missing, so an explicit `color` wins.\n * Not applied to KML: Gramps Connect's own KML carries `color` already, and\n * leaving foreign KML alone keeps every existing overlay looking the same. */\nfunction applySimplestyle(feature: Feature): Feature {\n const props = feature.properties ?? {};\n const isRegion = feature.geometry?.type === \"Polygon\" || feature.geometry?.type === \"MultiPolygon\";\n const color = props.color ?? (isRegion ? props.fill ?? props.stroke : props.stroke ?? props[\"marker-color\"]);\n const opacity = props.opacity ?? (isRegion ? props[\"fill-opacity\"] : undefined);\n if (color === props.color && opacity === props.opacity) return feature;\n return { ...feature, properties: { ...props, color, opacity } };\n}\n\n/** A GeoJSON file's features: a FeatureCollection, a single Feature or a\n * bare Geometry are all valid GeoJSON documents. */\nfunction geoJsonFeatures(doc: GeoJsonObject): Feature<Geometry | null>[] {\n if (doc.type === \"FeatureCollection\") return (doc as { features?: Feature<Geometry | null>[] }).features ?? [];\n if (doc.type === \"Feature\") return [doc as Feature<Geometry | null>];\n return [{ type: \"Feature\", geometry: doc as Geometry, properties: {} }];\n}\n\n/** Gramps Connect's GeoJSON image overlay (see mapItemToGeoJson), turned into\n * the same feature @tmcw/togeojson makes of a KML <gx:LatLonQuad>\n * GroundOverlay -- so fetchAllKmlImageOverlays and everything that skips\n * overlays read both formats the same way. */\nfunction asGroundOverlay(feature: Feature): Feature {\n const props = feature.properties ?? {};\n if (props[IMAGE_OVERLAY_PROPERTY] !== true || typeof props.image !== \"string\") return feature;\n const { [IMAGE_OVERLAY_PROPERTY]: _marker, image, ...rest } = props;\n return {\n ...feature,\n properties: { ...rest, \"@geometry-type\": \"groundoverlay\", icon: `${MEDIA_HANDLE_PREFIX}${image}` },\n };\n}\n\n/** A map file's text, as GeoJSON features. The format is read off the\n * content (GeoJSON is JSON; GPX and KML differ by root element) rather\n * than the media object's stored mime, which a file attached by another\n * client may not have set to anything Gramps Connect recognizes. Throws on\n * unparseable text; features with no geometry are dropped -- a KML\n * Placemark without Point/LineString/Polygon (see @tmcw/togeojson's\n * KMLOptions.skipNullGeometry), or a GeoJSON Feature with `geometry: null`,\n * is of no use to a caller here, so dropped rather than threaded through\n * as `Feature<Geometry | null>` everywhere downstream. */\nexport function parseMapFile(text: string): Feature[] {\n const hasGeometry = (f: Feature<Geometry | null>): f is Feature => f.geometry != null;\n if (text.trimStart().startsWith(\"{\")) {\n return geoJsonFeatures(JSON.parse(text) as GeoJsonObject).filter(hasGeometry).map(asGroundOverlay).map(applySimplestyle);\n }\n const dom = new DOMParser().parseFromString(text, \"text/xml\");\n if (dom.documentElement.localName === \"gpx\") {\n return gpx(dom).features.filter(hasGeometry).map(applySimplestyle);\n }\n return kml(dom).features.filter(hasGeometry);\n}\n\n/** An overlay file's SOURCE_PROPERTY, if it's GeoJSON that has one. */\nexport function overlaySourceOfText(text: string): string | undefined {\n if (!text.trimStart().startsWith(\"{\")) return undefined;\n try {\n const source = (JSON.parse(text) as Record<string, unknown>)[SOURCE_PROPERTY];\n return typeof source === \"string\" ? source : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Every Polygon ring inside `feature` -- itself (a plain Polygon), or each\n * Polygon sub-geometry of a GeometryCollection. A country-level Wikidata/\n * Commons outline (e.g. the United States) is often a disjoint shape --\n * islands/territories a single Polygon ring can't express -- unlike a\n * state's simpler single-ring Polygon. A KML file stores one as a\n * <MultiGeometry> of several <Polygon>s, and @tmcw/togeojson reads *any* multi-child\n * Placemark geometry back as a GeometryCollection (never reconstituting\n * MultiPolygon) -- so that's the shape that actually reaches here, not\n * \"MultiPolygon\" itself (confirmed live, 2026-09-09, round-tripping a\n * synthetic MultiPolygon through both libraries). A non-Polygon sub-geometry\n * (there shouldn't be one -- Gramps Connect never writes anything else into a\n * region's own Placemark) is simply skipped rather than failing the whole\n * feature. `[]` for anything else (a Point, a bare LineString route, ...),\n * meaning \"not a region\" to every caller below. */\nexport function polygonRingsOf(feature: Feature): Position[][] {\n if (feature.geometry?.type === \"Polygon\") return [feature.geometry.coordinates[0]];\n if (feature.geometry?.type === \"GeometryCollection\") {\n return feature.geometry.geometries.filter((g) => g.type === \"Polygon\").map((g) => g.coordinates[0]);\n }\n return [];\n}\n\n/** True for a feature fetchAllKmlRegions/MapCanvas.tsx's own shapes effect\n * both treat as one drawable/controllable region -- see polygonRingsOf.\n * Exported so MapCanvas.tsx's key/hidden/opacity stamping can use the exact\n * same test fetchAllKmlRegions does: the two must never drift, or a row's\n * key stops matching the feature it's meant to control -- found live as a\n * place whose outline drew on the map (MapLibre's GeoJSON source splits a\n * GeometryCollection into one sub-feature per geometry before rendering,\n * each individually typed \"Polygon\") but never showed up in\n * OverlayLayersPanel.tsx's list. */\nexport function isKmlRegion(feature: Feature): boolean {\n return polygonRingsOf(feature).length > 0;\n}\n\n/** Every vertex of `feature` if it's a line: a LineString, a MultiLineString\n * (a GPX track with several segments) or a GeometryCollection of only\n * LineStrings (how @tmcw/togeojson reads a KML MultiGeometry -- see\n * polygonRingsOf). `[]` for anything else, meaning \"not a line\". */\nexport function lineCoordsOf(feature: Feature): Position[] {\n const geometry = feature.geometry;\n if (geometry?.type === \"LineString\") return geometry.coordinates;\n if (geometry?.type === \"MultiLineString\") return geometry.coordinates.flat();\n if (geometry?.type === \"GeometryCollection\" && geometry.geometries.length > 0\n && geometry.geometries.every((g) => g.type === \"LineString\")) {\n return geometry.geometries.flatMap((g) => (g.type === \"LineString\" ? g.coordinates : []));\n }\n return [];\n}\n\n/** True for a feature fetchAllKmlLines lists and MapCanvas.tsx's shapes\n * effect lets the panel hide/dim -- shared for the same reason as\n * isKmlRegion: the two must never drift apart. A region is never a line. */\nexport function isKmlLine(feature: Feature): boolean {\n return !isKmlRegion(feature) && lineCoordsOf(feature).length > 0;\n}\n\n/** An image overlay, as MapItemEditorDialog.tsx tracks one -- always 4\n * explicit world corners; see kmlMedia.ts's KmlImageOverlay, which this\n * mirrors on the write side. */\nexport interface ImageOverlay {\n handle: string;\n corners: OverlayCorners;\n name?: string;\n opacity?: number;\n order?: number;\n}\n\n/** The property marking a feature as an image overlay rather than a shape:\n * its Polygon is the image's 4 corners (top-left, top-right, bottom-right,\n * bottom-left, closed), and `image` is the picture's Media handle. This\n * app's own convention -- plain GeoJSON has no image overlays -- read back\n * by parseMapFile. */\nexport const IMAGE_OVERLAY_PROPERTY = \"gramps:image-overlay\";\n\nfunction overlayFeature(overlay: ImageOverlay): Feature {\n const ring = [...overlay.corners, overlay.corners[0]];\n return {\n type: \"Feature\",\n geometry: { type: \"Polygon\", coordinates: [ring] },\n properties: {\n [IMAGE_OVERLAY_PROPERTY]: true,\n image: overlay.handle,\n ...(overlay.name ? { name: overlay.name } : {}),\n ...(overlay.opacity !== undefined && overlay.opacity !== 1 ? { opacity: overlay.opacity } : {}),\n ...(overlay.order !== undefined ? { order: overlay.order } : {}),\n },\n };\n}\n\n/** Records which Media object an overlay was made from (mapOverlays.ts) --\n * a \"foreign member\" of the FeatureCollection, which GeoJSON allows. */\nexport const SOURCE_PROPERTY = \"gramps:source\";\n\n/** Every shape plus every image overlay, as one GeoJSON FeatureCollection.\n * Overlays go last: kmlMedia.ts's region/line row indexes count every\n * feature in the file but MapCanvas.tsx's leave overlays out, and the two\n * only agree while no overlay comes before a shape. */\nexport function mapItemToGeoJson(features: Feature[], overlays: ImageOverlay[] = [], source?: string): string {\n const collection: FeatureCollection & { [SOURCE_PROPERTY]?: string } = {\n type: \"FeatureCollection\",\n ...(source ? { [SOURCE_PROPERTY]: source } : {}),\n features: [...features, ...overlays.map(overlayFeature)],\n };\n return JSON.stringify(collection);\n}\n", "// Map geometry for shapes and image overlays, as plain math (no map\n// library): image overlay corners moved, scaled and rotated in Web Mercator\n// space so a rectangle stays one at any latitude, and bounding boxes over\n// features and overlays. Moved here from Gramps Connect (its kmlMedia.ts),\n// which shares it with the Story Editor; the \"kml\" in some names is from\n// there, where KML was the first map file format.\nimport type { Feature, Position } from \"geojson\";\n\n/** An overlay's 4 world corners, maplibre's own ImageSource `coordinates`\n * order (top-left, top-right, bottom-right, bottom-left) and type. */\nexport type OverlayCorners = [[number, number], [number, number], [number, number], [number, number]];\n\nconst DEG_TO_RAD = Math.PI / 180;\nconst RAD_TO_DEG = 180 / Math.PI;\n\n/** [lng,lat] -> normalized Web Mercator x/y (x east-positive, y\n * *south*-positive) -- the exact projection maplibre's own map.project()\n * uses internally, reimplemented here as plain math (no maplibre-gl\n * import) so this module stays free of that ~900KB dependency (see\n * MapItemEditorDialog.tsx's own doc comment on why maplibre-gl is always\n * behind a lazy import elsewhere in Gramps Connect). Unlike raw [lng,lat],\n * Mercator x/y is locally isotropic -- equal scale in both directions at\n * any given point, which is the whole point of the projection -- making it\n * the correct space to rotate a box in; see rotatePoint. */\nfunction mercatorFromLngLat([lng, lat]: [number, number]): [number, number] {\n const x = (180 + lng) / 360;\n const y = (180 - RAD_TO_DEG * Math.log(Math.tan(Math.PI / 4 + (lat * DEG_TO_RAD) / 2))) / 360;\n return [x, y];\n}\n\n/** mercatorFromLngLat's inverse. */\nfunction lngLatFromMercator([x, y]: [number, number]): [number, number] {\n const lng = x * 360 - 180;\n const lat = 90 - 2 * Math.atan(Math.exp((y * 360 - 180) * DEG_TO_RAD)) * RAD_TO_DEG;\n return [lng, lat];\n}\n\n/** Rotates one point by `rotationDeg` around `center` (positive =\n * counterclockwise, matching KML's own <LatLonBox><rotation> convention)\n * -- done in Mercator-projected space (see mercatorFromLngLat), not raw\n * [lng,lat], so a rectangle stays a rectangle (right angles preserved)\n * after rotating, regardless of latitude. A naive rotation directly on\n * [lng,lat] -- this function's original implementation -- shears instead,\n * since a degree of longitude and a degree of latitude aren't the same\n * ground (or screen) distance away from the equator (found live: a square\n * image's corners visibly stopped being 90 degrees once rotated away from\n * 0). Gramps Connect's own image overlays are never meant to be opened in an\n * external viewer (their picture is an app-internal Media reference), so diverging here\n * from what Google Earth's own <LatLonBox><rotation> would render is an\n * acceptable trade for Gramps Connect always rendering its own files correctly.\n * Pass a negative `rotationDeg` to go the other way (world -> local). */\nexport function rotatePoint(point: [number, number], center: [number, number], rotationDeg: number): [number, number] {\n const angle = rotationDeg * DEG_TO_RAD;\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n const [px, py] = mercatorFromLngLat(point);\n const [cx, cy] = mercatorFromLngLat(center);\n // Mercator y increases southward -- negated here so this rotation is\n // expressed in a conventional north-up, east-right plane (dx\n // east-positive, dy north-positive), keeping \"positive rotationDeg =\n // counterclockwise\" the same sense every caller already expects.\n const dx = px - cx;\n const dy = -(py - cy);\n const rx = dx * cos - dy * sin;\n const ry = dx * sin + dy * cos;\n return lngLatFromMercator([cx + rx, cy - ry]);\n}\n\n/** Scales the distance from `center` to `point` by `scale`, in the same\n * Mercator-projected space rotatePoint rotates in -- so scaling a\n * rectangle (or an already-warped quad) uniformly from its own center\n * preserves its exact shape/aspect ratio regardless of latitude, the same\n * way rotatePoint preserves angles. MapItemEditorDialog.tsx's resize\n * handle applies this to all 4 corners at once (see mountOverlay). */\nexport function scalePoint(point: [number, number], center: [number, number], scale: number): [number, number] {\n const [px, py] = mercatorFromLngLat(point);\n const [cx, cy] = mercatorFromLngLat(center);\n return lngLatFromMercator([cx + (px - cx) * scale, cy + (py - cy) * scale]);\n}\n\n/** The distance between `a` and `b` in the same Mercator-projected space\n * scalePoint scales in -- not a real-world distance (Mercator distorts\n * those away from the equator), just a consistent unit for computing a\n * resize handle's before/after scale ratio, which only ever needs to be\n * internally consistent with scalePoint's own projection, not physically\n * meaningful on its own. */\nexport function mercatorDistance(a: [number, number], b: [number, number]): number {\n const [ax, ay] = mercatorFromLngLat(a);\n const [bx, by] = mercatorFromLngLat(b);\n return Math.hypot(bx - ax, by - ay);\n}\n\n/** The angle (degrees, positive = counterclockwise, 0 = due east) from\n * `from` to `to` -- measured in the same Mercator-projected, north-up\n * plane rotatePoint itself rotates in, so a caller tracking \"how far has\n * the user dragged this handle around the center\" gets an angle that\n * matches how rotatePoint will then actually render it (unlike a plain\n * atan2 on raw [lng,lat], which suffers the same latitude-dependent skew\n * rotatePoint's own doc comment describes). */\nexport function mercatorBearing(from: [number, number], to: [number, number]): number {\n const [fx, fy] = mercatorFromLngLat(from);\n const [tx, ty] = mercatorFromLngLat(to);\n return Math.atan2(-(ty - fy), tx - fx) * RAD_TO_DEG;\n}\n\n/** An axis-aligned box plus a rotation about its own center's 4 world\n * corners -- KML's own <LatLonBox><rotation> model. Only ever needed to\n * interpret an *old* overlay saved before Gramps Connect always wrote\n * explicit corners (see its fetchAllKmlImageOverlays); the map editor\n * itself only ever deals with corners directly, never this box shape. */\nexport function cornersFromBox(\n box: { north: number; south: number; east: number; west: number; rotation: number },\n): OverlayCorners {\n const center: [number, number] = [(box.west + box.east) / 2, (box.north + box.south) / 2];\n const corners: [number, number][] = [\n [box.west, box.north], [box.east, box.north], [box.east, box.south], [box.west, box.south],\n ];\n return corners.map((p) => rotatePoint(p, center, box.rotation)) as OverlayCorners;\n}\n\nfunction visitCoordinates(coords: unknown, bounds: [number, number, number, number]): void {\n if (typeof (coords as Position)[0] === \"number\") {\n const [lng, lat] = coords as Position;\n if (lng < bounds[0]) bounds[0] = lng;\n if (lat < bounds[1]) bounds[1] = lat;\n if (lng > bounds[2]) bounds[2] = lng;\n if (lat > bounds[3]) bounds[3] = lat;\n return;\n }\n for (const c of coords as unknown[]) visitCoordinates(c, bounds);\n}\n\n/** Every coordinate's bounding box across a set of KML features, as\n * [west, south, east, north] -- maplibre's own LngLatBoundsLike corner\n * order, so a caller can hand this straight to fitBounds/cameraForBounds to\n * frame a field boundary or a route at whatever zoom actually fits it,\n * rather than guessing one. Null when the features carry no coordinates at\n * all (an empty file, or every fetch above failed). */\nexport function kmlBounds(features: Feature[]): [west: number, south: number, east: number, north: number] | null {\n const bounds: [number, number, number, number] = [Infinity, Infinity, -Infinity, -Infinity];\n for (const feature of features) {\n const geometry = feature.geometry;\n if (!geometry) continue;\n if (geometry.type === \"GeometryCollection\") {\n for (const g of geometry.geometries) if (\"coordinates\" in g) visitCoordinates(g.coordinates, bounds);\n continue;\n }\n visitCoordinates(geometry.coordinates, bounds);\n }\n return Number.isFinite(bounds[0]) ? bounds : null;\n}\n\n/** The center of kmlBounds -- a plain bbox center rather than an\n * area-weighted centroid, which is all a \"roughly where does this file sit\"\n * marker position needs. */\nexport function kmlCenter(features: Feature[]): [lat: number, long: number] | null {\n const bounds = kmlBounds(features);\n if (!bounds) return null;\n return [(bounds[1] + bounds[3]) / 2, (bounds[0] + bounds[2]) / 2];\n}\n\n/** Same bbox as kmlBounds, but over a set of image overlays' corners instead\n * of vector features -- overlays (GroundOverlay/region placemarks) carry no\n * Point/LineString/Polygon geometry for kmlBounds to find anything in, since\n * fetchAllKmlFeatures excludes them entirely. Lets a caller fit the camera to\n * an overlay-only KML attachment the same way it would a vector one. */\nexport function kmlOverlayBounds(\n overlays: { corners: OverlayCorners }[],\n): [west: number, south: number, east: number, north: number] | null {\n if (overlays.length === 0) return null;\n const bounds: [number, number, number, number] = [Infinity, Infinity, -Infinity, -Infinity];\n for (const overlay of overlays) {\n for (const [lng, lat] of overlay.corners) {\n if (lng < bounds[0]) bounds[0] = lng;\n if (lat < bounds[1]) bounds[1] = lat;\n if (lng > bounds[2]) bounds[2] = lng;\n if (lat > bounds[3]) bounds[3] = lat;\n }\n }\n return bounds;\n}\n\n/** Combines two nullable bboxes (as returned by kmlBounds/kmlOverlayBounds)\n * into the box that encloses both -- a place's KML attachment(s) can carry\n * vector shapes and image overlays side by side, and framing the camera to\n * just one kind would clip whichever the caller didn't ask for. Either side\n * missing (no shapes, or no overlays) just passes the other through; both\n * missing is null, same as either input alone would be. */\nexport function unionBounds(\n a: [west: number, south: number, east: number, north: number] | null,\n b: [west: number, south: number, east: number, north: number] | null,\n): [west: number, south: number, east: number, north: number] | null {\n if (!a) return b;\n if (!b) return a;\n return [Math.min(a[0], b[0]), Math.min(a[1], b[1]), Math.max(a[2], b[2]), Math.max(a[3], b[3])];\n}\n\n/** Same bbox-center guess as kmlCenter, but over a set of image overlays'\n * corners instead of vector features -- useVisualData.ts's fallback for a\n * PendingKmlPlace whose only KML attachment is a GroundOverlay (an\n * overlay-only file: no Point/LineString/Polygon placemark for kmlCenter to\n * find anything in, since fetchAllKmlFeatures excludes GroundOverlay\n * placemarks entirely). Without this, a place with only an image overlay\n * attached and no lat/long of its own never gets a derived position and so\n * never renders on the map until someone sets its coordinates by hand\n * (found live). */\nexport function kmlOverlayCenter(overlays: { corners: OverlayCorners }[]): [lat: number, long: number] | null {\n const bounds = kmlOverlayBounds(overlays);\n if (!bounds) return null;\n return [(bounds[1] + bounds[3]) / 2, (bounds[0] + bounds[2]) / 2];\n}\n", "// A full map for drawing and editing shapes (points, lines, polygons,\n// rectangles, with terra-draw) and placing image overlays such as scanned\n// old maps (move, resize, rotate, drag each corner, opacity, order). It\n// edits what it's given and hands it back when asked (MapEditorHandle);\n// loading and saving are the host's: Gramps Connect's MapItemEditorDialog\n// reads and writes a map file on the server, the Story Editor a slide's\n// place.\n//\n// Shapes go through map-edit's model (prepareForEditing/assembleForSaving),\n// so multi-part shapes, GPS track times and properties this editor doesn't\n// know survive an edit; anything terra-draw can't take is shown dashed\n// (\"locked\") and saved back exactly as it was.\n//\n// Needs Mantine (like the rest of the editor), maplibre-gl, terra-draw and\n// terra-draw-maplibre-gl-adapter.\nimport { forwardRef, useEffect, useImperativeHandle, useRef, useState, type ReactNode } from \"react\";\nimport * as maplibregl from \"maplibre-gl\";\n// maplibre's stylesheet comes with the player, which this entry includes\n// (an import of it here would end up in the published declarations).\nimport type { Map as MapLibreMap } from \"maplibre-gl\";\nimport {\n TerraDraw, TerraDrawLineStringMode, TerraDrawPointMode, TerraDrawPolygonMode, TerraDrawRectangleMode,\n TerraDrawSelectMode,\n} from \"terra-draw\";\nimport type { GeoJSONStoreFeatures, HexColor } from \"terra-draw\";\nimport { TerraDrawMapLibreGLAdapter } from \"terra-draw-maplibre-gl-adapter\";\nimport type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport {\n Alert, Box, Button, ColorInput, Divider, Group, Kbd, List, Loader, NumberInput, SegmentedControl, Slider, Stack, Text,\n TextInput,\n} from \"@mantine/core\";\nimport {\n addToSession, assembleForSaving, lockPart, mercatorBearing, mercatorDistance, prepareForEditing, rotatePoint, scalePoint,\n type EditableGeometry, type EditablePart, type EditSession, type OverlayCorners, type SavedPart,\n} from \"../mapEdit\";\nimport { mapStyleUrl } from \"../player/mapStyles\";\nimport { defaultColors } from \"../player/theme\";\nimport { mapEditorStringsFor, type MapEditorStrings } from \"./mapEditorStrings\";\nimport { browserLanguages } from \"./strings\";\n\ntype DrawMode = \"point\" | \"linestring\" | \"polygon\" | \"rectangle\" | \"select\";\n\nconst TOOLBAR: { mode: DrawMode; label: keyof MapEditorStrings }[] = [\n { mode: \"point\", label: \"point\" },\n { mode: \"linestring\", label: \"line\" },\n { mode: \"polygon\", label: \"polygon\" },\n { mode: \"rectangle\", label: \"rectangle\" },\n { mode: \"select\", label: \"select\" },\n];\n\n// A handful of preset swatches for the color picker -- ColorInput's own\n// popover still offers the full picker for anything else, this just saves\n// a trip there for the common case.\nconst COLOR_SWATCHES = [\n \"#2a78d6\", \"#d64545\", \"#3aa657\", \"#e0a325\", \"#8654c9\", \"#2aa7a0\", \"#e0678a\", \"#555555\",\n];\n\n/** A region's fill with no opacity of its own, as the maps and the story\n * player draw it; also a new region's starting opacity. */\nconst UNSET_OPACITY = 0.25;\nconst EMPTY_LABEL_PREVIEW: FeatureCollection = { type: \"FeatureCollection\", features: [] };\n\n/** An image overlay as the host gives and gets it: `image` is the host's\n * own name for the picture (a media handle, a story media key), turned\n * into something displayable by `resolveImage`. */\nexport interface MapEditorOverlay {\n image: string;\n /** Top-left, top-right, bottom-right, bottom-left, as [lng, lat]. */\n corners: OverlayCorners;\n name?: string;\n /** 0-1; undefined is fully opaque. */\n opacity?: number;\n /** Stacking rank; higher draws on top. */\n order?: number;\n}\n\n/** What's in the editor, for the host to save. */\nexport interface MapEditorResult {\n features: Feature[];\n overlays: MapEditorOverlay[];\n}\n\nexport interface MapEditorStatus {\n /** Anything drawn or placed (shapes or images). */\n hasDrawn: boolean;\n /** Anything to save at all: drawn, placed, or locked. */\n hasContent: boolean;\n}\n\nexport interface MapEditorHandle {\n /** Everything as it is now: shapes put back together (see map-edit's\n * assembleForSaving) and the image overlays. */\n getResult: () => MapEditorResult;\n /** The box around everything drawn and placed, [west, south, east,\n * north], or null with nothing there yet. */\n drawnBounds: () => [number, number, number, number] | null;\n /** Places an image in the middle of the current view, at its own aspect\n * ratio, and selects it. False if that image is already one of the\n * overlays. Throws if it can't be loaded. */\n addImage: (image: string) => Promise<boolean>;\n /** Adds shapes (an imported map file's, see parseMapFile) after what's\n * there, and frames them. */\n addFeatures: (features: Feature[]) => void;\n}\n\nexport interface MapEditorProps {\n /** What to edit: null while the host is still loading it (the map shows,\n * and fills in once this arrives). Read once; later changes are\n * ignored. */\n initial: { features: Feature[]; overlays: MapEditorOverlay[] } | null;\n /** Where to look when what's loaded has nothing to frame. */\n initialView?: { center: [number, number]; zoom: number };\n /** A displayable URL for an overlay's image. */\n resolveImage: (image: string) => Promise<string>;\n /** Called with a URL from resolveImage once the editor is done with it\n * (e.g. URL.revokeObjectURL). */\n releaseImage?: (url: string) => void;\n /** Shows an Image button; the host picks one and calls addImage. */\n onAddImage?: () => void;\n onStatus?: (status: MapEditorStatus) => void;\n /** A map that wouldn't load, or a terra-draw failure. */\n onError?: (message: string) => void;\n dark?: boolean;\n /** A new shape's color until another is picked. */\n defaultColor?: string;\n /** For point labels drawn on the map. */\n labelColors?: { text: string; surface: string };\n /** Room to leave above the tool panel for the host's own bars. */\n toolbarTop?: number;\n /** Whether an image overlay has a name to edit (default true). */\n overlayNames?: boolean;\n /** More fields for the selected image overlay, below its own. */\n renderOverlayOptions?: (image: string) => ReactNode;\n strings?: Partial<MapEditorStrings>;\n}\n\n/** One placed-and-sized image overlay in this editor -- always 4 explicit\n * world corners. `id` is a local key only (React list key + maplibre\n * source/layer id prefix), not persisted.\n *\n * There's deliberately no separate \"box\" (north/south/east/west/rotation)\n * representation: move/resize/rotate/corner-drag all transform these same\n * 4 points directly (see mountOverlay) -- resize scales all 4 uniformly\n * from their shared center, rotate spins all 4 uniformly around it, a\n * corner drag moves just the one point -- so a plain rectangle is simply\n * the case where the 4 points happen to describe one, and resize/rotate\n * stay exactly as meaningful (and aspect-preserving) on an already-warped\n * quad as on a rectangle. The free-transform control only ever shows or\n * hides the 4 individual corner-drag handles (see showCornerHandles further\n * down) -- it never touches `corners` itself. */\ninterface ImageOverlayDraft extends MapEditorOverlay {\n id: string;\n}\n\n/** What's tracked per mounted image overlay -- everything needed to move\n * it (imperatively, outside React) and tear it down again. `box.corners`\n * is the live, authoritative geometry during a drag; `overlays` state\n * (committed on drag end) only needs to be right when read back and on\n * remount.\n *\n * No mousedown listener of its own -- maplibre's layer-filtered events\n * (`map.on(type, layerId, listener)`) work by hit-testing via\n * queryRenderedFeatures, which only supports vector-ish layer types\n * (circle/fill/fill-extrusion/line/symbol); a `type: \"raster\"` layer (what\n * an image source renders as) never matches, so a per-layer listener here\n * would simply never fire (found live: this is why clicking an image did\n * nothing at all). `startMove` is called instead by the one map-wide\n * mousedown handler in the map-setup effect, which does its own point-in-\n * box hit test against every mount's `box`. */\ninterface OverlayMount {\n sourceId: string;\n box: { corners: OverlayCorners };\n deleteMarker: maplibregl.Marker;\n resizeMarker: maplibregl.Marker;\n rotateMarker: maplibregl.Marker;\n /** The 4 free-transform corner handles, maplibre's own `coordinates`\n * order -- shown only while this overlay's id is in `warpHandleIds` (see\n * the selection/visibility effect below); dragging one is the only way\n * to actually turn a rectangle into a non-rectangular quad. */\n cornerMarkers: [maplibregl.Marker, maplibregl.Marker, maplibregl.Marker, maplibregl.Marker];\n startMove: (e: maplibregl.MapMouseEvent) => void;\n /** Applies a new set of corners to `box` and the live map source in one\n * step -- shared by every drag handler (move/resize/rotate/corner-drag),\n * so there's exactly one place that keeps `box` and the rendered image\n * in sync. */\n setCorners: (next: OverlayCorners) => void;\n /** Snaps every handle back onto `box`'s current corners -- called after\n * every geometry change. */\n repositionHandles: () => void;\n /** From resolveImage, given back to releaseImage on unmount, not\n * before: maplibre's `image` source keeps reading from it for as long as\n * the layer exists. */\n imageUrl: string;\n}\n\n/** See the style.load handler's own doc comment on why every image\n * overlay's raster layer is inserted directly below this one layer,\n * rather than wherever addLayer's default \"on top of everything\" would\n * otherwise put it. */\nconst OVERLAY_ANCHOR_LAYER = \"image-overlay-anchor\";\n\n/** terra-draw-maplibre-gl-adapter's own fixed layer ids (its default\n * `prefixId` is \"td\", never overridden here -- see the `TerraDraw`\n * constructor below) -- every one of these is always created by its\n * `register()` (called via `draw.start()`), regardless of which drawing\n * modes are actually used, so this list is safe to `queryRenderedFeatures`\n * against unconditionally once `ready` is true. Used by the map's own\n * mousedown handler to tell whether a click landed on an actual drawn\n * shape before falling through to the image-overlay hit test below it. */\nconst TERRA_DRAW_LAYERS = [\"td-polygon\", \"td-polygon-outline\", \"td-linestring\", \"td-point\", \"td-point-marker\"];\n\n/** Shapes loaded that terra-draw can't edit (see map-edit's lockPart) --\n * drawn dashed underneath, so they're still visible, and saved back\n * exactly as they were. */\nconst LOCKED_SOURCE = \"locked-shapes\";\nconst LOCKED_FILL_LAYER = \"locked-shapes-fill\";\nconst LOCKED_LINE_LAYER = \"locked-shapes-line\";\n\n/** terra-draw's own point mode has no text-label styling (see the\n * label-preview effect below), so a labeled point's text is drawn by this\n * separate, independent geojson source/layer stacked on top of\n * terra-draw's own -- purely visual, never read back from directly\n * (getResult reads terra-draw's own snapshot, this is a mirror of it). */\nconst LABEL_PREVIEW_SOURCE = \"label-preview\";\nconst LABEL_PREVIEW_LAYER = \"label-preview-text\";\n\n/** The tool panel sits over the map; its own background and the gaps\n * between controls let clicks through to the map below (a shape corner or\n * overlay handle that ends up under the panel's empty space would\n * otherwise be dead), the way maplibre's own control containers do. */\nconst TOOLBAR_CLASS = \"gc-map-editor-toolbar\";\nconst TOOLBAR_CSS = `.${TOOLBAR_CLASS} { pointer-events: none; } .${TOOLBAR_CLASS} > * { pointer-events: auto; }`;\n\n/** The average of `corners` -- a plain centroid, not an area-weighted one,\n * which is all a resize/rotate pivot or a delete-handle position needs.\n * Corner indices are tracked by identity (index 0 is always \"whichever\n * point started as top-left\", however far move/resize/rotate/warp has\n * since carried it), so this stays a stable, sensible center throughout. */\nfunction overlayCenter(corners: OverlayCorners): [number, number] {\n let lng = 0, lat = 0;\n for (const [x, y] of corners) { lng += x; lat += y; }\n return [lng / 4, lat / 4];\n}\n\n/** The rotate handle's own resting position -- beyond the midpoint of the\n * corners[0]-corners[1] edge (this overlay's \"top\" edge, by index, however\n * it's currently oriented), extended further out from `center` so the\n * handle doesn't crowd that edge. Since this is recomputed from the\n * *current* corners every time (not from a persisted rotation angle), it\n * naturally orbits the shape as move/resize/rotate/corner-drag change it,\n * the standard \"stalk above a selected object\" rotate-handle convention --\n * with no separate \"unrotated\" reference frame needed. */\nfunction rotateHandleAnchor(corners: OverlayCorners, center: [number, number]): [number, number] {\n const [topLeft, topRight] = corners;\n const topMid: [number, number] = [(topLeft[0] + topRight[0]) / 2, (topLeft[1] + topRight[1]) / 2];\n return [center[0] + (topMid[0] - center[0]) * 1.5, center[1] + (topMid[1] - center[1]) * 1.5];\n}\n\n/** Whether `point` (screen pixels) falls inside the convex quad described\n * by `corners` (in order around the shape) -- a plain same-side-of-every-\n * edge cross-product test, since a rotated overlay's screen footprint\n * isn't an axis-aligned rectangle a simple min/max bounds check could\n * handle anymore. */\nfunction pointInQuad(point: { x: number; y: number }, corners: { x: number; y: number }[]): boolean {\n let sign = 0;\n for (let i = 0; i < corners.length; i++) {\n const a = corners[i];\n const b = corners[(i + 1) % corners.length];\n const cross = (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x);\n if (cross === 0) continue;\n const s = cross > 0 ? 1 : -1;\n if (sign === 0) sign = s;\n else if (s !== sign) return false;\n }\n return true;\n}\n\n// How see-through a dragged overlay image gets, so whatever's underneath\n// (other images, map features) is visible for positioning it precisely.\nconst OVERLAY_DRAG_OPACITY = 0.5;\n\n// zIndex above the floating left toolbar's own 3 (see its `Stack` style\n// further down) -- that toolbar is positioned absolutely over the map\n// itself and grows taller once an overlay is selected (its \"Edit Options\"\n// section), so a handle whose current corner happens to land underneath\n// it would otherwise be unclickable: the toolbar, not the handle, receives\n// the click. Found live: rotating an overlay a little was enough to swing\n// its resize handle under that panel. Plain maplibre markers have no\n// z-index of their own (auto), so this alone is enough to always win.\nconst OVERLAY_HANDLE_STYLE = {\n width: \"20px\", height: \"20px\", borderRadius: \"50%\", background: \"white\",\n border: \"2px solid #333\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\",\n fontSize: \"12px\", fontWeight: \"700\", color: \"#333\", cursor: \"pointer\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.4)\", userSelect: \"none\", zIndex: 4,\n} as const;\n\nfunction loadImageElement(src: string, failed: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(failed));\n img.src = src;\n });\n}\n\nfunction extendBounds(bounds: maplibregl.LngLatBounds, geometry: Geometry): void {\n if (geometry.type === \"Point\") {\n bounds.extend(geometry.coordinates as [number, number]);\n } else if (geometry.type === \"LineString\") {\n for (const c of geometry.coordinates) bounds.extend(c as [number, number]);\n } else if (geometry.type === \"Polygon\") {\n for (const ring of geometry.coordinates) for (const c of ring) bounds.extend(c as [number, number]);\n }\n}\n\nexport const MapEditor = forwardRef<MapEditorHandle, MapEditorProps>(function MapEditor({\n initial, initialView, resolveImage, releaseImage, onAddImage, onStatus, onError, dark = false, defaultColor, labelColors,\n toolbarTop = 12, overlayNames = true, renderOverlayOptions, strings: stringOverrides,\n}, ref) {\n const strings = { ...mapEditorStringsFor(...browserLanguages()), ...stringOverrides };\n // Callbacks and words the once-per-map listeners below read, kept live.\n const live = useRef({ strings, resolveImage, releaseImage, onError });\n live.current = { strings, resolveImage, releaseImage, onError };\n const fail = (message: string) => live.current.onError?.(message);\n const release = (url: string) => live.current.releaseImage?.(url);\n\n // A callback ref surfaced as state, not a plain useRef -- a host may put\n // this inside a Mantine Modal, whose own children aren't necessarily\n // committed to the DOM in the same pass as this component's first render\n // (found live: a plain `useRef` read inside a `[]`-effect saw `null`\n // every time, so the map/draw setup below never ran at all). Assigning\n // the DOM node to state instead means the effect below (keyed on\n // `containerEl`) reliably fires once it's actually mounted.\n const [containerEl, setContainerEl] = useState<HTMLDivElement | null>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const drawRef = useRef<TerraDraw | null>(null);\n // Image overlays live outside terra-draw entirely (see ImageOverlayDraft's\n // own doc comment) -- this is their bookkeeping, keyed by\n // ImageOverlayDraft.id, imperative like drawRef itself.\n const overlayMountsRef = useRef<Map<string, OverlayMount>>(new Map());\n const [mode, setMode] = useState<DrawMode>(\"select\");\n // Mirrors `mode` state for the finish listener set up once below (same\n // reasoning as colorRef just under this) -- lets it tell a just-finished\n // region (polygon/rectangle) apart from a point/line, since it's\n // registered once per map rather than fresh on every `mode` change.\n const modeRef = useRef(mode);\n modeRef.current = mode;\n const [ready, setReady] = useState(false);\n // The color a newly-finished shape takes (draw.on(\"finish\") below), and\n // -- when a shape is currently selected -- what changing this recolors\n // in place.\n const [color, setColor] = useState(() => defaultColor ?? defaultColors(dark).mark);\n // Mirrors `color` state for the terra-draw styling functions/listeners\n // set up once (keyed on `containerEl`, see that effect) below -- they\n // close over this ref instead of `color` itself so a later color change\n // doesn't need the whole map/draw instance rebuilt to see it.\n const colorRef = useRef(color);\n colorRef.current = color;\n // A region's (polygon/rectangle) fill opacity, same pattern as `color`:\n // both a newly-finished region's own opacity and, while one is selected,\n // what changing this edits in place. 0.25 matches Gramps Connect's map\n // view default, so an untouched region renders the same there.\n const [opacity, setOpacity] = useState(UNSET_OPACITY);\n const opacityRef = useRef(opacity);\n opacityRef.current = opacity;\n // How a loaded shape with no color of its own is drawn: as the maps draw\n // it (their mark color), not in whatever the toolbar's color is now --\n // and it's saved still without one.\n const unsetColorRef = useRef(defaultColor ?? defaultColors(dark).mark);\n unsetColorRef.current = defaultColor ?? defaultColors(dark).mark;\n // The selected point/region's own `name` (a point's label text, or a\n // region's purely-descriptive name), mirroring `color`'s own pattern --\n // NOT derived from getSnapshot() on every render, since\n // updateFeatureProperties (called on every keystroke below) doesn't\n // itself trigger a re-render, which would leave a derived value stuck\n // showing whatever it read on the last unrelated render. Seeded/cleared\n // by the select/deselect listeners below instead.\n const [labelText, setLabelText] = useState(\"\");\n // Populated fresh every render by the effect below -- lets the map-setup\n // effect's own terra-draw listeners (registered once, see colorRef's own\n // doc comment on this pattern) call the latest refreshLabelPreview\n // without closing over a stale `labelText`.\n const refreshLabelPreviewRef = useRef<(() => void) | null>(null);\n // terra-draw's own select mode only ever has zero or one feature\n // selected at a time (see TOOLBAR's \"select\" mode) -- this mirrors that\n // via draw.on(\"select\"/\"deselect\") so the color picker knows whether a\n // change should recolor something instead of just setting the next\n // shape's color.\n const [selectedId, setSelectedId] = useState<string | null>(null);\n // Mirrors `selectedId` for the canvas keydown listener set up once\n // below (Backspace-deletes-the-selection), same reasoning as colorRef.\n const selectedIdRef = useRef(selectedId);\n selectedIdRef.current = selectedId;\n const labelColorsRef = useRef(labelColors ?? defaultColors(dark));\n labelColorsRef.current = labelColors ?? defaultColors(dark);\n // Keeps LABEL_PREVIEW_SOURCE (the editor's own text-rendering layer,\n // added in the style.load handler below since terra-draw's point mode\n // can't render text itself) in sync with every named point -- including,\n // for the currently selected feature only, `labelText` itself rather\n // than its last-saved `name` property, so a keystroke shows up\n // immediately instead of only once the point is deselected (terra-draw's\n // updateFeatureProperties, called on every keystroke by the text field\n // below, doesn't reliably fire draw's own \"change\" event).\n useEffect(() => {\n const draw = drawRef.current;\n const map = mapRef.current;\n const source = map?.getSource(LABEL_PREVIEW_SOURCE) as maplibregl.GeoJSONSource | undefined;\n const refresh = () => {\n const currentDraw = drawRef.current;\n const currentSource = mapRef.current?.getSource(LABEL_PREVIEW_SOURCE) as maplibregl.GeoJSONSource | undefined;\n if (!currentDraw || !currentSource) return;\n const features: Feature[] = [];\n for (const f of currentDraw.getSnapshot()) {\n if (f.geometry?.type !== \"Point\") continue;\n const isSelected = String(f.id) === selectedId;\n const name = (isSelected ? labelText : (f.properties?.name as string | undefined))?.trim();\n if (!name) continue;\n features.push({\n type: \"Feature\", geometry: f.geometry,\n properties: { name, color: f.properties?.color as string | undefined },\n });\n }\n currentSource.setData({ type: \"FeatureCollection\", features });\n };\n refreshLabelPreviewRef.current = refresh;\n if (draw && source) refresh();\n }, [labelText, selectedId]);\n // Every placed image overlay -- a wholly separate system from terra-draw\n // (which has no image geometry type), see the block of effects/handlers\n // below this component's map-setup effect.\n const [overlays, setOverlays] = useState<ImageOverlayDraft[]>([]);\n // Mirrors `overlays` for startMove's onUp (below), set up once per mount\n // and so unable to see a later opacity edit via closure alone -- same\n // colorRef/selectedIdRef pattern as elsewhere in this file.\n const overlaysRef = useRef(overlays);\n overlaysRef.current = overlays;\n // Which overlay's move/resize/delete handles are currently showing --\n // set on mousedown over that overlay's image (see mountOverlay), cleared\n // by clicking anywhere else on the map (see the map-setup effect's own\n // mousedown handler) or by deleting the selected overlay itself.\n const [selectedOverlayId, setSelectedOverlayId] = useState<string | null>(null);\n // Which overlays currently show their 4 free-transform corner handles\n // (in addition to the always-available delete/resize/rotate) -- purely a\n // display preference, never touched by geometry (see\n // setCornerHandlesVisible's own doc comment), so it lives here rather\n // than on ImageOverlayDraft/`overlays` state.\n const [warpHandleIds, setWarpHandleIds] = useState<Set<string>>(new Set());\n // Whether terra-draw currently holds any shape.\n const [hasFeatures, setHasFeatures] = useState(false);\n // What was set aside when loading (map-edit's model) -- the properties,\n // multi-part groups and track times terra-draw doesn't keep, put back by\n // getResult. Null with nothing loaded.\n const sessionRef = useRef<EditSession | null>(null);\n // How many of the loaded shapes terra-draw couldn't take, shown locked.\n const [lockedCount, setLockedCount] = useState(0);\n const [lockedNoticeDismissed, setLockedNoticeDismissed] = useState(false);\n\n const hasDrawn = hasFeatures || overlays.length > 0;\n const hasContent = hasDrawn || lockedCount > 0;\n const onStatusRef = useRef(onStatus);\n onStatusRef.current = onStatus;\n useEffect(() => { onStatusRef.current?.({ hasDrawn, hasContent }); }, [hasDrawn, hasContent]);\n\n useEffect(() => {\n if (!containerEl) return;\n const map = new maplibregl.Map({\n container: containerEl,\n style: mapStyleUrl(dark, null),\n center: [0, 20],\n zoom: 1.5,\n attributionControl: { compact: true },\n });\n mapRef.current = map;\n map.addControl(new maplibregl.NavigationControl({ showCompass: false }), \"top-right\");\n // maplibre's own default: holding Ctrl and dragging (or a two-finger\n // touch twist) rotates/pitches the *camera*, which collides directly\n // with terra-draw's own rotate gesture for rotating a *selected shape*\n // (see the select mode's `rotateable` flag below) -- found live,\n // holding the rotate key and dragging a vertex was spinning the whole\n // map instead of the shape. This editor has no use for a tilted/\n // rotated basemap anyway, so the camera's own rotate/pitch is disabled\n // outright rather than trying to make the two coexist.\n map.dragRotate.disable();\n map.touchZoomRotate.disableRotation();\n map.keyboard.disableRotation();\n\n // Every drawing mode's color comes from the feature's own `color`\n // property, not a fixed style -- colorRef (above) is what the styling\n // functions actually read, kept live via a ref rather than closing\n // over `color` state directly, since these mode instances are built\n // once per map (this effect is keyed on `containerEl`, not `color`)\n // and terra-draw calls a styling function fresh on every render, not\n // just at construction time.\n const readColor = (feature: GeoJSONStoreFeatures): HexColor =>\n (feature.properties.color as HexColor | undefined) ?? (unsetColorRef.current as HexColor);\n // Same pattern as readColor, for a region's own `opacity` property --\n // only polygon/rectangle modes take a `fillOpacity` style at all (point/\n // line have nothing to fill).\n const readOpacity = (feature: GeoJSONStoreFeatures): number =>\n (feature.properties.opacity as number | undefined) ?? UNSET_OPACITY;\n\n const draw = new TerraDraw({\n adapter: new TerraDrawMapLibreGLAdapter({ map }),\n modes: [\n new TerraDrawPointMode({ styles: { pointColor: readColor } }),\n new TerraDrawLineStringMode({ styles: { lineStringColor: readColor } }),\n new TerraDrawPolygonMode({ styles: { fillColor: readColor, fillOpacity: readOpacity, outlineColor: readColor } }),\n new TerraDrawRectangleMode({ styles: { fillColor: readColor, fillOpacity: readOpacity, outlineColor: readColor } }),\n // Dragging (both a whole feature and its individual vertices) and\n // deletion (terra-draw's own default keybinding, Delete/Backspace\n // on the current selection) are what this editor needs from\n // Select for every mode; `rotateable` additionally turns on\n // terra-draw's own built-in rotate gesture (hold R while dragging\n // a selected shape's vertex) for anything 2D enough for \"rotate\"\n // to mean something -- not `point`, a single vertex has nothing to\n // rotate around.\n new TerraDrawSelectMode({\n // While a feature is selected, terra-draw renders it through\n // *this* mode's own styling, not the drawing mode that created it\n // (see TerraDraw's own per-feature style dispatch: only the\n // selected feature goes through TerraDrawSelectMode.styleFeature;\n // every other feature keeps using its own mode's, which is why an\n // unselected shape's color/opacity already reflects its own\n // properties fine). Without these, the selected-state styling\n // falls back to terra-draw's fixed defaults regardless of\n // `feature.properties` -- so dragging the opacity slider (or\n // recoloring) while a shape is actively selected had no visible\n // effect until it was deselected. Found live.\n styles: {\n selectedPointColor: readColor,\n selectedLineStringColor: readColor,\n selectedPolygonColor: readColor,\n selectedPolygonOutlineColor: readColor,\n selectedPolygonFillOpacity: readOpacity,\n },\n // Half terra-draw's own default (40px) -- with labels sitting\n // right next to their point (see LABEL_PREVIEW_LAYER's\n // text-offset below) and vertices sometimes placed close\n // together, the default hit-test radius made clicking one point\n // too likely to grab a neighboring one instead. Found live.\n pointerDistance: 20,\n // Every field restated (terra-draw's own type doesn't allow a\n // partial override), only `rotate` actually changed from its\n // default -- plain \"r\" instead of the default Ctrl+R, an\n // awkward two-handed chord to hold through an entire drag. Bare\n // \"r\" is safe here the same way Backspace-delete is (see the\n // canvas keydown listener below): terra-draw's own keydown\n // listener is bound to the map canvas specifically, so it never\n // fires while typing \"r\" into a text field.\n keyEvents: { deselect: \"Escape\", delete: \"Delete\", rotate: [\"r\"], scale: [\"Control\", \"s\"] },\n flags: {\n point: { feature: { draggable: true } },\n linestring: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n polygon: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n rectangle: {\n feature: {\n draggable: true, rotateable: true,\n coordinates: { draggable: true, deletable: true, midpoints: true },\n },\n },\n },\n }),\n ],\n });\n drawRef.current = draw;\n draw.on(\"change\", () => {\n // Same guidance-point exclusion as getResult's own filter below --\n // otherwise a shape's selection handles alone (nothing actually\n // drawn) would count as \"has features\".\n setHasFeatures(\n draw.getSnapshot().some((f) => f.geometry != null && !f.properties?.selectionPoint && !f.properties?.midPoint),\n );\n refreshLabelPreviewRef.current?.();\n });\n // Shared by the \"select\" listener below and the finish handler just\n // under it: selecting an existing feature and just having finished\n // drawing a new one both need the color/opacity/label widgets to catch\n // up to *that* feature's own properties, not whatever the toolbar was\n // last left showing. `id` null means deselected -- nothing to edit, so\n // the widgets themselves go away entirely (see selectedFeature/\n // selectedIsRegion in the render body below).\n function syncSelection(id: string | null) {\n setSelectedId(id);\n const feature = id ? draw.getSnapshot().find((f) => String(f.id) === id) : undefined;\n setLabelText((feature?.properties?.name as string | undefined) ?? \"\");\n if (feature) {\n // An uncolored shape shows the color it's drawn in.\n setColor((feature.properties?.color as string | undefined) ?? unsetColorRef.current);\n setOpacity((feature.properties?.opacity as number | undefined) ?? UNSET_OPACITY);\n // Mirrors the overlay mousedown handler's own deselectFeature call\n // -- an image overlay and a drawn shape are mutually exclusive\n // selections, so a shape becoming selected clears any overlay\n // selection the same way.\n setSelectedOverlayId(null);\n }\n }\n // A shape takes the toolbar's current color (and, for a region, opacity)\n // the moment it's finished drawing -- colorRef/opacityRef (not `color`/\n // `opacity` state) since this listener, like the mode instances above,\n // is registered once per map. Opacity only for polygon/rectangle (both\n // land here as \"polygon\"/\"rectangle\" -- see modeRef): a point or line\n // has no fill for it to mean anything on.\n draw.on(\"finish\", (id) => {\n const isRegion = modeRef.current === \"polygon\" || modeRef.current === \"rectangle\";\n draw.updateFeatureProperties(\n id,\n isRegion ? { color: colorRef.current, opacity: opacityRef.current } : { color: colorRef.current },\n );\n // Every finished shape drops straight into Select mode with itself\n // selected -- lets someone place a boundary, say, and immediately\n // see/adjust its color and opacity without an extra click to the\n // Select tool and back onto the shape it just placed.\n draw.setMode(\"select\");\n setMode(\"select\");\n draw.selectFeature(id);\n syncSelection(String(id));\n });\n draw.on(\"select\", (id) => syncSelection(String(id)));\n draw.on(\"deselect\", () => syncSelection(null));\n\n // terra-draw's own delete keybinding only recognizes the literal\n // \"Delete\" key (terra-draw-maplibre-gl-adapter's default keyEvents) --\n // on a Mac laptop keyboard, the key labelled \"delete\" actually sends\n // \"Backspace\" (only Fn+Delete sends \"Delete\"), so without this a Mac\n // user's most natural keypress would silently do nothing. Bound to\n // the same canvas element terra-draw's own keydown listener uses\n // (getMapEventElement() in that adapter), so -- like terra-draw's own\n // handler -- this only fires while the map canvas has focus, never\n // while typing in a text field.\n const canvas = map.getCanvas();\n const onCanvasKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Backspace\" || !selectedIdRef.current) return;\n try {\n draw.removeFeatures([selectedIdRef.current]);\n } catch {\n // Selection may already be stale (e.g. removed some other way) --\n // nothing more to do.\n }\n setSelectedId(null);\n };\n canvas.addEventListener(\"keydown\", onCanvasKeyDown);\n\n // Some WebKit-based environments (found live: a desktop build's native\n // window) never dispatch PointerEvents for mouse input, even though\n // ordinary MouseEvents work fine there -- map pan/zoom and the\n // image-overlay drag below both ride on mousedown/mousemove/mouseup and\n // both work. terra-draw's own Select mode listens *exclusively* for\n // pointerdown/pointermove/pointerup on the map canvas (see\n // TerraDrawBaseAdapter), so without a bridge, selecting a shape to drag\n // it silently does nothing on such a platform while every other\n // gesture in this editor keeps working. Detected once at runtime -- a\n // \"mousedown\" on the canvas not followed by a real \"pointerdown\" within\n // a frame means this environment isn't dispatching pointer events for\n // mouse input at all, so from then on every mouse event on the canvas\n // is re-dispatched as the equivalent pointer event. terra-draw's own\n // listeners only read clientX/clientY/button/isPrimary/target, none of\n // which require an actual PointerEvent instance -- a MouseEvent with\n // `isPrimary` patched on satisfies them exactly the same.\n let sawNativePointerdown = false;\n let pointerBridgeActive = false;\n let pendingFirstMouseDown: MouseEvent | null = null;\n const onNativePointerDown = () => { sawNativePointerdown = true; };\n canvas.addEventListener(\"pointerdown\", onNativePointerDown, { once: true });\n const dispatchAsPointerEvent = (type: string, e: MouseEvent) => {\n const synthetic = new MouseEvent(type, {\n bubbles: true, cancelable: true, view: window,\n clientX: e.clientX, clientY: e.clientY, button: e.button, buttons: e.buttons,\n });\n Object.defineProperty(synthetic, \"isPrimary\", { value: true });\n canvas.dispatchEvent(synthetic);\n };\n const onMouseDownBridge = (e: MouseEvent) => {\n if (pointerBridgeActive) { dispatchAsPointerEvent(\"pointerdown\", e); return; }\n if (sawNativePointerdown) return;\n pendingFirstMouseDown = e;\n requestAnimationFrame(() => {\n if (sawNativePointerdown || !pendingFirstMouseDown) return;\n pointerBridgeActive = true;\n dispatchAsPointerEvent(\"pointerdown\", pendingFirstMouseDown);\n pendingFirstMouseDown = null;\n });\n };\n const onMouseMoveBridge = (e: MouseEvent) => { if (pointerBridgeActive) dispatchAsPointerEvent(\"pointermove\", e); };\n const onMouseUpBridge = (e: MouseEvent) => { if (pointerBridgeActive) dispatchAsPointerEvent(\"pointerup\", e); };\n canvas.addEventListener(\"mousedown\", onMouseDownBridge);\n canvas.addEventListener(\"mousemove\", onMouseMoveBridge);\n canvas.addEventListener(\"mouseup\", onMouseUpBridge);\n\n // Selects whichever image overlay (if any) was clicked, deselects\n // otherwise, and kicks off that overlay's move-drag -- all in one\n // map-wide handler rather than a per-overlay one, since raster/image\n // layers can't be hit-tested via maplibre's layer-filtered events (see\n // OverlayMount's own doc comment). Does its own point-in-quad check\n // (a rotated overlay's screen footprint isn't axis-aligned) against\n // every mounted overlay's live geometry, topmost (last-added) first,\n // mirroring how they're actually layered on screen.\n map.on(\"mousedown\", (e) => {\n // Marker handles (delete/resize/rotate/corner) are DOM elements\n // appended into maplibre's own canvas container, not the canvas\n // itself -- they still receive this same \"mousedown\" event, so\n // without this check a click that landed on one would also match the\n // point-in-quad test below (a handle sits right at or near the box's\n // own edge) and start a move, fighting the marker's own native drag\n // (found live: dragging the resize handle just moved the image\n // instead of resizing it -- the same bug recurred for the 4 warp-\n // mode corner handles until they were added to this same check).\n // Bail out entirely for a click on any handle and let its own\n // listener (Marker's built-in drag, or the delete element's own\n // click handler) run uncontested.\n const target = e.originalEvent.target;\n if (target instanceof Node) {\n for (const mount of overlayMountsRef.current.values()) {\n if (\n mount.deleteMarker.getElement().contains(target)\n || mount.resizeMarker.getElement().contains(target)\n || mount.rotateMarker.getElement().contains(target)\n || mount.cornerMarkers.some((marker) => marker.getElement().contains(target))\n ) return;\n }\n }\n // A drawn shape (point/line/region) always renders above every image\n // overlay in this editor (see OVERLAY_ANCHOR_LAYER's own doc\n // comment), but the point-in-quad test below has no notion of that --\n // it only asks \"is this pixel inside some overlay's bounds\", so a\n // shape drawn on top of (or overlapping) an image used to have its\n // clicks hijacked into moving that image out from under it instead of\n // ever reaching terra-draw's own selection. Found live: a rectangle\n // sitting over an image overlay was simply unclickable. Checking what\n // maplibre actually rendered at this pixel first -- rather than\n // reimplementing terra-draw's own per-geometry-type hit testing here\n // -- defers to terra-draw whenever a shape is really the topmost\n // thing at this point, same as a sighted user would expect from what\n // they're looking at.\n if (map.queryRenderedFeatures(e.point, { layers: TERRA_DRAW_LAYERS }).length > 0) return;\n const mounts = [...overlayMountsRef.current.entries()].reverse();\n for (const [id, mount] of mounts) {\n const corners = mount.box.corners.map((c) => map.project(c));\n if (pointInQuad(e.point, corners)) {\n // An image overlay and a drawn shape are mutually exclusive\n // selections -- deselect any terra-draw feature first, or its\n // own color/name/opacity controls would keep showing alongside\n // this overlay's, none of them meaningful for the other's kind\n // of item. Found live.\n if (selectedIdRef.current) draw.deselectFeature(selectedIdRef.current);\n setSelectedOverlayId(id);\n mount.startMove(e);\n return;\n }\n }\n setSelectedOverlayId(null);\n });\n\n // A failed style/tile fetch is the one thing that can leave this view\n // blank for a reason the user can't guess.\n map.on(\"error\", (e) => {\n const message = (e.error as Error | undefined)?.message ?? \"\";\n if (/style|sprite|tile|fetch|network|Failed/i.test(message)) fail(message || live.current.strings.basemapFailed);\n });\n\n map.on(\"style.load\", () => {\n // draw.start() registers terra-draw's own sources/layers on the map,\n // which maplibre only allows once the style has actually finished\n // loading -- wrapped so a failure here (a version mismatch, a mode\n // misconfiguration, ...) surfaces as a visible error instead of\n // leaving `ready` false forever.\n try {\n // A permanent, invisible layer added before draw.start() -- image\n // overlays (mountOverlay below) always insert themselves directly\n // below this anchor, so they stay under terra-draw's own shape\n // layers (added next, appended above everything as normal) no\n // matter what order shapes/images actually get added in during the\n // session: images first, geometries on top, matching how a photo\n // of an old map should sit relative to pins/routes drawn over it.\n map.addLayer({ id: OVERLAY_ANCHOR_LAYER, type: \"background\", paint: { \"background-opacity\": 0 } });\n map.addSource(LOCKED_SOURCE, { type: \"geojson\", data: { type: \"FeatureCollection\", features: [] } });\n map.addLayer({\n id: LOCKED_FILL_LAYER, type: \"fill\", source: LOCKED_SOURCE,\n filter: [\"==\", [\"geometry-type\"], \"Polygon\"],\n paint: { \"fill-color\": [\"coalesce\", [\"get\", \"color\"], \"#888888\"], \"fill-opacity\": 0.15 },\n });\n map.addLayer({\n id: LOCKED_LINE_LAYER, type: \"line\", source: LOCKED_SOURCE,\n filter: [\"any\", [\"==\", [\"geometry-type\"], \"Polygon\"], [\"==\", [\"geometry-type\"], \"LineString\"]],\n paint: { \"line-color\": [\"coalesce\", [\"get\", \"color\"], \"#888888\"], \"line-width\": 2, \"line-dasharray\": [2, 2] },\n });\n draw.start();\n draw.setMode(\"select\");\n // Added after draw.start() so it stacks above terra-draw's own\n // point layer -- see LABEL_PREVIEW_SOURCE's own doc comment on why\n // this mirror exists at all. refreshLabelPreviewRef is populated by\n // the effect above; called once here too, in case any features\n // were already loaded before this handler ran.\n const colors = labelColorsRef.current;\n map.addSource(LABEL_PREVIEW_SOURCE, { type: \"geojson\", data: EMPTY_LABEL_PREVIEW });\n map.addLayer({\n id: LABEL_PREVIEW_LAYER,\n type: \"symbol\",\n source: LABEL_PREVIEW_SOURCE,\n layout: {\n \"text-field\": [\"get\", \"name\"],\n \"text-size\": 12,\n \"text-font\": [\"Noto Sans Regular\"],\n // Offset right rather than centered on the point -- centered\n // text sat directly on top of the point, making it hard to see\n // (and, in the real map views, click) the point itself.\n \"text-anchor\": \"left\",\n \"text-offset\": [0.6, 0],\n },\n paint: {\n \"text-color\": [\"coalesce\", [\"get\", \"color\"], colors.text],\n \"text-halo-color\": colors.surface,\n \"text-halo-width\": 1.5,\n },\n });\n refreshLabelPreviewRef.current?.();\n } catch (err) {\n fail(err instanceof Error ? err.message : String(err));\n } finally {\n setReady(true);\n }\n });\n\n return () => {\n draw.stop();\n canvas.removeEventListener(\"keydown\", onCanvasKeyDown);\n canvas.removeEventListener(\"pointerdown\", onNativePointerDown);\n canvas.removeEventListener(\"mousedown\", onMouseDownBridge);\n canvas.removeEventListener(\"mousemove\", onMouseMoveBridge);\n canvas.removeEventListener(\"mouseup\", onMouseUpBridge);\n // Markers aren't part of the map's own style/source tree -- map.remove()\n // below doesn't clean these up on its own.\n for (const mount of overlayMountsRef.current.values()) {\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n release(mount.imageUrl);\n }\n overlayMountsRef.current.clear();\n map.remove();\n mapRef.current = null;\n drawRef.current = null;\n };\n // `dark` only matters for the very first style URL -- a scheme flip\n // while this editor happens to be open isn't worth a style reload.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [containerEl]);\n\n // Mounts one image overlay onto the live map: a maplibre `image` source +\n // `raster` layer (created once, then moved/resized via setCoordinates\n // rather than recreated) plus its handles and a whole-image move\n // gesture. Called both when a new image is added and when the initial\n // overlays are loaded in (the effect below).\n async function mountOverlay(overlay: ImageOverlayDraft) {\n const map = mapRef.current;\n if (!map) return;\n const sourceId = `img-${overlay.id}`;\n const box: { corners: OverlayCorners } = { corners: overlay.corners };\n const imageUrl = await live.current.resolveImage(overlay.image);\n map.addSource(sourceId, { type: \"image\", url: imageUrl, coordinates: box.corners });\n // beforeId keeps this under terra-draw's own shape layers -- see\n // OVERLAY_ANCHOR_LAYER's own doc comment.\n map.addLayer({ id: sourceId, type: \"raster\", source: sourceId }, OVERLAY_ANCHOR_LAYER);\n map.setPaintProperty(sourceId, \"raster-opacity\", overlay.opacity ?? 1);\n\n // The live geometry during a drag -- `overlays` state (below) is only\n // synced at gesture end, both for perf (no re-render per drag frame)\n // and because it's only read back at the end, not mid-drag.\n const setCorners = (next: OverlayCorners) => {\n box.corners = next;\n (map.getSource(sourceId) as maplibregl.ImageSource | undefined)?.setCoordinates(box.corners);\n };\n const commit = () => {\n setOverlays((prev) => prev.map((o) => (o.id === overlay.id ? { ...o, corners: box.corners } : o)));\n };\n\n // Not added to the map yet -- all handles are selection-gated (see the\n // sync effect below), same as terra-draw's own vertex handles only\n // showing up once a shape is actually selected, rather than cluttering\n // every image on screen with several more controls all the time.\n const words = live.current.strings;\n const deleteEl = document.createElement(\"div\");\n deleteEl.textContent = \"\u00D7\";\n deleteEl.title = words.removeImage;\n Object.assign(deleteEl.style, OVERLAY_HANDLE_STYLE);\n const deleteMarker = new maplibregl.Marker({ element: deleteEl, anchor: \"center\" });\n deleteEl.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n unmountOverlay(overlay.id);\n setOverlays((prev) => prev.filter((o) => o.id !== overlay.id));\n setSelectedOverlayId((current) => (current === overlay.id ? null : current));\n });\n\n const resizeEl = document.createElement(\"div\");\n resizeEl.textContent = \"\u2198\";\n resizeEl.title = words.resizeImage;\n Object.assign(resizeEl.style, OVERLAY_HANDLE_STYLE);\n const resizeMarker = new maplibregl.Marker({ element: resizeEl, anchor: \"center\", draggable: true });\n // Captured at the start of each drag: the corners and the handle's own\n // distance from their shared center right then, so every subsequent\n // \"drag\" frame computes one clean scale factor relative to the drag's\n // own start (distance-now / distance-then) rather than compounding a\n // per-frame ratio, which would drift.\n let resizeStartCorners: OverlayCorners = box.corners;\n let resizeStartDist = 1;\n resizeMarker.on(\"dragstart\", () => {\n resizeStartCorners = box.corners;\n const center = overlayCenter(resizeStartCorners);\n const p = resizeMarker.getLngLat();\n resizeStartDist = Math.max(1e-9, mercatorDistance(center, [p.lng, p.lat]));\n });\n resizeMarker.on(\"drag\", () => {\n // Scales every corner's distance from their shared center by the\n // same factor (in Mercator-projected space -- see scalePoint's own\n // doc comment), so this works identically whether the current\n // corners describe a plain rectangle or an already-warped quad: the\n // exact shape is preserved either way, just bigger or smaller. No\n // separate \"aspect ratio\" to track at all -- a uniform scale from\n // center can't distort it.\n const center = overlayCenter(resizeStartCorners);\n const p = resizeMarker.getLngLat();\n const scale = Math.max(0.02, mercatorDistance(center, [p.lng, p.lat]) / resizeStartDist);\n setCorners(resizeStartCorners.map((c) => scalePoint(c, center, scale)) as OverlayCorners);\n repositionHandles();\n });\n resizeMarker.on(\"dragend\", commit);\n\n const rotateEl = document.createElement(\"div\");\n rotateEl.textContent = \"\u21BB\";\n rotateEl.title = words.rotateImage;\n Object.assign(rotateEl.style, OVERLAY_HANDLE_STYLE);\n const rotateMarker = new maplibregl.Marker({ element: rotateEl, anchor: \"center\", draggable: true });\n // Same start-of-drag capture as resize, but for an angle instead of a\n // distance: every \"drag\" frame rotates the *start* corners by\n // (current handle bearing - start handle bearing), an incremental\n // delta from center rather than an absolute angle -- there's no\n // persisted \"rotation\" field to be absolute relative to anymore (see\n // rotateHandleAnchor's own doc comment on why that's fine).\n let rotateStartCorners: OverlayCorners = box.corners;\n let rotateStartAngle = 0;\n rotateMarker.on(\"dragstart\", () => {\n rotateStartCorners = box.corners;\n const center = overlayCenter(rotateStartCorners);\n const p = rotateMarker.getLngLat();\n rotateStartAngle = mercatorBearing(center, [p.lng, p.lat]);\n });\n rotateMarker.on(\"drag\", () => {\n const center = overlayCenter(rotateStartCorners);\n const p = rotateMarker.getLngLat();\n const delta = mercatorBearing(center, [p.lng, p.lat]) - rotateStartAngle;\n setCorners(rotateStartCorners.map((c) => rotatePoint(c, center, delta)) as OverlayCorners);\n repositionHandles();\n });\n rotateMarker.on(\"dragend\", commit);\n\n // Free-transform's 4 independent corner handles -- one per index of\n // maplibre's own `coordinates` order (top-left, top-right,\n // bottom-right, bottom-left). Each drag writes only its own corner,\n // leaving the other 3 exactly where they were -- the actual \"rubber\n // sheet\" warp, as opposed to resize/rotate's whole-shape transforms.\n const cornerMarkers = [0, 1, 2, 3].map((i) => {\n const el = document.createElement(\"div\");\n el.title = words.warpCorner;\n Object.assign(el.style, OVERLAY_HANDLE_STYLE);\n const marker = new maplibregl.Marker({ element: el, anchor: \"center\", draggable: true });\n marker.on(\"drag\", () => {\n const corners = [...box.corners] as OverlayCorners;\n const p = marker.getLngLat();\n corners[i] = [p.lng, p.lat];\n setCorners(corners);\n repositionHandles();\n });\n marker.on(\"dragend\", commit);\n return marker;\n }) as [maplibregl.Marker, maplibregl.Marker, maplibregl.Marker, maplibregl.Marker];\n\n // Snaps every handle back onto the box's current corners -- called\n // after every geometry change (move, resize, rotate, corner drag) so\n // they stay glued to the image instead of drifting back to a stale\n // position. Delete/resize/rotate always track the actual corners (no\n // separate \"rect\" representation to fall back to); the 4 corner\n // handles are additionally repositioned here too, since a resize or\n // rotate gesture moves them right along with everything else.\n const repositionHandles = () => {\n const [topLeft, topRight, bottomRight, bottomLeft] = box.corners;\n const center = overlayCenter(box.corners);\n deleteMarker.setLngLat(center);\n resizeMarker.setLngLat(bottomRight);\n rotateMarker.setLngLat(rotateHandleAnchor(box.corners, center));\n cornerMarkers[0].setLngLat(topLeft);\n cornerMarkers[1].setLngLat(topRight);\n cornerMarkers[2].setLngLat(bottomRight);\n cornerMarkers[3].setLngLat(bottomLeft);\n };\n\n // Move -- dragging anywhere on the image itself (not a small handle;\n // the image can be much bigger than one). Called by the map-wide\n // mousedown handler in the map-setup effect once its own point-in-box\n // test picks this overlay out (see OverlayMount's own doc comment on\n // why that test exists instead of a listener here). Tracked via plain\n // document listeners rather than map-scoped ones so a fast drag that\n // leaves the map div doesn't get stuck without a mouseup.\n const startMove = (e: maplibregl.MapMouseEvent) => {\n e.preventDefault();\n map.dragPan.disable();\n // Nearly-transparent while being dragged so whatever's underneath\n // (other images, the base map) stays visible for positioning --\n // restored on mouseup.\n map.setPaintProperty(sourceId, \"raster-opacity\", OVERLAY_DRAG_OPACITY);\n // In screen pixels, not raw lng/lat degrees -- a fixed degree offset\n // covers a different on-screen distance depending on latitude (Web\n // Mercator isn't uniformly scaled north-south), so translating this\n // way visibly grew/shrank the image as it crossed latitudes mid-drag,\n // even though its own lat/lng span never actually changed. Found\n // live. Projecting each corner once up front, shifting all of them by\n // the same pixel delta the cursor has moved, and unprojecting back\n // keeps the dragged image's on-screen size constant -- the same\n // \"work in projected space, not raw degrees\" fix rotatePoint/\n // scalePoint already apply to rotate/resize (see their own doc\n // comments), just via maplibre's own project/unproject here, since\n // screen pixels (not zoom-independent normalized Mercator units) are\n // exactly what a mouse drag is measured in.\n const startPoint = e.point;\n const startScreenCorners = box.corners.map((corner) => map.project(corner));\n const container = map.getContainer();\n const onMove = (moveEvent: MouseEvent) => {\n const rect = container.getBoundingClientRect();\n const dx = moveEvent.clientX - rect.left - startPoint.x;\n const dy = moveEvent.clientY - rect.top - startPoint.y;\n const newCorners = startScreenCorners.map((screenCorner) => {\n const lngLat = map.unproject([screenCorner.x + dx, screenCorner.y + dy]);\n return [lngLat.lng, lngLat.lat] as [number, number];\n });\n setCorners(newCorners as OverlayCorners);\n repositionHandles();\n };\n const onUp = () => {\n document.removeEventListener(\"mousemove\", onMove);\n document.removeEventListener(\"mouseup\", onUp);\n map.dragPan.enable();\n // Restores this overlay's own opacity (not necessarily fully\n // opaque) -- overlaysRef, not the `overlay` param captured at\n // mount time, so an opacity edit made since this overlay was\n // mounted is still honored.\n const current = overlaysRef.current.find((o) => o.id === overlay.id);\n map.setPaintProperty(sourceId, \"raster-opacity\", current?.opacity ?? 1);\n commit();\n };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n };\n\n repositionHandles();\n overlayMountsRef.current.set(overlay.id, {\n sourceId, box, deleteMarker, resizeMarker, rotateMarker, cornerMarkers, startMove, setCorners, repositionHandles, imageUrl,\n });\n }\n\n function unmountOverlay(id: string) {\n const map = mapRef.current;\n const mount = overlayMountsRef.current.get(id);\n if (!map || !mount) return;\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n if (map.getLayer(mount.sourceId)) map.removeLayer(mount.sourceId);\n if (map.getSource(mount.sourceId)) map.removeSource(mount.sourceId);\n release(mount.imageUrl);\n overlayMountsRef.current.delete(id);\n }\n\n /** Shows or hides one overlay's 4 free-transform corner handles -- the\n * \"Scale\" / \"Transform\" SegmentedControl's onChange. Purely a display\n * preference (see warpHandleIds' own doc comment): move/resize/rotate/\n * delete always work the same way regardless of this, uniformly\n * transforming whatever the current corners are (see mountOverlay), so\n * picking either option never touches geometry at all. */\n function setCornerHandlesVisible(id: string, visible: boolean) {\n setWarpHandleIds((prev) => {\n const next = new Set(prev);\n if (visible) next.add(id); else next.delete(id);\n return next;\n });\n }\n\n // Shows the selected overlay's delete/resize/rotate handles (always) and\n // its 4 free-transform corner handles (only while its id is in\n // warpHandleIds), hides every other overlay's -- mountOverlay creates\n // every marker detached (not added to the map), so a freshly-added or\n // freshly-loaded overlay correctly starts with nothing showing until\n // it's actually clicked.\n const showCornerHandles = selectedOverlayId !== null && warpHandleIds.has(selectedOverlayId);\n useEffect(() => {\n const map = mapRef.current;\n if (!map) return;\n for (const [id, mount] of overlayMountsRef.current) {\n if (id !== selectedOverlayId) {\n mount.deleteMarker.remove();\n mount.resizeMarker.remove();\n mount.rotateMarker.remove();\n for (const marker of mount.cornerMarkers) marker.remove();\n continue;\n }\n mount.deleteMarker.addTo(map);\n mount.resizeMarker.addTo(map);\n mount.rotateMarker.addTo(map);\n for (const marker of mount.cornerMarkers) (showCornerHandles ? marker.addTo(map) : marker.remove());\n }\n }, [selectedOverlayId, showCornerHandles]);\n\n const selectedOverlay = overlays.find((o) => o.id === selectedOverlayId) ?? null;\n\n /** Patches the selected overlay's name/opacity/order in `overlays` state\n * -- and, for opacity, also pushes the change straight onto the live\n * mounted layer for immediate visual feedback, the same way color\n * changes update terra-draw's own selected feature in place. No-op with\n * nothing selected. */\n function updateSelectedOverlay(patch: Partial<Pick<ImageOverlayDraft, \"name\" | \"opacity\" | \"order\">>) {\n if (!selectedOverlayId) return;\n setOverlays((prev) => prev.map((o) => (o.id === selectedOverlayId ? { ...o, ...patch } : o)));\n if (patch.opacity !== undefined) {\n const mount = overlayMountsRef.current.get(selectedOverlayId);\n if (mount) mapRef.current?.setPaintProperty(mount.sourceId, \"raster-opacity\", patch.opacity);\n }\n }\n\n // Loads what's to be edited once the map/draw instance is ready and the\n // host has it, then frames it -- shapes and image overlays together (an\n // overlay-only item has no shape to frame), or the host's initialView\n // when there's nothing to frame.\n const loaded = useRef(false);\n useEffect(() => {\n if (!ready || !initial || loaded.current) return;\n const draw = drawRef.current;\n const map = mapRef.current;\n if (!draw || !map) return;\n loaded.current = true;\n const bounds = new maplibregl.LngLatBounds();\n if (initial.features.length > 0) {\n const session = prepareForEditing(initial.features);\n sessionRef.current = session;\n for (const geometry of showShapes(session, session)) extendBounds(bounds, geometry);\n }\n const drafts = initial.overlays.map((overlay): ImageOverlayDraft => ({ ...overlay, id: crypto.randomUUID() }));\n setOverlays(drafts);\n for (const draft of drafts) {\n // One image that won't load shouldn't keep the rest from editing.\n mountOverlay(draft).catch(() => {});\n for (const corner of draft.corners) bounds.extend(corner);\n }\n if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: 60, maxZoom: 17, duration: 0 });\n else if (initialView) map.jumpTo(initialView);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ready, initial]);\n\n /** Puts a session's parts on the canvas -- `added`, the ones new to it\n * (all of them on load, an import's after) -- locking any terra-draw\n * refuses (a polygon that crosses itself, say) so the save keeps it.\n * Returns every new part's geometry, for framing. */\n function showShapes(session: EditSession, added: EditSession): Geometry[] {\n const draw = drawRef.current;\n const map = mapRef.current;\n if (!draw || !map) return [];\n // Split into single, 2D parts with everything terra-draw won't keep\n // set aside (map-edit's model), so a multi-part shape, a GPS track or\n // a property this editor doesn't know survives the save.\n const parts: EditablePart[] = [...added.parts];\n const results = draw.addFeatures(parts.map((part) => ({\n type: \"Feature\" as const,\n geometry: part.geometry,\n properties: {\n mode: part.mode, sourceKey: part.sourceKey, color: part.color, name: part.name,\n ...(part.mode === \"polygon\" ? { opacity: part.opacity } : {}),\n },\n })) as GeoJSONStoreFeatures[]);\n results.forEach((result, i) => {\n if (!result.valid) lockPart(session, parts[i].sourceKey);\n });\n const locked = [...session.locked.values()];\n setLockedCount(locked.length);\n (map.getSource(LOCKED_SOURCE) as maplibregl.GeoJSONSource | undefined)?.setData({\n type: \"FeatureCollection\",\n features: locked.map((part) => ({ type: \"Feature\", geometry: part.geometry, properties: { color: part.color } })),\n });\n return [...parts, ...added.locked.values()].map((part) => part.geometry);\n }\n\n function handleModeChange(next: DrawMode) {\n // Guarded, not just disabled on the button below: terra-draw's own\n // setMode() throws (\"Terra Draw is not enabled\") until draw.start() has\n // actually run (the style.load handler above), and a click landing in\n // that window before `ready` flips would otherwise be an uncaught\n // exception -- found live.\n if (!ready) return;\n setMode(next);\n // Switching drawing tools while an image overlay is selected leaves it\n // selected otherwise -- the overlay mousedown handler and syncSelection\n // (map-setup effect above) only clear it from the *other* direction\n // (a shape getting selected), not a mere tool change with nothing\n // clicked yet.\n setSelectedOverlayId(null);\n drawRef.current?.setMode(next);\n }\n\n useImperativeHandle(ref, () => ({\n getResult() {\n // Geometry plus the editor's own color/name (and, for a region,\n // opacity) and the part's sourceKey -- terra-draw's other bookkeeping\n // properties (mode, id, ...) mean nothing outside the editor.\n // Everything set aside when loading is put back by assembleForSaving.\n //\n // Also excluded: terra-draw's own selection-mode guidance points --\n // the small vertex/midpoint handle dots it draws on a shape's corners\n // and edges while selected. Select mode stores those as ordinary\n // Point features in the same snapshot (tagged `selectionPoint`/\n // `midPoint`), so saving mid-selection without this filter wrote them\n // into the file as if they were real map-item points. Found live.\n const savedParts: SavedPart[] = (drawRef.current?.getSnapshot() ?? [])\n .filter((f) => f.geometry != null && !f.properties?.selectionPoint && !f.properties?.midPoint)\n .map((f) => {\n // Trimmed, and omitted entirely rather than written as \"\" -- a\n // label point placed but never typed into should round-trip as a\n // plain, nameless point (the presence of `name` is itself what\n // marks a point as a label), not an invisible label with empty\n // text.\n const name = (f.properties?.name as string | undefined)?.trim();\n // Opacity only for a region (Polygon) -- meaningless on a point/\n // line, which have nothing to fill (see readOpacity/opacityRef).\n // Color and opacity only as the shape has them: a drawn shape got\n // both when finished, and one loaded without them stays that way.\n const regionOpacity = f.geometry.type === \"Polygon\"\n ? f.properties?.opacity as number | undefined\n : undefined;\n const color = f.properties?.color as string | undefined;\n const sourceKey = f.properties?.sourceKey;\n return {\n ...(typeof sourceKey === \"string\" ? { sourceKey } : {}),\n geometry: f.geometry as EditableGeometry,\n ...(color !== undefined ? { color } : {}),\n ...(name ? { name } : {}),\n ...(regionOpacity !== undefined ? { opacity: regionOpacity } : {}),\n };\n });\n const session = sessionRef.current ?? { parts: [], sources: new Map(), locked: new Map() };\n return {\n features: assembleForSaving(session, savedParts),\n overlays: overlaysRef.current.map(({ image, corners, name, opacity, order }) => ({ image, corners, name, opacity, order })),\n };\n },\n drawnBounds() {\n const bounds = new maplibregl.LngLatBounds();\n for (const f of drawRef.current?.getSnapshot() ?? []) {\n if (f.geometry == null || f.properties?.selectionPoint || f.properties?.midPoint) continue;\n extendBounds(bounds, f.geometry as Geometry);\n }\n for (const overlay of overlaysRef.current) for (const corner of overlay.corners) bounds.extend(corner);\n return bounds.isEmpty() ? null : (bounds.toArray().flat() as [number, number, number, number]);\n },\n async addImage(image: string) {\n // The same image placed twice has no use: in Gramps Connect an\n // overlay's dates are its place's, so a second copy couldn't even be\n // given a different era -- it would just always show (or not) in\n // lockstep with the first.\n if (overlaysRef.current.some((o) => o.image === image)) return false;\n const map = mapRef.current;\n if (!map) return false;\n // Only to measure the image's own pixel dimensions: mountOverlay\n // asks for it again for its persistent `image` source.\n const url = await live.current.resolveImage(image);\n const element = await loadImageElement(url, live.current.strings.imageFailed).finally(() => release(url));\n const aspect = element.naturalWidth / element.naturalHeight;\n const centerScreen = map.project(map.getCenter());\n const halfWidthPx = 130;\n const halfHeightPx = halfWidthPx / aspect;\n const topLeft = map.unproject([centerScreen.x - halfWidthPx, centerScreen.y - halfHeightPx]);\n const bottomRight = map.unproject([centerScreen.x + halfWidthPx, centerScreen.y + halfHeightPx]);\n const draft: ImageOverlayDraft = {\n id: crypto.randomUUID(),\n image,\n corners: [\n [topLeft.lng, topLeft.lat], [bottomRight.lng, topLeft.lat],\n [bottomRight.lng, bottomRight.lat], [topLeft.lng, bottomRight.lat],\n ],\n // Leaves room to insert between existing overlays later without\n // renumbering.\n order: overlaysRef.current.length * 10,\n };\n setOverlays((prev) => [...prev, draft]);\n // Awaited so the overlay's mount exists before selecting it --\n // selecting one before it's mounted would have nothing for the\n // handle-visibility effect above to find. Auto-selected so its\n // resize/move handles are immediately visible: the initial placement\n // is only ever an approximation.\n await mountOverlay(draft);\n setSelectedOverlayId(draft.id);\n return true;\n },\n addFeatures(features: Feature[]) {\n const map = mapRef.current;\n if (!map || features.length === 0) return;\n const session = sessionRef.current ?? { parts: [], sources: new Map(), locked: new Map() };\n sessionRef.current = session;\n const bounds = new maplibregl.LngLatBounds();\n for (const geometry of showShapes(session, addToSession(session, features))) extendBounds(bounds, geometry);\n if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: 60, maxZoom: 17 });\n },\n // mountOverlay and friends read only refs: a fresh handle each render\n // is fine.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }));\n\n // Cheap to recompute on every render (getSnapshot() is just an array\n // read) rather than mirrored into its own state -- selectedId already\n // triggers a re-render via draw.on(\"select\"/\"deselect\") above, so this\n // stays in sync for free.\n const selectedFeature = selectedId ? drawRef.current?.getSnapshot().find((f) => String(f.id) === selectedId) : undefined;\n const selectedIsPoint = selectedFeature?.geometry?.type === \"Point\";\n // Covers both polygon and rectangle tools -- a rectangle is stored as a\n // Polygon feature under the hood.\n const selectedIsRegion = selectedFeature?.geometry?.type === \"Polygon\";\n\n function renderModeButton(entry: { mode: DrawMode; label: keyof MapEditorStrings }) {\n return (\n <Button\n key={entry.mode}\n size=\"xs\"\n variant={mode === entry.mode ? \"filled\" : \"default\"}\n disabled={!ready}\n onClick={() => handleModeChange(entry.mode)}\n >\n {strings[entry.label] as string}\n </Button>\n );\n }\n\n return (\n <Box style={{ position: \"absolute\", inset: 0, overflow: \"hidden\" }}>\n <style>{TOOLBAR_CSS}</style>\n <div ref={setContainerEl} style={{ position: \"absolute\", inset: 0 }} />\n\n {/* Left toolbar: which terra-draw mode is active, then the selected\n item's own options. */}\n <Stack\n gap={4}\n p={6}\n className={TOOLBAR_CLASS}\n style={{\n position: \"absolute\", top: toolbarTop, left: 12, zIndex: 3, borderRadius: 8,\n background: dark ? \"rgba(20,20,20,0.75)\" : \"rgba(255,255,255,0.85)\",\n }}\n >\n {/* Point/Line/Polygon/Rectangle -- the terra-draw creation tools,\n TOOLBAR's own order minus its trailing \"select\" entry, which\n renders last below. */}\n {TOOLBAR.filter((entry) => entry.mode !== \"select\").map(renderModeButton)}\n {/* Not a terra-draw mode (there's no drawing gesture for it, just\n the host's picker), so it never shows as \"active\" the way the\n others do -- but it's one more kind of thing to add, same as\n Point/Line/Rectangle, and more than one image is supported. */}\n {onAddImage && (\n <Button size=\"xs\" variant=\"default\" disabled={!ready} onClick={onAddImage}>\n {strings.image}\n </Button>\n )}\n {TOOLBAR.filter((entry) => entry.mode === \"select\").map(renderModeButton)}\n\n <Divider my={2} />\n <Text size=\"xs\" fw={600} c=\"dimmed\">{strings.editOptions}</Text>\n\n {/* Only a selected drawn shape (point/line/region) offers this --\n hidden, not just disabled, the rest of the time: a picker with\n nothing to recolor is more confusing left sitting there than\n gone. */}\n {selectedFeature && (\n <ColorInput\n size=\"xs\"\n value={color}\n onChange={(next) => {\n setColor(next);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { color: next });\n }}\n swatches={COLOR_SWATCHES}\n disabled={!ready}\n popoverProps={{ withinPortal: true, zIndex: 1000 }}\n />\n )}\n {/* A point's `name` places a text label on the map -- a label is\n always its own point. A region's `name` is purely descriptive,\n the same as an image overlay's own. */}\n {(selectedIsPoint || selectedIsRegion) && (\n <TextInput\n size=\"xs\"\n placeholder={selectedIsPoint ? strings.labelText : strings.regionName}\n value={labelText}\n onChange={(e) => {\n setLabelText(e.currentTarget.value);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { name: e.currentTarget.value });\n }}\n disabled={!ready}\n />\n )}\n {/* Only a selected region (polygon/rectangle) offers this, same\n reasoning as the color picker above. */}\n {selectedIsRegion && (\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\">{strings.fillOpacity}</Text>\n <Slider\n size=\"xs\"\n min={0.1}\n max={1}\n step={0.05}\n label={(v) => `${Math.round(v * 100)}%`}\n value={opacity}\n onChange={(v) => {\n setOpacity(v);\n const draw = drawRef.current;\n if (draw && selectedId) draw.updateFeatureProperties(selectedId, { opacity: v });\n }}\n disabled={!ready}\n />\n </Stack>\n )}\n {/* Only a selected image overlay offers this -- purely shows or\n hides the 4 corner-drag handles (see setCornerHandlesVisible's\n own doc comment). */}\n {selectedOverlayId && (\n <SegmentedControl\n size=\"xs\"\n value={showCornerHandles ? \"transform\" : \"scale\"}\n onChange={(value) => setCornerHandlesVisible(selectedOverlayId, value === \"transform\")}\n disabled={!ready}\n data={[\n { label: strings.scale, value: \"scale\" },\n { label: strings.transform, value: \"transform\" },\n ]}\n />\n )}\n {/* The selected image overlay's own name/opacity/order. Opacity\n applies live (see updateSelectedOverlay). */}\n {selectedOverlay && (\n <>\n {overlayNames && (\n <TextInput\n size=\"xs\"\n placeholder={strings.overlayName}\n value={selectedOverlay.name ?? \"\"}\n onChange={(e) => updateSelectedOverlay({ name: e.currentTarget.value })}\n disabled={!ready}\n />\n )}\n <Stack gap={2}>\n <Text size=\"xs\" c=\"dimmed\">{strings.opacity}</Text>\n <Slider\n size=\"xs\"\n min={0.1}\n max={1}\n step={0.05}\n label={(v) => `${Math.round(v * 100)}%`}\n value={selectedOverlay.opacity ?? 1}\n onChange={(v) => updateSelectedOverlay({ opacity: v })}\n disabled={!ready}\n />\n </Stack>\n <NumberInput\n size=\"xs\"\n label={strings.stackingOrder}\n hideControls={false}\n value={selectedOverlay.order ?? 0}\n onChange={(v) => updateSelectedOverlay({ order: Number(v) || 0 })}\n disabled={!ready}\n />\n {renderOverlayOptions?.(selectedOverlay.image)}\n </>\n )}\n </Stack>\n\n {!ready && (\n <Group justify=\"center\" align=\"center\" style={{ position: \"absolute\", inset: 0, zIndex: 2 }}>\n <Loader size=\"sm\" />\n </Group>\n )}\n\n {lockedCount > 0 && !lockedNoticeDismissed && (\n <Alert\n color=\"yellow\"\n title={lockedCount === 1 ? strings.lockedOne : strings.lockedMany(lockedCount)}\n withCloseButton\n onClose={() => setLockedNoticeDismissed(true)}\n style={{ position: \"absolute\", bottom: 12, right: 12, zIndex: 3, maxWidth: 360 }}\n >\n {strings.lockedExplain}\n </Alert>\n )}\n </Box>\n );\n});\n\n/** How to use the map editor, for the host to show where it likes (Gramps\n * Connect: an info button's modal). */\nexport function MapEditorHelp({ strings: stringOverrides, images = true }: { strings?: Partial<MapEditorStrings>; images?: boolean }) {\n const strings = { ...mapEditorStringsFor(...browserLanguages()), ...stringOverrides };\n return (\n <Stack gap=\"md\">\n <Text size=\"sm\" fw={600}>{strings.helpDrawing}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpPoint}</List.Item>\n <List.Item>\n {strings.helpLine}{\" \"}\n <Kbd>Enter</Kbd> {strings.helpEnterFinishes} <Kbd>Esc</Kbd> {strings.helpEscCancels}\n </List.Item>\n <List.Item>{strings.helpRectangle}</List.Item>\n {images && (\n <List.Item>{strings.helpImage} <Text span fw={600}>{strings.helpImages}</Text>{\" \"}\n {strings.helpBelow}\n </List.Item>\n )}\n </List>\n <Text size=\"sm\" fw={600}>{strings.helpEditing}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpSelect}</List.Item>\n <List.Item>{strings.helpVertex}</List.Item>\n <List.Item>{strings.helpColor}</List.Item>\n <List.Item>\n {strings.helpDelete} <Kbd>Delete</Kbd> {strings.helpOr} <Kbd>Backspace</Kbd>.\n </List.Item>\n <List.Item>\n {strings.helpRotate} <Kbd>R</Kbd>{\" \"}\n {strings.helpRotateHandle}\n </List.Item>\n </List>\n {images && (\n <>\n <Text size=\"sm\" fw={600}>{strings.helpImages}</Text>\n <List spacing={4} size=\"sm\">\n <List.Item>{strings.helpImageMove}</List.Item>\n <List.Item>{strings.helpImageResize}</List.Item>\n <List.Item>{strings.helpImageRotate}</List.Item>\n <List.Item>{strings.helpImageTransform}</List.Item>\n <List.Item>{strings.helpImageRemove}</List.Item>\n </List>\n </>\n )}\n </Stack>\n );\n}\n", "import type { EditorStrings } from \"../strings\";\nimport type { MapEditorStrings } from \"../mapEditorStrings\";\n\nexport const editor: EditorStrings = {\n story: \"Geschichte\",\n storySettings: \"Titel, Sprache und Karte\",\n title: \"Titel\",\n language: \"Sprache\",\n languageHint: \"Die Sprache, in der die Geschichte geschrieben ist, z. B. en, de oder fr-CA. Daten werden in ihr gelesen.\",\n map: \"Karte\",\n mapHint: \"Wie die Karte beim Abspielen der Geschichte beginnt. Leser k\u00F6nnen sie trotzdem \u00E4ndern.\",\n mapStandard: \"Heutige Karte\",\n mapHistorical: \"Historische Karten zum Jahr jeder Folie\",\n mapAuto: \"Wahl des Betrachters\",\n mapNone: \"Keine Karte\",\n slides: \"Folien\",\n untitledSlide: \"Folie ohne Titel\",\n addSlide: \"Folie hinzuf\u00FCgen\",\n duplicateSlide: \"Duplizieren\",\n deleteSlide: \"L\u00F6schen\",\n moveUp: \"Nach oben\",\n moveDown: \"Nach unten\",\n slideTitle: \"Titel\",\n text: \"Text\",\n bold: \"Fett\",\n italic: \"Kursiv\",\n date: \"Datum\",\n dateHint: \"So, wie Leser es sehen sollen, z. B. um 1850, 3. Mai 1850, zwischen 1850 und 1860.\",\n preciseDate: \"Genaues Datum (EDTF)\",\n preciseDateHint: \"Setzt die Folie auf die Zeitleiste und w\u00E4hlt die historischen Karten.\",\n preciseDateFollows: \"Aus dem geschriebenen Datum ermittelt.\",\n preciseDateNotUnderstood: \"Kein Datum, das die Zeitleiste verwenden kann.\",\n matchDateAsWritten: \"Aus dem Datum ermitteln\",\n noPreciseDate: \"Keines: Diese Folie bleibt au\u00DFerhalb der Zeitleiste.\",\n place: \"Ort\",\n placeName: \"Name\",\n removePlace: \"Ort entfernen\",\n findPlace: \"Auf Wikidata suchen\",\n findPlaceHint: \"Sucht den Namen auf Wikidata, um die Stecknadel dorthin zu setzen. Nur der Name wird gesendet, und nur, wenn Sie es w\u00FCnschen.\",\n findPlaceNone: \"Wikidata kennt keinen Ort mit diesem Namen.\",\n findPlaceFailed: \"Wikidata war nicht erreichbar.\",\n findPlaceNoPoint: (name) => `Wikidata hat keine Kartenposition f\u00FCr ${name}.`,\n coordinates: \"Breite, L\u00E4nge\",\n coordinatesHint: \"z. B. 47.3769, 8.5417\",\n coordinatesInvalid: \"Zwei Zahlen: Breite (-90 bis 90), dann L\u00E4nge (-180 bis 180).\",\n placeMap: \"Karte: klicken, um die Stecknadel zu setzen\",\n placeMapHint: \"Klicken Sie auf die Karte, um die Stecknadel dorthin zu setzen, oder ziehen Sie die Stecknadel.\",\n placeShape: \"eine Form\",\n placeOverlays: (count) => (count === 1 ? \"eine Karten\u00FCberlagerung\" : `${count} Karten\u00FCberlagerungen`),\n placeKeeps: (what) => `Dieser Ort hat au\u00DFerdem ${what}.`,\n editMap: \"Karte bearbeiten\",\n editMapHint: \"Formen unter der Stecknadel (eine Pfarrei, eine Route) und dar\u00FCbergelegte Scans alter Karten.\",\n mapHelpImage: \"Bild: F\u00FCgen Sie eine Bilddatei hinzu, etwa den Scan einer alten Karte \u2013 siehe\",\n mapDialogTitle: (placeName) => (placeName ? `Karte: ${placeName}` : \"Karte\"),\n mapHelp: \"So benutzen Sie diesen Editor\",\n importShapes: \"Formen importieren\",\n importShapesHint: \"F\u00FCgt die Punkte, Linien und Fl\u00E4chen einer KML-, GPX- oder GeoJSON-Datei zu dieser Karte hinzu.\",\n importFailed: (fileName) => `${fileName} konnte nicht als KML-, GPX- oder GeoJSON-Datei gelesen werden.`,\n importNothing: (fileName) => `${fileName} enth\u00E4lt keine Formen.`,\n overlayAlready: \"Dieses Bild ist bereits auf dieser Karte.\",\n overlayDate: \"Jahre, die sie zeigt\",\n overlayDateHint: \"z. B. 1850, oder 1850 bis 1880. Mit historischen Karten ist sie auf Folien au\u00DFerhalb dieser Jahre ausgeblendet.\",\n cancel: \"Abbrechen\",\n done: \"Fertig\",\n photos: \"Fotos\",\n photosHint: \"F\u00FCgen Sie ein Foto hinzu, ziehen Sie es hierher oder f\u00FCgen Sie es ein. Es wird f\u00FCr den Bildschirm verkleinert, und versteckte Angaben wie Kamera und Standort werden weggelassen.\",\n addPhoto: \"Foto hinzuf\u00FCgen\",\n replacePhoto: \"Ersetzen\",\n movePhotoUp: \"Foto nach oben\",\n movePhotoDown: \"Foto nach unten\",\n removePhoto: \"Entfernen\",\n caption: \"Bildunterschrift\",\n credit: \"Bildnachweis\",\n creditHint: \"Wer es aufgenommen hat oder woher es stammt\",\n description: \"Beschreibung\",\n descriptionHint: \"Was das Foto zeigt, f\u00FCr alle, die es nicht sehen k\u00F6nnen.\",\n photoFailed: (name) => `${name} konnte nicht verwendet werden: Dieser Browser kann es nicht als Bild lesen.`,\n undo: \"R\u00FCckg\u00E4ngig\",\n redo: \"Wiederholen\",\n present: \"Vorf\u00FChren\",\n preview: \"Vorschau\",\n problems: (count) => (count === 1 ? \"1 Problem vor dem Speichern beheben\" : `${count} Probleme vor dem Speichern beheben`),\n openingSlide: \"Er\u00F6ffnungsfolie\",\n};\n\nexport const mapEditor: MapEditorStrings = {\n point: \"Punkt\",\n line: \"Linie\",\n polygon: \"Polygon\",\n rectangle: \"Rechteck\",\n select: \"Ausw\u00E4hlen\",\n image: \"Bild\",\n editOptions: \"Bearbeitungsoptionen\",\n labelText: \"Beschriftung\",\n regionName: \"Name des Gebiets (optional)\",\n fillOpacity: \"Deckkraft der F\u00FCllung\",\n scale: \"Skalieren\",\n transform: \"Verzerren\",\n overlayName: \"Name der \u00DCberlagerung (optional)\",\n opacity: \"Deckkraft\",\n stackingOrder: \"Stapelreihenfolge\",\n removeImage: \"Dieses Bild entfernen\",\n resizeImage: \"Ziehen, um die Gr\u00F6\u00DFe zu \u00E4ndern (beh\u00E4lt die genaue Form, verzerrt oder nicht)\",\n rotateImage: \"Ziehen, um zu drehen\",\n warpCorner: \"Ziehen, um diese Ecke zu verzerren\",\n basemapFailed: \"Die Grundkarte konnte nicht geladen werden.\",\n imageFailed: \"Das Bild konnte nicht geladen werden.\",\n lockedOne: \"1 Form kann hier nicht bearbeitet werden\",\n lockedMany: (count) => `${count} Formen k\u00F6nnen hier nicht bearbeitet werden`,\n lockedExplain: \"Zum Beispiel ein Gebiet mit einem Loch oder eines, dessen Umriss sich selbst kreuzt. Es wird gestrichelt gezeichnet und genau so gespeichert, wie es war.\",\n helpTitle: \"So benutzen Sie diesen Editor\",\n helpDrawing: \"Zeichnen\",\n helpPoint: \"Punkt: einmal klicken, um ihn zu setzen.\",\n helpLine: \"Linie, Polygon: klicken, um jeden Punkt zu setzen, dann erneut auf die Markierung des ersten Punktes klicken, \"\n + \"um abzuschlie\u00DFen \u2013 sie sieht anders aus, sobald es genug Punkte gibt, um die Form zu schlie\u00DFen. Auch\",\n helpEnterFinishes: \"schlie\u00DFt sie ab;\",\n helpEscCancels: \"bricht sie ab.\",\n helpRectangle: \"Rechteck: von einer Ecke zur gegen\u00FCberliegenden Ecke klicken und ziehen.\",\n helpImage: \"Bild: ein Medienobjekt zum \u00DCberlagern w\u00E4hlen \u2013 siehe\",\n helpImages: \"Bilder\",\n helpBelow: \"unten.\",\n helpEditing: \"Eine Form bearbeiten\",\n helpSelect: \"Ausw\u00E4hlen: auf eine Form klicken, um sie auszuw\u00E4hlen, dann sie oder einen ihrer Griffe ziehen.\",\n helpVertex: \"Einen Eckpunkt ziehen, um ihn zu verschieben. F\u00FCr einen neuen Punkt auf einer Linie, einem Polygon oder Rechteck \"\n + \"die kleine Mittelpunktmarkierung zwischen zwei Eckpunkten nach au\u00DFen ziehen.\",\n helpColor: \"Das Farbfeld legt die Farbe der n\u00E4chsten Form fest \u2013 oder \u00E4ndert, wenn eine Form ausgew\u00E4hlt ist, deren Farbe.\",\n helpDelete: \"Eine ausgew\u00E4hlte Form oder ein Bild l\u00F6schen mit\",\n helpOr: \"oder\",\n helpRotate: \"Ein ausgew\u00E4hltes Polygon, Rechteck oder eine Linie drehen:\",\n helpRotateHandle: \"gedr\u00FCckt halten und dabei einen ihrer Griffe ziehen.\",\n helpImageMove: \"Irgendwo auf ein Bild klicken und ziehen, um es zu verschieben.\",\n helpImageResize: \"Seinen \u2198-Griff ziehen, um die Gr\u00F6\u00DFe zu \u00E4ndern \u2013 es w\u00E4chst oder schrumpft um seine eigene Mitte \"\n + \"und beh\u00E4lt seine genaue Form (auch bei einem verzerrten Bild).\",\n helpImageRotate: \"Seinen \u21BB-Griff ziehen, um es zu drehen \u2013 praktisch, um eine gescannte alte Karte auszurichten.\",\n helpImageTransform: \"Auf \u201EVerzerren\u201C umschalten, um zus\u00E4tzlich 4 Eckgriffe zu zeigen, die sich einzeln ziehen lassen \"\n + \"(Entzerrung) \u2013 f\u00FCr eine gescannte Karte ohne einheitlichen Ma\u00DFstab oder einheitliche Ausrichtung. \"\n + \"Zur\u00FCck auf \u201ESkalieren\u201C blendet diese 4 Griffe nur wieder aus; Verschieben, Gr\u00F6\u00DFe \u00E4ndern und Drehen \"\n + \"wirken in beiden F\u00E4llen auf die genaue aktuelle Form des Bildes.\",\n helpImageRemove: \"Auf seinen \u00D7-Griff klicken, um es zu entfernen.\",\n};\n", "import type { EditorStrings } from \"../strings\";\nimport type { MapEditorStrings } from \"../mapEditorStrings\";\n\nexport const editor: EditorStrings = {\n story: \"Historia\",\n storySettings: \"T\u00EDtulo, idioma y mapa\",\n title: \"T\u00EDtulo\",\n language: \"Idioma\",\n languageHint: \"El idioma en que est\u00E1 escrita la historia, p. ej. en, de o fr-CA. Las fechas se leen en \u00E9l.\",\n map: \"Mapa\",\n mapHint: \"C\u00F3mo empieza el mapa al reproducir la historia. Los lectores a\u00FAn pueden cambiarlo.\",\n mapStandard: \"Mapa actual\",\n mapHistorical: \"Mapas hist\u00F3ricos del a\u00F1o de cada diapositiva\",\n mapAuto: \"A elecci\u00F3n del lector\",\n mapNone: \"Sin mapa\",\n slides: \"Diapositivas\",\n untitledSlide: \"Diapositiva sin t\u00EDtulo\",\n addSlide: \"A\u00F1adir diapositiva\",\n duplicateSlide: \"Duplicar\",\n deleteSlide: \"Eliminar\",\n moveUp: \"Subir\",\n moveDown: \"Bajar\",\n slideTitle: \"T\u00EDtulo\",\n text: \"Texto\",\n bold: \"Negrita\",\n italic: \"Cursiva\",\n date: \"Fecha\",\n dateHint: \"Como deben verla los lectores, p. ej. hacia 1850, 3 de mayo de 1850, entre 1850 y 1860.\",\n preciseDate: \"Fecha precisa (EDTF)\",\n preciseDateHint: \"Sit\u00FAa la diapositiva en la l\u00EDnea de tiempo y elige los mapas hist\u00F3ricos.\",\n preciseDateFollows: \"Deducida de la fecha tal como est\u00E1 escrita.\",\n preciseDateNotUnderstood: \"No es una fecha que la l\u00EDnea de tiempo pueda usar.\",\n matchDateAsWritten: \"Deducirla de la fecha\",\n noPreciseDate: \"Ninguna: esta diapositiva queda fuera de la l\u00EDnea de tiempo.\",\n place: \"Lugar\",\n placeName: \"Nombre\",\n removePlace: \"Quitar el lugar\",\n findPlace: \"Buscar en Wikidata\",\n findPlaceHint: \"Busca el nombre en Wikidata para poner all\u00ED el marcador. Solo se env\u00EDa el nombre, y solo cuando usted lo pide.\",\n findPlaceNone: \"Wikidata no tiene ning\u00FAn lugar con ese nombre.\",\n findPlaceFailed: \"No se pudo conectar con Wikidata.\",\n findPlaceNoPoint: (name) => `Wikidata no tiene una posici\u00F3n en el mapa para ${name}.`,\n coordinates: \"Latitud, longitud\",\n coordinatesHint: \"p. ej. 47.3769, 8.5417\",\n coordinatesInvalid: \"Dos n\u00FAmeros: la latitud (de -90 a 90) y luego la longitud (de -180 a 180).\",\n placeMap: \"Mapa: haga clic para poner el marcador\",\n placeMapHint: \"Haga clic en el mapa para poner all\u00ED el marcador, o arrastre el marcador.\",\n placeShape: \"una forma\",\n placeOverlays: (count) => (count === 1 ? \"una superposici\u00F3n de mapa\" : `${count} superposiciones de mapa`),\n placeKeeps: (what) => `Este lugar tambi\u00E9n tiene ${what}.`,\n editMap: \"Editar el mapa\",\n editMapHint: \"Formas bajo el marcador (una parroquia, una ruta) y escaneos de mapas antiguos superpuestos.\",\n mapHelpImage: \"Imagen: a\u00F1ada un archivo de imagen, como el escaneo de un mapa antiguo; consulte\",\n mapDialogTitle: (placeName) => (placeName ? `Mapa: ${placeName}` : \"Mapa\"),\n mapHelp: \"C\u00F3mo usar este editor\",\n importShapes: \"Importar formas\",\n importShapesHint: \"A\u00F1ade a este mapa los puntos, l\u00EDneas y \u00E1reas de un archivo KML, GPX o GeoJSON.\",\n importFailed: (fileName) => `No se pudo leer ${fileName} como archivo KML, GPX o GeoJSON.`,\n importNothing: (fileName) => `${fileName} no contiene formas.`,\n overlayAlready: \"Esa imagen ya est\u00E1 en este mapa.\",\n overlayDate: \"A\u00F1os que muestra\",\n overlayDateHint: \"p. ej. 1850, o de 1850 a 1880. Con mapas hist\u00F3ricos, se oculta en las diapositivas fuera de esos a\u00F1os.\",\n cancel: \"Cancelar\",\n done: \"Listo\",\n photos: \"Fotos\",\n photosHint: \"A\u00F1ada, suelte o pegue una foto. Se reduce para la pantalla y se omiten datos ocultos como la c\u00E1mara y la ubicaci\u00F3n.\",\n addPhoto: \"A\u00F1adir foto\",\n replacePhoto: \"Reemplazar\",\n movePhotoUp: \"Subir la foto\",\n movePhotoDown: \"Bajar la foto\",\n removePhoto: \"Quitar\",\n caption: \"Pie de foto\",\n credit: \"Cr\u00E9ditos\",\n creditHint: \"Qui\u00E9n la tom\u00F3 o de d\u00F3nde procede\",\n description: \"Descripci\u00F3n\",\n descriptionHint: \"Lo que muestra la foto, para quien no pueda verla.\",\n photoFailed: (name) => `No se pudo usar ${name}: este navegador no puede leerlo como imagen.`,\n undo: \"Deshacer\",\n redo: \"Rehacer\",\n present: \"Presentar\",\n preview: \"Vista previa\",\n problems: (count) => (count === 1 ? \"1 problema que corregir antes de guardar\" : `${count} problemas que corregir antes de guardar`),\n openingSlide: \"Diapositiva inicial\",\n};\n\nexport const mapEditor: MapEditorStrings = {\n point: \"Punto\",\n line: \"L\u00EDnea\",\n polygon: \"Pol\u00EDgono\",\n rectangle: \"Rect\u00E1ngulo\",\n select: \"Seleccionar\",\n image: \"Imagen\",\n editOptions: \"Opciones de edici\u00F3n\",\n labelText: \"Texto de la etiqueta\",\n regionName: \"Nombre de la regi\u00F3n (opcional)\",\n fillOpacity: \"Opacidad del relleno\",\n scale: \"Escalar\",\n transform: \"Deformar\",\n overlayName: \"Nombre de la superposici\u00F3n (opcional)\",\n opacity: \"Opacidad\",\n stackingOrder: \"Orden de apilamiento\",\n removeImage: \"Quitar esta imagen\",\n resizeImage: \"Arrastre para cambiar el tama\u00F1o (mantiene su forma exacta, deformada o no)\",\n rotateImage: \"Arrastre para girar\",\n warpCorner: \"Arrastre para deformar esta esquina\",\n basemapFailed: \"No se pudo cargar el mapa base.\",\n imageFailed: \"No se pudo cargar la imagen.\",\n lockedOne: \"1 forma no se puede editar aqu\u00ED\",\n lockedMany: (count) => `${count} formas no se pueden editar aqu\u00ED`,\n lockedExplain: \"Por ejemplo, una regi\u00F3n con un hueco, o una cuyo contorno se cruza a s\u00ED mismo. Se dibuja con trazo discontinuo y se guarda exactamente como estaba.\",\n helpTitle: \"C\u00F3mo usar este editor\",\n helpDrawing: \"Dibujar\",\n helpPoint: \"Punto: haga clic una vez para colocarlo.\",\n helpLine: \"L\u00EDnea, Pol\u00EDgono: haga clic para colocar cada punto y luego vuelva a hacer clic en el marcador del primer punto \"\n + \"para terminar; cambia de aspecto cuando hay puntos suficientes para cerrar la forma. Pulsar\",\n helpEnterFinishes: \"tambi\u00E9n la termina;\",\n helpEscCancels: \"la cancela.\",\n helpRectangle: \"Rect\u00E1ngulo: haga clic y arrastre de una esquina a la opuesta.\",\n helpImage: \"Imagen: elija un objeto multimedia para superponer; consulte\",\n helpImages: \"Im\u00E1genes\",\n helpBelow: \"m\u00E1s abajo.\",\n helpEditing: \"Editar una forma\",\n helpSelect: \"Seleccionar: haga clic en una forma para seleccionarla y luego arr\u00E1strela a ella o a uno de sus tiradores.\",\n helpVertex: \"Arrastre un v\u00E9rtice para moverlo. Para a\u00F1adir un punto nuevo a una L\u00EDnea, Pol\u00EDgono o Rect\u00E1ngulo, arrastre hacia fuera \"\n + \"el peque\u00F1o marcador del punto medio entre dos v\u00E9rtices.\",\n helpColor: \"La muestra de color fija el color de la siguiente forma o, con una forma seleccionada, cambia su color.\",\n helpDelete: \"Elimine una forma o imagen seleccionada con\",\n helpOr: \"o\",\n helpRotate: \"Para girar un Pol\u00EDgono, Rect\u00E1ngulo o L\u00EDnea seleccionado, mantenga pulsada\",\n helpRotateHandle: \"mientras arrastra uno de sus tiradores.\",\n helpImageMove: \"Arrastre desde cualquier punto de una imagen para moverla.\",\n helpImageResize: \"Arrastre su tirador \u2198 para cambiar el tama\u00F1o: crece o se encoge desde su propio centro \"\n + \"y mantiene su forma exacta (tambi\u00E9n en una imagen deformada).\",\n helpImageRotate: \"Arrastre su tirador \u21BB para girarla: \u00FAtil para alinear un mapa antiguo escaneado.\",\n helpImageTransform: \"Cambie a \u00ABDeformar\u00BB para mostrar adem\u00E1s 4 tiradores de esquina que se arrastran por separado \"\n + \"(georreferenciaci\u00F3n el\u00E1stica): para un mapa escaneado que no tiene una escala u orientaci\u00F3n uniforme. \"\n + \"Volver a \u00ABEscalar\u00BB solo oculta de nuevo esos 4 tiradores; mover, cambiar el tama\u00F1o y girar \"\n + \"siguen funcionando sobre la forma actual exacta de la imagen en ambos casos.\",\n helpImageRemove: \"Haga clic en su tirador \u00D7 para quitarla.\",\n};\n", "import type { EditorStrings } from \"../strings\";\nimport type { MapEditorStrings } from \"../mapEditorStrings\";\n\nexport const editor: EditorStrings = {\n story: \"Histoire\",\n storySettings: \"Titre, langue et carte\",\n title: \"Titre\",\n language: \"Langue\",\n languageHint: \"La langue dans laquelle l\u2019histoire est \u00E9crite, p. ex. en, de ou fr-CA. Les dates sont lues dans cette langue.\",\n map: \"Carte\",\n mapHint: \"Comment la carte commence quand l\u2019histoire est lue. Les lecteurs peuvent toujours la changer.\",\n mapStandard: \"Carte actuelle\",\n mapHistorical: \"Cartes historiques de l\u2019ann\u00E9e de chaque diapositive\",\n mapAuto: \"Au choix du lecteur\",\n mapNone: \"Pas de carte\",\n slides: \"Diapositives\",\n untitledSlide: \"Diapositive sans titre\",\n addSlide: \"Ajouter une diapositive\",\n duplicateSlide: \"Dupliquer\",\n deleteSlide: \"Supprimer\",\n moveUp: \"Monter\",\n moveDown: \"Descendre\",\n slideTitle: \"Titre\",\n text: \"Texte\",\n bold: \"Gras\",\n italic: \"Italique\",\n date: \"Date\",\n dateHint: \"Telle que les lecteurs doivent la voir, p. ex. vers 1850, 3 mai 1850, entre 1850 et 1860.\",\n preciseDate: \"Date pr\u00E9cise (EDTF)\",\n preciseDateHint: \"Place la diapositive sur la frise chronologique et choisit les cartes historiques.\",\n preciseDateFollows: \"D\u00E9duite de la date telle qu\u2019\u00E9crite.\",\n preciseDateNotUnderstood: \"Ce n\u2019est pas une date utilisable par la frise chronologique.\",\n matchDateAsWritten: \"La d\u00E9duire de la date\",\n noPreciseDate: \"Aucune : cette diapositive reste hors de la frise chronologique.\",\n place: \"Lieu\",\n placeName: \"Nom\",\n removePlace: \"Retirer le lieu\",\n findPlace: \"Chercher sur Wikidata\",\n findPlaceHint: \"Cherche le nom sur Wikidata pour y placer l\u2019\u00E9pingle. Seul le nom est envoy\u00E9, et seulement quand vous le demandez.\",\n findPlaceNone: \"Wikidata n\u2019a aucun lieu de ce nom.\",\n findPlaceFailed: \"Impossible de joindre Wikidata.\",\n findPlaceNoPoint: (name) => `Wikidata n\u2019a pas de position sur la carte pour ${name}.`,\n coordinates: \"Latitude, longitude\",\n coordinatesHint: \"p. ex. 47.3769, 8.5417\",\n coordinatesInvalid: \"Deux nombres : la latitude (-90 \u00E0 90), puis la longitude (-180 \u00E0 180).\",\n placeMap: \"Carte : cliquez pour placer l\u2019\u00E9pingle\",\n placeMapHint: \"Cliquez sur la carte pour y placer l\u2019\u00E9pingle, ou faites glisser l\u2019\u00E9pingle.\",\n placeShape: \"une forme\",\n placeOverlays: (count) => (count === 1 ? \"une superposition de carte\" : `${count} superpositions de carte`),\n placeKeeps: (what) => `Ce lieu a aussi ${what}.`,\n editMap: \"Modifier la carte\",\n editMapHint: \"Des formes sous l\u2019\u00E9pingle (une paroisse, un itin\u00E9raire) et des scans de cartes anciennes pos\u00E9s dessus.\",\n mapHelpImage: \"Image : ajoutez un fichier image, comme le scan d\u2019une carte ancienne \u2013 voir\",\n mapDialogTitle: (placeName) => (placeName ? `Carte : ${placeName}` : \"Carte\"),\n mapHelp: \"Comment utiliser cet \u00E9diteur\",\n importShapes: \"Importer des formes\",\n importShapesHint: \"Ajoute \u00E0 cette carte les points, lignes et zones d\u2019un fichier KML, GPX ou GeoJSON.\",\n importFailed: (fileName) => `Impossible de lire ${fileName} comme fichier KML, GPX ou GeoJSON.`,\n importNothing: (fileName) => `${fileName} ne contient aucune forme.`,\n overlayAlready: \"Cette image est d\u00E9j\u00E0 sur cette carte.\",\n overlayDate: \"Ann\u00E9es qu\u2019elle montre\",\n overlayDateHint: \"p. ex. 1850, ou 1850 \u00E0 1880. Avec les cartes historiques, elle est masqu\u00E9e sur les diapositives hors de ces ann\u00E9es.\",\n cancel: \"Annuler\",\n done: \"Termin\u00E9\",\n photos: \"Photos\",\n photosHint: \"Ajoutez, d\u00E9posez ou collez une photo. Elle est r\u00E9duite pour l\u2019\u00E9cran, et les d\u00E9tails cach\u00E9s comme l\u2019appareil et le lieu sont laiss\u00E9s de c\u00F4t\u00E9.\",\n addPhoto: \"Ajouter une photo\",\n replacePhoto: \"Remplacer\",\n movePhotoUp: \"Monter la photo\",\n movePhotoDown: \"Descendre la photo\",\n removePhoto: \"Retirer\",\n caption: \"L\u00E9gende\",\n credit: \"Cr\u00E9dit\",\n creditHint: \"Qui l\u2019a prise, ou d\u2019o\u00F9 elle vient\",\n description: \"Description\",\n descriptionHint: \"Ce que montre la photo, pour qui ne peut pas la voir.\",\n photoFailed: (name) => `Impossible d\u2019utiliser ${name} : ce navigateur ne peut pas le lire comme une image.`,\n undo: \"Annuler\",\n redo: \"R\u00E9tablir\",\n present: \"Pr\u00E9senter\",\n preview: \"Aper\u00E7u\",\n problems: (count) => (count === 1 ? \"1 probl\u00E8me \u00E0 corriger avant d\u2019enregistrer\" : `${count} probl\u00E8mes \u00E0 corriger avant d\u2019enregistrer`),\n openingSlide: \"Diapositive d\u2019ouverture\",\n};\n\nexport const mapEditor: MapEditorStrings = {\n point: \"Point\",\n line: \"Ligne\",\n polygon: \"Polygone\",\n rectangle: \"Rectangle\",\n select: \"S\u00E9lectionner\",\n image: \"Image\",\n editOptions: \"Options de modification\",\n labelText: \"Texte de l\u2019\u00E9tiquette\",\n regionName: \"Nom de la r\u00E9gion (facultatif)\",\n fillOpacity: \"Opacit\u00E9 du remplissage\",\n scale: \"\u00C9chelle\",\n transform: \"D\u00E9former\",\n overlayName: \"Nom de la superposition (facultatif)\",\n opacity: \"Opacit\u00E9\",\n stackingOrder: \"Ordre d\u2019empilement\",\n removeImage: \"Retirer cette image\",\n resizeImage: \"Faire glisser pour redimensionner (garde sa forme exacte, d\u00E9form\u00E9e ou non)\",\n rotateImage: \"Faire glisser pour pivoter\",\n warpCorner: \"Faire glisser pour d\u00E9former ce coin\",\n basemapFailed: \"Le fond de carte n\u2019a pas pu \u00EAtre charg\u00E9.\",\n imageFailed: \"L\u2019image n\u2019a pas pu \u00EAtre charg\u00E9e.\",\n lockedOne: \"1 forme ne peut pas \u00EAtre modifi\u00E9e ici\",\n lockedMany: (count) => `${count} formes ne peuvent pas \u00EAtre modifi\u00E9es ici`,\n lockedExplain: \"Par exemple, une r\u00E9gion perc\u00E9e d\u2019un trou, ou dont le contour se croise lui-m\u00EAme. Elle est dessin\u00E9e en pointill\u00E9s et enregistr\u00E9e exactement telle quelle.\",\n helpTitle: \"Comment utiliser cet \u00E9diteur\",\n helpDrawing: \"Dessiner\",\n helpPoint: \"Point : cliquez une fois pour le placer.\",\n helpLine: \"Ligne, Polygone : cliquez pour placer chaque point, puis cliquez de nouveau sur le rep\u00E8re du premier point \"\n + \"pour terminer \u2013 il change d\u2019aspect d\u00E8s qu\u2019il y a assez de points pour fermer la forme. Appuyer sur\",\n helpEnterFinishes: \"la termine aussi ;\",\n helpEscCancels: \"l\u2019annule.\",\n helpRectangle: \"Rectangle : cliquez et faites glisser d\u2019un coin au coin oppos\u00E9.\",\n helpImage: \"Image : choisissez un objet m\u00E9dia \u00E0 superposer \u2013 voir\",\n helpImages: \"Images\",\n helpBelow: \"ci-dessous.\",\n helpEditing: \"Modifier une forme\",\n helpSelect: \"S\u00E9lectionner : cliquez sur une forme pour la s\u00E9lectionner, puis faites-la glisser, elle ou l\u2019une de ses poign\u00E9es.\",\n helpVertex: \"Faites glisser un sommet pour le d\u00E9placer. Pour ajouter un point \u00E0 une Ligne, un Polygone ou un Rectangle, \"\n + \"faites glisser vers l\u2019ext\u00E9rieur le petit rep\u00E8re du milieu entre deux sommets.\",\n helpColor: \"La pastille de couleur fixe la couleur de la prochaine forme \u2013 ou, avec une forme s\u00E9lectionn\u00E9e, change sa couleur.\",\n helpDelete: \"Supprimez une forme ou une image s\u00E9lectionn\u00E9e avec\",\n helpOr: \"ou\",\n helpRotate: \"Pour faire pivoter un Polygone, un Rectangle ou une Ligne s\u00E9lectionn\u00E9, maintenez\",\n helpRotateHandle: \"en faisant glisser l\u2019une de ses poign\u00E9es.\",\n helpImageMove: \"Faites glisser n\u2019importe o\u00F9 sur une image pour la d\u00E9placer.\",\n helpImageResize: \"Faites glisser sa poign\u00E9e \u2198 pour la redimensionner \u2013 elle grandit ou r\u00E9tr\u00E9cit depuis son propre centre \"\n + \"en gardant sa forme exacte (de m\u00EAme pour une image d\u00E9form\u00E9e).\",\n helpImageRotate: \"Faites glisser sa poign\u00E9e \u21BB pour la faire pivoter \u2013 pratique pour aligner une carte ancienne scann\u00E9e.\",\n helpImageTransform: \"Passez \u00E0 \u00AB D\u00E9former \u00BB pour afficher aussi 4 poign\u00E9es d\u2019angle \u00E0 faire glisser s\u00E9par\u00E9ment \"\n + \"(calage \u00E9lastique) \u2013 pour une carte scann\u00E9e dont l\u2019\u00E9chelle ou l\u2019orientation n\u2019est pas uniforme. \"\n + \"Revenir \u00E0 \u00AB \u00C9chelle \u00BB masque simplement ces 4 poign\u00E9es ; d\u00E9placer, redimensionner et pivoter \"\n + \"agissent dans les deux cas sur la forme exacte actuelle de l\u2019image.\",\n helpImageRemove: \"Cliquez sur sa poign\u00E9e \u00D7 pour la retirer.\",\n};\n", "import type { EditorStrings } from \"../strings\";\nimport type { MapEditorStrings } from \"../mapEditorStrings\";\n\nexport const editor: EditorStrings = {\n story: \"Verhaal\",\n storySettings: \"Titel, taal en kaart\",\n title: \"Titel\",\n language: \"Taal\",\n languageHint: \"De taal waarin het verhaal is geschreven, bijv. en, de of fr-CA. Datums worden in die taal gelezen.\",\n map: \"Kaart\",\n mapHint: \"Hoe de kaart begint als het verhaal wordt afgespeeld. Lezers kunnen hem nog steeds wijzigen.\",\n mapStandard: \"Huidige kaart\",\n mapHistorical: \"Historische kaarten voor het jaar van elke dia\",\n mapAuto: \"Keuze van de lezer\",\n mapNone: \"Geen kaart\",\n slides: \"Dia's\",\n untitledSlide: \"Dia zonder titel\",\n addSlide: \"Dia toevoegen\",\n duplicateSlide: \"Dupliceren\",\n deleteSlide: \"Verwijderen\",\n moveUp: \"Omhoog\",\n moveDown: \"Omlaag\",\n slideTitle: \"Titel\",\n text: \"Tekst\",\n bold: \"Vet\",\n italic: \"Cursief\",\n date: \"Datum\",\n dateHint: \"Zoals lezers hem moeten zien, bijv. omstreeks 1850, 3 mei 1850, tussen 1850 en 1860.\",\n preciseDate: \"Precieze datum (EDTF)\",\n preciseDateHint: \"Plaatst de dia op de tijdlijn en kiest de historische kaarten.\",\n preciseDateFollows: \"Afgeleid uit de datum zoals geschreven.\",\n preciseDateNotUnderstood: \"Geen datum die de tijdlijn kan gebruiken.\",\n matchDateAsWritten: \"Afleiden uit de datum\",\n noPreciseDate: \"Geen: deze dia blijft buiten de tijdlijn.\",\n place: \"Plaats\",\n placeName: \"Naam\",\n removePlace: \"Plaats verwijderen\",\n findPlace: \"Zoeken op Wikidata\",\n findPlaceHint: \"Zoekt de naam op Wikidata om de speld daar te zetten. Alleen de naam wordt verstuurd, en alleen als u erom vraagt.\",\n findPlaceNone: \"Wikidata heeft geen plaats met die naam.\",\n findPlaceFailed: \"Wikidata was niet bereikbaar.\",\n findPlaceNoPoint: (name) => `Wikidata heeft geen kaartpositie voor ${name}.`,\n coordinates: \"Breedte, lengte\",\n coordinatesHint: \"bijv. 47.3769, 8.5417\",\n coordinatesInvalid: \"Twee getallen: breedte (-90 tot 90), dan lengte (-180 tot 180).\",\n placeMap: \"Kaart: klik om de speld te zetten\",\n placeMapHint: \"Klik op de kaart om de speld daar te zetten, of sleep de speld.\",\n placeShape: \"een vorm\",\n placeOverlays: (count) => (count === 1 ? \"een kaartoverlay\" : `${count} kaartoverlays`),\n placeKeeps: (what) => `Deze plaats heeft ook ${what}.`,\n editMap: \"Kaart bewerken\",\n editMapHint: \"Vormen onder de speld (een parochie, een route) en scans van oude kaarten erover gelegd.\",\n mapHelpImage: \"Afbeelding: voeg een afbeeldingsbestand toe, zoals een scan van een oude kaart \u2013 zie\",\n mapDialogTitle: (placeName) => (placeName ? `Kaart: ${placeName}` : \"Kaart\"),\n mapHelp: \"Zo gebruikt u deze editor\",\n importShapes: \"Vormen importeren\",\n importShapesHint: \"Voegt de punten, lijnen en gebieden uit een KML-, GPX- of GeoJSON-bestand aan deze kaart toe.\",\n importFailed: (fileName) => `${fileName} kon niet worden gelezen als KML-, GPX- of GeoJSON-bestand.`,\n importNothing: (fileName) => `${fileName} bevat geen vormen.`,\n overlayAlready: \"Die afbeelding staat al op deze kaart.\",\n overlayDate: \"Jaren die hij toont\",\n overlayDateHint: \"bijv. 1850, of 1850 tot 1880. Met historische kaarten is hij verborgen op dia's buiten die jaren.\",\n cancel: \"Annuleren\",\n done: \"Klaar\",\n photos: \"Foto's\",\n photosHint: \"Voeg een foto toe, sleep hem hierheen of plak hem. Hij wordt verkleind voor het scherm, en verborgen gegevens zoals camera en locatie worden weggelaten.\",\n addPhoto: \"Foto toevoegen\",\n replacePhoto: \"Vervangen\",\n movePhotoUp: \"Foto omhoog\",\n movePhotoDown: \"Foto omlaag\",\n removePhoto: \"Verwijderen\",\n caption: \"Bijschrift\",\n credit: \"Bron\",\n creditHint: \"Wie hem heeft gemaakt, of waar hij vandaan komt\",\n description: \"Beschrijving\",\n descriptionHint: \"Wat de foto laat zien, voor wie hem niet kan zien.\",\n photoFailed: (name) => `${name} kon niet worden gebruikt: deze browser kan het niet als afbeelding lezen.`,\n undo: \"Ongedaan maken\",\n redo: \"Opnieuw\",\n present: \"Presenteren\",\n preview: \"Voorbeeld\",\n problems: (count) => (count === 1 ? \"1 probleem op te lossen v\u00F3\u00F3r het opslaan\" : `${count} problemen op te lossen v\u00F3\u00F3r het opslaan`),\n openingSlide: \"Openingsdia\",\n};\n\nexport const mapEditor: MapEditorStrings = {\n point: \"Punt\",\n line: \"Lijn\",\n polygon: \"Veelhoek\",\n rectangle: \"Rechthoek\",\n select: \"Selecteren\",\n image: \"Afbeelding\",\n editOptions: \"Bewerkingsopties\",\n labelText: \"Labeltekst\",\n regionName: \"Naam van het gebied (optioneel)\",\n fillOpacity: \"Dekking van de vulling\",\n scale: \"Schalen\",\n transform: \"Vervormen\",\n overlayName: \"Naam van de overlay (optioneel)\",\n opacity: \"Dekking\",\n stackingOrder: \"Stapelvolgorde\",\n removeImage: \"Deze afbeelding verwijderen\",\n resizeImage: \"Sleep om de grootte te wijzigen (behoudt de exacte vorm, vervormd of niet)\",\n rotateImage: \"Sleep om te draaien\",\n warpCorner: \"Sleep om deze hoek te vervormen\",\n basemapFailed: \"De basiskaart kon niet worden geladen.\",\n imageFailed: \"De afbeelding kon niet worden geladen.\",\n lockedOne: \"1 vorm kan hier niet worden bewerkt\",\n lockedMany: (count) => `${count} vormen kunnen hier niet worden bewerkt`,\n lockedExplain: \"Bijvoorbeeld een gebied met een gat erin, of een gebied waarvan de omtrek zichzelf kruist. Het wordt gestippeld getekend en precies zo opgeslagen als het was.\",\n helpTitle: \"Zo gebruikt u deze editor\",\n helpDrawing: \"Tekenen\",\n helpPoint: \"Punt: klik \u00E9\u00E9n keer om het te plaatsen.\",\n helpLine: \"Lijn, Veelhoek: klik om elk punt te plaatsen en klik dan opnieuw op de markering van het eerste punt \"\n + \"om af te ronden \u2013 die ziet er anders uit zodra er genoeg punten zijn om de vorm te sluiten. Ook\",\n helpEnterFinishes: \"rondt hem af;\",\n helpEscCancels: \"breekt hem af.\",\n helpRectangle: \"Rechthoek: klik en sleep van de ene hoek naar de tegenoverliggende hoek.\",\n helpImage: \"Afbeelding: kies een mediaobject om over de kaart te leggen \u2013 zie\",\n helpImages: \"Afbeeldingen\",\n helpBelow: \"hieronder.\",\n helpEditing: \"Een vorm bewerken\",\n helpSelect: \"Selecteren: klik op een vorm om hem te selecteren en sleep dan de vorm of een van zijn grepen.\",\n helpVertex: \"Sleep een hoekpunt om het te verplaatsen. Voor een nieuw punt op een Lijn, Veelhoek of Rechthoek sleept u \"\n + \"de kleine middelpuntmarkering tussen twee hoekpunten naar buiten.\",\n helpColor: \"Het kleurvlak bepaalt de kleur van de volgende vorm \u2013 of wijzigt, met een vorm geselecteerd, diens kleur.\",\n helpDelete: \"Verwijder een geselecteerde vorm of afbeelding met\",\n helpOr: \"of\",\n helpRotate: \"Een geselecteerde Veelhoek, Rechthoek of Lijn draaien: houd\",\n helpRotateHandle: \"ingedrukt terwijl u een van de grepen sleept.\",\n helpImageMove: \"Sleep ergens op een afbeelding om hem te verplaatsen.\",\n helpImageResize: \"Sleep de \u2198-greep om de grootte te wijzigen \u2013 hij groeit of krimpt vanuit zijn eigen midden \"\n + \"en behoudt zijn exacte vorm (ook bij een vervormde afbeelding).\",\n helpImageRotate: \"Sleep de \u21BB-greep om hem te draaien \u2013 handig om een gescande oude kaart uit te lijnen.\",\n helpImageTransform: \"Schakel over naar \u2018Vervormen\u2019 om ook 4 hoekgrepen te tonen die u los kunt slepen \"\n + \"(rubber-sheeting) \u2013 voor een gescande kaart zonder gelijkmatige schaal of richting. \"\n + \"Terug naar \u2018Schalen\u2019 verbergt die 4 grepen gewoon weer; verplaatsen, grootte wijzigen en draaien \"\n + \"werken in beide gevallen op de exacte huidige vorm van de afbeelding.\",\n helpImageRemove: \"Klik op de \u00D7-greep om hem te verwijderen.\",\n};\n", "// The editors' words in the player's other languages (player/strings.ts),\n// one file each: the story editor's, and its map editor's.\nimport type { EditorStrings } from \"../strings\";\nimport type { MapEditorStrings } from \"../mapEditorStrings\";\nimport * as de from \"./de\";\nimport * as es from \"./es\";\nimport * as fr from \"./fr\";\nimport * as nl from \"./nl\";\n\nexport interface EditorTranslation {\n editor: EditorStrings;\n mapEditor: MapEditorStrings;\n}\n\nexport const TRANSLATIONS: Record<string, EditorTranslation> = { de, es, fr, nl };\n", "// The editor's own words, in English and the player's other languages\n// (translations/). The editor picks by the browser's languages; a host\n// with its own translations (Gramps Connect) passes StoryEditor's\n// `strings` instead.\nimport { TRANSLATIONS } from \"./translations\";\n\nexport interface EditorStrings {\n story: string;\n storySettings: string;\n title: string;\n language: string;\n languageHint: string;\n map: string;\n mapHint: string;\n mapStandard: string;\n mapHistorical: string;\n mapAuto: string;\n mapNone: string;\n slides: string;\n untitledSlide: string;\n addSlide: string;\n duplicateSlide: string;\n deleteSlide: string;\n moveUp: string;\n moveDown: string;\n slideTitle: string;\n text: string;\n bold: string;\n italic: string;\n date: string;\n dateHint: string;\n preciseDate: string;\n preciseDateHint: string;\n preciseDateFollows: string;\n preciseDateNotUnderstood: string;\n matchDateAsWritten: string;\n noPreciseDate: string;\n place: string;\n placeName: string;\n removePlace: string;\n findPlace: string;\n findPlaceHint: string;\n findPlaceNone: string;\n findPlaceFailed: string;\n findPlaceNoPoint: (name: string) => string;\n coordinates: string;\n coordinatesHint: string;\n coordinatesInvalid: string;\n placeMap: string;\n placeMapHint: string;\n placeShape: string;\n placeOverlays: (count: number) => string;\n placeKeeps: (what: string) => string;\n editMap: string;\n editMapHint: string;\n /** The map editor's help on adding an image, where images are files. */\n mapHelpImage: string;\n mapDialogTitle: (placeName: string | undefined) => string;\n mapHelp: string;\n importShapes: string;\n importShapesHint: string;\n importFailed: (fileName: string) => string;\n importNothing: (fileName: string) => string;\n overlayAlready: string;\n overlayDate: string;\n overlayDateHint: string;\n cancel: string;\n done: string;\n photos: string;\n photosHint: string;\n addPhoto: string;\n replacePhoto: string;\n movePhotoUp: string;\n movePhotoDown: string;\n removePhoto: string;\n caption: string;\n credit: string;\n creditHint: string;\n description: string;\n descriptionHint: string;\n photoFailed: (name: string) => string;\n undo: string;\n redo: string;\n present: string;\n preview: string;\n problems: (count: number) => string;\n openingSlide: string;\n}\n\nexport const EDITOR_ENGLISH: EditorStrings = {\n story: \"Story\",\n storySettings: \"Title, language and map\",\n title: \"Title\",\n language: \"Language\",\n languageHint: \"The language the story is written in, e.g. en, de or fr-CA. Dates are read in it.\",\n map: \"Map\",\n mapHint: \"How the map starts when the story plays. Readers can still change it.\",\n mapStandard: \"Today's map\",\n mapHistorical: \"Historical maps for each slide's year\",\n mapAuto: \"Viewer's choice\",\n mapNone: \"No map\",\n slides: \"Slides\",\n untitledSlide: \"Untitled slide\",\n addSlide: \"Add slide\",\n duplicateSlide: \"Duplicate\",\n deleteSlide: \"Delete\",\n moveUp: \"Move up\",\n moveDown: \"Move down\",\n slideTitle: \"Title\",\n text: \"Text\",\n bold: \"Bold\",\n italic: \"Italic\",\n date: \"Date\",\n dateHint: \"As readers should see it, e.g. about 1850, 3 May 1850, between 1850 and 1860.\",\n preciseDate: \"Precise date (EDTF)\",\n preciseDateHint: \"Places the slide on the timeline and picks historical maps.\",\n preciseDateFollows: \"Worked out from the date as written.\",\n preciseDateNotUnderstood: \"Not a date the timeline can use.\",\n matchDateAsWritten: \"Work it out from the date\",\n noPreciseDate: \"None: this slide stays off the timeline.\",\n place: \"Place\",\n placeName: \"Name\",\n removePlace: \"Remove place\",\n findPlace: \"Find on Wikidata\",\n findPlaceHint: \"Looks the name up on Wikidata, to put the pin there. The name is all that's sent, and only when you ask.\",\n findPlaceNone: \"Wikidata has no place by that name.\",\n findPlaceFailed: \"Couldn't reach Wikidata.\",\n findPlaceNoPoint: (name) => `Wikidata has no map position for ${name}.`,\n coordinates: \"Latitude, longitude\",\n coordinatesHint: \"e.g. 47.3769, 8.5417\",\n coordinatesInvalid: \"Two numbers: latitude (-90 to 90), then longitude (-180 to 180).\",\n placeMap: \"Map: click to put the pin\",\n placeMapHint: \"Click the map to put the pin there, or drag the pin.\",\n placeShape: \"a shape\",\n placeOverlays: (count) => (count === 1 ? \"a map overlay\" : `${count} map overlays`),\n placeKeeps: (what) => `This place also has ${what}.`,\n editMap: \"Edit map\",\n editMapHint: \"Shapes under the pin (a parish, a route) and scans of old maps laid over it.\",\n mapHelpImage: \"Image: add a picture file, such as a scan of an old map -- see\",\n mapDialogTitle: (placeName) => (placeName ? `Map: ${placeName}` : \"Map\"),\n mapHelp: \"How to use this editor\",\n importShapes: \"Import shapes\",\n importShapesHint: \"Adds the points, lines and areas in a KML, GPX or GeoJSON file to this map.\",\n importFailed: (fileName) => `Couldn't read ${fileName} as a KML, GPX or GeoJSON file.`,\n importNothing: (fileName) => `${fileName} has no shapes in it.`,\n overlayAlready: \"That image is already on this map.\",\n overlayDate: \"Years it shows\",\n overlayDateHint: \"e.g. 1850, or 1850 to 1880. With historical maps, it's hidden on slides outside them.\",\n cancel: \"Cancel\",\n done: \"Done\",\n photos: \"Photos\",\n photosHint: \"Add, drop or paste a photo. It's resized for the screen, and hidden details like camera and location are left out.\",\n addPhoto: \"Add photo\",\n replacePhoto: \"Replace\",\n movePhotoUp: \"Move photo up\",\n movePhotoDown: \"Move photo down\",\n removePhoto: \"Remove\",\n caption: \"Caption\",\n credit: \"Credit\",\n creditHint: \"Who took it, or where it's from\",\n description: \"Description\",\n descriptionHint: \"What the photo shows, for anyone who can't see it.\",\n photoFailed: (name) => `Couldn't use ${name}: this browser can't read it as an image.`,\n undo: \"Undo\",\n redo: \"Redo\",\n present: \"Present\",\n preview: \"Preview\",\n problems: (count) => (count === 1 ? \"1 problem to fix before saving\" : `${count} problems to fix before saving`),\n openingSlide: \"Opening slide\",\n};\n\n/** The browser's languages, most preferred first (none outside one). */\nexport function browserLanguages(): readonly string[] {\n if (typeof navigator === \"undefined\") return [];\n return navigator.languages?.length ? navigator.languages : [navigator.language];\n}\n\n/** The first of `languages` (BCP 47 tags, or Gramps' de_AT form) the\n * editors have words for, as its base code: \"de-CH\" is \"de\". English\n * counts, so \"en-US, de\" stays English. */\nexport function editorLanguage(languages: readonly (string | undefined)[]): string | undefined {\n for (const tag of languages) {\n const base = tag?.toLowerCase().split(/[-_]/)[0];\n if (base === \"en\" || (base && Object.prototype.hasOwnProperty.call(TRANSLATIONS, base))) return base;\n }\n return undefined;\n}\n\n/** The translations for the first of `languages` the editors have;\n * none for English. */\nexport function translationFor(languages: readonly (string | undefined)[]) {\n const lang = editorLanguage(languages);\n return lang && lang !== \"en\" ? TRANSLATIONS[lang] : undefined;\n}\n\n/** The editor's words in the first of `languages` it has; English when\n * none. */\nexport function editorStringsFor(...languages: (string | undefined)[]): EditorStrings {\n return translationFor(languages)?.editor ?? EDITOR_ENGLISH;\n}\n\n/** Languages the editors have words for, besides English. */\nexport const EDITOR_LANGUAGES = Object.keys(TRANSLATIONS);\n", "// The map editor's words, in English and the story editor's other\n// languages (translations/). Gramps Connect passes its own where it has\n// them (its t() is keyed by these same English texts).\nimport { translationFor } from \"./strings\";\n\nexport interface MapEditorStrings {\n point: string;\n line: string;\n polygon: string;\n rectangle: string;\n select: string;\n image: string;\n editOptions: string;\n labelText: string;\n regionName: string;\n fillOpacity: string;\n scale: string;\n transform: string;\n overlayName: string;\n opacity: string;\n stackingOrder: string;\n removeImage: string;\n resizeImage: string;\n rotateImage: string;\n warpCorner: string;\n basemapFailed: string;\n imageFailed: string;\n lockedOne: string;\n lockedMany: (count: number) => string;\n lockedExplain: string;\n // The help (MapEditorHelp), in the pieces it's put together from.\n helpTitle: string;\n helpDrawing: string;\n helpPoint: string;\n helpLine: string;\n helpEnterFinishes: string;\n helpEscCancels: string;\n helpRectangle: string;\n helpImage: string;\n helpImages: string;\n helpBelow: string;\n helpEditing: string;\n helpSelect: string;\n helpVertex: string;\n helpColor: string;\n helpDelete: string;\n helpOr: string;\n helpRotate: string;\n helpRotateHandle: string;\n helpImageMove: string;\n helpImageResize: string;\n helpImageRotate: string;\n helpImageTransform: string;\n helpImageRemove: string;\n}\n\nexport const MAP_EDITOR_ENGLISH: MapEditorStrings = {\n point: \"Point\",\n line: \"Line\",\n polygon: \"Polygon\",\n rectangle: \"Rectangle\",\n select: \"Select\",\n image: \"Image\",\n editOptions: \"Edit Options\",\n labelText: \"Label text\",\n regionName: \"Region name (optional)\",\n fillOpacity: \"Fill opacity\",\n scale: \"Scale\",\n transform: \"Transform\",\n overlayName: \"Overlay name (optional)\",\n opacity: \"Opacity\",\n stackingOrder: \"Stacking order\",\n removeImage: \"Remove this image\",\n resizeImage: \"Drag to resize (keeps its exact shape, warped or not)\",\n rotateImage: \"Drag to rotate\",\n warpCorner: \"Drag to warp this corner\",\n basemapFailed: \"The basemap could not be loaded.\",\n imageFailed: \"The image failed to load.\",\n lockedOne: \"1 shape can't be edited here\",\n lockedMany: (count) => `${count} shapes can't be edited here`,\n lockedExplain: \"For example, a region with a hole in it, or one whose outline crosses itself. It's drawn dashed, and saved exactly as it was.\",\n helpTitle: \"How to use this editor\",\n helpDrawing: \"Drawing\",\n helpPoint: \"Point: click once to place it.\",\n helpLine: \"Line, Polygon: click to place each point, then click that first point's own marker again to \"\n + \"finish -- it's styled differently once there's enough points to close the shape. Pressing\",\n helpEnterFinishes: \"finishes it too;\",\n helpEscCancels: \"cancels it.\",\n helpRectangle: \"Rectangle: click and drag from one corner to the opposite corner.\",\n helpImage: \"Image: pick a media object to overlay -- see\",\n helpImages: \"Images\",\n helpBelow: \"below.\",\n helpEditing: \"Editing a shape\",\n helpSelect: \"Select: click a shape to select it, then drag it or one of its handles.\",\n helpVertex: \"Drag a vertex to move it. To add a new point on a Line, Polygon, or Rectangle, drag the small \"\n + \"midpoint marker between two existing vertices outward.\",\n helpColor: \"The color swatch sets the next shape's color -- or, with a shape selected, changes its color.\",\n helpDelete: \"Delete a selected shape or image with\",\n helpOr: \"or\",\n helpRotate: \"Rotate a selected Polygon, Rectangle, or Line: hold\",\n helpRotateHandle: \"while dragging one of its handles.\",\n helpImageMove: \"Drag anywhere on an image to move it.\",\n helpImageResize: \"Drag its \u2198 handle to resize it -- grows or shrinks from its own center, \"\n + \"keeping its exact shape (works the same on a warped image, too).\",\n helpImageRotate: \"Drag its \u21BB handle to rotate it -- handy for aligning a scanned old map.\",\n helpImageTransform: \"Switch to \\\"Transform\\\" to also show 4 corner handles you can drag independently \"\n + \"(rubber-sheeting) -- for a scanned map that isn't printed at a uniform scale/orientation. \"\n + \"Switching back to \\\"Scale\\\" just hides those 4 handles again; move/resize/rotate keep \"\n + \"working on the image's exact current shape either way.\",\n helpImageRemove: \"Click its \u00D7 handle to remove it.\",\n};\n\n/** The map editor's words in the first of `languages` it has; English\n * when none. */\nexport function mapEditorStringsFor(...languages: (string | undefined)[]): MapEditorStrings {\n return translationFor(languages)?.mapEditor ?? MAP_EDITOR_ENGLISH;\n}\n", "// A slide's place as the map editor sees it, and back: the place's\n// `geometry` (a FeatureCollection, a Feature or a bare geometry) as\n// features, and its `overlays` as image overlays keyed by media. Whatever\n// the editor doesn't edit -- an overlay's date, fields this version\n// doesn't know, a FeatureCollection's own members -- is carried over from\n// the place as it was.\nimport type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport type { Overlay, Place, StoryDate } from \"../types\";\nimport type { MapEditorOverlay, MapEditorResult } from \"./MapEditor\";\nimport { patchPlace } from \"./model\";\n\n/** The features in a place's `geometry`, whichever form it takes. */\nexport function placeFeatures(place: Place | undefined): Feature[] {\n const geometry = place?.geometry as { type: string; features?: unknown[] } | undefined;\n if (!geometry) return [];\n if (geometry.type === \"FeatureCollection\") {\n return ((geometry.features ?? []) as Feature[]).filter((f) => f && f.geometry);\n }\n if (geometry.type === \"Feature\") return (geometry as unknown as Feature).geometry ? [geometry as unknown as Feature] : [];\n return [{ type: \"Feature\", properties: {}, geometry: geometry as unknown as Geometry }];\n}\n\n/** What the map editor opens with for a place. */\nexport function placeToEditor(place: Place | undefined): { features: Feature[]; overlays: MapEditorOverlay[] } {\n return {\n features: placeFeatures(place),\n overlays: (place?.overlays ?? []).map((o) => ({\n image: o.media, corners: o.corners,\n ...(o.opacity !== undefined ? { opacity: o.opacity } : {}),\n ...(o.order !== undefined ? { order: o.order } : {}),\n })),\n };\n}\n\n/** The place with what the map editor ended with. `dates` holds each\n * overlay's date by media key, as edited beside the editor. */\nexport function editorToPlace(\n place: Place | undefined, result: MapEditorResult, dates: Map<string, StoryDate | undefined>,\n): Place | undefined {\n const before = place?.geometry as (FeatureCollection & Record<string, unknown>) | undefined;\n const geometry = result.features.length === 0\n ? undefined\n // A FeatureCollection keeps its own other members; anything else\n // becomes one.\n : { ...(before?.type === \"FeatureCollection\" ? before : {}), type: \"FeatureCollection\", features: result.features };\n const previous = new Map((place?.overlays ?? []).map((o) => [o.media, o]));\n const overlays = result.overlays.map((o): Overlay => {\n const { opacity: _o, order: _r, date: _d, ...kept } = previous.get(o.image) ?? ({} as Partial<Overlay>);\n const date = dates.has(o.image) ? dates.get(o.image) : previous.get(o.image)?.date;\n return {\n ...kept,\n media: o.image,\n corners: o.corners,\n ...(o.opacity !== undefined && o.opacity !== 1 ? { opacity: o.opacity } : {}),\n ...(o.order !== undefined ? { order: Math.round(o.order) } : {}),\n ...(date ? { date } : {}),\n };\n });\n return patchPlace(place, {\n geometry: geometry as Place[\"geometry\"],\n overlays: overlays.length ? overlays : undefined,\n });\n}\n", "// Finding a place by name, for the place field's opt-in search: Wikidata's\n// own search, then the chosen item's coordinates (P625). Both endpoints\n// allow any origin and need no key. This is the only thing the editor\n// sends anywhere, and only when asked to: it sends the name typed.\n// (Gramps Connect's place lookup walks the same API further, up the\n// \"located in\" chain, to build a place hierarchy; a story place is just a\n// name and a point.)\n\nconst WIKIDATA_API = \"https://www.wikidata.org/w/api.php\";\nconst WIKIDATA_ENTITY_DATA = \"https://www.wikidata.org/wiki/Special:EntityData\";\n\nexport interface PlaceSearchResult {\n /** The Wikidata item, e.g. \"Q72\". */\n id: string;\n label: string;\n /** Usually names the region and country, which tells same-named places\n * apart. */\n description?: string;\n}\n\nexport interface PlaceSearch {\n search: (term: string, language: string | undefined, signal?: AbortSignal) => Promise<PlaceSearchResult[]>;\n /** The result's position, or null when it has none. */\n point: (result: PlaceSearchResult, signal?: AbortSignal) => Promise<{ lat: number; lon: number } | null>;\n}\n\n/** \"fr_CA\" or \"fr-CA\" -> \"fr-ca\", Wikidata's form. */\nfunction wikidataLanguage(language: string | undefined): string {\n return (language ?? \"\").trim().toLowerCase().replace(/_/g, \"-\") || \"en\";\n}\n\nexport async function searchWikidataPlaces(term: string, language?: string, signal?: AbortSignal): Promise<PlaceSearchResult[]> {\n const code = wikidataLanguage(language);\n const params = new URLSearchParams({\n action: \"wbsearchentities\", search: term, language: code, uselang: code, format: \"json\", limit: \"7\",\n origin: \"*\", // what makes an anonymous api.php GET answer cross-origin\n });\n const res = await fetch(`${WIKIDATA_API}?${params}`, { signal });\n if (!res.ok) throw new Error(`Wikidata search failed (${res.status})`);\n const data = (await res.json()) as { search?: { id: string; label?: string; description?: string }[] };\n return (data.search ?? []).map((hit) => ({\n id: hit.id,\n label: hit.label ?? hit.id,\n ...(hit.description ? { description: hit.description } : {}),\n }));\n}\n\nexport async function wikidataPoint(result: PlaceSearchResult, signal?: AbortSignal): Promise<{ lat: number; lon: number } | null> {\n const res = await fetch(`${WIKIDATA_ENTITY_DATA}/${encodeURIComponent(result.id)}.json`, { signal });\n if (!res.ok) throw new Error(`Wikidata fetch failed for ${result.id} (${res.status})`);\n const data = (await res.json()) as {\n entities?: Record<string, { claims?: Record<string, { mainsnak?: { datavalue?: { value?: unknown } } }[]> }>;\n };\n // A redirected item comes back under its new id: take whichever is there.\n const entity = data.entities?.[result.id] ?? Object.values(data.entities ?? {})[0];\n const value = entity?.claims?.P625?.[0]?.mainsnak?.datavalue?.value as { latitude?: number; longitude?: number } | undefined;\n if (typeof value?.latitude !== \"number\" || typeof value.longitude !== \"number\") return null;\n return { lat: value.latitude, lon: value.longitude };\n}\n\nexport const WIKIDATA_PLACE_SEARCH: PlaceSearch = { search: searchWikidataPlaces, point: wikidataPoint };\n", "// A list of slides to pick from and reorder by dragging -- generic over\n// what a slide is, so any story editor can use it with its own rows.\nimport { useState, type ReactNode } from \"react\";\nimport { Stack, UnstyledButton } from \"@mantine/core\";\n\nexport interface SlideListProps<T> {\n items: T[];\n selected: number;\n onSelect: (index: number) => void;\n /** Called when a row is dropped somewhere else. */\n onMove: (from: number, to: number) => void;\n getKey: (item: T, index: number) => string;\n renderItem: (item: T, index: number) => ReactNode;\n label?: string;\n}\n\nexport function SlideList<T>({ items, selected, onSelect, onMove, getKey, renderItem, label }: SlideListProps<T>) {\n const [dragging, setDragging] = useState<number | null>(null);\n const [over, setOver] = useState<number | null>(null);\n const end = () => { setDragging(null); setOver(null); };\n\n return (\n <Stack gap={4} role=\"listbox\" aria-label={label}>\n {items.map((item, i) => {\n const isSelected = i === selected;\n // A line on the side the row will land: below when moving down.\n const dropLine = over === i && dragging !== null && dragging !== i\n ? (dragging < i ? { borderBottom: \"2px solid var(--mantine-primary-color-filled)\" } : { borderTop: \"2px solid var(--mantine-primary-color-filled)\" })\n : {};\n return (\n <UnstyledButton\n key={getKey(item, i)}\n role=\"option\"\n aria-selected={isSelected}\n draggable\n onClick={() => onSelect(i)}\n onDragStart={(e) => { setDragging(i); e.dataTransfer.effectAllowed = \"move\"; e.dataTransfer.setData(\"text/plain\", String(i)); }}\n onDragOver={(e) => { if (dragging === null) return; e.preventDefault(); setOver(i); }}\n onDrop={(e) => { e.preventDefault(); if (dragging !== null && dragging !== i) onMove(dragging, i); end(); }}\n onDragEnd={end}\n style={{\n display: \"block\", width: \"100%\", padding: \"6px 8px\", borderRadius: 6,\n background: isSelected ? \"var(--mantine-primary-color-light)\" : undefined,\n opacity: dragging === i ? 0.5 : 1,\n ...dropLine,\n }}\n >\n {renderItem(item, i)}\n </UnstyledButton>\n );\n })}\n </Stack>\n );\n}\n", "// A plain Textarea plus Bold/Italic buttons that wrap the selection in the\n// story format's `**`/`*` markers -- the only formatting a slide's text has\n// (parseStoryText is the matching reader), so no rich-text editor.\nimport { useRef } from \"react\";\nimport { Button, Group, Stack, Text, Textarea } from \"@mantine/core\";\n\n/** Wraps the textarea's selection in `marker` (or unwraps it, if the\n * selection is already exactly `marker\u2026marker`); with nothing selected,\n * inserts an empty pair and leaves the cursor between them. */\nfunction applyMarker(el: HTMLTextAreaElement, marker: string, value: string, onChange: (v: string) => void) {\n const start = el.selectionStart ?? value.length;\n const end = el.selectionEnd ?? value.length;\n if (start === end) {\n onChange(value.slice(0, start) + marker + marker + value.slice(end));\n requestAnimationFrame(() => {\n el.focus();\n el.setSelectionRange(start + marker.length, start + marker.length);\n });\n return;\n }\n const selected = value.slice(start, end);\n const alreadyWrapped = selected.length > marker.length * 2 && selected.startsWith(marker) && selected.endsWith(marker);\n const replacement = alreadyWrapped ? selected.slice(marker.length, selected.length - marker.length) : `${marker}${selected}${marker}`;\n onChange(value.slice(0, start) + replacement + value.slice(end));\n}\n\nexport interface StoryTextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n boldLabel?: string;\n italicLabel?: string;\n minRows?: number;\n}\n\nexport function StoryTextField({ label, value, onChange, boldLabel = \"Bold\", italicLabel = \"Italic\", minRows = 3 }: StoryTextFieldProps) {\n const ref = useRef<HTMLTextAreaElement>(null);\n return (\n <Stack gap={4}>\n <Group gap=\"xs\">\n <Text size=\"sm\" fw={500}>{label}</Text>\n <Button\n variant=\"default\" size=\"compact-xs\" fw={700} aria-label={boldLabel} title={boldLabel}\n onClick={() => ref.current && applyMarker(ref.current, \"**\", value, onChange)}\n >\n B\n </Button>\n <Button\n variant=\"default\" size=\"compact-xs\" fs=\"italic\" aria-label={italicLabel} title={italicLabel}\n onClick={() => ref.current && applyMarker(ref.current, \"*\", value, onChange)}\n >\n i\n </Button>\n </Group>\n <Textarea\n ref={ref} aria-label={label} autosize minRows={minRows} maxRows={14} value={value}\n onChange={(e) => onChange(e.currentTarget.value)}\n />\n </Stack>\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["useEffect", "useMemo", "useRef", "useState", "ActionIcon", "Box", "Button", "Divider", "Group", "Modal", "Stack", "Text", "TextInput", "Tooltip", "UnstyledButton", "blob", "validate", "usedMedia", "useEffect", "useRef", "useState", "jsx", "useEffect", "useRef", "useState", "jsx", "jsxs", "useRef", "useState", "useEffect", "jsx", "jsxs", "useState", "useEffect", "useRef", "useEffect", "useRef", "useState", "key", "jsx", "jsxs", "useState", "useRef", "useEffect", "edtf", "useEffect", "useRef", "useState", "Group", "Stack", "Text", "TextInput", "jsx", "jsxs", "useEffect", "useMemo", "useRef", "useState", "Button", "Group", "Loader", "Stack", "Text", "TextInput", "Tooltip", "useEffect", "useRef", "maplibregl", "jsx", "useRef", "useEffect", "jsx", "jsxs", "useState", "useEffect", "useRef", "useMemo", "Stack", "Group", "Text", "Button", "Tooltip", "Loader", "TextInput", "useMemo", "useRef", "useState", "ActionIcon", "Box", "Button", "Group", "Stack", "Text", "TextInput", "Tooltip", "useEffect", "useRef", "useState", "maplibregl", "Box", "Button", "Group", "Loader", "Stack", "Text", "TextInput", "editor", "mapEditor", "editor", "mapEditor", "editor", "mapEditor", "Fragment", "jsx", "jsxs", "MapEditor", "useRef", "useState", "useEffect", "color", "opacity", "Button", "Box", "Stack", "Text", "TextInput", "Group", "Loader", "jsx", "jsxs", "BAR_HEIGHT", "useState", "useRef", "Stack", "TextInput", "Text", "useMemo", "s", "editor", "Box", "Group", "Tooltip", "ActionIcon", "Button", "useState", "Stack", "UnstyledButton", "jsx", "useRef", "Button", "Group", "Stack", "Text", "jsx", "jsxs", "jsx", "jsxs", "BAR_HEIGHT", "useState", "useEffect", "Box", "useMemo", "useRef", "slideId", "validate", "Group", "Tooltip", "ActionIcon", "Button", "Stack", "Text", "TextInput", "UnstyledButton", "Divider", "Modal"]
7
7
  }