From 9b4aa552f9f0940e38f503bac852bdfe331ec9fe Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Sat, 14 Mar 2026 01:55:03 +0700 Subject: [PATCH 01/11] Move the loading position into aroun the first `row` level. --- components/table.tsx | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index b2afb4f6..1e4054ed 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -568,24 +568,32 @@ function Table({ })()} )} - - {isLoading && ( - - - - )} + + {isLoading && ( + + + + )} @@ -691,9 +699,9 @@ const PaginationSelectedItem = styled.span<{ $style?: CSSProp }>` `; const TableContainer = styled.div<{ $hasSelected: boolean }>` + position: relative; display: flex; flex-direction: column; - position: relative; height: 100%; overflow: hidden; From 4582674bd09573e2f853860e7cf314e7f14a3d01 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Sat, 14 Mar 2026 02:21:37 +0700 Subject: [PATCH 02/11] Ensures the test for isLoading from the top 60px and 120px. --- test/component/table.cy.tsx | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index aeec56c6..a0864731 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -57,6 +57,82 @@ describe("Table", () => { type: TYPES_DATA[i % TYPES_DATA.length], })); + context("isLoading", () => { + it("should render loading-spinner around the row.level", () => { + cy.mount( + + {rawRows?.map((row, index) => ( + + {[row.name, row.type].map((rowCell, i) => ( + + {rowCell} + + ))} + + ))} +
+ ); + + cy.findByLabelText("overlay-blocker") + .should("exist") + .and("have.css", "padding-top", "60px"); + + cy.findByLabelText("overlay-blocker").then(($overlay) => { + const overlayRect = $overlay[0].getBoundingClientRect(); + + cy.findByLabelText("circle").then(($spinner) => { + const spinnerRect = $spinner[0].getBoundingClientRect(); + + const distance = spinnerRect.top - overlayRect.top; + + expect(distance).to.be.closeTo(60, 10); // 60px is overlay padding-top + }); + }); + }); + + context("when given actions", () => { + it("should render loading-spinner around the row.level", () => { + cy.mount( + + {rawRows?.map((row, index) => ( + + {[row.name, row.type].map((rowCell, i) => ( + + {rowCell} + + ))} + + ))} +
+ ); + + cy.findByLabelText("overlay-blocker") + .should("exist") + .and("have.css", "padding-top", "120px"); + + cy.findByLabelText("overlay-blocker").then(($overlay) => { + const overlayRect = $overlay[0].getBoundingClientRect(); + + cy.findByLabelText("circle").then(($spinner) => { + const spinnerRect = $spinner[0].getBoundingClientRect(); + + const distance = spinnerRect.top - overlayRect.top; + + expect(distance).to.be.closeTo(120, 10); // 120px is overlay padding-top + }); + }); + }); + }); + }); + context("actions in main table", () => { context("when not given type", () => { it("should render with button", () => { From 2e24e42c75b45bf8dc374c42f2d12e94ee52d436 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Sat, 14 Mar 2026 10:25:11 +0700 Subject: [PATCH 03/11] Choose to `top-left` the loading. --- components/table.tsx | 7 ------- test/component/table.cy.tsx | 12 ++---------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index 29efdcf5..56877135 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -576,13 +576,6 @@ function Table({ self: css` display: flex; align-items: start; - justify-content: center; - padding-top: 60px; - - ${(actions || showPagination) && - css` - padding-top: 120px; - `} backdrop-filter: blur(0.5px); background-color: rgba(255, 255, 255, 0.6); diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index 12e8c0e8..269562eb 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -87,10 +87,6 @@ describe("Table", () => { it("should render loading-spinner around the row.level", () => { cy.mount(); - cy.findByLabelText("overlay-blocker") - .should("exist") - .and("have.css", "padding-top", "60px"); - cy.findByLabelText("overlay-blocker").then(($overlay) => { const overlayRect = $overlay[0].getBoundingClientRect(); @@ -99,7 +95,7 @@ describe("Table", () => { const distance = spinnerRect.top - overlayRect.top; - expect(distance).to.be.closeTo(60, 10); // 60px is overlay padding-top + expect(distance).to.be.closeTo(0, 10); // render on the left top }); }); }); @@ -117,10 +113,6 @@ describe("Table", () => { /> ); - cy.findByLabelText("overlay-blocker") - .should("exist") - .and("have.css", "padding-top", "120px"); - cy.findByLabelText("overlay-blocker").then(($overlay) => { const overlayRect = $overlay[0].getBoundingClientRect(); @@ -129,7 +121,7 @@ describe("Table", () => { const distance = spinnerRect.top - overlayRect.top; - expect(distance).to.be.closeTo(120, 10); // 120px is overlay padding-top + expect(distance).to.be.closeTo(0, 10); // render on the left top }); }); }); From e46b4210c4467d7f6b6d6e96235e4d2bf3751349 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Sat, 14 Mar 2026 10:49:26 +0700 Subject: [PATCH 04/11] Ensure the loading in the `table.row` body. --- components/table.tsx | 6 ++++++ test/component/table.cy.tsx | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index f3ebfe0a..34736da0 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -576,6 +576,12 @@ function Table({ self: css` display: flex; align-items: start; + padding-top: 60px; + + ${(actions || showPagination) && + css` + padding-top: 120px; + `} backdrop-filter: blur(0.5px); background-color: rgba(255, 255, 255, 0.6); diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index 62729f48..6a983c63 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -95,7 +95,7 @@ describe("Table", () => { const distance = spinnerRect.top - overlayRect.top; - expect(distance).to.be.closeTo(0, 10); // render on the left top + expect(distance).to.be.closeTo(60, 10); // 60px is overlay padding-top }); }); }); @@ -121,7 +121,7 @@ describe("Table", () => { const distance = spinnerRect.top - overlayRect.top; - expect(distance).to.be.closeTo(0, 10); // render on the left top + expect(distance).to.be.closeTo(110, 10); // 110px is overlay padding-top }); }); }); From 1938b08f4e6a823b45723a60cc5a0692577a7664 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 08:46:59 +0700 Subject: [PATCH 05/11] Add padding top better in all condition. --- components/table.tsx | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index 34736da0..898dcd90 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -224,7 +224,10 @@ function Table({ const rowChildren = Children.map(children, (child, index) => { if (!isValidElement(child)) return null; - if (child.type === TableRowGroup) { + const hasRowGroup = child.type === TableRowGroup; + const hasRow = child.type === TableRow; + + if (hasRowGroup) { return cloneElement(child, { selectable, selectedData, @@ -241,7 +244,7 @@ function Table({ }); } - if (child.type === TableRow) { + if (hasRow) { const props = child.props as TableRowProps; const isSelected = selectedData.some( @@ -301,6 +304,10 @@ function Table({ return () => el.removeEventListener("scroll", handleScroll); }, [openRowId]); + const hasRowGroup = Children.toArray(children).some( + (child) => isValidElement(child) && child.type === TableRowGroup + ); + return ( @@ -576,12 +583,13 @@ function Table({ self: css` display: flex; align-items: start; - padding-top: 60px; - - ${(actions || showPagination) && - css` - padding-top: 120px; - `} + padding-left: 16px; + padding-top: ${(() => { + if (showPagination && hasRowGroup) return "152px"; + if (showPagination || hasRowGroup) return "140px"; + if (actions || searchable) return "126px"; + return "60px"; + })()}; backdrop-filter: blur(0.5px); background-color: rgba(255, 255, 255, 0.6); From cf687f34a61cced640ea35de69c205b0a8f77d30 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 08:47:47 +0700 Subject: [PATCH 06/11] Ensure the test for condition isLoading placement with showPage, actions, hasRow, etc. --- test/component/table.cy.tsx | 133 ++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 43 deletions(-) diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index 6a983c63..b1bd1e92 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -59,69 +59,116 @@ describe("Table", () => { type: TYPES_DATA[i % TYPES_DATA.length], })); - function BasicTable(props: Omit) { + function BasicTable( + props: Omit & { hasRowGroup?: boolean } + ) { const [selectedItems, setSelectedItems] = useState([]); + const pageNumberText = props?.labels?.pageNumberText ?? "12"; + + const groupedRows = props.hasRowGroup + ? TYPES_DATA.map((type) => ({ + type, + rows: rawRows.filter((r) => r.type === type), + })) + : null; + return ( - {rawRows?.map((row, index) => ( - - {[row.name, row.type].map((rowCell, i) => ( - - {rowCell} - + {props.hasRowGroup + ? groupedRows?.map((group, gi) => ( + + {group.rows.map((row, ri) => ( + + {[row.name, row.type].map((cell, ci) => ( + + {cell} + + ))} + + ))} + + )) + : rawRows?.map((row, index) => ( + + {[row.name, row.type].map((rowCell, i) => ( + + {rowCell} + + ))} + ))} - - ))}
); } - context("isLoading", () => { - it("should render loading-spinner around the row.level", () => { - cy.mount(); - - cy.findByLabelText("overlay-blocker").then(($overlay) => { - const overlayRect = $overlay[0].getBoundingClientRect(); - - cy.findByLabelText("circle").then(($spinner) => { - const spinnerRect = $spinner[0].getBoundingClientRect(); - - const distance = spinnerRect.top - overlayRect.top; - - expect(distance).to.be.closeTo(60, 10); // 60px is overlay padding-top - }); - }); - }); + const scenarios = [ + { + description: "isLoading only", + props: { isLoading: true }, + expectedPadding: 60, + }, + { + description: "isLoading with actions", + props: { isLoading: true, actions: [{ caption: "Test" }] }, + expectedPadding: 126, + }, + { + description: "isLoading with showPagination", + props: { isLoading: true, showPagination: true }, + expectedPadding: 140, + }, + { + description: "isLoading with showPagination + hasRowGroup", + props: { + isLoading: true, + showPagination: true, + labels: { pageNumberText: "12" }, + hasRowGroup: true, + }, + expectedPadding: 152, + }, + { + description: "isLoading with hasRowGroup", + props: { isLoading: true, hasRowGroup: true }, + expectedPadding: 140, + }, + { + description: "isLoading with searchable", + props: { isLoading: true, searchable: true }, + expectedPadding: 126, + }, + ]; - context("when given actions", () => { - it("should render loading-spinner around the row.level", () => { - cy.mount( - - ); + scenarios.forEach(({ description, props, expectedPadding }) => { + context(`when given ${description}`, () => { + it(`should render spinner with padding-top ~${expectedPadding}px and padding-left 16px`, () => { + cy.mount(); - cy.findByLabelText("overlay-blocker").then(($overlay) => { - const overlayRect = $overlay[0].getBoundingClientRect(); + cy.findByLabelText("overlay-blocker").then(($overlay) => { + const overlayRect = $overlay[0].getBoundingClientRect(); - cy.findByLabelText("circle").then(($spinner) => { - const spinnerRect = $spinner[0].getBoundingClientRect(); + cy.findByLabelText("circle").then(($spinner) => { + const spinnerRect = $spinner[0].getBoundingClientRect(); - const distance = spinnerRect.top - overlayRect.top; + const paddingTop = spinnerRect.top - overlayRect.top; + const paddingLeft = spinnerRect.left - overlayRect.left; - expect(distance).to.be.closeTo(110, 10); // 110px is overlay padding-top + expect(paddingTop).to.be.closeTo(expectedPadding, 10); + expect(paddingLeft).to.be.closeTo(16, 4); + }); }); }); }); From f2cc2451ff028882718f1675b192844f44666412 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 09:49:15 +0700 Subject: [PATCH 07/11] Add loading with label and background color black. --- components/table.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index 898dcd90..4cb3ff79 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -584,12 +584,7 @@ function Table({ display: flex; align-items: start; padding-left: 16px; - padding-top: ${(() => { - if (showPagination && hasRowGroup) return "152px"; - if (showPagination || hasRowGroup) return "140px"; - if (actions || searchable) return "126px"; - return "60px"; - })()}; + padding-top: 16px; backdrop-filter: blur(0.5px); background-color: rgba(255, 255, 255, 0.6); @@ -598,7 +593,20 @@ function Table({ show={isLoading} onClick="preventDefault" > - + )} From 70ffba28fc67274884d2e6d37b859f0a3833ef9e Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 10:08:22 +0700 Subject: [PATCH 08/11] Update the style inside on the table --- components/table.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/table.tsx b/components/table.tsx index 4cb3ff79..f6983b48 100644 --- a/components/table.tsx +++ b/components/table.tsx @@ -583,8 +583,8 @@ function Table({ self: css` display: flex; align-items: start; - padding-left: 16px; - padding-top: 16px; + padding-left: 10px; + padding-top: 10px; backdrop-filter: blur(0.5px); background-color: rgba(255, 255, 255, 0.6); @@ -598,8 +598,9 @@ function Table({ containerStyle: css` background-color: black; border-radius: 20px; - opacity: 0.7; + opacity: 0.8; color: white; + padding: 4px; padding-right: 8px; `, }} From f3107bed4c3e4d9a7d2b354fb9e1ceba258bff5d Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 10:08:29 +0700 Subject: [PATCH 09/11] Add aria label on spinner. --- components/loading-spinner.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/loading-spinner.tsx b/components/loading-spinner.tsx index 26ce375d..6bc5bc55 100644 --- a/components/loading-spinner.tsx +++ b/components/loading-spinner.tsx @@ -21,7 +21,11 @@ function LoadingSpinner({ styles, }: LoadingSpinnerProps) { return ( - + Date: Mon, 16 Mar 2026 10:09:25 +0700 Subject: [PATCH 10/11] Ensure the test for position, color, padding in the isLoading condition. --- test/component/table.cy.tsx | 73 +++++++++++-------------------------- 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index b1bd1e92..b9da09e4 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -114,64 +114,35 @@ describe("Table", () => { ); } context("isLoading", () => { - const scenarios = [ - { - description: "isLoading only", - props: { isLoading: true }, - expectedPadding: 60, - }, - { - description: "isLoading with actions", - props: { isLoading: true, actions: [{ caption: "Test" }] }, - expectedPadding: 126, - }, - { - description: "isLoading with showPagination", - props: { isLoading: true, showPagination: true }, - expectedPadding: 140, - }, - { - description: "isLoading with showPagination + hasRowGroup", - props: { - isLoading: true, - showPagination: true, - labels: { pageNumberText: "12" }, - hasRowGroup: true, - }, - expectedPadding: 152, - }, - { - description: "isLoading with hasRowGroup", - props: { isLoading: true, hasRowGroup: true }, - expectedPadding: 140, - }, - { - description: "isLoading with searchable", - props: { isLoading: true, searchable: true }, - expectedPadding: 126, - }, - ]; - - scenarios.forEach(({ description, props, expectedPadding }) => { - context(`when given ${description}`, () => { - it(`should render spinner with padding-top ~${expectedPadding}px and padding-left 16px`, () => { - cy.mount(); + context(`when given true`, () => { + it(`should render spinner with position padding-top 10px and padding-left 10px`, () => { + cy.mount(); - cy.findByLabelText("overlay-blocker").then(($overlay) => { - const overlayRect = $overlay[0].getBoundingClientRect(); + cy.findByLabelText("overlay-blocker").then(($overlay) => { + const overlayRect = $overlay[0].getBoundingClientRect(); - cy.findByLabelText("circle").then(($spinner) => { - const spinnerRect = $spinner[0].getBoundingClientRect(); + cy.findByLabelText("circle").then(($spinner) => { + const spinnerRect = $spinner[0].getBoundingClientRect(); - const paddingTop = spinnerRect.top - overlayRect.top; - const paddingLeft = spinnerRect.left - overlayRect.left; + const paddingTop = spinnerRect.top - overlayRect.top; + const paddingLeft = spinnerRect.left - overlayRect.left; - expect(paddingTop).to.be.closeTo(expectedPadding, 10); - expect(paddingLeft).to.be.closeTo(16, 4); - }); + expect(paddingTop).to.be.closeTo(10, 2); + expect(paddingLeft).to.be.closeTo(10, 2); }); }); }); + + it(`should render spinner with padding 4px and with caption loading`, () => { + cy.mount(); + + cy.findByText("Loading").should("exist"); + + cy.findByLabelText("loading-spinner") + .should("have.css", "background-color", "rgb(0, 0, 0)") + .and("have.css", "opacity", "0.8") + .and("have.css", "padding", "4px 8px 4px 4px"); + }); }); }); From cf37bf438e0310bc4743d5d0be43f5e71ba95e71 Mon Sep 17 00:00:00 2001 From: Alimnfl Date: Mon, 16 Mar 2026 10:11:40 +0700 Subject: [PATCH 11/11] Update the sentence on the table. --- test/component/table.cy.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/component/table.cy.tsx b/test/component/table.cy.tsx index b9da09e4..24a44425 100644 --- a/test/component/table.cy.tsx +++ b/test/component/table.cy.tsx @@ -114,8 +114,8 @@ describe("Table", () => { ); } context("isLoading", () => { - context(`when given true`, () => { - it(`should render spinner with position padding-top 10px and padding-left 10px`, () => { + context("when given true", () => { + it("renders spinner positioned ~10px from the top and ~10px from the left", () => { cy.mount(); cy.findByLabelText("overlay-blocker").then(($overlay) => { @@ -133,7 +133,7 @@ describe("Table", () => { }); }); - it(`should render spinner with padding 4px and with caption loading`, () => { + it("renders spinner with padding 4px and with caption loading", () => { cy.mount(); cy.findByText("Loading").should("exist");