<commit_before>Reactabular's sorting helpers make it possible to manage sorting related classes and to sort rows based on them. You can either use them through `reactabular` or `reactabular-sort`.

## How to Use?

The general workflow goes as follows:

1. Set up the `sort` transform. Its purpose is to track when the user requests sorting and render possibly matching sorting condition as a class for styling.
2. Set up a sort helper. There are helpers for sorting per one column (`sort.byColumn`) and one for sorting per multiple columns (`sort.byColumns`). The helpers handle managing sorting conditions and actual sorting. If you have a back-end, you can skip the latter.
3. Sort the rows before rendering.
4. Feed the sorted rows to a `Table`.

> You can find suggested default styling for the package at `style.css` in the package root.

**Example:**

```jsx
/*
import React from 'react';
import orderBy from 'lodash/orderBy';
import { Table, sort, resolve } from 'reactabular';
import { compose } from 'redux';
*/

const initialRows = [
  {
    id: 100,
    name: {
      first: 'Adam',
      last: 'West'
    },
    age: 10
  },
  {
    id: 101,
    name: {
      first: 'Brian',
      last: 'Eno'
    },
    age: 43
  },
  {
    id: 102,
    name: {
      first: 'Brian',
      last: 'Wilson'
    },
    age: 23
  },
  {
    id: 103,
    name: {
      first: 'Jake',
      last: 'Dalton'
    },
    age: 33
  },
  {
    id: 104,
    name: {
      first: 'Jill',
      last: 'Jackson'
    },
    age: 63
  }
];

class SortTable extends React.Component {
  constructor(props) {
    super(props);

    const getSortingColumns = () => this.state.sortingColumns || {};
    const sortable = sort.sort({
      // Point the transform to your rows. React state can work for this purpose
      // but you can use a state manager as well.
      getSortingColumns,

      // The user requested sorting, adjust the sorting state accordingly.
      // This is a good chance to pass the request through a sorter.
      onSort: selectedColumn => {
        this.setState({
          sortingColumns: sort.byColumns({ // sort.byColumn would work too
            sortingColumns: this.state.sortingColumns,
            selectedColumn
          })
        });
      }
    });
    const resetable = sort.reset({
      event: 'onDoubleClick',
      getSortingColumns,
      onReset: ({ sortingColumns }) => this.setState({ sortingColumns })
    });

    this.state = {
      // Sort the first column in a descending way by default.
      // "asc" would work too and you can set multiple if you want.
      sortingColumns: {
        0: {
          direction: 'desc',
          position: 0
        }
      },
      columns: [
        {
          header: {
            label: 'Name'
          },
          children: [
            {
              property: 'name.first',
              header: {
                label: '<NAME>',
                transforms: [resetable],
                formatters: [
                  sort.header({
                    sortable,
                    getSortingColumns
                  })
                ]
              }
            },
            {
              property: 'name.last',
              header: {
                label: '<NAME>',
                transforms: [resetable],
                formatters: [
                  sort.header({
                    sortable,
                    getSortingColumns
                  })
                ]
              }
            }
          ]
        },
        {
          property: 'age',
          header: {
            label: 'Age',
            transforms: [resetable],
            formatters: [
              sort.header({
                sortable,
                getSortingColumns
              })
            ]
            // Alternative if you don't need reset.
            // transforms: [sortable]
          }
        }
      ],
      rows: initialRows
    };
  }
  render() {
    const { rows, sortingColumns, columns } = this.state;
    const resolvedColumns = resolve.columnChildren({ columns });
    const sortedRows = compose(
      sort.sorter({
        columns: resolvedColumns,
        sortingColumns,
        sort: orderBy
      }),
      resolve.resolve({
        columns: resolvedColumns,
        method: resolve.nested
      })
    )(rows);

    return (
      <div>
        <Table.Provider columns={resolvedColumns}>
          <Table.Header
            headerRows={resolve.headerRows({ columns })}
          />

          <Table.Body rows={sortedRows} rowKey="id" />
        </Table.Provider>
      </div>
    );
  }
}

<SortTable />
```

## API

The API consists of the sort helpers, transforms, formatters, and strategies. These can be combined together to set up sort in various ways. There's control over the algorithm used as well as how it's bound to the user interface. You can also control how sorting is tracked (per column index or per property).

### Helpers

**`sort.byColumn({ sortingColumns: <sorting columns>, sortingOrder: {FIRST: <string>, <string>: <string>}, selectedColumn: <string> }) => <sorting colums> || {}`**<commit_msg>fix(sort) - Use property strategy due to nesting<commit_after>Reactabular's sorting helpers make it possible to manage sorting related classes and to sort rows based on them. You can either use them through `reactabular` or `reactabular-sort`.

## How to Use?

The general workflow goes as follows:

1. Set up the `sort` transform. Its purpose is to track when the user requests sorting and render possibly matching sorting condition as a class for styling.
2. Set up a sort helper. There are helpers for sorting per one column (`sort.byColumn`) and one for sorting per multiple columns (`sort.byColumns`). The helpers handle managing sorting conditions and actual sorting. If you have a back-end, you can skip the latter.
3. Sort the rows before rendering.
4. Feed the sorted rows to a `Table`.

> You can find suggested default styling for the package at `style.css` in the package root.

**Example:**

```jsx
/*
import React from 'react';
import orderBy from 'lodash/orderBy';
import { Table, sort, resolve } from 'reactabular';
import { compose } from 'redux';
*/

const initialRows = [
  {
    id: 100,
    name: {
      first: 'Adam',
      last: 'West'
    },
    age: 10
  },
  {
    id: 101,
    name: {
      first: 'Brian',
      last: 'Eno'
    },
    age: 43
  },
  {
    id: 102,
    name: {
      first: 'Brian',
      last: 'Wilson'
    },
    age: 23
  },
  {
    id: 103,
    name: {
      first: 'Jake',
      last: 'Dalton'
    },
    age: 33
  },
  {
    id: 104,
    name: {
      first: 'Jill',
      last: 'Jackson'
    },
    age: 63
  }
];

class SortTable extends React.Component {
  constructor(props) {
    super(props);

    const getSortingColumns = () => this.state.sortingColumns || {};
    const sortable = sort.sort({
      // Point the transform to your rows. React state can work for this purpose
      // but you can use a state manager as well.
      getSortingColumns,

      // The user requested sorting, adjust the sorting state accordingly.
      // This is a good chance to pass the request through a sorter.
      onSort: selectedColumn => {
        this.setState({
          sortingColumns: sort.byColumns({ // sort.byColumn would work too
            sortingColumns: this.state.sortingColumns,
            selectedColumn
          })
        });
      },

      // Use property strategy over index one given we have nested data
      strategy: sort.strategies.byProperty
    });
    const resetable = sort.reset({
      event: 'onDoubleClick',
      getSortingColumns,
      onReset: ({ sortingColumns }) => this.setState({ sortingColumns }),
      strategy: sort.strategies.byProperty
    });

    this.state = {
      // Sort the first column in a descending way by default.
      // "asc" would work too and you can set multiple if you want.
      sortingColumns: {
        'name.first': {
          direction: 'desc',
          position: 0
        }
      },
      columns: [
        {
          header: {
            label: 'Name'
          },
          children: [
            {
              property: 'name.first',
              header: {
                label: 'First Name',
                transforms: [resetable],
                formatters: [
                  sort.header({
                    sortable,
                    getSortingColumns,
                    strategy: sort.strategies.byProperty
                  })
                ]
              }
            },
            {
              property: 'name.last',
              header: {
                label: '<NAME>',
                transforms: [resetable],
                formatters: [
                  sort.header({
                    sortable,
                    getSortingColumns,
                    strategy: sort.strategies.byProperty
                  })
                ]
              }
            }
          ]
        },
        {
          property: 'age',
          header: {
            label: 'Age',
            transforms: [resetable],
            formatters: [
              sort.header({
                sortable,
                getSortingColumns,
                strategy: sort.strategies.byProperty
              })
            ]
            // Alternative if you don't need reset.
            // transforms: [sortable]
          }
        }
      ],
      rows: initialRows
    };
  }
  render() {
    const { rows, sortingColumns, columns } = this.state;
    const resolvedColumns = resolve.columnChildren({ columns });
    const sortedRows = compose(
      sort.sorter({
        columns: resolvedColumns,
        sortingColumns,
        sort: orderBy,
        strategy: sort.strategies.byProperty
      }),
      resolve.resolve({
        columns: resolvedColumns,
        method: resolve.nested
      })
    )(rows);

    return (
      <div>
        <Table.Provider columns={resolvedColumns}>
          <Table.Header
            headerRows={resolve.headerRows({ columns })}
          />

          <Table.Body rows={sortedRows} rowKey="id" />
        </Table.Provider>
      </div>
    );
  }
}

<SortTable />
```

## API

The API consists of the sort helpers, transforms, formatters, and strategies. These can be combined together to set up sort in various ways. There's control over the algorithm used as well as how it's bound to the user interface. You can also control how sorting is tracked (per column index or per property).

### Helpers

**`sort.byColumn({ sortingColumns: <sorting columns>, sortingOrder: {FIRST: <string>, <string>: <string>}, selectedColumn: <string> }) => <sorting colums> || {}`**
{'fraction_non_alphanumeric': 0.10354172507242314, 'fraction_numerical': 0.005700401831604523, 'mean_word_length': 1.7231552162849872, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4210452', 'n_tokens_mistral': 3014, 'n_tokens_neox': 2836, 'n_words': 954}