From 14ff07da834a60cf1d01ac6cdab09b4fdd425620 Mon Sep 17 00:00:00 2001 From: Mikhail Malcev <47668236+Mishnya@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:38:31 +0300 Subject: [PATCH 1/3] feat(List): support RTL (#1145) --- src/components/List/List.tsx | 4 ++++ src/components/List/components/ListItem.tsx | 11 ++++++++++- src/components/Select/__stories__/SelectShowcase.tsx | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/List/List.tsx b/src/components/List/List.tsx index f688d2fd00..eb9e6f2a7b 100644 --- a/src/components/List/List.tsx +++ b/src/components/List/List.tsx @@ -10,6 +10,7 @@ import {VariableSizeList as ListContainer} from 'react-window'; import {SelectLoadingIndicator} from '../Select/components/SelectList/SelectLoadingIndicator'; import {TextInput} from '../controls'; import {MobileContext} from '../mobile'; +import {ThemeContext} from '../theme'; import {block} from '../utils/cn'; import {getUniqId} from '../utils/common'; @@ -44,6 +45,7 @@ export const listDefaultProps: Partial>> = { export class List extends React.Component, ListState> { static defaultProps: Partial>> = listDefaultProps; + static contextType = ThemeContext; static moveListElement( list: ListItemData[], @@ -72,6 +74,7 @@ export class List extends React.Component, ListState; state: ListState = { items: this.props.items, filter: '', @@ -342,6 +345,7 @@ export class List extends React.Component, ListState extends React.Component> { role = 'listitem', } = this.props; + /* + This fixes item drag layout for rtl direction. + react-window has a bug where in rtl it setting "right" to 0 instead of undefined. + */ + const fixedStyle = { + ...style, + right: undefined, + }; + return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events
extends React.Component> { }, itemClassName, )} - style={style} + style={fixedStyle} onClick={item.disabled ? undefined : this.onClick} onClickCapture={item.disabled ? undefined : this.onClickCapture} onMouseEnter={this.onMouseEnter} diff --git a/src/components/Select/__stories__/SelectShowcase.tsx b/src/components/Select/__stories__/SelectShowcase.tsx index 4babd7cdd9..6fa696330b 100644 --- a/src/components/Select/__stories__/SelectShowcase.tsx +++ b/src/components/Select/__stories__/SelectShowcase.tsx @@ -95,7 +95,7 @@ const ExampleItem = (props: { code.map((codeItem, i) => { return ( -
+                            
                                 {codeItem}
                                 
Date: Fri, 24 Nov 2023 10:32:42 +0100
Subject: [PATCH 2/3] =?UTF-8?q?feat:=20updated=20TextInput=20"type"=20prop?=
 =?UTF-8?q?erty=20to=20allow=20using=20only=20well-know=E2=80=A6=20(#1158)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/components/controls/TextInput/README.md   | 66 +++++++++----------
 .../controls/TextInput/TextInput.tsx          |  2 +-
 2 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/src/components/controls/TextInput/README.md b/src/components/controls/TextInput/README.md
index 802d0073a1..4a74ef0f05 100644
--- a/src/components/controls/TextInput/README.md
+++ b/src/components/controls/TextInput/README.md
@@ -235,36 +235,36 @@ LANDING_BLOCK-->
 
 ## Properties
 
-| Name            | Description                                                                                                             |                     Type                      |     Default     |
-| :-------------- | :---------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------: | :-------------: |
-| autoComplete    | The control's `autocomplete` attribute                                                                                  |              `boolean` `string`               |                 |
-| autoFocus       | The control's `autofocus` attribute                                                                                     |                   `boolean`                   |                 |
-| className       | The control's wrapper class name                                                                                        |                   `string`                    |                 |
-| controlProps    | The control's html attributes                                                                                           | `React.InputHTMLAttributes` |                 |
-| controlRef      | React ref provided to the control                                                                                       |         `React.Ref`         |                 |
-| defaultValue    | The control's default value, used when the component is not controlled                                                  |                   `string`                    |                 |
-| disabled        | Indicates that the user cannot interact with the control                                                                |                   `boolean`                   |     `false`     |
-| errorMessage    | Error text                                                                                                              |                   `string`                    |                 |
-| errorPlacement  | Error placement                                                                                                         |              `outside` `inside`               |    `outside`    |
-| hasClear        | Shows the icon for clearing control's value                                                                             |                   `boolean`                   |     `false`     |
-| id              | The control's `id` attribute                                                                                            |                   `string`                    |                 |
-| label           | Help text rendered to the left of the input node                                                                        |                   `string`                    |                 |
-| leftContent     | The user`s node rendered before label and input                                                                         |               `React.ReactNode`               |                 |
-| name            | The `name` attribute of the control. If unspecified, it will be autogenerated if not specified                          |                   `string`                    |                 |
-| note            | An optional element displayed under the bottom-right corner of the control that shares a space with the error container |               `React.ReactNode`               |                 |
-| onBlur          | Fires when the control lost focus. Provides focus event as a callback's argument                                        |                  `function`                   |                 |
-| onChange        | Fires when the input’s value is changed by the user. Provides change event as an callback's argument                    |                  `function`                   |                 |
-| onFocus         | Fires when the control gets focus. Provides focus event as a callback's argument                                        |                  `function`                   |                 |
-| onKeyDown       | Fires when a key is pressed. Provides keyboard event as a callback's argument                                           |                  `function`                   |                 |
-| onKeyUp         | Fires when a key is released. Provides keyboard event as a callback's argument                                          |                  `function`                   |                 |
-| onUpdate        | Fires when the input’s value is changed by the user. Provides new value as an callback's argument                       |                  `function`                   |                 |
-| pin             | The control's border view                                                                                               |                   `string`                    | `'round-round'` |
-| placeholder     | Text that appears in the control when it has no value set                                                               |                   `string`                    |                 |
-| qa              | Test ID attribute (`data-qa`)                                                                                           |                   `string`                    |                 |
-| rightContent    | User`s node rendered after the input node and clear button                                                              |               `React.ReactNode`               |                 |
-| size            | The size of the control                                                                                                 |           `"s"` `"m"` `"l"` `"xl"`            |      `"m"`      |
-| tabIndex        | The `tabindex` attribute of the control                                                                                 |                   `string`                    |                 |
-| type            | The type of the control                                                                                                 |                   `string`                    |                 |
-| validationState | Validation state                                                                                                        |                  `"invalid"`                  |                 |
-| value           | The value of the control                                                                                                |                   `string`                    |                 |
-| view            | The view of the control                                                                                                 |             `"normal"` `"clear"`              |   `"normal"`    |
+| Name            | Description                                                                                                             |                                 Type                                  |     Default     |
+| :-------------- | :---------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------: | :-------------: |
+| autoComplete    | The control's `autocomplete` attribute                                                                                  |                          `boolean` `string`                           |                 |
+| autoFocus       | The control's `autofocus` attribute                                                                                     |                               `boolean`                               |                 |
+| className       | The control's wrapper class name                                                                                        |                               `string`                                |                 |
+| controlProps    | The control's html attributes                                                                                           |             `React.InputHTMLAttributes`             |                 |
+| controlRef      | React ref provided to the control                                                                                       |                     `React.Ref`                     |                 |
+| defaultValue    | The control's default value, used when the component is not controlled                                                  |                               `string`                                |                 |
+| disabled        | Indicates that the user cannot interact with the control                                                                |                               `boolean`                               |     `false`     |
+| errorMessage    | Error text                                                                                                              |                               `string`                                |                 |
+| errorPlacement  | Error placement                                                                                                         |                          `outside` `inside`                           |    `outside`    |
+| hasClear        | Shows the icon for clearing control's value                                                                             |                               `boolean`                               |     `false`     |
+| id              | The control's `id` attribute                                                                                            |                               `string`                                |                 |
+| label           | Help text rendered to the left of the input node                                                                        |                               `string`                                |                 |
+| leftContent     | The user`s node rendered before label and input                                                                         |                           `React.ReactNode`                           |                 |
+| name            | The `name` attribute of the control. If unspecified, it will be autogenerated if not specified                          |                               `string`                                |                 |
+| note            | An optional element displayed under the bottom-right corner of the control that shares a space with the error container |                           `React.ReactNode`                           |                 |
+| onBlur          | Fires when the control lost focus. Provides focus event as a callback's argument                                        |                              `function`                               |                 |
+| onChange        | Fires when the input’s value is changed by the user. Provides change event as an callback's argument                    |                              `function`                               |                 |
+| onFocus         | Fires when the control gets focus. Provides focus event as a callback's argument                                        |                              `function`                               |                 |
+| onKeyDown       | Fires when a key is pressed. Provides keyboard event as a callback's argument                                           |                              `function`                               |                 |
+| onKeyUp         | Fires when a key is released. Provides keyboard event as a callback's argument                                          |                              `function`                               |                 |
+| onUpdate        | Fires when the input’s value is changed by the user. Provides new value as an callback's argument                       |                              `function`                               |                 |
+| pin             | The control's border view                                                                                               |                               `string`                                | `'round-round'` |
+| placeholder     | Text that appears in the control when it has no value set                                                               |                               `string`                                |                 |
+| qa              | Test ID attribute (`data-qa`)                                                                                           |                               `string`                                |                 |
+| rightContent    | User`s node rendered after the input node and clear button                                                              |                           `React.ReactNode`                           |                 |
+| size            | The size of the control                                                                                                 |                       `"s"` `"m"` `"l"` `"xl"`                        |      `"m"`      |
+| tabIndex        | The `tabindex` attribute of the control                                                                                 |                               `string`                                |                 |
+| type            | The type of the control                                                                                                 | `"email"` `"number"` `"password"` `"search"` `"tel"` `"text"` `"url"` |                 |
+| validationState | Validation state                                                                                                        |                              `"invalid"`                              |                 |
+| value           | The value of the control                                                                                                |                               `string`                                |                 |
+| view            | The view of the control                                                                                                 |                         `"normal"` `"clear"`                          |   `"normal"`    |
diff --git a/src/components/controls/TextInput/TextInput.tsx b/src/components/controls/TextInput/TextInput.tsx
index ffbd1cf488..dedd79f84f 100644
--- a/src/components/controls/TextInput/TextInput.tsx
+++ b/src/components/controls/TextInput/TextInput.tsx
@@ -31,7 +31,7 @@ const b = block('text-input');
 
 export type TextInputProps = BaseInputControlProps & {
     /** The control's [type](https://developer.mozilla.org/en-US/docs/Learn/Forms/HTML5_input_types) */
-    type?: string;
+    type?: 'email' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'url';
     /** The control's html attributes */
     controlProps?: React.InputHTMLAttributes;
     /** Help text rendered to the left of the input node */

From b5d7ed92bee4c6210f4e032e69644bbb578c6cce Mon Sep 17 00:00:00 2001
From: Hellen 
Date: Mon, 27 Nov 2023 18:49:12 +0300
Subject: [PATCH 3/3] feat(Table): support rtl (#1152)

---
 CODEOWNERS                                    |  2 +-
 src/components/Table/README.md                |  4 +--
 src/components/Table/Table.scss               | 14 ++++----
 src/components/Table/Table.tsx                | 35 ++++++++++++++-----
 src/components/Table/__stories__/utils.tsx    |  2 +-
 src/components/Table/__tests__/utils.ts       |  2 +-
 .../hoc/withTableActions/withTableActions.tsx |  2 +-
 .../withTableSelection.scss                   |  8 ++---
 .../withTableSelection/withTableSelection.tsx |  2 +-
 .../TableColumnSetup/TableColumnSetup.scss    |  2 +-
 .../hoc/withTableSorting/withTableSorting.tsx |  2 +-
 11 files changed, 47 insertions(+), 28 deletions(-)

diff --git a/CODEOWNERS b/CODEOWNERS
index fd4ca3ea1d..6b38e9a92a 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -38,7 +38,7 @@
 /src/components/Spin @SeqviriouM
 /src/components/Stories @DarkGenius
 /src/components/Switch @zamkovskaya
-#/src/components/Table
+/src/components/Table @Raubzeug
 /src/components/Tabs @sofiushko
 /src/components/Text @IsaevAlexandr
 /src/components/controls/TextArea @korvin89
diff --git a/src/components/Table/README.md b/src/components/Table/README.md
index 191fb573fb..a2757b1878 100644
--- a/src/components/Table/README.md
+++ b/src/components/Table/README.md
@@ -47,8 +47,8 @@ Additional functionality is enabled via HOCs:
 | name                             | Column name (header)                                                                                                                                                            |             `string` `(() => React.ReactNode)`             |                          column ID                          |
 | placeholder                      | The stub when there is no data in a cell                                                                                                                                        | `string` `((item: any, index: number) => React.ReactNode)` |                        `— (—)`                        |
 | template                         | Cell contents. If you skip a row, the cell contents will be the value of the field with the same name as this row.                                                              | `string` `((item: any, index: number) => React.ReactNode)` | The value of the field with the name equal to the column ID |
-| align                            | Content alignment                                                                                                                                                               |               `"left"` `"center"` `"right"`                |                                                             |
-| sticky                           | Sticky column                                                                                                                                                                   |                     `"left"` `"right"`                     |                                                             |
+| align                            | Content alignment                                                                                                                                                               |                `"start"` `"center"` `"end"`                |                                                             |
+| sticky                           | Sticky column                                                                                                                                                                   |                     `"start"` `"end"`                      |                                                             |
 | primary                          | Distinguishes a column among other                                                                                                                                              |                         `boolean`                          |                                                             |
 | width                            | Column width in px                                                                                                                                                              |                          `number`                          |                                                             |
 | stickyHorizontalScroll           | A horizontal sticky scroll in a table. NB: A table cannot have a fixed height and a sticky scroll at the same time. A sticky scroll will not work if the table has an overflow. |                         `boolean`                          |                           `false`                           |
diff --git a/src/components/Table/Table.scss b/src/components/Table/Table.scss
index 567c6d0369..a2e5b70a46 100644
--- a/src/components/Table/Table.scss
+++ b/src/components/Table/Table.scss
@@ -74,18 +74,18 @@
             text-align: center;
         }
 
-        &_align_right {
+        &_align_end {
             text-align: end;
         }
 
-        &_sticky_left,
-        &_sticky_right {
+        &_sticky_start,
+        &_sticky_end {
             position: sticky;
             z-index: 2;
         }
 
-        &_sticky_left,
-        &_sticky_right {
+        &_sticky_start,
+        &_sticky_end {
             background: var(--g-color-base-background);
         }
 
@@ -133,8 +133,8 @@
         background-color: var(--g-color-base-simple-hover-solid);
         cursor: pointer;
 
-        #{variables.$block}__cell_sticky_left,
-        #{variables.$block}__cell_sticky_right {
+        #{variables.$block}__cell_sticky_start,
+        #{variables.$block}__cell_sticky_end {
             background: var(--g-color-base-simple-hover-solid);
         }
     }
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx
index a462982e3e..60abbee193 100644
--- a/src/components/Table/Table.tsx
+++ b/src/components/Table/Table.tsx
@@ -19,6 +19,16 @@ export interface TableDataItem {
 
 type ActiveScrollElementType = 'scrollBar' | 'scrollContainer';
 
+function normalizeSides(side: TableColumnConfig['align'] | TableColumnConfig['sticky']) {
+    if (side === 'left') {
+        return 'start';
+    }
+    if (side === 'right') {
+        return 'end';
+    }
+    return side;
+}
+
 interface TableState {
     // activeScrollElement is required so listener on table scroll won't fire when scrollbar will appear (and vice-versa)
     // without that page will wobble on scrolling
@@ -39,9 +49,9 @@ export interface TableColumnConfig {
     /** Cell contents. If you pass a row, the cell contents will be the value of the field named the same as this row. By default: The value of the field with the name equal to the column ID */
     template?: string | ((item: I, index: number) => React.ReactNode);
     /** Content alignment. */
-    align?: 'left' | 'center' | 'right';
+    align?: 'start' | 'end' | 'center' | 'left' | 'right';
     /** Sticky column. */
-    sticky?: 'left' | 'right';
+    sticky?: 'start' | 'end' | 'left' | 'right';
     /** Distinguishes a column among other. */
     primary?: boolean;
     /** Column width in px or in %. Width can behave unexpectedly (it's more like min-width in block-elements). Sometimes you want to use `table-layout: fixed` */
@@ -344,7 +354,9 @@ export class Table> extends Rea
             
                 
                     {columns.map((column, index) => {
-                        const {id, align, primary, sticky, className} = column;
+                        const {id, align: rawAlign, primary, sticky: rawSticky, className} = column;
+                        const align = normalizeSides(rawAlign);
+                        const sticky = normalizeSides(rawSticky);
                         const content = Table.getHeadCellContent(column);
 
                         return (
@@ -439,9 +451,10 @@ export class Table> extends Rea
                 )}
             >
                 {columns.map((column, colIndex) => {
-                    const {id, align, primary, className, sticky} = column;
+                    const {id, align: rawAlign, primary, className, sticky: rawSticky} = column;
                     const content = Table.getBodyCellContent(column, item, rowIndex);
-
+                    const align = normalizeSides(rawAlign);
+                    const sticky = normalizeSides(rawSticky);
                     return (
                         > extends Rea
         }
 
         const filteredColumns =
-            column.sticky === 'left' ? columnsWidth.slice(0, index) : columnsWidth.slice(index + 1);
-        style[column.sticky] = filteredColumns.reduce((left, width) => {
-            return _isNumber(width) ? left + width : left;
+            column.sticky === 'left' || column.sticky === 'start'
+                ? columnsWidth.slice(0, index)
+                : columnsWidth.slice(index + 1);
+        const styleName: keyof React.CSSProperties =
+            column.sticky === 'left' || column.sticky === 'start'
+                ? 'insetInlineStart'
+                : 'insetInlineEnd';
+        style[styleName] = filteredColumns.reduce((start, width) => {
+            return _isNumber(width) ? start + width : start;
         }, 0);
 
         return style;
diff --git a/src/components/Table/__stories__/utils.tsx b/src/components/Table/__stories__/utils.tsx
index 51c1ad1967..c9d14ecc00 100644
--- a/src/components/Table/__stories__/utils.tsx
+++ b/src/components/Table/__stories__/utils.tsx
@@ -66,7 +66,7 @@ export const columns: TableColumnConfig[] = [
     {
         id: 'count',
         name: 'Count',
-        align: 'right',
+        align: 'end',
     },
     {
         id: 'date',
diff --git a/src/components/Table/__tests__/utils.ts b/src/components/Table/__tests__/utils.ts
index b81b3ca3ef..588fdee34a 100644
--- a/src/components/Table/__tests__/utils.ts
+++ b/src/components/Table/__tests__/utils.ts
@@ -63,7 +63,7 @@ export const columns: TableColumnConfig[] = [
     {
         id: 'count',
         name: 'Count',
-        align: 'right',
+        align: 'end',
     },
     {
         id: 'date',
diff --git a/src/components/Table/hoc/withTableActions/withTableActions.tsx b/src/components/Table/hoc/withTableActions/withTableActions.tsx
index 7e1f390594..2aa8a04b06 100644
--- a/src/components/Table/hoc/withTableActions/withTableActions.tsx
+++ b/src/components/Table/hoc/withTableActions/withTableActions.tsx
@@ -24,7 +24,7 @@ export function enhanceSystemColumn(
     const systemColumn = existedColumn || {
         id: actionsColumnId,
         name: '',
-        sticky: 'right',
+        sticky: 'end',
         width: 28, // button width
         placeholder: '',
     };
diff --git a/src/components/Table/hoc/withTableSelection/withTableSelection.scss b/src/components/Table/hoc/withTableSelection/withTableSelection.scss
index 1d27b4a78b..61c1cc5a7a 100644
--- a/src/components/Table/hoc/withTableSelection/withTableSelection.scss
+++ b/src/components/Table/hoc/withTableSelection/withTableSelection.scss
@@ -16,8 +16,8 @@
     &__row_selected {
         background: var(--g-color-base-selection);
 
-        #{variables.$block}__cell_sticky_left,
-        #{variables.$block}__cell_sticky_right {
+        #{variables.$block}__cell_sticky_start,
+        #{variables.$block}__cell_sticky_end {
             background: linear-gradient(
                     to right,
                     var(--g-color-base-selection),
@@ -33,8 +33,8 @@
         &#{variables.$block}__row_interactive:hover {
             background: var(--g-color-base-selection-hover);
 
-            #{variables.$block}__cell_sticky_left,
-            #{variables.$block}__cell_sticky_right {
+            #{variables.$block}__cell_sticky_start,
+            #{variables.$block}__cell_sticky_end {
                 background: linear-gradient(
                         to right,
                         var(--g-color-base-selection-hover),
diff --git a/src/components/Table/hoc/withTableSelection/withTableSelection.tsx b/src/components/Table/hoc/withTableSelection/withTableSelection.tsx
index a8dac459cd..6b176a094b 100644
--- a/src/components/Table/hoc/withTableSelection/withTableSelection.tsx
+++ b/src/components/Table/hoc/withTableSelection/withTableSelection.tsx
@@ -163,7 +163,7 @@ export function withTableSelection(
                 name: this.renderHeadCell,
                 template: this.renderBodyCell,
                 className: b('checkbox_cell'),
-                sticky: _get(columns, [0, 'sticky']) === 'left' ? 'left' : undefined,
+                sticky: _get(columns, [0, 'sticky']) === 'start' ? 'start' : undefined,
             };
 
             return [selectionColumn, ...columns];
diff --git a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss
index 46f903355d..d962bd6a04 100644
--- a/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss
+++ b/src/components/Table/hoc/withTableSettings/TableColumnSetup/TableColumnSetup.scss
@@ -52,7 +52,7 @@ $block: '.#{variables.$ns}table-column-setup';
     &__item {
         // Increasing specificity for overrides
         &#{&} {
-            padding: 0 8px 0 32px;
+            padding-inline: 32px 8px;
             cursor: pointer;
             position: relative;
 
diff --git a/src/components/Table/hoc/withTableSorting/withTableSorting.tsx b/src/components/Table/hoc/withTableSorting/withTableSorting.tsx
index 994fd13b09..51186974ca 100644
--- a/src/components/Table/hoc/withTableSorting/withTableSorting.tsx
+++ b/src/components/Table/hoc/withTableSorting/withTableSorting.tsx
@@ -143,7 +143,7 @@ export function withTableSorting(
                                 
, ]; - if (column.align === 'right') { + if (column.align === 'right' || column.align === 'end') { content.reverse(); }