reka-ui
Version:
Vue port for Radix UI Primitives.
117 lines (105 loc) • 3.39 kB
text/typescript
import type { PanelGroupStorage } from '../SplitterGroup.vue'
import type { PanelData } from '../SplitterPanel.vue'
// PanelGroup might be rendering in a server-side environment where localStorage is not available
// or on a browser with cookies/storage disabled.
// In either case, this function avoids accessing localStorage until needed,
// and avoids throwing user-visible errors.
export function initializeDefaultStorage(storageObject: PanelGroupStorage) {
try {
if (typeof localStorage !== 'undefined') {
// Bypass this check for future calls
storageObject.getItem = (name: string) => {
return localStorage.getItem(name)
}
storageObject.setItem = (name: string, value: string) => {
localStorage.setItem(name, value)
}
}
else {
throw new TypeError('localStorage not supported in this environment')
}
}
catch (error) {
console.error(error)
storageObject.getItem = () => null
storageObject.setItem = () => {}
}
}
export type PanelConfigurationState = {
expandToSizes: {
[panelId: string]: number
}
layout: number[]
}
export type SerializedPanelGroupState = {
[panelIds: string]: PanelConfigurationState
}
function getPanelGroupKey(autoSaveId: string): string {
return `reka:${autoSaveId}`
}
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
// so they should not be used as part of the serialization key.
// Using the min/max size attributes should work well enough as a backup.
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
function getPanelKey(panels: PanelData[]): string {
return panels
.map((panel) => {
const { constraints, id, idIsFromProps, order } = panel
if (idIsFromProps) {
return id
}
else {
return order
? `${order}:${JSON.stringify(constraints)}`
: JSON.stringify(constraints)
}
})
.sort((a, b) => a.localeCompare(b))
.join(',')
}
function loadSerializedPanelGroupState(
autoSaveId: string,
storage: PanelGroupStorage,
): SerializedPanelGroupState | null {
try {
const panelGroupKey = getPanelGroupKey(autoSaveId)
const serialized = storage.getItem(panelGroupKey)
if (serialized) {
const parsed = JSON.parse(serialized)
if (typeof parsed === 'object' && parsed != null)
return parsed as SerializedPanelGroupState
}
}
catch (error) {}
return null
}
export function loadPanelGroupState(
autoSaveId: string,
panels: PanelData[],
storage: PanelGroupStorage,
): PanelConfigurationState | null {
const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}
const panelKey = getPanelKey(panels)
return state[panelKey] ?? null
}
export function savePanelGroupState(
autoSaveId: string,
panels: PanelData[],
panelSizesBeforeCollapse: Map<string, number>,
sizes: number[],
storage: PanelGroupStorage,
): void {
const panelGroupKey = getPanelGroupKey(autoSaveId)
const panelKey = getPanelKey(panels)
const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}
state[panelKey] = {
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
layout: sizes,
}
try {
storage.setItem(panelGroupKey, JSON.stringify(state))
}
catch (error) {
console.error(error)
}
}