Таблица выдавливает родительские контейнеры

Чего я хочу добиться:

  1. Контейнер таблицы должен заполнять 100% от оставшегося свободного места
  2. Таблица никак не должна аффектить родительские блоки
  3. Скроллиться должен только второй маппинг под хидерами (скролл хидеров будет управляться через ref)

Я понимаю, что могу установить фиксированный размер контейнера и написать ресайз обсервер, который будет растягивать в зависимости от размера окна, но это нежелательный сценарий. Есть ощущение, что можно это сделать гораздо проще.

Сделал песочницу, для упрощенного понимания

И дублирую сюда код:

const MOCK_DATA = [
  {
    id: 0,
    columnName: '0',
    cards: Array(50)
      .fill('1')
      .map((item, index) => ({
        id: index,
        cardType: 'someType',
        description: 'Описание',
        date: '3.09.24',
      })),
  },
];

for (let i = 1; i < 50; i += 1) {
  MOCK_DATA.push({
    id: i,
    columnName: i.toString(),
    cards: [
      {
        id: i,
        cardType: 'someType',
        description: 'Описание',
        date: '3.09.24',
      },
    ],
  });
}

export const App = () => {
  return (
    <div style={{ display: 'flex', width: '100%', height: '100%' }}>
      <div style={{ display: 'flex', width: '100%' }}>
        <div style={{ width: 200, height: '100%', background: 'lightblue' }}>
          Menu
        </div>
        <div style={{ width: '100%' }}>
          <div style={{ width: '100%', height: 200, background: 'lightgreen' }}>
            Header
          </div>
          <MyTable />
        </div>
      </div>
    </div>
  );
};

export const MyTable = () => {
  return (
    // Этот контейнер должен занимать всю оставшуюся площадь после меню и хидера
    <div style={{ maxWidth: '100%', overflow: 'auto' }}>
      <div style={{ display: 'flex', overflow: 'hidden' }}>
        {MOCK_DATA.map((column) => {
          return <div style={{ width: 165 }}>{column.columnName}</div>;
        })}
      </div>
      {/* // Этот контейнер должен скроллиться */}
      <div style={{ display: 'flex', overflow: 'auto' }}>
        {MOCK_DATA.map((column) => {
          return (
            <div style={{ minWidth: 165 }}>
              {column.cards.map((card) => {
                return <div>{card.description}</div>;
              })}
            </div>
          );
        })}
      </div>
    </div>
  );
};

Ответы (1 шт):

Автор решения: MrYogurt

Разобрался сам:

export const App = () => {
  return (
    <div style={{ display: 'flex', width: '100%', height: '100%' }}>
      <div style={{ display: 'flex', width: '100%' }}>
        <div style={{ width: 200, height: '100%', background: 'lightblue' }}>
          Menu
        </div>
        <div
          style={{
            width: '100%',
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden',
          }}
        >
          <div
            style={{
              width: '100%',
              height: 200,
              background: 'lightgreen',
            }}
          >
            Header
          </div>
          <MyTable />
        </div>
      </div>
    </div>
  );
};

export const MyTable = () => {
  return (
    // Этот контейнер должен занимать всю оставшуюся площадь после меню и хидера
    <div
      style={{
        maxWidth: '100%',
        overflow: 'auto',
        flex: 1,
        display: 'flex',
        flexDirection: 'column',
      }}
    >
      <div
        style={{
          display: 'flex',
          overflow: 'hidden',
        }}
      >
        {MOCK_DATA.map((column) => {
          return <div style={{ minWidth: 165 }}>{column.columnName}</div>;
        })}
      </div>
      {/* // Этот контейнер должен скроллиться */}
      <div style={{ display: 'flex', overflow: 'auto' }}>
        {MOCK_DATA.map((column) => {
          return (
            <div style={{ minWidth: 165 }}>
              {column.cards.map((card) => {
                return <div>{card.description}</div>;
              })}
            </div>
          );
        })}
      </div>
    </div>
  );
};
→ Ссылка