@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
189 lines (188 loc) • 5.65 kB
JavaScript
import { atom } from "@tldraw/state";
import { getDefaultTranslationLocale } from "@tldraw/tlschema";
import { getFromLocalStorage, setInLocalStorage, structuredClone, uniqueId } from "@tldraw/utils";
import { T } from "@tldraw/validate";
const USER_DATA_KEY = "TLDRAW_USER_DATA_v3";
const userTypeValidator = T.object({
id: T.string,
name: T.string.nullable().optional(),
color: T.string.nullable().optional(),
// N.B. These are duplicated in TLdrawAppUser.
locale: T.string.nullable().optional(),
animationSpeed: T.number.nullable().optional(),
areKeyboardShortcutsEnabled: T.boolean.nullable().optional(),
edgeScrollSpeed: T.number.nullable().optional(),
colorScheme: T.literalEnum("light", "dark", "system").optional(),
isSnapMode: T.boolean.nullable().optional(),
isWrapMode: T.boolean.nullable().optional(),
isDynamicSizeMode: T.boolean.nullable().optional(),
isPasteAtCursorMode: T.boolean.nullable().optional()
});
const Versions = {
AddAnimationSpeed: 1,
AddIsSnapMode: 2,
MakeFieldsNullable: 3,
AddEdgeScrollSpeed: 4,
AddExcalidrawSelectMode: 5,
AddDynamicSizeMode: 6,
AllowSystemColorScheme: 7,
AddPasteAtCursor: 8,
AddKeyboardShortcuts: 9
};
const CURRENT_VERSION = Math.max(...Object.values(Versions));
function migrateSnapshot(data) {
if (data.version < Versions.AddAnimationSpeed) {
data.user.animationSpeed = 1;
}
if (data.version < Versions.AddIsSnapMode) {
data.user.isSnapMode = false;
}
if (data.version < Versions.MakeFieldsNullable) {
}
if (data.version < Versions.AddEdgeScrollSpeed) {
data.user.edgeScrollSpeed = 1;
}
if (data.version < Versions.AddExcalidrawSelectMode) {
data.user.isWrapMode = false;
}
if (data.version < Versions.AllowSystemColorScheme) {
if (data.user.isDarkMode === true) {
data.user.colorScheme = "dark";
} else if (data.user.isDarkMode === false) {
data.user.colorScheme = "light";
}
delete data.user.isDarkMode;
}
if (data.version < Versions.AddDynamicSizeMode) {
data.user.isDynamicSizeMode = false;
}
if (data.version < Versions.AddPasteAtCursor) {
data.user.isPasteAtCursorMode = false;
}
if (data.version < Versions.AddKeyboardShortcuts) {
data.user.areKeyboardShortcutsEnabled = true;
}
data.version = CURRENT_VERSION;
}
const USER_COLORS = [
"#FF802B",
"#EC5E41",
"#F2555A",
"#F04F88",
"#E34BA9",
"#BD54C6",
"#9D5BD2",
"#7B66DC",
"#02B1CC",
"#11B3A3",
"#39B178",
"#55B467"
];
function getRandomColor() {
return USER_COLORS[Math.floor(Math.random() * USER_COLORS.length)];
}
function userPrefersReducedMotion() {
if (typeof window !== "undefined" && "matchMedia" in window) {
return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches ?? false;
}
return false;
}
const defaultUserPreferences = Object.freeze({
name: "",
locale: getDefaultTranslationLocale(),
color: getRandomColor(),
// N.B. These are duplicated in TLdrawAppUser.
edgeScrollSpeed: 1,
animationSpeed: userPrefersReducedMotion() ? 0 : 1,
areKeyboardShortcutsEnabled: true,
isSnapMode: false,
isWrapMode: false,
isDynamicSizeMode: false,
isPasteAtCursorMode: false,
colorScheme: "light"
});
function getFreshUserPreferences() {
return {
id: uniqueId(),
color: getRandomColor()
};
}
function migrateUserPreferences(userData) {
if (userData === null || typeof userData !== "object") {
return getFreshUserPreferences();
}
if (!("version" in userData) || !("user" in userData) || typeof userData.version !== "number") {
return getFreshUserPreferences();
}
const snapshot = structuredClone(userData);
migrateSnapshot(snapshot);
try {
return userTypeValidator.validate(snapshot.user);
} catch {
return getFreshUserPreferences();
}
}
function loadUserPreferences() {
const userData = JSON.parse(getFromLocalStorage(USER_DATA_KEY) || "null") ?? null;
return migrateUserPreferences(userData);
}
const globalUserPreferences = atom("globalUserData", null);
function storeUserPreferences() {
setInLocalStorage(
USER_DATA_KEY,
JSON.stringify({
version: CURRENT_VERSION,
user: globalUserPreferences.get()
})
);
}
function setUserPreferences(user) {
userTypeValidator.validate(user);
globalUserPreferences.set(user);
storeUserPreferences();
broadcastUserPreferencesChange();
}
const isTest = typeof process !== "undefined" && process.env.NODE_ENV === "test";
const channel = typeof BroadcastChannel !== "undefined" && !isTest ? new BroadcastChannel("tldraw-user-sync") : null;
channel?.addEventListener("message", (e) => {
const data = e.data;
if (data?.type === broadcastEventKey && data?.origin !== getBroadcastOrigin()) {
globalUserPreferences.set(migrateUserPreferences(data.data));
}
});
let _broadcastOrigin = null;
function getBroadcastOrigin() {
if (_broadcastOrigin === null) {
_broadcastOrigin = uniqueId();
}
return _broadcastOrigin;
}
const broadcastEventKey = "tldraw-user-preferences-change";
function broadcastUserPreferencesChange() {
channel?.postMessage({
type: broadcastEventKey,
origin: getBroadcastOrigin(),
data: {
user: getUserPreferences(),
version: CURRENT_VERSION
}
});
}
function getUserPreferences() {
let prefs = globalUserPreferences.get();
if (!prefs) {
prefs = loadUserPreferences();
setUserPreferences(prefs);
}
return prefs;
}
export {
USER_COLORS,
defaultUserPreferences,
getFreshUserPreferences,
getUserPreferences,
setUserPreferences,
userPrefersReducedMotion,
userTypeValidator
};
//# sourceMappingURL=TLUserPreferences.mjs.map