@hexclave/dashboard-ui-components 1.0.48 → 1.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/button.d.ts +4 -4
- package/dist/components/data-grid/data-grid.js +7 -5
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/data-grid.test.js +36 -3
- package/dist/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/dashboard-ui-components.global.js +49 -47
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/data-grid-AJi1TNDa.d.ts.map +1 -1
- package/dist/esm/components/button.d.ts +4 -4
- package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js +7 -5
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.test.js +36 -3
- package/dist/esm/components/data-grid/data-grid.test.js.map +1 -1
- package/package.json +3 -3
- package/src/components/data-grid/data-grid.test.tsx +46 -3
- package/src/components/data-grid/data-grid.tsx +19 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid.test.js","names":["DataGrid","vi"],"sources":["../../../src/components/data-grid/data-grid.test.tsx"],"sourcesContent":["// @vitest-environment jsdom\n\nimport { act, cleanup, fireEvent, render, waitFor } from \"@testing-library/react\";\nimport { useMemo, useState } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n createDefaultDataGridState,\n DataGrid,\n isDataGridInteractiveRowClickTarget,\n useDataSource,\n type DataGridColumnDef,\n type DataGridDataSource,\n type DataGridProps,\n} from \"./index\";\n\ntype Row = {\n id: string,\n name: string,\n};\n\nconst columns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 160,\n minWidth: 80,\n sortable: true,\n type: \"string\",\n },\n];\n\nconst wideColumns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 320,\n minWidth: 80,\n type: \"string\",\n },\n {\n id: \"email\",\n header: \"Email\",\n accessor: (row) => `${row.name.toLowerCase().replaceAll(\" \", \".\")}@example.com`,\n width: 420,\n minWidth: 80,\n type: \"string\",\n },\n];\n\ntype ObserverRecord = {\n options?: IntersectionObserverInit,\n};\n\nlet intersectionObserverRecords: ObserverRecord[] = [];\nlet intersectionObserverInstances: MockIntersectionObserver[] = [];\n\nclass MockIntersectionObserver implements IntersectionObserver {\n readonly root: Element | Document | null;\n readonly rootMargin: string;\n readonly scrollMargin: string;\n readonly thresholds: ReadonlyArray<number>;\n private readonly callback: IntersectionObserverCallback;\n private readonly record: ObserverRecord;\n\n constructor(\n callback: IntersectionObserverCallback,\n options?: IntersectionObserverInit,\n ) {\n this.callback = callback;\n this.root = options?.root ?? null;\n this.rootMargin = options?.rootMargin ?? \"\";\n this.scrollMargin = \"\";\n this.thresholds = Array.isArray(options?.threshold)\n ? options.threshold\n : [options?.threshold ?? 0];\n this.record = { options };\n intersectionObserverRecords.push(this.record);\n intersectionObserverInstances.push(this);\n }\n\n disconnect() {}\n observe() {}\n takeRecords(): IntersectionObserverEntry[] {\n return [];\n }\n unobserve() {}\n\n trigger(entry: Partial<IntersectionObserverEntry> = {}) {\n this.callback(\n [\n {\n boundingClientRect: {} as DOMRectReadOnly,\n intersectionRatio: 1,\n intersectionRect: {} as DOMRectReadOnly,\n isIntersecting: true,\n rootBounds: null,\n target: document.createElement(\"div\"),\n time: 0,\n ...entry,\n },\n ],\n this,\n );\n }\n}\n\nclass MockResizeObserver implements ResizeObserver {\n private readonly callback: ResizeObserverCallback;\n\n constructor(callback: ResizeObserverCallback) {\n this.callback = callback;\n }\n\n disconnect() {}\n observe(target: Element) {\n const el = target instanceof HTMLElement ? target : null;\n const parentWidth = el?.parentElement instanceof HTMLElement ? el.parentElement.clientWidth : 0;\n const width = (el?.clientWidth ?? 0) > 0 ? (el?.clientWidth ?? 320) : parentWidth > 0 ? parentWidth : 320;\n const height = (el?.clientHeight ?? 0) > 0 ? (el?.clientHeight ?? 400) : 400;\n this.callback(\n [\n {\n target,\n contentRect: {\n x: 0,\n y: 0,\n width,\n height,\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n toJSON() {\n return this;\n },\n } as DOMRectReadOnly,\n borderBoxSize: [],\n contentBoxSize: [],\n devicePixelContentBoxSize: [],\n },\n ],\n this,\n );\n }\n unobserve() {}\n}\n\nfunction DataGridHarness(props: { fillHeight?: boolean }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore\n fillHeight={props.fillHeight}\n />\n </div>\n );\n}\n\nfunction InteractiveDataGridHarness(props: {\n onSortChange?: DataGridProps<Row>[\"onSortChange\"],\n onSelectionChange?: DataGridProps<Row>[\"onSelectionChange\"],\n}) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n selectionMode=\"multiple\"\n onSortChange={props.onSortChange}\n onSelectionChange={props.onSelectionChange}\n />\n );\n}\n\nfunction WideDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(wideColumns));\n\n return (\n <div style={{ width: 320 }}>\n <DataGrid<Row>\n columns={wideColumns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"observes against the grid body when the grid owns vertical scrolling\", async () => {\n const { container } = render(<DataGridHarness fillHeight />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n it(\"falls back to the viewport when the page owns vertical scrolling\", async () => {\n render(<DataGridHarness fillHeight={false} />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n expect(intersectionObserverRecords.at(-1)?.options?.root ?? null).toBeNull();\n });\n});\n\n// Drives a real `useDataSource` infinite-scroll grid whose data source\n// always reports `hasMore: true`, mirroring a project with a long\n// transaction / customer history (e.g. the transactions table and customers\n// tab). Used to prove the sentinel doesn't thrash its IntersectionObserver.\nfunction InfiniteScrollLoadMoreHarness({ onFetch }: { onFetch: () => void }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n const dataSource = useMemo<DataGridDataSource<Row>>(\n () => {\n let page = 0;\n return async function* () {\n onFetch();\n const current = page++;\n yield {\n rows: [{ id: `row-${current}`, name: `Row ${current}` }],\n hasMore: true,\n nextCursor: `cursor-${current}`,\n };\n };\n },\n [onFetch],\n );\n\n const gridData = useDataSource<Row>({\n dataSource,\n columns,\n getRowId: (row) => row.id,\n sorting: state.sorting,\n quickSearch: state.quickSearch,\n pagination: state.pagination,\n paginationMode: \"infinite\",\n });\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={gridData.rows}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore={gridData.hasMore}\n isLoading={gridData.isLoading}\n isLoadingMore={gridData.isLoadingMore}\n onLoadMore={gridData.loadMore}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer stability\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n intersectionObserverInstances = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n // Regression: the sentinel used to re-create its IntersectionObserver every\n // time the `onLoadMore` callback changed identity (which happens on every\n // `isLoadingMore` / `hasMore` toggle). A freshly-created observer re-reports\n // the sentinel's current intersection state, so a sentinel that stays in\n // view fires `onLoadMore` again after every page — auto-loading the entire\n // history back-to-back and OOM-crashing the tab (\"Aw snap\") on large\n // datasets. The observer must stay stable across load-more cycles.\n it(\"does not re-create the observer on load-more cycles\", async () => {\n const onFetch = vi.fn();\n render(<InfiniteScrollLoadMoreHarness onFetch={onFetch} />);\n\n // Initial page load, after which the sentinel (and its observer) mounts.\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(1));\n await waitFor(() => expect(intersectionObserverInstances.length).toBeGreaterThan(0));\n\n const observersBeforeLoadMore = intersectionObserverInstances.length;\n\n // Simulate the sentinel scrolling into view exactly once.\n await act(async () => {\n intersectionObserverInstances.at(-1)?.trigger();\n await Promise.resolve();\n });\n\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(2));\n\n // A single scroll-in must trigger a single fetch, without spawning new\n // observers — otherwise each new observer would re-fire and runaway.\n expect(intersectionObserverInstances.length).toBe(observersBeforeLoadMore);\n });\n});\n\ndescribe(\"DataGrid controlled callbacks\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"fires onSortChange from the current controlled sort state\", () => {\n const onSortChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSortChange={onSortChange} />);\n\n fireEvent.click(getByRole(\"columnheader\", { name: /name/i }));\n\n expect(onSortChange).toHaveBeenCalledTimes(1);\n expect(onSortChange).toHaveBeenCalledWith([{ columnId: \"name\", direction: \"asc\" }]);\n });\n\n it(\"fires onSelectionChange when selecting all rows\", () => {\n const onSelectionChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSelectionChange={onSelectionChange} />);\n\n fireEvent.click(getByRole(\"checkbox\", { name: /select all rows/i }));\n\n expect(onSelectionChange).toHaveBeenCalledTimes(1);\n const [selectedIds, selectedRows] = onSelectionChange.mock.calls[0];\n expect([...selectedIds]).toEqual([\"row-1\"]);\n expect(selectedRows).toEqual([{ id: \"row-1\", name: \"Row 1\" }]);\n });\n\n it(\"identifies nested interactive controls as row-click blockers\", () => {\n const cell = document.createElement(\"div\");\n const button = document.createElement(\"button\");\n const label = document.createElement(\"span\");\n label.textContent = \"Open menu\";\n button.append(label);\n cell.append(button);\n\n expect(isDataGridInteractiveRowClickTarget(label.firstChild)).toBe(true);\n expect(isDataGridInteractiveRowClickTarget(cell)).toBe(false);\n });\n});\n\ndescribe(\"DataGrid horizontal scrolling\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n Object.defineProperty(HTMLElement.prototype, \"clientWidth\", {\n configurable: true,\n get() {\n return 320;\n },\n });\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"sizes the sticky clipping layer to the full row width\", () => {\n const { container } = render(<WideDataGridHarness />);\n\n const rowsClip = container.querySelector(\"[data-data-grid-rows-clip]\");\n\n expect(rowsClip).toBeInstanceOf(HTMLElement);\n expect((rowsClip as HTMLElement).style.minWidth).toBe(\"740px\");\n });\n\n it(\"lets the columns popover escape the sticky toolbar bounds\", () => {\n const { container, getByTitle } = render(<WideDataGridHarness />);\n\n fireEvent.click(getByTitle(\"Columns\"));\n\n const stickyChrome = container.querySelector('[role=\"grid\"]')?.firstElementChild;\n expect(stickyChrome).toBeInstanceOf(HTMLElement);\n expect((stickyChrome as HTMLElement).className).toContain(\"overflow-visible\");\n expect(container.textContent).toContain(\"Email\");\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid.test.js","names":["DataGrid","vi"],"sources":["../../../src/components/data-grid/data-grid.test.tsx"],"sourcesContent":["// @vitest-environment jsdom\n\nimport { act, cleanup, fireEvent, render, waitFor } from \"@testing-library/react\";\nimport { useMemo, useState } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n createDefaultDataGridState,\n DataGrid,\n isDataGridInteractiveRowClickTarget,\n useDataSource,\n type DataGridColumnDef,\n type DataGridDataSource,\n type DataGridProps,\n} from \"./index\";\n\ntype Row = {\n id: string,\n name: string,\n};\n\nconst columns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 160,\n minWidth: 80,\n sortable: true,\n type: \"string\",\n },\n];\n\nconst wideColumns: DataGridColumnDef<Row>[] = [\n {\n id: \"name\",\n header: \"Name\",\n accessor: (row) => row.name,\n width: 320,\n minWidth: 80,\n type: \"string\",\n },\n {\n id: \"email\",\n header: \"Email\",\n accessor: (row) => `${row.name.toLowerCase().replaceAll(\" \", \".\")}@example.com`,\n width: 420,\n minWidth: 80,\n type: \"string\",\n },\n];\n\ntype ObserverRecord = {\n options?: IntersectionObserverInit,\n};\n\nlet intersectionObserverRecords: ObserverRecord[] = [];\nlet intersectionObserverInstances: MockIntersectionObserver[] = [];\n\nclass MockIntersectionObserver implements IntersectionObserver {\n readonly root: Element | Document | null;\n readonly rootMargin: string;\n readonly scrollMargin: string;\n readonly thresholds: ReadonlyArray<number>;\n private readonly callback: IntersectionObserverCallback;\n private readonly record: ObserverRecord;\n\n constructor(\n callback: IntersectionObserverCallback,\n options?: IntersectionObserverInit,\n ) {\n this.callback = callback;\n this.root = options?.root ?? null;\n this.rootMargin = options?.rootMargin ?? \"\";\n this.scrollMargin = \"\";\n this.thresholds = Array.isArray(options?.threshold)\n ? options.threshold\n : [options?.threshold ?? 0];\n this.record = { options };\n intersectionObserverRecords.push(this.record);\n intersectionObserverInstances.push(this);\n }\n\n disconnect() {}\n observe() {}\n takeRecords(): IntersectionObserverEntry[] {\n return [];\n }\n unobserve() {}\n\n trigger(entry: Partial<IntersectionObserverEntry> = {}) {\n this.callback(\n [\n {\n boundingClientRect: {} as DOMRectReadOnly,\n intersectionRatio: 1,\n intersectionRect: {} as DOMRectReadOnly,\n isIntersecting: true,\n rootBounds: null,\n target: document.createElement(\"div\"),\n time: 0,\n ...entry,\n },\n ],\n this,\n );\n }\n}\n\nclass MockResizeObserver implements ResizeObserver {\n private readonly callback: ResizeObserverCallback;\n\n constructor(callback: ResizeObserverCallback) {\n this.callback = callback;\n }\n\n disconnect() {}\n observe(target: Element) {\n const el = target instanceof HTMLElement ? target : null;\n const parentWidth = el?.parentElement instanceof HTMLElement ? el.parentElement.clientWidth : 0;\n const width = (el?.clientWidth ?? 0) > 0 ? (el?.clientWidth ?? 320) : parentWidth > 0 ? parentWidth : 320;\n const height = (el?.clientHeight ?? 0) > 0 ? (el?.clientHeight ?? 400) : 400;\n this.callback(\n [\n {\n target,\n contentRect: {\n x: 0,\n y: 0,\n width,\n height,\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n toJSON() {\n return this;\n },\n } as DOMRectReadOnly,\n borderBoxSize: [],\n contentBoxSize: [],\n devicePixelContentBoxSize: [],\n },\n ],\n this,\n );\n }\n unobserve() {}\n}\n\nfunction DataGridHarness(props: { fillHeight?: boolean }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore\n fillHeight={props.fillHeight}\n />\n </div>\n );\n}\n\nfunction PaginatedDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"paginated\"\n fillHeight={false}\n />\n </div>\n );\n}\n\nfunction InteractiveDataGridHarness(props: {\n onSortChange?: DataGridProps<Row>[\"onSortChange\"],\n onSelectionChange?: DataGridProps<Row>[\"onSelectionChange\"],\n}) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n\n return (\n <DataGrid<Row>\n columns={columns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n selectionMode=\"multiple\"\n onSortChange={props.onSortChange}\n onSelectionChange={props.onSelectionChange}\n />\n );\n}\n\nfunction WideDataGridHarness() {\n const [state, setState] = useState(() => createDefaultDataGridState(wideColumns));\n\n return (\n <div style={{ width: 320 }}>\n <DataGrid<Row>\n columns={wideColumns}\n rows={[{ id: \"row-1\", name: \"Row 1\" }]}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"observes against the grid body when the grid owns vertical scrolling\", async () => {\n const { container } = render(<DataGridHarness fillHeight />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n // Regression: an infinite grid left unbounded (`fillHeight={false}`, no `maxHeight`) used to\n // grow its scroll container to fit every loaded row, which defeats virtualization (the\n // virtualizer measures the container as fully visible and mounts every row) and OOMs the tab on\n // large datasets. Such grids now fall back to a default `maxHeight`, so the grid owns its own\n // bounded scroll container and observes against it rather than the viewport.\n it(\"bounds an unbounded infinite grid and observes against its own scroll container\", async () => {\n const { container } = render(<DataGridHarness fillHeight={false} />);\n\n await waitFor(() => {\n expect(intersectionObserverRecords.length).toBeGreaterThan(0);\n });\n\n const grid = container.querySelector('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n const scrollContainer = grid?.children.item(1);\n\n expect(intersectionObserverRecords.at(-1)?.options?.root).toBe(scrollContainer);\n });\n\n it(\"applies a default maxHeight to an otherwise-unbounded infinite grid\", () => {\n const { container } = render(<DataGridHarness fillHeight={false} />);\n\n const grid = container.querySelector<HTMLElement>('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n expect(grid?.style.maxHeight).toBe(\"calc(100dvh - 16rem)\");\n });\n\n it(\"does not force a maxHeight onto a paginated grid\", () => {\n const { container } = render(<PaginatedDataGridHarness />);\n\n const grid = container.querySelector<HTMLElement>('[role=\"grid\"]');\n expect(grid).not.toBeNull();\n expect(grid?.style.maxHeight).toBe(\"\");\n });\n});\n\n// Drives a real `useDataSource` infinite-scroll grid whose data source\n// always reports `hasMore: true`, mirroring a project with a long\n// transaction / customer history (e.g. the transactions table and customers\n// tab). Used to prove the sentinel doesn't thrash its IntersectionObserver.\nfunction InfiniteScrollLoadMoreHarness({ onFetch }: { onFetch: () => void }) {\n const [state, setState] = useState(() => createDefaultDataGridState(columns));\n const dataSource = useMemo<DataGridDataSource<Row>>(\n () => {\n let page = 0;\n return async function* () {\n onFetch();\n const current = page++;\n yield {\n rows: [{ id: `row-${current}`, name: `Row ${current}` }],\n hasMore: true,\n nextCursor: `cursor-${current}`,\n };\n };\n },\n [onFetch],\n );\n\n const gridData = useDataSource<Row>({\n dataSource,\n columns,\n getRowId: (row) => row.id,\n sorting: state.sorting,\n quickSearch: state.quickSearch,\n pagination: state.pagination,\n paginationMode: \"infinite\",\n });\n\n return (\n <div style={{ height: 400 }}>\n <DataGrid<Row>\n columns={columns}\n rows={gridData.rows}\n getRowId={(row) => row.id}\n state={state}\n onChange={setState}\n paginationMode=\"infinite\"\n hasMore={gridData.hasMore}\n isLoading={gridData.isLoading}\n isLoadingMore={gridData.isLoadingMore}\n onLoadMore={gridData.loadMore}\n />\n </div>\n );\n}\n\ndescribe(\"DataGrid infinite scroll observer stability\", () => {\n beforeEach(() => {\n intersectionObserverRecords = [];\n intersectionObserverInstances = [];\n\n vi.stubGlobal(\"IntersectionObserver\", MockIntersectionObserver);\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n // Regression: the sentinel used to re-create its IntersectionObserver every\n // time the `onLoadMore` callback changed identity (which happens on every\n // `isLoadingMore` / `hasMore` toggle). A freshly-created observer re-reports\n // the sentinel's current intersection state, so a sentinel that stays in\n // view fires `onLoadMore` again after every page — auto-loading the entire\n // history back-to-back and OOM-crashing the tab (\"Aw snap\") on large\n // datasets. The observer must stay stable across load-more cycles.\n it(\"does not re-create the observer on load-more cycles\", async () => {\n const onFetch = vi.fn();\n render(<InfiniteScrollLoadMoreHarness onFetch={onFetch} />);\n\n // Initial page load, after which the sentinel (and its observer) mounts.\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(1));\n await waitFor(() => expect(intersectionObserverInstances.length).toBeGreaterThan(0));\n\n const observersBeforeLoadMore = intersectionObserverInstances.length;\n\n // Simulate the sentinel scrolling into view exactly once.\n await act(async () => {\n intersectionObserverInstances.at(-1)?.trigger();\n await Promise.resolve();\n });\n\n await waitFor(() => expect(onFetch).toHaveBeenCalledTimes(2));\n\n // A single scroll-in must trigger a single fetch, without spawning new\n // observers — otherwise each new observer would re-fire and runaway.\n expect(intersectionObserverInstances.length).toBe(observersBeforeLoadMore);\n });\n});\n\ndescribe(\"DataGrid controlled callbacks\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"fires onSortChange from the current controlled sort state\", () => {\n const onSortChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSortChange={onSortChange} />);\n\n fireEvent.click(getByRole(\"columnheader\", { name: /name/i }));\n\n expect(onSortChange).toHaveBeenCalledTimes(1);\n expect(onSortChange).toHaveBeenCalledWith([{ columnId: \"name\", direction: \"asc\" }]);\n });\n\n it(\"fires onSelectionChange when selecting all rows\", () => {\n const onSelectionChange = vi.fn();\n const { getByRole } = render(<InteractiveDataGridHarness onSelectionChange={onSelectionChange} />);\n\n fireEvent.click(getByRole(\"checkbox\", { name: /select all rows/i }));\n\n expect(onSelectionChange).toHaveBeenCalledTimes(1);\n const [selectedIds, selectedRows] = onSelectionChange.mock.calls[0];\n expect([...selectedIds]).toEqual([\"row-1\"]);\n expect(selectedRows).toEqual([{ id: \"row-1\", name: \"Row 1\" }]);\n });\n\n it(\"identifies nested interactive controls as row-click blockers\", () => {\n const cell = document.createElement(\"div\");\n const button = document.createElement(\"button\");\n const label = document.createElement(\"span\");\n label.textContent = \"Open menu\";\n button.append(label);\n cell.append(button);\n\n expect(isDataGridInteractiveRowClickTarget(label.firstChild)).toBe(true);\n expect(isDataGridInteractiveRowClickTarget(cell)).toBe(false);\n });\n});\n\ndescribe(\"DataGrid horizontal scrolling\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n Object.defineProperty(HTMLElement.prototype, \"clientWidth\", {\n configurable: true,\n get() {\n return 320;\n },\n });\n vi.spyOn(HTMLElement.prototype, \"getBoundingClientRect\").mockImplementation(\n function getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: 320,\n height: 44,\n top: 0,\n left: 0,\n right: 320,\n bottom: 44,\n toJSON() {\n return this;\n },\n } as DOMRect;\n },\n );\n Object.defineProperty(HTMLElement.prototype, \"clientHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n Object.defineProperty(HTMLElement.prototype, \"scrollHeight\", {\n configurable: true,\n get() {\n return 400;\n },\n });\n });\n\n afterEach(() => {\n cleanup();\n vi.restoreAllMocks();\n vi.unstubAllGlobals();\n });\n\n it(\"sizes the sticky clipping layer to the full row width\", () => {\n const { container } = render(<WideDataGridHarness />);\n\n const rowsClip = container.querySelector(\"[data-data-grid-rows-clip]\");\n\n expect(rowsClip).toBeInstanceOf(HTMLElement);\n expect((rowsClip as HTMLElement).style.minWidth).toBe(\"740px\");\n });\n\n it(\"lets the columns popover escape the sticky toolbar bounds\", () => {\n const { container, getByTitle } = render(<WideDataGridHarness />);\n\n fireEvent.click(getByTitle(\"Columns\"));\n\n const stickyChrome = container.querySelector('[role=\"grid\"]')?.firstElementChild;\n expect(stickyChrome).toBeInstanceOf(HTMLElement);\n expect((stickyChrome as HTMLElement).className).toContain(\"overflow-visible\");\n expect(container.textContent).toContain(\"Email\");\n });\n});\n"],"mappings":"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"}
|
|
@@ -4461,49 +4461,6 @@ This is likely an error in Hexclave. Please make sure you are running the newest
|
|
|
4461
4461
|
return Object.assign(Result.error(new RetryError(errors)), { attempts: totalAttempts });
|
|
4462
4462
|
}
|
|
4463
4463
|
|
|
4464
|
-
// ../shared/dist/esm/utils/bytes.js
|
|
4465
|
-
function decodeBase64(input) {
|
|
4466
|
-
return new Uint8Array(atob(input).split("").map((char) => char.charCodeAt(0)));
|
|
4467
|
-
}
|
|
4468
|
-
function isBase64(input) {
|
|
4469
|
-
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(input);
|
|
4470
|
-
}
|
|
4471
|
-
|
|
4472
|
-
// ../shared/dist/esm/utils/urls.js
|
|
4473
|
-
function createUrlIfValid(...args) {
|
|
4474
|
-
try {
|
|
4475
|
-
return new URL(...args);
|
|
4476
|
-
} catch (e40) {
|
|
4477
|
-
return null;
|
|
4478
|
-
}
|
|
4479
|
-
}
|
|
4480
|
-
function isValidUrl(url) {
|
|
4481
|
-
return !!createUrlIfValid(url);
|
|
4482
|
-
}
|
|
4483
|
-
function isValidHostname(hostname) {
|
|
4484
|
-
if (!hostname || hostname.startsWith(".") || hostname.endsWith(".") || hostname.includes("..")) return false;
|
|
4485
|
-
const url = createUrlIfValid(`https://${hostname}`);
|
|
4486
|
-
if (!url) return false;
|
|
4487
|
-
return url.hostname === hostname;
|
|
4488
|
-
}
|
|
4489
|
-
function isValidHostnameWithWildcards(hostname) {
|
|
4490
|
-
if (!hostname) return false;
|
|
4491
|
-
if (!hostname.includes("*")) return isValidHostname(hostname);
|
|
4492
|
-
if (hostname.startsWith(".") || hostname.endsWith(".")) return false;
|
|
4493
|
-
if (hostname.includes("..")) return false;
|
|
4494
|
-
const testHostname = hostname.replace(/\*+/g, "wildcard");
|
|
4495
|
-
if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) return false;
|
|
4496
|
-
const segments = hostname.split(/\*+/);
|
|
4497
|
-
for (let i = 0; i < segments.length; i++) {
|
|
4498
|
-
const segment = segments[i];
|
|
4499
|
-
if (segment === "") continue;
|
|
4500
|
-
if (i === 0 && segment.startsWith(".")) return false;
|
|
4501
|
-
if (i === segments.length - 1 && segment.endsWith(".")) return false;
|
|
4502
|
-
if (segment.includes("..")) return false;
|
|
4503
|
-
}
|
|
4504
|
-
return true;
|
|
4505
|
-
}
|
|
4506
|
-
|
|
4507
4464
|
// ../shared/dist/esm/known-errors.js
|
|
4508
4465
|
var KnownError = class extends StatusError {
|
|
4509
4466
|
constructor(statusCode, humanReadableMessage, details) {
|
|
@@ -5260,6 +5217,49 @@ This is likely an error in Hexclave. Please make sure you are running the newest
|
|
|
5260
5217
|
knownErrorCodes.add(KnownError2.errorCode);
|
|
5261
5218
|
}
|
|
5262
5219
|
|
|
5220
|
+
// ../shared/dist/esm/utils/bytes.js
|
|
5221
|
+
function decodeBase64(input) {
|
|
5222
|
+
return new Uint8Array(atob(input).split("").map((char) => char.charCodeAt(0)));
|
|
5223
|
+
}
|
|
5224
|
+
function isBase64(input) {
|
|
5225
|
+
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(input);
|
|
5226
|
+
}
|
|
5227
|
+
|
|
5228
|
+
// ../shared/dist/esm/utils/urls.js
|
|
5229
|
+
function createUrlIfValid(...args) {
|
|
5230
|
+
try {
|
|
5231
|
+
return new URL(...args);
|
|
5232
|
+
} catch (e40) {
|
|
5233
|
+
return null;
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
function isValidUrl(url) {
|
|
5237
|
+
return !!createUrlIfValid(url);
|
|
5238
|
+
}
|
|
5239
|
+
function isValidHostname(hostname) {
|
|
5240
|
+
if (!hostname || hostname.startsWith(".") || hostname.endsWith(".") || hostname.includes("..")) return false;
|
|
5241
|
+
const url = createUrlIfValid(`https://${hostname}`);
|
|
5242
|
+
if (!url) return false;
|
|
5243
|
+
return url.hostname === hostname;
|
|
5244
|
+
}
|
|
5245
|
+
function isValidHostnameWithWildcards(hostname) {
|
|
5246
|
+
if (!hostname) return false;
|
|
5247
|
+
if (!hostname.includes("*")) return isValidHostname(hostname);
|
|
5248
|
+
if (hostname.startsWith(".") || hostname.endsWith(".")) return false;
|
|
5249
|
+
if (hostname.includes("..")) return false;
|
|
5250
|
+
const testHostname = hostname.replace(/\*+/g, "wildcard");
|
|
5251
|
+
if (!/^[a-zA-Z0-9.-]+$/.test(testHostname)) return false;
|
|
5252
|
+
const segments = hostname.split(/\*+/);
|
|
5253
|
+
for (let i = 0; i < segments.length; i++) {
|
|
5254
|
+
const segment = segments[i];
|
|
5255
|
+
if (segment === "") continue;
|
|
5256
|
+
if (i === 0 && segment.startsWith(".")) return false;
|
|
5257
|
+
if (i === segments.length - 1 && segment.endsWith(".")) return false;
|
|
5258
|
+
if (segment.includes("..")) return false;
|
|
5259
|
+
}
|
|
5260
|
+
return true;
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5263
5263
|
// ../../node_modules/.pnpm/yup@1.7.1/node_modules/yup/index.esm.js
|
|
5264
5264
|
var import_property_expr = __toESM(require_property_expr());
|
|
5265
5265
|
var import_tiny_case = __toESM(require_tiny_case());
|
|
@@ -23005,6 +23005,7 @@ ${colorConfig.map(([key, itemConfig]) => {
|
|
|
23005
23005
|
}
|
|
23006
23006
|
|
|
23007
23007
|
// src/components/data-grid/data-grid.tsx
|
|
23008
|
+
var DEFAULT_INFINITE_MAX_HEIGHT = "calc(100dvh - 16rem)";
|
|
23008
23009
|
function getEventTargetElement(target) {
|
|
23009
23010
|
if (target instanceof Element) return target;
|
|
23010
23011
|
if (target instanceof Node) return target.parentElement;
|
|
@@ -23705,7 +23706,8 @@ ${colorConfig.map(([key, itemConfig]) => {
|
|
|
23705
23706
|
);
|
|
23706
23707
|
const allSelected = rowIds.length > 0 && rowIds.every((id) => state.selection.selectedIds.has(id));
|
|
23707
23708
|
const someSelected = !allSelected && rowIds.some((id) => state.selection.selectedIds.has(id));
|
|
23708
|
-
const
|
|
23709
|
+
const effectiveMaxHeight = maxHeight ?? (paginationMode === "infinite" && !fillHeight ? DEFAULT_INFINITE_MAX_HEIGHT : void 0);
|
|
23710
|
+
const infiniteScrollRootRef = paginationMode === "infinite" && (fillHeight || effectiveMaxHeight != null) ? scrollContainerRef : void 0;
|
|
23709
23711
|
const headers = (0, import_react35.useMemo)(
|
|
23710
23712
|
() => table.getHeaderGroups()[0]?.headers.filter((h) => visibleColumns.some((c4) => c4.id === h.column.id)) ?? [],
|
|
23711
23713
|
[table, visibleColumns]
|
|
@@ -23715,7 +23717,7 @@ ${colorConfig.map(([key, itemConfig]) => {
|
|
|
23715
23717
|
for (const h of headers) m5.set(h.column.id, h);
|
|
23716
23718
|
return m5;
|
|
23717
23719
|
}, [headers]);
|
|
23718
|
-
const isBounded = fillHeight ||
|
|
23720
|
+
const isBounded = fillHeight || effectiveMaxHeight != null;
|
|
23719
23721
|
return /* @__PURE__ */ jsxs(Fragment24, { children: [
|
|
23720
23722
|
/* @__PURE__ */ jsx(
|
|
23721
23723
|
DataGridExportDialog,
|
|
@@ -23738,7 +23740,7 @@ ${colorConfig.map(([key, itemConfig]) => {
|
|
|
23738
23740
|
isBounded && "overflow-hidden",
|
|
23739
23741
|
className
|
|
23740
23742
|
),
|
|
23741
|
-
style:
|
|
23743
|
+
style: effectiveMaxHeight != null ? { ...cssVars, maxHeight: effectiveMaxHeight } : cssVars,
|
|
23742
23744
|
role: "grid",
|
|
23743
23745
|
"aria-rowcount": totalRowCount ?? rows.length,
|
|
23744
23746
|
"aria-colcount": visibleColumns.length,
|
|
@@ -23748,7 +23750,7 @@ ${colorConfig.map(([key, itemConfig]) => {
|
|
|
23748
23750
|
{
|
|
23749
23751
|
ref: stickyChromeRef,
|
|
23750
23752
|
className: "sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl",
|
|
23751
|
-
style: { top: stickyTop ?? (
|
|
23753
|
+
style: { top: stickyTop ?? (effectiveMaxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") },
|
|
23752
23754
|
children: [
|
|
23753
23755
|
toolbar !== false && /* @__PURE__ */ jsx("div", { className: "relative bg-transparent", children: toolbar ? toolbar(toolbarCtx) : /* @__PURE__ */ jsx(
|
|
23754
23756
|
DataGridToolbar,
|