Panel Actions

Built-in panel actions, custom menu items, and new-tab hooks.

Panel actions are for commands that belong to the panel shell: menus, maximize and minimize controls, and app-defined new-tab behavior. Open the menu and use the new-tab demo to see how Tilery leaves product-specific commands to your app.

The tab bar stays built in, but renderPanelActions and onNewTab let you extend the controls without replacing the whole header.

const actionsLayout: TileryInitialLayout<TabData> = {
  type: 'group',
  direction: 'horizontal',
  children: [
    {
      type: 'panel',
      id: 'explorer',
      size: 30,
      tabs: [
        {
          id: 'files',
          data: {
            title: 'Files',
            body: 'Project files, outlines, and search results live here.',
          },
        },
      ],
    },
    {
      type: 'group',
      direction: 'vertical',
      size: 70,
      children: [
        {
          type: 'panel',
          id: 'editor',
          size: 62,
          tabs: [
            {
              id: 'readme',
              data: {
                title: 'README.md',
                body: 'The editor menu includes one app-defined command.',
              },
            },
            {
              id: 'notes',
              data: {
                title: 'Notes',
                body: 'Built-in actions stay available beside custom commands.',
              },
            },
          ],
        },
        {
          type: 'panel',
          id: 'terminal',
          size: 38,
          tabs: [
            {
              id: 'shell',
              data: {
                title: 'Terminal',
                body: '$ pnpm test',
              },
            },
          ],
        },
      ],
    },
  ],
};

<Tilery<TabData>
  initialLayout={actionsLayout}
  showActionsButton={true}
  renderActionsButtonIcon={EllipsisIcon}
  renderPanelActions={(panel, ctx) =>
    panel.id === 'editor' ? (
      <button
        type="button"
        className="tilery__panel-menu-item"
        onClick={() => {
          panel.setActiveTab('readme');
          ctx.closeMenu();
        }}>
        Focus README
      </button>
    ) : null
  }
  renderTabHeader={renderHeader}
  renderTabContent={renderContent}
/>
const newTabLayout: TileryInitialLayout<TabData> = {
  type: 'group',
  direction: 'horizontal',
  children: [
    {
      type: 'panel',
      id: 'drafts',
      size: 55,
      tabs: [
        {
          id: 'draft-0',
          data: {
            title: 'Draft 0',
            body: 'The plus button asks the host app for a new tab object.',
          },
        },
      ],
    },
    {
      type: 'panel',
      id: 'reference',
      size: 45,
      tabs: [
        {
          id: 'api',
          data: {
            title: 'API Notes',
            body: 'The reference panel does not show the new-tab affordance.',
          },
        },
      ],
    },
  ],
};

const newTabCounterRef = useRef(0);
const tileryRef = useRef<TileryController | null>(null);

<Tilery<TabData>
  ref={tileryRef as React.Ref<TileryController>}
  initialLayout={newTabLayout}
  showNewTabButton={(panel) => panel.id === 'drafts'}
  onNewTab={(panel: TileryPanel) => {
    newTabCounterRef.current += 1;
    return {
      id: `${panel.id}-${newTabCounterRef.current}`,
      data: {
        title: `Draft ${newTabCounterRef.current}`,
        body: 'This tab was supplied by the host application.',
      },
    };
  }}
  renderTabHeader={renderHeader}
  renderTabContent={renderContent}
/>

Related