From edc7143f77c427a71443d83f097d78a49eabda98 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:34:08 +0100 Subject: [PATCH] fix(base): match inline-embed placeholder skeleton to seeded 3 col / 1 row shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The placeholder rendered a default 10×6 BaseTableSkeleton while waiting on the create-base API, then swapped to the real table once the response landed. Because the inline-embed flow now seeds Title + Text 1 + Text 2 with one default row, the real table is 3×1 — the swap visibly collapsed a large fake table down to a small empty one. The scroll didn't jump (initialOffset takes care of that) but the flicker was jarring. Re-introduce rows + columns props on BaseTableSkeleton (default still 10 / 6 so other call sites are unaffected) and pass rows=1 columns=3 from the inline-embed placeholder so the swap is visually stable. --- .../base/components/base-table-skeleton.tsx | 29 ++++++++++++++----- .../components/base-embed/base-embed-view.tsx | 9 ++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/client/src/features/base/components/base-table-skeleton.tsx b/apps/client/src/features/base/components/base-table-skeleton.tsx index dfcae12fc..9e499fbc2 100644 --- a/apps/client/src/features/base/components/base-table-skeleton.tsx +++ b/apps/client/src/features/base/components/base-table-skeleton.tsx @@ -4,18 +4,31 @@ import classes from "@/features/base/styles/base-table-skeleton.module.css"; const ROW_NUMBER_WIDTH = 64; const COLUMN_WIDTH = 180; -const COLUMN_COUNT = 6; -const ROW_COUNT = 10; +const DEFAULT_COLUMN_COUNT = 6; +const DEFAULT_ROW_COUNT = 10; // Deterministic per-cell widths so the skeleton doesn't flicker between // renders. Values are rough normal distribution around 55-85 % of cell. const CELL_WIDTH_RATIOS = [0.78, 0.62, 0.84, 0.55, 0.71, 0.66]; const HEADER_WIDTH_RATIOS = [0.42, 0.58, 0.5, 0.64, 0.46, 0.54]; -export function BaseTableSkeleton() { +type BaseTableSkeletonProps = { + // Override the rendered shape to match what the eventual content + // will be — the inline-embed placeholder passes rows=1, columns=3 + // (matching the seeded Title + Text 1 + Text 2 with one default + // row) so the swap from skeleton to real table doesn't visibly + // collapse a large fake table down to a small empty one. + rows?: number; + columns?: number; +}; + +export function BaseTableSkeleton({ + rows = DEFAULT_ROW_COUNT, + columns = DEFAULT_COLUMN_COUNT, +}: BaseTableSkeletonProps = {}) { const gridTemplateColumns = [ `${ROW_NUMBER_WIDTH}px`, - ...Array.from({ length: COLUMN_COUNT }, () => `${COLUMN_WIDTH}px`), + ...Array.from({ length: columns }, () => `${COLUMN_WIDTH}px`), ].join(" "); return ( @@ -41,27 +54,27 @@ export function BaseTableSkeleton() { - {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + {Array.from({ length: columns }).map((_, colIndex) => (
))} - {Array.from({ length: ROW_COUNT }).map((_, rowIndex) => ( + {Array.from({ length: rows }).map((_, rowIndex) => (
- {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + {Array.from({ length: columns }).map((_, colIndex) => (
; + // assigned pageId. Match the shape the create endpoint will + // return for an inline-embed (Title + Text 1 + Text 2, one + // empty row — see BaseService.create's `defaults`) so the swap + // to the real table doesn't visibly collapse a large fake table + // down to a small empty one. + content = ; } else if (!pageId) { content = (