@tldraw/tlschema
Version:
A tiny little drawing app (schema).
160 lines (159 loc) • 5.51 kB
JavaScript
import { annotateError, structuredClone } from "@tldraw/utils";
import { CameraRecordType } from "./records/TLCamera.mjs";
import { DocumentRecordType, TLDOCUMENT_ID } from "./records/TLDocument.mjs";
import { TLINSTANCE_ID } from "./records/TLInstance.mjs";
import { PageRecordType } from "./records/TLPage.mjs";
import { InstancePageStateRecordType } from "./records/TLPageState.mjs";
import { PointerRecordType, TLPOINTER_ID } from "./records/TLPointer.mjs";
function sortByIndex(a, b) {
if (a.index < b.index) {
return -1;
} else if (a.index > b.index) {
return 1;
}
return 0;
}
function redactRecordForErrorReporting(record) {
if (record.typeName === "asset") {
if ("src" in record) {
record.src = "<redacted>";
}
if ("src" in record.props) {
record.props.src = "<redacted>";
}
}
}
function onValidationFailure({
error,
phase,
record,
recordBefore
}) {
const isExistingValidationIssue = (
// if we're initializing the store for the first time, we should
// allow invalid records so people can load old buggy data:
(phase === "initialize")
);
annotateError(error, {
tags: {
origin: "store.validateRecord",
storePhase: phase,
isExistingValidationIssue
},
extras: {
recordBefore: recordBefore ? redactRecordForErrorReporting(structuredClone(recordBefore)) : void 0,
recordAfter: redactRecordForErrorReporting(structuredClone(record))
}
});
throw error;
}
function getDefaultPages() {
return [
PageRecordType.create({
id: "page:page",
name: "Page 1",
index: "a1",
meta: {}
})
];
}
function createIntegrityChecker(store) {
const $pageIds = store.query.ids("page");
const $pageStates = store.query.records("instance_page_state");
const ensureStoreIsUsable = () => {
if (!store.has(TLDOCUMENT_ID)) {
store.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })]);
return ensureStoreIsUsable();
}
if (!store.has(TLPOINTER_ID)) {
store.put([PointerRecordType.create({ id: TLPOINTER_ID })]);
return ensureStoreIsUsable();
}
const pageIds = $pageIds.get();
if (pageIds.size === 0) {
store.put(getDefaultPages());
return ensureStoreIsUsable();
}
const getFirstPageId = () => [...pageIds].map((id) => store.get(id)).sort(sortByIndex)[0].id;
const instanceState = store.get(TLINSTANCE_ID);
if (!instanceState) {
store.put([
store.schema.types.instance.create({
id: TLINSTANCE_ID,
currentPageId: getFirstPageId(),
exportBackground: true
})
]);
return ensureStoreIsUsable();
} else if (!pageIds.has(instanceState.currentPageId)) {
store.put([{ ...instanceState, currentPageId: getFirstPageId() }]);
return ensureStoreIsUsable();
}
const missingPageStateIds = /* @__PURE__ */ new Set();
const missingCameraIds = /* @__PURE__ */ new Set();
for (const id of pageIds) {
const pageStateId = InstancePageStateRecordType.createId(id);
const pageState = store.get(pageStateId);
if (!pageState) {
missingPageStateIds.add(pageStateId);
}
const cameraId = CameraRecordType.createId(id);
if (!store.has(cameraId)) {
missingCameraIds.add(cameraId);
}
}
if (missingPageStateIds.size > 0) {
store.put(
[...missingPageStateIds].map(
(id) => InstancePageStateRecordType.create({
id,
pageId: InstancePageStateRecordType.parseId(id)
})
)
);
}
if (missingCameraIds.size > 0) {
store.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })));
}
const pageStates = $pageStates.get();
for (const pageState of pageStates) {
if (!pageIds.has(pageState.pageId)) {
store.remove([pageState.id]);
continue;
}
if (pageState.croppingShapeId && !store.has(pageState.croppingShapeId)) {
store.put([{ ...pageState, croppingShapeId: null }]);
return ensureStoreIsUsable();
}
if (pageState.focusedGroupId && !store.has(pageState.focusedGroupId)) {
store.put([{ ...pageState, focusedGroupId: null }]);
return ensureStoreIsUsable();
}
if (pageState.hoveredShapeId && !store.has(pageState.hoveredShapeId)) {
store.put([{ ...pageState, hoveredShapeId: null }]);
return ensureStoreIsUsable();
}
const filteredSelectedIds = pageState.selectedShapeIds.filter((id) => store.has(id));
if (filteredSelectedIds.length !== pageState.selectedShapeIds.length) {
store.put([{ ...pageState, selectedShapeIds: filteredSelectedIds }]);
return ensureStoreIsUsable();
}
const filteredHintingIds = pageState.hintingShapeIds.filter((id) => store.has(id));
if (filteredHintingIds.length !== pageState.hintingShapeIds.length) {
store.put([{ ...pageState, hintingShapeIds: filteredHintingIds }]);
return ensureStoreIsUsable();
}
const filteredErasingIds = pageState.erasingShapeIds.filter((id) => store.has(id));
if (filteredErasingIds.length !== pageState.erasingShapeIds.length) {
store.put([{ ...pageState, erasingShapeIds: filteredErasingIds }]);
return ensureStoreIsUsable();
}
}
};
return ensureStoreIsUsable;
}
export {
createIntegrityChecker,
onValidationFailure
};
//# sourceMappingURL=TLStore.mjs.map