Source: lib/State.js

import {Template} from 'meteor/templating'

/**
 * Hassle-free shared state between parent and children.
 * Helps to prevent "prop-drilling".
 * The parent needs to pass `context=balzeui_context` to the child
 * in `Template.contentBlock`, while
 * children need to use state from this context, instead of
 * creating a new ReactiveDict.
 * Children can then read/write to the state.
 *
 * @namespace
 */
export const State = {}

/**
 * You can use this to manually create and share context
 * but usually you just need the `blazeui_context` helper.
 */
State.createContext = () => function ({ instance } = {}) {
  const current = instance ?? Template.instance()
  return {
    root: current,
    state: current.state
  }
}

/**
 *
 */
State.useFromContext = () => ({ instance }) => {
  const parentData = Template.parentData()
  const currentData = Template.currentData()

  let state
  if (parentData?.context?.state) {
    state = parentData.context.state
  }

  if (currentData?.context?.state) {
    state = currentData.context.state
  }

  if (!state) {
    throw new Error(`${instance.view.name}: No context provided to resolve state.`)
  }

  instance.state = state
  return state
}


Template.registerHelper('blazeui_context', function () {
  const instance = Template.instance()
  const ctxFn = State.createContext()
  return ctxFn({ instance })
})