Style Inheritance

Implementing prototype chains and style inheritance for themes, defaults, and templates.

Application Pattern

Style inheritance is an application-level pattern built on top of CRDTs, not a CRDT feature itself. It leverages CRDT properties (automatic sync, conflict resolution) while keeping the inheritance logic in application code.

The Pattern

Instead of storing all properties on each element:

  1. Store a reference to a parent style/template
  2. Store only the overridden properties
const styles = yDoc.getMap('styles')
styles.set('heading', {
  fontSize: 24,
  fontWeight: 'bold',
  color: '#333333'
})

const elements = yDoc.getMap('elements')
elements.set('title', {
  text: 'Welcome',
  styleId: 'heading',
  overrides: { color: '#0066cc' }  // Override just this
})

Resolving Styles

function resolveStyle(element: ElementData): ResolvedStyle {
  const baseStyle = styles.get(element.styleId) || {}
  return { ...baseStyle, ...element.overrides }
}

// { fontSize: 24, fontWeight: 'bold', color: '#0066cc' }

Multi-Level Inheritance

Chain multiple levels for complex theming:

theme/colors     → { primary: '#0066cc', text: '#333' }
      ↓
templates/card   → { padding: 16, titleColor: 'theme.colors.primary' }
      ↓
elements/card-1  → { templateId: 'card', overrides: { padding: 24 } }

Resolution cascades: element overrides → template defaults → theme values.

Named Style Classes

Like CSS classes, elements can reference multiple styles by name. Store class definitions in a map (styleClasses), and let elements specify an array of class names. Resolution merges classes in order, then applies overrides.

Cascading Updates

When a base style changes, all dependent elements automatically get new values:

theme.observeDeep(() => {
  renderAll()  // Elements resolve to new values
})

See Also