diff --git a/README.md b/README.md index ca01b1c3fe..ed856f3cf9 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ - [Cell copy / pasting](https://adazzle.github.io/react-data-grid/#/all-features) - [Cell value dragging / filling](https://adazzle.github.io/react-data-grid/#/all-features) - [Customizable Components](https://adazzle.github.io/react-data-grid/#/customizable-components) +- Right-to-left (RTL) support. We recommend using Firefox as Chrome has a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1140374) with frozen columns, and the [`:dir` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:dir) is not supported ## Links @@ -232,6 +233,15 @@ function MyGrid() { ###### `rowClass?: Maybe<(row: R) => Maybe>` +##### `direction?: Maybe<'ltr' | 'rtl'>` + +This property sets the text direction of the grid, it defaults to `'ltr'` (left-to-right). Setting `direction` to `'rtl'` has the following effects: + +- Columns flow from right to left +- Frozen columns are pinned on the right +- Column resize handle is shown on the left edge of the column +- Scrollbar is moved to the left + ###### `className?: string | undefined` ###### `style?: CSSProperties | undefined` diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 1ef31a6903..51300089e5 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -39,6 +39,7 @@ import { getColSpan, max, sign, + abs, getSelectedCellColSpan } from './utils'; @@ -54,7 +55,8 @@ import type { SortColumn, RowHeightArgs, Maybe, - Components + Components, + Direction } from './types'; export interface SelectCellState extends Position { @@ -169,6 +171,7 @@ export interface DataGridProps extends Sha */ components?: Maybe>; rowClass?: Maybe<(row: R) => Maybe>; + direction?: Maybe; 'data-testid'?: Maybe; } @@ -216,6 +219,7 @@ function DataGrid( className, style, rowClass, + direction, // ARIA 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, @@ -238,6 +242,7 @@ function DataGrid( const noRowsFallback = components?.noRowsFallback ?? defaultComponents?.noRowsFallback; const cellNavigationMode = rawCellNavigationMode ?? 'NONE'; enableVirtualization ??= true; + direction ??= 'ltr'; /** * states @@ -270,6 +275,9 @@ function DataGrid( const clientHeight = gridHeight - headerRowHeight - summaryRowsCount * summaryRowHeight; const isSelectable = selectedRows != null && onSelectedRowsChange != null; const isHeaderRowSelected = selectedPosition.rowIdx === -1; + const isRtl = direction === 'rtl'; + const leftKey = isRtl ? 'ArrowRight' : 'ArrowLeft'; + const rightKey = isRtl ? 'ArrowLeft' : 'ArrowRight'; const defaultGridComponents = useMemo( () => ({ @@ -566,9 +574,9 @@ function DataGrid( isGroupRow(row) && selectedPosition.idx === -1 && // Collapse the current group row if it is focused and is in expanded state - ((key === 'ArrowLeft' && row.isExpanded) || + ((key === leftKey && row.isExpanded) || // Expand the current group row if it is focused and is in collapsed state - (key === 'ArrowRight' && !row.isExpanded)) + (key === rightKey && !row.isExpanded)) ) { event.preventDefault(); // Prevents scrolling toggleGroup(row.id); @@ -600,7 +608,8 @@ function DataGrid( function handleScroll(event: React.UIEvent) { const { scrollTop, scrollLeft } = event.currentTarget; setScrollTop(scrollTop); - setScrollLeft(scrollLeft); + // scrollLeft is nagative when direction is rtl + setScrollLeft(abs(scrollLeft)); onScroll?.(event); } @@ -749,10 +758,11 @@ function DataGrid( const isCellAtLeftBoundary = left < scrollLeft + totalFrozenColumnWidth; const isCellAtRightBoundary = right > clientWidth + scrollLeft; + const sign = isRtl ? -1 : 1; if (isCellAtLeftBoundary) { - current.scrollLeft = left - totalFrozenColumnWidth; + current.scrollLeft = (left - totalFrozenColumnWidth) * sign; } else if (isCellAtRightBoundary) { - current.scrollLeft = right - clientWidth; + current.scrollLeft = (right - clientWidth) * sign; } } @@ -775,13 +785,7 @@ function DataGrid( const isRowSelected = selectedCellIsWithinSelectionBounds && idx === -1; // If a group row is focused, and it is collapsed, move to the parent group row (if there is one). - if ( - key === 'ArrowLeft' && - isRowSelected && - isGroupRow(row) && - !row.isExpanded && - row.level !== 0 - ) { + if (key === leftKey && isRowSelected && isGroupRow(row) && !row.isExpanded && row.level !== 0) { let parentRowIdx = -1; for (let i = selectedPosition.rowIdx - 1; i >= 0; i--) { const parentRow = rows[i]; @@ -801,9 +805,9 @@ function DataGrid( case 'ArrowDown': return { idx, rowIdx: rowIdx + 1 }; case 'ArrowLeft': - return { idx: idx - 1, rowIdx }; + return isRtl ? { idx: idx + 1, rowIdx } : { idx: idx - 1, rowIdx }; case 'ArrowRight': - return { idx: idx + 1, rowIdx }; + return isRtl ? { idx: idx - 1, rowIdx } : { idx: idx + 1, rowIdx }; case 'Tab': return { idx: idx + (shiftKey ? -1 : 1), rowIdx }; case 'Home': @@ -1117,16 +1121,18 @@ function DataGrid( ...style, gridTemplateRows: templateRows, '--rdg-header-row-height': `${headerRowHeight}px`, - '--rdg-row-width': `${totalColumnWidth}px`, + '--rdg-grid-inline-size': `${totalColumnWidth}px`, '--rdg-summary-row-height': `${summaryRowHeight}px`, - '--rdg-grid-height': `${ + '--rdg-grid-block-size': `${ max(totalRowHeight, clientHeight) + headerRowHeight + summaryRowsCount * summaryRowHeight }px`, + '--rdg-sign': isRtl ? -1 : 1, ...getLayoutCssVars() } as unknown as React.CSSProperties } + dir={direction} ref={gridRef} onScroll={handleScroll} onKeyDown={handleKeyDown} @@ -1156,6 +1162,7 @@ function DataGrid( selectedCellIdx={isHeaderRowSelected ? selectedPosition.idx : undefined} selectCell={selectHeaderCellLatest} shouldFocusGrid={!selectedCellIsWithinSelectionBounds} + direction={direction} /> {rows.length === 0 && noRowsFallback ? ( noRowsFallback diff --git a/src/DragHandle.tsx b/src/DragHandle.tsx index b03c1231e1..4c84c8f253 100644 --- a/src/DragHandle.tsx +++ b/src/DragHandle.tsx @@ -6,15 +6,15 @@ import type { DataGridProps, SelectCellState } from './DataGrid'; const cellDragHandle = css` cursor: move; position: absolute; - right: 0; - bottom: 0; - width: 8px; - height: 8px; + inset-inline-end: 0; + inset-block-end: 0; + inline-size: 8px; + block-size: 8px; background-color: var(--rdg-selection-color); &:hover { - width: 16px; - height: 16px; + inline-size: 16px; + block-size: 16px; border: 2px solid var(--rdg-selection-color); background-color: var(--rdg-background-color); } diff --git a/src/GroupRow.tsx b/src/GroupRow.tsx index 3aa824389f..6d5b45f93f 100644 --- a/src/GroupRow.tsx +++ b/src/GroupRow.tsx @@ -33,7 +33,7 @@ const groupRow = css` } > .${cell}:not(:last-child):not(.${cellFrozenLast}) { - border-right: none; + border-inline-end: none; } `; diff --git a/src/HeaderCell.tsx b/src/HeaderCell.tsx index 51dbbf5388..638c076765 100644 --- a/src/HeaderCell.tsx +++ b/src/HeaderCell.tsx @@ -13,10 +13,10 @@ const cellResizable = css` content: ''; cursor: col-resize; position: absolute; - top: 0; - right: 0; - bottom: 0; - width: 10px; + inset-block-start: 0; + inset-inline-end: 0; + inset-block-end: 0; + inline-size: 10px; } `; @@ -31,6 +31,7 @@ type SharedHeaderRowProps = Pick< | 'selectCell' | 'onColumnResize' | 'shouldFocusGrid' + | 'direction' >; export interface HeaderCellProps extends SharedHeaderRowProps { @@ -49,8 +50,10 @@ export default function HeaderCell({ sortColumns, onSortColumnsChange, selectCell, - shouldFocusGrid + shouldFocusGrid, + direction }: HeaderCellProps) { + const isRtl = direction === 'rtl'; const { ref, tabIndex, onFocus } = useRovingCellRef(isCellSelected); const sortIndex = sortColumns?.findIndex((sort) => sort.columnKey === column.key); const sortColumn = @@ -72,8 +75,8 @@ export default function HeaderCell({ } const { currentTarget, pointerId } = event; - const { right } = currentTarget.getBoundingClientRect(); - const offset = right - event.clientX; + const { right, left } = currentTarget.getBoundingClientRect(); + const offset = isRtl ? event.clientX - left : right - event.clientX; if (offset > 11) { // +1px to account for the border size @@ -81,7 +84,8 @@ export default function HeaderCell({ } function onPointerMove(event: PointerEvent) { - const width = event.clientX + offset - currentTarget.getBoundingClientRect().left; + const { right, left } = currentTarget.getBoundingClientRect(); + const width = isRtl ? right + offset - event.clientX : event.clientX + offset - left; if (width > 0) { onColumnResize(column, width); } @@ -139,8 +143,8 @@ export default function HeaderCell({ } function onDoubleClick(event: React.MouseEvent) { - const { right } = event.currentTarget.getBoundingClientRect(); - const offset = right - event.clientX; + const { right, left } = event.currentTarget.getBoundingClientRect(); + const offset = isRtl ? event.clientX - left : right - event.clientX; if (offset > 11) { // +1px to account for the border size diff --git a/src/HeaderRow.tsx b/src/HeaderRow.tsx index 109cf3d419..e24abf968d 100644 --- a/src/HeaderRow.tsx +++ b/src/HeaderRow.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { css } from '@linaria/core'; import HeaderCell from './HeaderCell'; -import type { CalculatedColumn } from './types'; +import type { CalculatedColumn, Direction } from './types'; import { getColSpan, getRowStyle } from './utils'; import type { DataGridProps } from './DataGrid'; import { cell, cellFrozen, rowSelectedClassname } from './style'; @@ -22,6 +22,7 @@ export interface HeaderRowProps extends SharedDataGr lastFrozenColumnIndex: number; selectedCellIdx: number | undefined; shouldFocusGrid: boolean; + direction: Direction; } const headerRow = css` @@ -34,7 +35,7 @@ const headerRow = css` /* Should have a higher value than 1 to show up above frozen cells */ z-index: 2; position: sticky; - top: 0; + inset-block-start: 0; } > .${cellFrozen} { @@ -54,7 +55,8 @@ function HeaderRow({ lastFrozenColumnIndex, selectedCellIdx, selectCell, - shouldFocusGrid + shouldFocusGrid, + direction }: HeaderRowProps) { const cells = []; for (let index = 0; index < columns.length; index++) { @@ -77,6 +79,7 @@ function HeaderRow({ sortColumns={sortColumns} selectCell={selectCell} shouldFocusGrid={shouldFocusGrid && index === 0} + direction={direction} /> ); } diff --git a/src/SummaryCell.tsx b/src/SummaryCell.tsx index 071161b036..86411c701a 100644 --- a/src/SummaryCell.tsx +++ b/src/SummaryCell.tsx @@ -6,8 +6,8 @@ import type { CalculatedColumn, CellRendererProps } from './types'; import { useRovingCellRef } from './hooks'; export const summaryCellClassname = css` - top: var(--rdg-summary-row-top); - bottom: var(--rdg-summary-row-bottom); + inset-block-start: var(--rdg-summary-row-top); + inset-block-end: var(--rdg-summary-row-bottom); `; interface SharedCellRendererProps diff --git a/src/SummaryRow.tsx b/src/SummaryRow.tsx index 55ef46d1d4..6991d57d00 100644 --- a/src/SummaryRow.tsx +++ b/src/SummaryRow.tsx @@ -33,7 +33,7 @@ const summaryRow = css` const summaryRowBorderClassname = css` & > .${cell} { - border-top: 2px solid var(--rdg-summary-border-color); + border-block-start: 2px solid var(--rdg-summary-border-color); } `; diff --git a/src/editors/TextEditor.tsx b/src/editors/TextEditor.tsx index 4dcb2c0374..82ddeee647 100644 --- a/src/editors/TextEditor.tsx +++ b/src/editors/TextEditor.tsx @@ -5,9 +5,10 @@ const textEditor = css` appearance: none; box-sizing: border-box; - width: 100%; - height: 100%; - padding: 0px 6px 0 6px; + inline-size: 100%; + block-size: 100%; + padding-block: 0; + padding-inline: 6px; border: 2px solid #ccc; vertical-align: top; color: var(--rdg-color); diff --git a/src/formatters/CheckboxFormatter.tsx b/src/formatters/CheckboxFormatter.tsx index 7ee52460b5..7a42cf6756 100644 --- a/src/formatters/CheckboxFormatter.tsx +++ b/src/formatters/CheckboxFormatter.tsx @@ -11,7 +11,7 @@ const checkboxLabel = css` justify-content: center; position: absolute; inset: 0; - margin-right: 1px; /* align checkbox in row group cell */ + margin-inline-end: 1px; /* align checkbox in row group cell */ `; const checkboxLabelClassname = `rdg-checkbox-label ${checkboxLabel}`; @@ -24,8 +24,8 @@ const checkboxInputClassname = `rdg-checkbox-input ${checkboxInput}`; const checkbox = css` content: ''; - width: 20px; - height: 20px; + inline-size: 20px; + block-size: 20px; border: 2px solid var(--rdg-border-color); background-color: var(--rdg-background-color); .${checkboxInput}:checked + & { diff --git a/src/formatters/ToggleGroupFormatter.tsx b/src/formatters/ToggleGroupFormatter.tsx index 67eddae8cf..f076c3019b 100644 --- a/src/formatters/ToggleGroupFormatter.tsx +++ b/src/formatters/ToggleGroupFormatter.tsx @@ -9,7 +9,7 @@ const groupCellContent = css` const groupCellContentClassname = `rdg-group-cell-content ${groupCellContent}`; const caret = css` - margin-left: 4px; + margin-inline-start: 4px; stroke: currentColor; stroke-width: 1.5px; fill: transparent; diff --git a/src/style/cell.ts b/src/style/cell.ts index aaa091a4f5..04c7495c5a 100644 --- a/src/style/cell.ts +++ b/src/style/cell.ts @@ -3,9 +3,10 @@ import { css } from '@linaria/core'; export const cell = css` contain: strict; contain: size layout style paint; - padding: 0 8px; - border-right: 1px solid var(--rdg-border-color); - border-bottom: 1px solid var(--rdg-border-color); + padding-block: 0; + padding-inline: 8px; + border-inline-end: 1px solid var(--rdg-border-color); + border-block-end: 1px solid var(--rdg-border-color); grid-row-start: var(--rdg-grid-row-start); background-color: inherit; diff --git a/src/style/core.ts b/src/style/core.ts index 4037d0c4d3..077d4478ee 100644 --- a/src/style/core.ts +++ b/src/style/core.ts @@ -36,7 +36,7 @@ const darkTheme = ` const root = css` ${lightTheme} --rdg-selection-color: #66afe9; - --rdg-frozen-cell-box-shadow: 2px 0 5px -2px rgba(136, 136, 136, 0.3); + --rdg-frozen-cell-box-shadow: calc(2px * var(--rdg-sign)) 0 5px -2px rgba(136, 136, 136, 0.3); --rdg-font-size: 14px; display: grid; @@ -48,7 +48,7 @@ const root = css` contain: strict; contain: size layout style paint; content-visibility: auto; - height: 350px; + block-size: 350px; border: 1px solid var(--rdg-border-color); box-sizing: border-box; overflow: auto; @@ -56,7 +56,6 @@ const root = css` background-color: var(--rdg-background-color); color: var(--rdg-color); font-size: var(--rdg-font-size); - direction: ltr; /* set stacking context in safari */ @supports not (contain: strict) { @@ -74,10 +73,10 @@ const root = css` &::before { content: ''; position: absolute; - top: 0; - left: 0; - height: var(--rdg-grid-height); - width: var(--rdg-row-width); + inset-block-start: 0; + inset-inline-start: 0; + block-size: var(--rdg-grid-block-size); + inline-size: var(--rdg-grid-inline-size); } &.rdg-dark { @@ -108,6 +107,6 @@ export const viewportDraggingClassname = `rdg-viewport-dragging ${viewportDraggi export const focusSinkClassname = css` position: sticky; - left: 0; + inset-inline-start: 0; grid-column-start: 1; `; diff --git a/src/style/row.ts b/src/style/row.ts index 604c7c8e9f..350b74eb33 100644 --- a/src/style/row.ts +++ b/src/style/row.ts @@ -23,9 +23,9 @@ export const row = css` export const rowClassname = `rdg-row ${row}`; const topBoxShadow = 'inset 0 2px 0 0 var(--rdg-selection-color)'; -const rightBoxShadow = 'inset -2px 0 0 0 var(--rdg-selection-color)'; +const rightBoxShadow = 'inset calc(-2px * var(--rdg-sign)) 0 0 0 var(--rdg-selection-color)'; const bottomBoxShadow = 'inset 0 -2px 0 0 var(--rdg-selection-color)'; -const leftBoxShadow = 'inset 2px 0 0 0 var(--rdg-selection-color)'; +const leftBoxShadow = 'inset calc(2px * var(--rdg-sign)) 0 0 0 var(--rdg-selection-color)'; const rowSelected = css` outline: none; diff --git a/src/types.ts b/src/types.ts index b1541d6025..f7f01b6514 100644 --- a/src/types.ts +++ b/src/types.ts @@ -224,3 +224,5 @@ export interface Components { rowRenderer?: Maybe>>; noRowsFallback?: Maybe; } + +export type Direction = 'ltr' | 'rtl'; diff --git a/src/utils/index.ts b/src/utils/index.ts index 1ce63bba44..2e91479e49 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -9,7 +9,7 @@ export * from './domUtils'; export * from './keyboardUtils'; export * from './selectedCellUtils'; -export const { min, max, round, floor, sign } = Math; +export const { min, max, round, floor, sign, abs } = Math; export function assertIsValidKeyGetter( keyGetter: unknown @@ -36,7 +36,7 @@ export function getCellStyle( return { gridColumnStart: column.idx + 1, gridColumnEnd: colSpan !== undefined ? `span ${colSpan}` : undefined, - left: column.frozen ? `var(--rdg-frozen-left-${column.idx})` : undefined + insetInlineStart: column.frozen ? `var(--rdg-frozen-left-${column.idx})` : undefined }; } diff --git a/test/direction.test.ts b/test/direction.test.ts new file mode 100644 index 0000000000..8e2dc8d12e --- /dev/null +++ b/test/direction.test.ts @@ -0,0 +1,35 @@ +import type { Column } from '../src'; +import { getGrid, setup } from './utils'; + +interface Row { + id: number; + name: string; +} + +const columns: readonly Column[] = [ + { + key: 'id', + name: 'ID' + }, + { + key: 'name', + name: 'Name' + } +]; + +const rows: readonly Row[] = []; + +test('should use left to right direction by default', () => { + setup({ rows, columns }); + expect(getGrid()).toHaveAttribute('dir', 'ltr'); +}); + +test('should use left to right direction if direction prop is set to ltr', () => { + setup({ rows, columns, direction: 'ltr' }); + expect(getGrid()).toHaveAttribute('dir', 'ltr'); +}); + +test('should use right to left direction if direction prop is set to rtl', () => { + setup({ rows, columns, direction: 'rtl' }); + expect(getGrid()).toHaveAttribute('dir', 'rtl'); +}); diff --git a/test/keyboardNavigation.test.tsx b/test/keyboardNavigation.test.tsx index fa7bdb27b4..c694b6059f 100644 --- a/test/keyboardNavigation.test.tsx +++ b/test/keyboardNavigation.test.tsx @@ -377,3 +377,19 @@ test('reset selected cell when row is removed', () => { expect(getSelectedCell()).not.toBeInTheDocument(); }); + +test('should not change the left and right arrow behavior for right to left languages', () => { + setup({ rows, columns, direction: 'rtl' }); + userEvent.tab(); + validateCellPosition(0, 0); + userEvent.tab(); + validateCellPosition(1, 0); + userEvent.keyboard('{arrowright}'); + validateCellPosition(0, 0); + userEvent.keyboard('{arrowright}'); + validateCellPosition(0, 0); + userEvent.keyboard('{arrowleft}'); + validateCellPosition(1, 0); + userEvent.keyboard('{arrowleft}'); + validateCellPosition(2, 0); +}); diff --git a/test/virtualization.test.ts b/test/virtualization.test.ts index a37f475b8c..03e4eb2149 100644 --- a/test/virtualization.test.ts +++ b/test/virtualization.test.ts @@ -39,7 +39,7 @@ function setupGrid( function assertHeightFill(height: number) { // if there are not enough rows, we need to fill the rows viewport's height so summary rows stick to the bottom of the container - expect(getGrid()).toHaveStyle({ '--rdg-grid-height': `${height}px` }); + expect(getGrid()).toHaveStyle({ '--rdg-grid-block-size': `${height}px` }); } function assertElements( @@ -144,7 +144,7 @@ test('virtualization is enabled', () => { assertCells(66, 18, 1, 18); // max left = row width - grid width - grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-row-width'), 10) - 1920; + grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-grid-inline-size'), 10) - 1920; assertHeaderCells(17, 13, 29); assertCells(66, 17, 13, 29); }); @@ -166,7 +166,7 @@ test('virtualization is enabled with 4 frozen columns', () => { assertCellIndexes(0, indexes); // max left = row width - grid width - grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-row-width'), 10) - 1920; + grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-grid-inline-size'), 10) - 1920; indexes = [0, 1, 2, 3, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]; assertHeaderCellIndexes(indexes); assertCellIndexes(0, indexes); @@ -191,7 +191,7 @@ test('virtualization is enabled with all columns frozen', () => { assertCellIndexes(0, indexes); // max left = row width - grid width - grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-row-width'), 10) - 1920; + grid.scrollLeft = parseInt(grid.style.getPropertyValue('--rdg-grid-inline-size'), 10) - 1920; assertHeaderCellIndexes(indexes); assertCellIndexes(0, indexes); }); diff --git a/website/Nav.tsx b/website/Nav.tsx index e8af4d9ad6..a6a609888b 100644 --- a/website/Nav.tsx +++ b/website/Nav.tsx @@ -1,16 +1,18 @@ import { NavLink } from 'react-router-dom'; import { css } from '@linaria/core'; +import type { Direction } from '../src/types'; + const navClassname = css` display: flex; flex-direction: column; white-space: nowrap; @media (prefers-color-scheme: light) { - border-left: 4px solid hsl(210deg 50% 80%); + border-inline-start: 4px solid hsl(210deg 50% 80%); } @media (prefers-color-scheme: dark) { - border-left: 4px solid hsl(210deg 50% 40%); + border-inline-start: 4px solid hsl(210deg 50% 40%); } h1, @@ -23,7 +25,8 @@ const navClassname = css` font-size: 14px; line-height: 22px; text-decoration: none; - padding: 0 16px; + padding-block: 0; + padding-inline: 16px; transition: 0.1s background-color; &:hover { @@ -57,7 +60,16 @@ const activeNavClassname = css` } `; -export default function Nav() { +const rtlCheckboxClassname = css` + padding-inline-start: 8px; +`; + +interface Props { + direction: Direction; + onDirectionChange: (direction: Direction) => void; +} + +export default function Nav({ direction, onDirectionChange }: Props) { return ( ); } diff --git a/website/demos/AllFeatures.tsx b/website/demos/AllFeatures.tsx index c918eb2ded..4ecc6f5f29 100644 --- a/website/demos/AllFeatures.tsx +++ b/website/demos/AllFeatures.tsx @@ -5,6 +5,7 @@ import DataGrid, { SelectColumn, TextEditor } from '../../src'; import type { Column, FillEvent, PasteEvent } from '../../src'; import DropDownEditor from './components/Editors/DropDownEditor'; import { ImageFormatter } from './components/Formatters'; +import type { Props } from './types'; const highlightClassname = css` .rdg-cell { @@ -169,7 +170,7 @@ function createRows(): Row[] { return rows; } -export default function AllFeatures() { +export default function AllFeatures({ direction }: Props) { const [rows, setRows] = useState(createRows); const [selectedRows, setSelectedRows] = useState>(() => new Set()); @@ -210,6 +211,7 @@ export default function AllFeatures() { onSelectedRowsChange={setSelectedRows} className="fill-grid" rowClass={(row) => (row.id.includes('7') ? highlightClassname : undefined)} + direction={direction} /> ); } diff --git a/website/demos/CellNavigation.tsx b/website/demos/CellNavigation.tsx index ac15b52b36..c128918908 100644 --- a/website/demos/CellNavigation.tsx +++ b/website/demos/CellNavigation.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import DataGrid from '../../src'; import type { Column, CellNavigationMode } from '../../src'; +import type { Props } from './types'; interface Row { id: number; @@ -69,13 +70,13 @@ function createRows(): Row[] { return rows; } -export default function CellNavigation() { +export default function CellNavigation({ direction }: Props) { const [rows] = useState(createRows); const [cellNavigationMode, setCellNavigationMode] = useState('CHANGE_ROW'); return ( <> -
+
Cell Navigation Modes:
- + ); } diff --git a/website/demos/ColumnSpanning.tsx b/website/demos/ColumnSpanning.tsx index 79f479774d..2cb415effa 100644 --- a/website/demos/ColumnSpanning.tsx +++ b/website/demos/ColumnSpanning.tsx @@ -3,6 +3,7 @@ import { css } from '@linaria/core'; import DataGrid from '../../src'; import type { Column, FormatterProps } from '../../src'; +import type { Props } from './types'; type Row = number; const rows: readonly Row[] = [...Array(100).keys()]; @@ -21,7 +22,7 @@ function CellFormatter(props: FormatterProps) { ); } -export default function ColumnSpanning() { +export default function ColumnSpanning({ direction }: Props) { const columns = useMemo((): readonly Column[] => { const columns: Column[] = []; @@ -63,5 +64,13 @@ export default function ColumnSpanning() { return columns; }, []); - return ; + return ( + + ); } diff --git a/website/demos/ColumnsReordering.tsx b/website/demos/ColumnsReordering.tsx index f150347ceb..11c9207f12 100644 --- a/website/demos/ColumnsReordering.tsx +++ b/website/demos/ColumnsReordering.tsx @@ -5,6 +5,7 @@ import { HTML5Backend } from 'react-dnd-html5-backend'; import { DraggableHeaderRenderer } from './components/HeaderRenderers'; import DataGrid from '../../src'; import type { Column, HeaderRendererProps, SortColumn } from '../../src'; +import type { Props } from './types'; interface Row { id: number; @@ -63,7 +64,7 @@ function createColumns(): Column[] { ]; } -export default function ColumnsReordering() { +export default function ColumnsReordering({ direction }: Props) { const [rows] = useState(createRows); const [columns, setColumns] = useState(createColumns); const [sortColumns, setSortColumns] = useState([]); @@ -123,6 +124,7 @@ export default function ColumnsReordering() { rows={sortedRows} sortColumns={sortColumns} onSortColumnsChange={onSortColumnsChange} + direction={direction} /> ); diff --git a/website/demos/CommonFeatures.tsx b/website/demos/CommonFeatures.tsx index 9280d5d4af..609f2a8da5 100644 --- a/website/demos/CommonFeatures.tsx +++ b/website/demos/CommonFeatures.tsx @@ -7,10 +7,12 @@ import DataGrid, { SelectColumn, TextEditor, SelectCellFormatter } from '../../s import type { Column, SortColumn } from '../../src'; import { exportToCsv, exportToXlsx, exportToPdf } from './exportUtils'; import { textEditorClassname } from '../../src/editors/TextEditor'; +import type { Props } from './types'; +import type { Direction } from '../../src/types'; const toolbarClassname = css` - text-align: right; - margin-bottom: 8px; + text-align: end; + margin-block-end: 8px; `; const dialogContainerClassname = css` @@ -27,7 +29,7 @@ const dialogContainerClassname = css` } > menu { - text-align: right; + text-align: end; } } `; @@ -70,7 +72,7 @@ interface Row { available: boolean; } -function getColumns(countries: string[]): readonly Column[] { +function getColumns(countries: string[], direction: Direction): readonly Column[] { return [ SelectColumn, { @@ -145,13 +147,14 @@ function getColumns(countries: string[]): readonly Column[] { const value = props.row.progress; return ( <> - {Math.round(value)}% + {Math.round(value)}% ); }, editor({ row, onRowChange, onClose }) { return createPortal(
{ if (event.key === 'Escape') { @@ -304,7 +307,7 @@ function getComparator(sortColumn: string): Comparator { } } -export default function CommonFeatures() { +export default function CommonFeatures({ direction }: Props) { const [rows, setRows] = useState(createRows); const [sortColumns, setSortColumns] = useState([]); const [selectedRows, setSelectedRows] = useState>(() => new Set()); @@ -313,7 +316,7 @@ export default function CommonFeatures() { return [...new Set(rows.map((r) => r.country))].sort(new Intl.Collator().compare); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const columns = useMemo(() => getColumns(countries), [countries]); + const columns = useMemo(() => getColumns(countries, direction), [countries, direction]); const summaryRows = useMemo(() => { const summaryRow: SummaryRow = { @@ -355,6 +358,7 @@ export default function CommonFeatures() { onSortColumnsChange={setSortColumns} summaryRows={summaryRows} className="fill-grid" + direction={direction} /> ); diff --git a/website/demos/ContextMenu.tsx b/website/demos/ContextMenu.tsx index 5a389e3964..c0fddb8ad7 100644 --- a/website/demos/ContextMenu.tsx +++ b/website/demos/ContextMenu.tsx @@ -6,6 +6,7 @@ import { css } from '@linaria/core'; import DataGrid, { Row as GridRow } from '../../src'; import type { Column, RowRendererProps } from '../../src'; +import type { Props } from './types'; css` @at-root { @@ -20,13 +21,17 @@ css` border-radius: 0.25rem; color: #373a3c; font-size: 16px; - margin: 2px 0 0; - min-width: 160px; + margin-block-start: 2px; + margin-block-end: 0; + margin-inline-start: 0; + margin-inline-end: 0; + min-inline-size: 160px; outline: none; opacity: 0; - padding: 5px 0; + padding-block: 5px; + padding-inline: 0; pointer-events: none; - text-align: left; + text-align: start; transition: opacity 250ms ease !important; } @@ -42,7 +47,8 @@ css` cursor: pointer; font-weight: 400; line-height: 1.5; - padding: 3px 20px; + padding-block: 3px; + padding-inline: 20px; text-align: inherit; white-space: nowrap; } @@ -63,10 +69,11 @@ css` } .react-contextmenu-item--divider { - border-bottom: 1px solid rgba(0, 0, 0, 0.15); + border-block-end: 1px solid rgba(0, 0, 0, 0.15); cursor: inherit; - margin-bottom: 3px; - padding: 2px 0; + margin-block-end: 3px; + padding-block: 2px; + padding-inline: 0; } .react-contextmenu-item--divider:hover { @@ -82,7 +89,7 @@ css` content: '▶'; display: inline-block; position: absolute; - right: 7px; + inset-inline-end: 7px; } .example-multiple-targets::after { @@ -128,7 +135,7 @@ function RowRenderer(props: RowRendererProps) { ); } -export default function ContextMenuDemo() { +export default function ContextMenuDemo({ direction }: Props) { const [rows, setRows] = useState(createRows); const [nextId, setNextId] = useReducer((id: number) => id + 1, rows[rows.length - 1].id + 1); @@ -163,15 +170,18 @@ export default function ContextMenuDemo() { rows={rows} components={{ rowRenderer: RowRenderer }} className="fill-grid" + direction={direction} /> {createPortal( - - Delete Row - - Above - Below - - , +
+ + Delete Row + + Above + Below + + +
, document.body )} diff --git a/website/demos/CustomizableComponents.tsx b/website/demos/CustomizableComponents.tsx index 8d15d2b7dc..10a843637e 100644 --- a/website/demos/CustomizableComponents.tsx +++ b/website/demos/CustomizableComponents.tsx @@ -2,6 +2,7 @@ import { useMemo, useState, forwardRef } from 'react'; import DataGrid, { SelectColumn, TextEditor } from '../../src'; import type { Column, CheckboxFormatterProps, SortColumn, SortIconProps } from '../../src'; +import type { Props } from './types'; interface Row { id: number; @@ -56,7 +57,7 @@ const columns: readonly Column[] = [ } ]; -export default function CustomizableComponents() { +export default function CustomizableComponents({ direction }: Props) { const [rows, setRows] = useState(createRows); const [sortColumns, setSortColumns] = useState([]); const [selectedRows, setSelectedRows] = useState>(() => new Set()); @@ -88,6 +89,7 @@ export default function CustomizableComponents() { selectedRows={selectedRows} onSelectedRowsChange={setSelectedRows} components={{ sortIcon: SortIcon, checkboxFormatter: CheckboxFormatter }} + direction={direction} /> ); } diff --git a/website/demos/Grouping.tsx b/website/demos/Grouping.tsx index 98609c2c03..a3722f0dff 100644 --- a/website/demos/Grouping.tsx +++ b/website/demos/Grouping.tsx @@ -5,11 +5,12 @@ import { css } from '@linaria/core'; import DataGrid, { SelectColumn } from '../../src'; import type { Column } from '../../src'; +import type { Props } from './types'; const groupingClassname = css` display: flex; flex-direction: column; - height: 100%; + block-size: 100%; gap: 8px; > .rdg { @@ -140,7 +141,7 @@ function createRows(): readonly Row[] { const options = ['country', 'year', 'sport', 'athlete'] as const; -export default function Grouping() { +export default function Grouping({ direction }: Props) { const [rows] = useState(createRows); const [selectedRows, setSelectedRows] = useState>(() => new Set()); const [selectedOptions, setSelectedOptions] = useState([ @@ -194,6 +195,7 @@ export default function Grouping() { expandedGroupIds={expandedGroupIds} onExpandedGroupIdsChange={setExpandedGroupIds} defaultColumnOptions={{ resizable: true }} + direction={direction} />
); diff --git a/website/demos/HeaderFilters.tsx b/website/demos/HeaderFilters.tsx index aad268dc4e..fdb24059f1 100644 --- a/website/demos/HeaderFilters.tsx +++ b/website/demos/HeaderFilters.tsx @@ -6,11 +6,12 @@ import DataGrid from '../../src'; import type { Column, HeaderRendererProps } from '../../src'; import type { Omit } from '../../src/types'; import { useFocusRef } from '../../src/hooks'; +import type { Props } from './types'; const rootClassname = css` display: flex; flex-direction: column; - height: 100%; + block-size: 100%; gap: 10px; > .rdg { @@ -30,17 +31,18 @@ const filterContainerClassname = css` padding: 0; > div { - padding: 0 8px; + padding-block: 0; + padding-inline: 8px; &:first-child { - border-bottom: 1px solid var(--rdg-border-color); + border-block-end: 1px solid var(--rdg-border-color); } } } `; const filterClassname = css` - width: 100%; + inline-size: 100%; padding: 4px; font-size: 14px; `; @@ -75,7 +77,7 @@ function selectStopPropagation(event: React.KeyboardEvent) { } } -export default function HeaderFilters() { +export default function HeaderFilters({ direction }: Props) { const [rows] = useState(createRows); const [filters, setFilters] = useState({ task: '', @@ -284,6 +286,7 @@ export default function HeaderFilters() { columns={columns} rows={filteredRows} headerRowHeight={filters.enabled ? 70 : undefined} + direction={direction} /> diff --git a/website/demos/InfiniteScrolling.tsx b/website/demos/InfiniteScrolling.tsx index b44672095d..823f32dc88 100644 --- a/website/demos/InfiniteScrolling.tsx +++ b/website/demos/InfiniteScrolling.tsx @@ -4,13 +4,15 @@ import { css } from '@linaria/core'; import DataGrid from '../../src'; import type { Column } from '../../src'; +import type { Props } from './types'; const loadMoreRowsClassname = css` - width: 180px; - padding: 8px 16px; + inline-size: 180px; + padding-block: 8px; + padding-inline: 16px; position: absolute; - bottom: 8px; - right: 8px; + inset-block-end: 8px; + inset-inline-end: 8px; color: white; line-height: 35px; background: rgb(0 0 0 / 0.6); @@ -87,7 +89,7 @@ function loadMoreRows(newRowsCount: number, length: number): Promise { }); } -export default function InfiniteScrolling() { +export default function InfiniteScrolling({ direction }: Props) { const [rows, setRows] = useState(() => createRows(50)); const [isLoading, setIsLoading] = useState(false); @@ -112,6 +114,7 @@ export default function InfiniteScrolling() { rowHeight={30} onScroll={handleScroll} className="fill-grid" + direction={direction} /> {isLoading &&
Loading more rows...
} diff --git a/website/demos/MasterDetail.tsx b/website/demos/MasterDetail.tsx index cc5b3988c6..196508e392 100644 --- a/website/demos/MasterDetail.tsx +++ b/website/demos/MasterDetail.tsx @@ -1,10 +1,12 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { css } from '@linaria/core'; import faker from 'faker'; import DataGrid from '../../src'; import type { Column, RowsChangeData, DataGridHandle } from '../../src'; import { CellExpanderFormatter } from './components/Formatters'; +import type { Props } from './types'; +import type { Direction } from '../../src/types'; type DepartmentRow = | { @@ -62,43 +64,50 @@ const productColumns: readonly Column[] = [ { key: 'price', name: 'Price' } ]; -const departmentColumns: readonly Column[] = [ - { - key: 'expanded', - name: '', - minWidth: 30, - width: 30, - colSpan(args) { - return args.type === 'ROW' && args.row.type === 'DETAIL' ? 3 : undefined; - }, - cellClass(row) { - return row.type === 'DETAIL' - ? css` - padding: 24px; - ` - : undefined; - }, - formatter({ row, isCellSelected, onRowChange }) { - if (row.type === 'DETAIL') { - return ; - } - - return ( - { - onRowChange({ ...row, expanded: !row.expanded }); - }} - /> - ); - } - }, - { key: 'id', name: 'ID', width: 35 }, - { key: 'department', name: 'Department' } -]; +export default function MasterDetail({ direction }: Props) { + const columns = useMemo((): readonly Column[] => { + return [ + { + key: 'expanded', + name: '', + minWidth: 30, + width: 30, + colSpan(args) { + return args.type === 'ROW' && args.row.type === 'DETAIL' ? 3 : undefined; + }, + cellClass(row) { + return row.type === 'DETAIL' + ? css` + padding: 24px; + ` + : undefined; + }, + formatter({ row, isCellSelected, onRowChange }) { + if (row.type === 'DETAIL') { + return ( + + ); + } -export default function MasterDetail() { + return ( + { + onRowChange({ ...row, expanded: !row.expanded }); + }} + /> + ); + } + }, + { key: 'id', name: 'ID', width: 35 }, + { key: 'department', name: 'Department' } + ]; + }, [direction]); const [rows, setRows] = useState(createDepartments); function onRowsChange(rows: DepartmentRow[], { indexes }: RowsChangeData) { @@ -120,18 +129,27 @@ export default function MasterDetail() { return ( (args.type === 'ROW' && args.row.type === 'DETAIL' ? 300 : 45)} className="fill-grid" enableVirtualization={false} + direction={direction} /> ); } -function ProductGrid({ parentId, isCellSelected }: { parentId: number; isCellSelected: boolean }) { +function ProductGrid({ + parentId, + isCellSelected, + direction +}: { + parentId: number; + isCellSelected: boolean; + direction: Direction; +}) { const gridRef = useRef(null); useEffect(() => { if (!isCellSelected) return; @@ -154,7 +172,8 @@ function ProductGrid({ parentId, isCellSelected }: { parentId: number; isCellSel rows={products} columns={productColumns} rowKeyGetter={rowKeyGetter} - style={{ height: 250 }} + style={{ blockSize: 250 }} + direction={direction} />
); diff --git a/website/demos/MillionCells.tsx b/website/demos/MillionCells.tsx index cce4e37418..8879948ff1 100644 --- a/website/demos/MillionCells.tsx +++ b/website/demos/MillionCells.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import DataGrid from '../../src'; import type { Column, FormatterProps } from '../../src'; +import type { Props } from './types'; type Row = number; const rows: readonly Row[] = [...Array(1000).keys()]; @@ -13,7 +14,7 @@ function CellFormatter(props: FormatterProps) { ); } -export default function MillionCells() { +export default function MillionCells({ direction }: Props) { const columns = useMemo((): readonly Column[] => { const columns: Column[] = []; @@ -31,5 +32,13 @@ export default function MillionCells() { return columns; }, []); - return ; + return ( + + ); } diff --git a/website/demos/NoRows.tsx b/website/demos/NoRows.tsx index 967c936df5..654e09a71d 100644 --- a/website/demos/NoRows.tsx +++ b/website/demos/NoRows.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import DataGrid, { SelectColumn } from '../../src'; import type { Column } from '../../src'; +import type { Props } from './types'; function EmptyRowsRenderer() { return ( @@ -32,7 +33,7 @@ function rowKeyGetter(row: Row) { return row.id; } -export default function NoRows() { +export default function NoRows({ direction }: Props) { const [selectedRows, onSelectedRowsChange] = useState((): ReadonlySet => new Set()); return ( @@ -44,6 +45,7 @@ export default function NoRows() { onSelectedRowsChange={onSelectedRowsChange} rowKeyGetter={rowKeyGetter} className="small-grid" + direction={direction} /> ); } diff --git a/website/demos/Resizable.tsx b/website/demos/Resizable.tsx index e0adf25d4c..2f40487351 100644 --- a/website/demos/Resizable.tsx +++ b/website/demos/Resizable.tsx @@ -1,5 +1,6 @@ import DataGrid from '../../src'; import type { Column, FormatterProps } from '../../src'; +import type { Props } from './types'; type Row = number; const rows: readonly Row[] = [...Array(100).keys()]; @@ -23,8 +24,14 @@ for (let i = 0; i < 50; i++) { }); } -export default function ResizableGrid() { +export default function ResizableGrid({ direction }: Props) { return ( - + ); } diff --git a/website/demos/RowsReordering.tsx b/website/demos/RowsReordering.tsx index 72bb7746c6..732b758bae 100644 --- a/website/demos/RowsReordering.tsx +++ b/website/demos/RowsReordering.tsx @@ -5,6 +5,7 @@ import { HTML5Backend } from 'react-dnd-html5-backend'; import { DraggableRowRenderer } from './components/RowRenderers'; import DataGrid, { TextEditor } from '../../src'; import type { Column, RowRendererProps } from '../../src'; +import type { Props } from './types'; interface Row { id: number; @@ -54,7 +55,7 @@ const columns: readonly Column[] = [ } ]; -export default function RowsReordering() { +export default function RowsReordering({ direction }: Props) { const [rows, setRows] = useState(createRows); const RowRenderer = useCallback((props: RowRendererProps) => { @@ -76,6 +77,7 @@ export default function RowsReordering() { rows={rows} onRowsChange={setRows} components={{ rowRenderer: RowRenderer }} + direction={direction} /> ); diff --git a/website/demos/ScrollToRow.tsx b/website/demos/ScrollToRow.tsx index 35a69bfbf5..15c1eda99a 100644 --- a/website/demos/ScrollToRow.tsx +++ b/website/demos/ScrollToRow.tsx @@ -1,6 +1,7 @@ import { useState, useRef } from 'react'; import DataGrid from '../../src'; import type { Column, DataGridHandle } from '../../src'; +import type { Props } from './types'; interface Row { id: number; @@ -14,7 +15,7 @@ const columns: readonly Column[] = [ { key: 'count', name: 'Count' } ]; -export default function ScrollToRow() { +export default function ScrollToRow({ direction }: Props) { const [rows] = useState(() => { const rows: Row[] = []; @@ -33,10 +34,10 @@ export default function ScrollToRow() { return ( <> -
- Row index: +
+ Row index: setValue(event.target.value)} @@ -45,7 +46,7 @@ export default function ScrollToRow() { Scroll to row
- + ); } diff --git a/website/demos/TreeView.tsx b/website/demos/TreeView.tsx index 621f2397e8..6bc8f6847a 100644 --- a/website/demos/TreeView.tsx +++ b/website/demos/TreeView.tsx @@ -3,6 +3,7 @@ import { useState, useReducer, useMemo } from 'react'; import DataGrid from '../../src'; import type { Column } from '../../src'; import { CellExpanderFormatter, ChildRowDeleteButton } from './components/Formatters'; +import type { Props } from './types'; interface Row { id: string; @@ -111,7 +112,7 @@ function reducer(rows: Row[], { type, id }: Action): Row[] { const defaultRows = createRows(); -export default function TreeView() { +export default function TreeView({ direction }: Props) { const [rows, dispatch] = useReducer(reducer, defaultRows); const [allowDelete, setAllowDelete] = useState(true); const columns: Column[] = useMemo(() => { @@ -130,7 +131,7 @@ export default function TreeView() { name: 'format', formatter({ row, isCellSelected }) { const hasChildren = row.children !== undefined; - const style = !hasChildren ? { marginLeft: 30 } : undefined; + const style = !hasChildren ? { marginInlineStart: 30 } : undefined; return ( <> {hasChildren && ( @@ -175,7 +176,7 @@ export default function TreeView() { onChange={() => setAllowDelete(!allowDelete)} /> - + ); } diff --git a/website/demos/VariableRowHeight.tsx b/website/demos/VariableRowHeight.tsx index af77ff3d4a..f6bdb2cb35 100644 --- a/website/demos/VariableRowHeight.tsx +++ b/website/demos/VariableRowHeight.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import DataGrid from '../../src'; import type { Column, FormatterProps } from '../../src'; +import type { Props } from './types'; type Row = number; const rows: readonly Row[] = [...Array(500).keys()]; @@ -14,7 +15,7 @@ function CellFormatter(props: FormatterProps) { ); } -export default function VariableRowHeight() { +export default function VariableRowHeight({ direction }: Props) { const columns = useMemo((): readonly Column[] => { const columns: Column[] = []; @@ -32,7 +33,15 @@ export default function VariableRowHeight() { return columns; }, []); - return ; + return ( + + ); } function rowHeight() { diff --git a/website/demos/components/Formatters/CellExpanderFormatter.tsx b/website/demos/components/Formatters/CellExpanderFormatter.tsx index ca410bc9cf..6a09978bc2 100644 --- a/website/demos/components/Formatters/CellExpanderFormatter.tsx +++ b/website/demos/components/Formatters/CellExpanderFormatter.tsx @@ -2,9 +2,11 @@ import { css } from '@linaria/core'; import { useFocusRef } from '../../../../src/hooks'; const cellExpandClassname = css` + /* needed on chrome */ float: right; + float: inline-end; display: table; - height: 100%; + block-size: 100%; > span { display: table-cell; diff --git a/website/demos/components/Formatters/ChildRowDeleteButton.tsx b/website/demos/components/Formatters/ChildRowDeleteButton.tsx index e0cd57d928..1fcf1a3b19 100644 --- a/website/demos/components/Formatters/ChildRowDeleteButton.tsx +++ b/website/demos/components/Formatters/ChildRowDeleteButton.tsx @@ -10,16 +10,16 @@ const childRowActionCrossClassname = css` } &::before { - left: 21px; - width: 1px; - height: 100%; + inset-inline-start: 21px; + inline-size: 1px; + block-size: 100%; } &::after { - top: 50%; - left: 20px; - height: 1px; - width: 15px; + inset-block-start: 50%; + inset-inline-start: 20px; + block-size: 1px; + inline-size: 15px; } &:hover { @@ -30,9 +30,12 @@ const childRowActionCrossClassname = css` const childRowButtonClassname = css` cursor: pointer; position: absolute; - left: 21px; + inset-inline-start: 21px; transform: translateX(-50%); filter: grayscale(1); + &:dir(rtl) { + transform: translateX(50%); + } `; interface ChildRowDeleteButtonProps { diff --git a/website/demos/components/Formatters/ImageFormatter.tsx b/website/demos/components/Formatters/ImageFormatter.tsx index 9344e1adc7..68bc8228b3 100644 --- a/website/demos/components/Formatters/ImageFormatter.tsx +++ b/website/demos/components/Formatters/ImageFormatter.tsx @@ -9,8 +9,8 @@ const imageCellClassname = css` background: #efefef; background-size: 100%; display: inline-block; - height: 28px; - width: 28px; + block-size: 28px; + inline-size: 28px; vertical-align: middle; background-position: center; `; diff --git a/website/demos/types.ts b/website/demos/types.ts new file mode 100644 index 0000000000..413b505c7f --- /dev/null +++ b/website/demos/types.ts @@ -0,0 +1,5 @@ +import type { Direction } from '../../src/types'; + +export interface Props { + direction: Direction; +} diff --git a/website/root.tsx b/website/root.tsx index 88b3bf93d7..a9792c3b6a 100644 --- a/website/root.tsx +++ b/website/root.tsx @@ -1,8 +1,9 @@ -import { StrictMode } from 'react'; +import React, { StrictMode, useState } from 'react'; import { render } from 'react-dom'; import { css } from '@linaria/core'; import { HashRouter as Router, Switch, Redirect, Route } from 'react-router-dom'; +import type { Direction } from '../src/types'; import Nav from './Nav'; import CommonFeatures from './demos/CommonFeatures'; @@ -53,15 +54,15 @@ css` } .rdg.fill-grid { - height: 100%; + block-size: 100%; } .rdg.small-grid { - height: 300px; + block-size: 300px; } .rdg.big-grid { - height: 600px; + block-size: 600px; } .rdg-cell .Select { @@ -76,72 +77,72 @@ const mainClassname = css` display: flex; flex-direction: column; box-sizing: border-box; - height: 100vh; + block-size: 100vh; padding: 8px; overflow: hidden; `; function Root() { + const [direction, setDirection] = useState('ltr'); return ( -