Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce @fluentui-contrib/react-data-grid-react-window-grid #41

Merged
merged 35 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f8dc2d8
New react-data-grid-react-window-grid uses FixedSizeGrid of react-win…
Oct 16, 2023
7c23f7e
add virtualized header(horizontal list) and stick header scroll with …
Oct 17, 2023
f072202
clean code
Oct 17, 2023
55fbacb
add back dataGridContextValue to CellRenderer of HeaderRow; rename it…
Oct 18, 2023
cecb836
minor clean unused code
Oct 18, 2023
14e808b
add aria-colindex and aria-rowindex to storybook sample
Oct 18, 2023
075b42b
Move sticky header into Body and HeaderRow, and use RowHeaderContextP…
Oct 19, 2023
f8912e2
update readme
Oct 19, 2023
b1cded4
fix build; fix with prettier: yarn nx format
Oct 19, 2023
3299110
clean cide
Oct 19, 2023
6eb1c98
fix typing
Oct 19, 2023
92497da
add dependencies
Oct 20, 2023
032ea3b
clean code
Oct 20, 2023
1814e4f
fix format
Oct 23, 2023
7c1856e
remove reference ForwardRefComponent as it was internally fluentui used
FengQiMS Oct 31, 2023
4744bb4
remove reference ForwardRefComponent
FengQiMS Oct 31, 2023
8425690
remove null check as already has one
FengQiMS Oct 31, 2023
4358af8
remove unused param
FengQiMS Oct 31, 2023
bf86126
update peer depenedency version
Oct 31, 2023
52ecd08
resolve comments minor improve
Oct 31, 2023
df3982d
recompose DataGridCell and add row/col index context to move aria-col…
Oct 31, 2023
a0e2633
fix format
Oct 31, 2023
07960e4
update constant naming style
FengQiMS Nov 8, 2023
9fb83a7
fix last commit
Nov 8, 2023
da9f6da
passing null in renderRow function as not used
Nov 8, 2023
420a805
export DataGridHeaderRowProps and HeaderCellRenderer
Nov 8, 2023
bf7c0cb
make header list ref context internal
Nov 8, 2023
6f4b7af
Fix navigate with keyboard arrow right does not scroll in body: use s…
Nov 10, 2023
f65a6ed
split columnIndexContext and rowIndexContext
Nov 10, 2023
4ef2c43
reuse ColumnIndexContext in header to set aria-colIndex internally
Nov 10, 2023
86e4b4a
update readme
Nov 10, 2023
467af86
update comments
Nov 10, 2023
f2e6c68
Merge branch 'main' into usr/fengqi/datagrid-2dvirtualization
ling1726 Nov 13, 2023
e16b345
formatting fixes
ling1726 Nov 13, 2023
27617a0
update CODEOWNERS
ling1726 Nov 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ packages/react-chat/ @microsoft/teams-prg
packages/react-data-grid-react-window/ @microsoft/teams-prg
packages/react-shadow/ @microsoft/teams-prg
packages/nx-plugin/ @microsoft/teams-prg
packages/react-data-grid-react-window-grid/ @microsoft/ms-fabric

#### Build/Infra
/.github/ @microsoft/teams-prg
Expand Down
24 changes: 24 additions & 0 deletions packages/react-data-grid-react-window-grid/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["stories/**/*.tsx", "stories/**/*.ts"],
"rules": {
"@nx/enforce-module-boundaries": "off"
}
}
]
}
26 changes: 26 additions & 0 deletions packages/react-data-grid-react-window-grid/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { StorybookConfig } from '@storybook/react-webpack5';

const config: StorybookConfig = {
stories: ['../stories/**/index.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@nx/react/plugins/storybook',
{
name: '@storybook/addon-storysource',
options: {
loaderOptions: {
injectStoryParameters: true,
},
},
},
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};

export default config;

// To customize your webpack configuration you can use the webpackFinal field.
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
// and https://nx.dev/packages/storybook/documents/custom-builder-configs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';

import { Preview } from '@storybook/react';

import { FluentProvider, webLightTheme } from '@fluentui/react-components';

const preview: Preview = {
decorators: [
(Story) => (
<FluentProvider theme={webLightTheme}>
<Story />
</FluentProvider>
),
],
};

export default preview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"outDir": ""
},
"files": [
"../../../node_modules/@nx/react/typings/styled-jsx.d.ts",
"../../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"../**/*.spec.ts",
"../**/*.spec.js",
"../**/*.spec.tsx",
"../**/*.spec.jsx"
],
"include": [
"../stories/**/*.stories.ts",
"../stories/**/*.stories.js",
"../stories/**/*.stories.jsx",
"../stories/**/*.stories.tsx",
"../stories/**/*.stories.mdx",
"*.ts",
"*.js"
]
}
30 changes: 30 additions & 0 deletions packages/react-data-grid-react-window-grid/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"jsc": {
"target": "es2019",
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"transform": {
"react": {
"runtime": "classic",
"useSpread": true
}
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"sourceMaps": true,
"exclude": [
"jest.config.ts",
".*\\.spec.tsx?$",
".*\\.test.tsx?$",
"./src/jest-setup.ts$",
"./**/jest-setup.ts$",
".*.js$"
],
"$schema": "https://json.schemastore.org/swcrc"
}
28 changes: 28 additions & 0 deletions packages/react-data-grid-react-window-grid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# react-data-grid-react-window-grid

A variant of the Fluent UI [DataGrid](https://react.fluentui.dev/?path=/docs/components-datagrid--default) that is
virtualized 2 dimentionally using [react-window](https://react-window.vercel.app/#/examples/grid/fixed-size).

## Building

Run `nx build react-data-grid-react-window-grid` to build the library.

## What is different from `react-data-grid-react-window`?

- `react-data-grid-react-window` support vertical virtualization using FixedSizeList in react-window
- `react-data-grid-react-window-grid` support 2 dimentional virtualization (including both horizontal and vertical) using FixedSizeGrid in react-window.
- `react-data-grid-react-window-grid` has a virtualized header as well using FixedSizeList in react-window

## `DataGridHeaderRow`

Be aware of `DataGridHeaderRow` is a new component that does not has in fluentui v9 `DataGrid`, it is for supporting header virtualization. And be aware of there is no need to use `DataGridRow` in `react-data-grid-react-window-grid`, as for virtualized grid is using cell to render instead of using row.

## Try it out

```sh
yarn add @fluentui-contrib/react-data-grid-react-window-grid

npm install @fluentui-contrib/react-data-grid-react-window-grid
```

For a full usage example please take a look at [The documentation sample](https://github.com/microsoft/fluentui-contrib/blob/main/packages/react-data-grid-react-window-grid/stories/DataGrid/VirtualizedDataGrid.stories.tsx).
29 changes: 29 additions & 0 deletions packages/react-data-grid-react-window-grid/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* eslint-disable */
import { readFileSync } from 'fs';

// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
);

// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}

// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;

export default {
displayName: 'button',
preset: '../../jest.preset.js',
transform: {
'^.+\\.[tj]sx?$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['js', 'ts', 'tsx', 'html'],
coverageDirectory: '../../coverage/packages/button',
};
15 changes: 15 additions & 0 deletions packages/react-data-grid-react-window-grid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@fluentui-contrib/react-data-grid-react-window-grid",
"version": "0.0.1",
"private": true,
"peerDependencies": {
"@fluentui/react-components": ">=9.30.0 <10.0.0",
"@types/react": ">=16.8.0 <19.0.0",
"@types/react-dom": ">=16.8.0 <19.0.0",
"react": ">=16.8.0 <19.0.0",
"react-dom": ">=16.8.0 <19.0.0"
},
"dependencies": {
"react-window": "^1.8.5"
}
}
68 changes: 68 additions & 0 deletions packages/react-data-grid-react-window-grid/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"name": "react-data-grid-react-window-grid",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/react-data-grid-react-window-grid/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@fluentui-contrib/nx-plugin:build"
},
"publish": {
"command": "node tools/scripts/publish.mjs react-data-grid-react-window-grid {args.ver} {args.tag}",
"dependsOn": ["build"]
},
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": [
"packages/react-data-grid-react-window-grid/**/*.ts",
"packages/react-data-grid-react-window-grid/**/*.tsx"
]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "packages/react-data-grid-react-window-grid/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"type-check": {
"executor": "@fluentui-contrib/nx-plugin:type-check"
},
"storybook": {
"executor": "@nx/storybook:storybook",
"options": {
"port": 4400,
"configDir": "packages/react-data-grid-react-window-grid/.storybook"
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"build-storybook": {
"executor": "@nx/storybook:build",
"outputs": ["{options.outputDir}"],
"options": {
"outputDir": "dist/storybook/react-data-grid-react-window-grid",
"configDir": "packages/react-data-grid-react-window-grid/.storybook"
},
"configurations": {
"ci": {
"quiet": true
}
}
}
},
"tags": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import { useDataGrid_unstable } from './useDataGrid';
import {
renderDataGrid_unstable,
useDataGridStyles_unstable,
useDataGridContextValues_unstable,
DataGridProps,
} from '@fluentui/react-components';
import { HeaderListRefContextProvider } from '../../contexts/headerListRefContext';
import { FixedSizeGrid, FixedSizeList } from 'react-window';
import { BodyRefContextProvider } from '../../contexts/bodyRefContext';

export const DataGrid = React.forwardRef<HTMLDivElement, DataGridProps>(
(props, ref) => {
const headerRef = React.useRef<FixedSizeList>(null);
const bodyRef = React.useRef<FixedSizeGrid>(null);
const state = useDataGrid_unstable(props, ref);

useDataGridStyles_unstable(state);
return (
<HeaderListRefContextProvider value={headerRef}>
<BodyRefContextProvider value={bodyRef}>
{renderDataGrid_unstable(
state,
useDataGridContextValues_unstable(state)
)}
</BodyRefContextProvider>
</HeaderListRefContextProvider>
);
}
);

DataGrid.displayName = 'DataGrid';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './DataGrid';
export * from './useDataGrid';
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import {
useDataGrid_unstable as useBaseState,
DataGridProps,
DataGridState,
} from '@fluentui/react-components';
import { useFluent, useScrollbarWidth } from '@fluentui/react-components';

const TABLE_SELECTION_CELL_WIDTH = 44;

/**
* Create the state required to render DataGrid.
*
* The returned state can be modified with hooks such as useDataGridStyles_unstable,
* before being passed to renderDataGrid_unstable.
*
* @param props - props from this instance of DataGrid
* @param ref - reference to root HTMLElement of DataGrid
*/
export const useDataGrid_unstable = (
props: DataGridProps,
ref: React.Ref<HTMLElement>
): DataGridState => {
const { targetDocument } = useFluent();
const scrollbarWidth = useScrollbarWidth({ targetDocument });

let containerWidthOffset = props.containerWidthOffset;

if (containerWidthOffset === undefined) {
containerWidthOffset = props.selectionMode
? -TABLE_SELECTION_CELL_WIDTH
: 0;
containerWidthOffset -= scrollbarWidth || 0;
}

return useBaseState(
{ ...props, 'aria-rowcount': props.items.length, containerWidthOffset },
ref
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-components';
import { useDataGridBodyStyles_unstable } from './useDataGridBodyStyles.styles';
import { useDataGridBody_unstable } from './useDataGridBody';
import { renderDataGridBody_unstable } from './renderDataGridBody';
import type { DataGridBodyProps } from './DataGridBody.types';

/**
* DataGridBody component
*/
export const DataGridBody: ForwardRefComponent<DataGridBodyProps> &
(<TItem>(props: DataGridBodyProps<TItem>) => JSX.Element) = React.forwardRef(
(props, ref) => {
const state = useDataGridBody_unstable(props, ref);

useDataGridBodyStyles_unstable(state);
return renderDataGridBody_unstable(state);
}
) as ForwardRefComponent<DataGridBodyProps> &
(<TItem>(props: DataGridBodyProps<TItem>) => JSX.Element);

DataGridBody.displayName = 'DataGridBody';
Loading
Loading