{"version":3,"file":"index.cjs","sources":["../../src/page-layouts/index.ts"],"sourcesContent":["import {\n  Navbar,\n  Button,\n  ButtonGroup,\n  NavbarGroup,\n  Alignment,\n  Intent,\n  Position,\n} from \"@blueprintjs/core\";\nimport hyper from \"@macrostrat/hyper\";\nimport styles from \"./main.module.sass\";\nimport { useReducer, useEffect } from \"react\";\nimport useElementDimensions from \"use-element-dimensions\";\nimport { useContext, createContext } from \"react\";\nimport classNames from \"classnames\";\nconst h = hyper.styled(styles);\n\ninterface ThreeColumnLayoutProps {\n  contextPanel: React.ReactNode;\n  children: React.ReactNode;\n  detailPanel: React.ReactNode;\n  footer?: React.ReactNode;\n  panelState: {\n    [key in SidePanel]?: boolean;\n  };\n  title?: string;\n  twoPanelBreakpoint?: number;\n  preferredMainWidth?: number;\n  expandedContext?: boolean;\n  contextButtonPlacement?: \"left\" | \"right\";\n  headerActions: any;\n}\n\nenum SidePanel {\n  Context = \"context\",\n  Detail = \"detail\",\n}\n\ntype PanelState = {\n  [key in SidePanel]: boolean;\n};\ninterface LayoutState {\n  panelState: PanelState;\n  keyPanel: SidePanel | null;\n  isReduced: boolean;\n}\n\ntype LayoutAction =\n  | { type: \"toggle-panel\"; panel: SidePanel }\n  | { type: \"show-panel\"; panel: SidePanel; shouldShow: boolean }\n  | { type: \"set-is-reduced\"; value: boolean };\n\nfunction openPanels(panelState: PanelState): Set<SidePanel> {\n  const keys = Object.keys(panelState) as SidePanel[];\n  return new Set(keys.filter((k) => panelState[k]));\n}\n\nconst LayoutDispatchContext = createContext<React.Dispatch<LayoutAction>>(\n  (a) => a,\n);\n\nfunction useLayoutDispatch() {\n  return useContext(LayoutDispatchContext);\n}\n\nfunction layoutReducer(state: LayoutState, action: LayoutAction) {\n  let panel: SidePanel;\n  let shouldShow: boolean;\n  switch (action.type) {\n    case \"set-is-reduced\":\n      return { ...state, isReduced: action.value };\n    case \"show-panel\":\n      shouldShow = action.shouldShow;\n    case \"toggle-panel\":\n      panel = action.panel;\n      shouldShow ??= !state.panelState[panel];\n      const panelState = {\n        ...state.panelState,\n        [panel]: shouldShow,\n      };\n      let keyPanel = state.keyPanel;\n      if (shouldShow) {\n        keyPanel = panel;\n      } else if (state.keyPanel == panel) {\n        keyPanel = null;\n      }\n      const currentPanels = openPanels(panelState);\n      if (currentPanels.size == 1) {\n        keyPanel = currentPanels.values().next().value;\n      }\n      return { ...state, panelState, keyPanel };\n  }\n}\n\nfunction buttonProps(\n  panel: SidePanel,\n  desiredState: PanelState,\n  actualState: PanelState,\n  dispatch: React.Dispatch<LayoutAction>,\n) {\n  const active = desiredState[panel];\n  const isActuallyShown = active && active == actualState[panel];\n  return {\n    active,\n    minimal: true,\n    intent: isActuallyShown ? Intent.PRIMARY : null,\n    onClick() {\n      dispatch({ type: \"show-panel\", panel, shouldShow: !isActuallyShown });\n    },\n  };\n}\n\nfunction ThreeColumnLayout(props: ThreeColumnLayoutProps) {\n  const {\n    contextPanel,\n    detailPanel,\n    title = \"User interface\",\n    children,\n    footer,\n    panelState = {},\n    twoPanelBreakpoint = 800,\n    preferredMainWidth,\n    expandedContext = false,\n    headerActions = null,\n    contextButtonPlacement = Position.LEFT,\n    ...rest\n  } = props;\n\n  let keyPanel = null;\n  if (panelState.detail) {\n    keyPanel = SidePanel.Detail;\n  } else if (panelState.context) {\n    keyPanel = SidePanel.Context;\n  }\n\n  const [layoutState, dispatch] = useReducer(\n    layoutReducer,\n    {\n      panelState: { context: true, ...panelState },\n      keyPanel,\n      isReduced: false,\n    },\n    undefined,\n  );\n\n  const [size, ref] = useElementDimensions();\n  const [mainSize, mainRef] = useElementDimensions();\n\n  const panelDesiredState = { ...layoutState.panelState, ...panelState };\n\n  let panelActualState = { ...panelDesiredState };\n  const nonKeyPanel =\n    layoutState.keyPanel == SidePanel.Context\n      ? SidePanel.Detail\n      : SidePanel.Context;\n\n  // We'd like the main panel to take up at least half the screen width\n  const preferredMainPanelWidth =\n    preferredMainWidth ??\n    Math.max((size?.width ?? 0) * 0.5, twoPanelBreakpoint * 0.66);\n\n  if (layoutState.isReduced) {\n    panelActualState[nonKeyPanel] = false;\n  }\n\n  if (expandedContext) {\n    panelActualState[SidePanel.Context] = true;\n    panelActualState[SidePanel.Detail] = false;\n  }\n\n  useEffect(() => {\n    if (openPanels(panelActualState).size <= 1) {\n      return;\n    }\n    // Decide whether we need to reduce the layout ONLY when both panels are open\n    const shouldReduce = mainSize?.width < preferredMainPanelWidth;\n    dispatch({ type: \"set-is-reduced\", value: shouldReduce });\n  }, [mainSize]);\n\n  const contextButton = h.if(contextPanel != null)(Button, {\n    icon: \"projects\",\n    ...buttonProps(\n      SidePanel.Context,\n      panelDesiredState,\n      panelActualState,\n      dispatch,\n    ),\n  });\n\n  return h(\n    LayoutDispatchContext.Provider,\n    { value: dispatch },\n    h(\n      \"div.user-interface\",\n      {\n        ref,\n        ...rest,\n      },\n      [\n        h(Navbar, [\n          h(Navbar.Group, [\n            h.if(contextButtonPlacement == \"left\")([\n              contextButton,\n              h(\"div.spacer\"),\n            ]),\n            h(Navbar.Heading, null, title),\n          ]),\n          h(NavbarGroup, { align: Alignment.RIGHT }, [\n            headerActions,\n            h(\"div.spacer\"),\n            h(ButtonGroup, { minimal: true }, [\n              h.if(contextButtonPlacement == \"right\")([contextButton]),\n              h.if(detailPanel != null)(Button, {\n                icon: \"properties\",\n                ...buttonProps(\n                  SidePanel.Detail,\n                  panelDesiredState,\n                  panelActualState,\n                  dispatch,\n                ),\n              }),\n            ]),\n          ]),\n        ]),\n        h(\"div.three-column\", [\n          h.if(contextPanel != null && panelActualState.context)(\n            \"div.column.context-column\",\n            { className: classNames({ expanded: expandedContext ?? false }) },\n            contextPanel,\n          ),\n          h.if(children != null)(\n            \"div.column.main-column\",\n            { ref: mainRef },\n            children,\n          ),\n          h.if(detailPanel != null && panelActualState.detail)(\n            \"div.column.detail-column\",\n            null,\n            detailPanel,\n          ),\n        ]),\n        h.if(footer != null)(\"footer\", null, footer),\n      ],\n    ),\n  );\n}\n\nThreeColumnLayout.Panels = SidePanel;\n\nexport { ThreeColumnLayout, ThreeColumnLayoutProps, useLayoutDispatch };\n"],"names":["hyper","styles","SidePanel","createContext","useContext","Intent","Position","useReducer","useElementDimensions","useEffect","Button","Navbar","NavbarGroup","Alignment","ButtonGroup","classNames"],"mappings":"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"}