@atlaskit/table 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +13 -0
  3. package/README.md +83 -0
  4. package/constellation/index/examples.mdx +19 -0
  5. package/constellation/index/props.mdx +32 -0
  6. package/dist/cjs/body.js +105 -0
  7. package/dist/cjs/head-cell.js +42 -0
  8. package/dist/cjs/hooks/selection-provider.js +52 -0
  9. package/dist/cjs/hooks/use-row-id.js +26 -0
  10. package/dist/cjs/hooks/use-selectable.js +183 -0
  11. package/dist/cjs/hooks/use-sorting.js +59 -0
  12. package/dist/cjs/hooks/use-table-body.js +28 -0
  13. package/dist/cjs/hooks/use-table.js +56 -0
  14. package/dist/cjs/index.js +63 -0
  15. package/dist/cjs/row.js +70 -0
  16. package/dist/cjs/selectable-cell.js +53 -0
  17. package/dist/cjs/sortable-column.js +129 -0
  18. package/dist/cjs/table.js +60 -0
  19. package/dist/cjs/thead.js +73 -0
  20. package/dist/cjs/ui/base-cell.js +72 -0
  21. package/dist/cjs/ui/bulk-action-overlay.js +39 -0
  22. package/dist/cjs/ui/index.js +69 -0
  23. package/dist/cjs/ui/selectable-cell.js +39 -0
  24. package/dist/cjs/ui/table.js +31 -0
  25. package/dist/cjs/ui/tbody.js +38 -0
  26. package/dist/cjs/ui/td.js +38 -0
  27. package/dist/cjs/ui/th.js +40 -0
  28. package/dist/cjs/ui/thead.js +40 -0
  29. package/dist/cjs/ui/tr.js +68 -0
  30. package/dist/cjs/version.json +5 -0
  31. package/dist/es2019/body.js +66 -0
  32. package/dist/es2019/head-cell.js +31 -0
  33. package/dist/es2019/hooks/selection-provider.js +33 -0
  34. package/dist/es2019/hooks/use-row-id.js +13 -0
  35. package/dist/es2019/hooks/use-selectable.js +158 -0
  36. package/dist/es2019/hooks/use-sorting.js +37 -0
  37. package/dist/es2019/hooks/use-table-body.js +13 -0
  38. package/dist/es2019/hooks/use-table.js +34 -0
  39. package/dist/es2019/index.js +7 -0
  40. package/dist/es2019/row.js +41 -0
  41. package/dist/es2019/selectable-cell.js +25 -0
  42. package/dist/es2019/sortable-column.js +109 -0
  43. package/dist/es2019/table.js +38 -0
  44. package/dist/es2019/thead.js +46 -0
  45. package/dist/es2019/ui/base-cell.js +54 -0
  46. package/dist/es2019/ui/bulk-action-overlay.js +27 -0
  47. package/dist/es2019/ui/index.js +11 -0
  48. package/dist/es2019/ui/selectable-cell.js +28 -0
  49. package/dist/es2019/ui/table.js +22 -0
  50. package/dist/es2019/ui/tbody.js +26 -0
  51. package/dist/es2019/ui/td.js +21 -0
  52. package/dist/es2019/ui/th.js +26 -0
  53. package/dist/es2019/ui/thead.js +31 -0
  54. package/dist/es2019/ui/tr.js +55 -0
  55. package/dist/es2019/version.json +5 -0
  56. package/dist/esm/body.js +84 -0
  57. package/dist/esm/head-cell.js +31 -0
  58. package/dist/esm/hooks/selection-provider.js +32 -0
  59. package/dist/esm/hooks/use-row-id.js +15 -0
  60. package/dist/esm/hooks/use-selectable.js +171 -0
  61. package/dist/esm/hooks/use-sorting.js +46 -0
  62. package/dist/esm/hooks/use-table-body.js +13 -0
  63. package/dist/esm/hooks/use-table.js +36 -0
  64. package/dist/esm/index.js +7 -0
  65. package/dist/esm/row.js +46 -0
  66. package/dist/esm/selectable-cell.js +31 -0
  67. package/dist/esm/sortable-column.js +114 -0
  68. package/dist/esm/table.js +39 -0
  69. package/dist/esm/thead.js +51 -0
  70. package/dist/esm/ui/base-cell.js +58 -0
  71. package/dist/esm/ui/bulk-action-overlay.js +28 -0
  72. package/dist/esm/ui/index.js +11 -0
  73. package/dist/esm/ui/selectable-cell.js +28 -0
  74. package/dist/esm/ui/table.js +21 -0
  75. package/dist/esm/ui/tbody.js +27 -0
  76. package/dist/esm/ui/td.js +26 -0
  77. package/dist/esm/ui/th.js +28 -0
  78. package/dist/esm/ui/thead.js +30 -0
  79. package/dist/esm/ui/tr.js +55 -0
  80. package/dist/esm/version.json +5 -0
  81. package/dist/types/body.d.ts +15 -0
  82. package/dist/types/head-cell.d.ts +10 -0
  83. package/dist/types/hooks/selection-provider.d.ts +25 -0
  84. package/dist/types/hooks/use-row-id.d.ts +10 -0
  85. package/dist/types/hooks/use-selectable.d.ts +14 -0
  86. package/dist/types/hooks/use-sorting.d.ts +6 -0
  87. package/dist/types/hooks/use-table-body.d.ts +7 -0
  88. package/dist/types/hooks/use-table.d.ts +21 -0
  89. package/dist/types/index.d.ts +7 -0
  90. package/dist/types/row.d.ts +14 -0
  91. package/dist/types/selectable-cell.d.ts +3 -0
  92. package/dist/types/sortable-column.d.ts +17 -0
  93. package/dist/types/table.d.ts +26 -0
  94. package/dist/types/thead.d.ts +7 -0
  95. package/dist/types/ui/base-cell.d.ts +30 -0
  96. package/dist/types/ui/bulk-action-overlay.d.ts +8 -0
  97. package/dist/types/ui/index.d.ts +11 -0
  98. package/dist/types/ui/selectable-cell.d.ts +10 -0
  99. package/dist/types/ui/table.d.ts +23 -0
  100. package/dist/types/ui/tbody.d.ts +8 -0
  101. package/dist/types/ui/td.d.ts +11 -0
  102. package/dist/types/ui/th.d.ts +11 -0
  103. package/dist/types/ui/thead.d.ts +10 -0
  104. package/dist/types/ui/tr.d.ts +16 -0
  105. package/package.json +101 -0
  106. package/primitives/package.json +15 -0
  107. package/report.api.md +139 -0
  108. package/tmp/api-report-tmp.d.ts +99 -0
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SelectableCell = void 0;
7
+
8
+ var _react = require("@emotion/react");
9
+
10
+ var _baseCell = require("./base-cell");
11
+
12
+ /** @jsx jsx */
13
+ var spacingStyles = (0, _react.css)({
14
+ width: 32,
15
+ padding: "var(--ds-space-0, 0px)",
16
+ paddingLeft: "var(--ds-space-100, 8px)",
17
+ // eslint-disable-next-line @repo/internal/styles/no-nested-styles
18
+ '& + *': {
19
+ // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage-spacing
20
+ paddingLeft: '8px !important'
21
+ }
22
+ });
23
+ /**
24
+ * __Selectable cell__
25
+ *
26
+ * A selectable cell primitive designed to be used for light weight composition.
27
+ */
28
+
29
+ var SelectableCell = function SelectableCell(_ref) {
30
+ var children = _ref.children,
31
+ _ref$as = _ref.as,
32
+ as = _ref$as === void 0 ? 'td' : _ref$as;
33
+ return (0, _react.jsx)(_baseCell.BaseCell, {
34
+ as: as,
35
+ css: spacingStyles
36
+ }, children);
37
+ };
38
+
39
+ exports.SelectableCell = SelectableCell;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Table = void 0;
7
+
8
+ var _react = require("@emotion/react");
9
+
10
+ /** @jsx jsx */
11
+
12
+ /**
13
+ * __Table__
14
+ *
15
+ * A primitive table container. Applies the HTML native element with no other styling.
16
+ *
17
+ * - [Examples](https://atlassian.design/components/table/examples)
18
+ *
19
+ * @primitive
20
+ * @see https://hello.atlassian.net/wiki/spaces/DST/pages/1947062524/Dynamic+table+2.0+implementation+spec
21
+ */
22
+ var Table = function Table(_ref) {
23
+ var children = _ref.children,
24
+ testId = _ref.testId,
25
+ summary = _ref.summary;
26
+ return (0, _react.jsx)("table", {
27
+ "data-testid": testId
28
+ }, summary && (0, _react.jsx)("caption", null, summary), children);
29
+ };
30
+
31
+ exports.Table = Table;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.TBody = void 0;
7
+
8
+ var _react = require("@emotion/react");
9
+
10
+ /* eslint-disable @repo/internal/react/no-clone-element */
11
+
12
+ /** @jsx jsx */
13
+ var bodyStyles = (0, _react.css)({
14
+ position: 'relative',
15
+ border: 'none',
16
+ '&:after': {
17
+ position: 'absolute',
18
+ boxShadow: "inset 0 -2px 0 0 ".concat("var(--ds-border, #eee)"),
19
+ content: "''",
20
+ inset: 0,
21
+ pointerEvents: 'none'
22
+ }
23
+ });
24
+ /**
25
+ * __TBody__
26
+ * @primitive
27
+ */
28
+
29
+ var TBody = function TBody(_ref) {
30
+ var children = _ref.children;
31
+ return (0, _react.jsx)("tbody", {
32
+ css: bodyStyles
33
+ }, children);
34
+ };
35
+
36
+ exports.TBody = TBody;
37
+ var _default = TBody;
38
+ exports.default = _default;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.TD = void 0;
9
+
10
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
+
12
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
13
+
14
+ var _react = require("@emotion/react");
15
+
16
+ var _baseCell = require("./base-cell");
17
+
18
+ var _excluded = ["testId"];
19
+
20
+ /**
21
+ * __Cell__
22
+ *
23
+ * A data cell.
24
+ *
25
+ * @primitive
26
+ */
27
+ var TD = function TD(_ref) {
28
+ var testId = _ref.testId,
29
+ props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
30
+ return (// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
31
+ (0, _react.jsx)(_baseCell.BaseCell, (0, _extends2.default)({
32
+ as: "td",
33
+ testId: testId
34
+ }, props))
35
+ );
36
+ };
37
+
38
+ exports.TD = TD;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.TH = void 0;
9
+
10
+ var _react = _interopRequireDefault(require("react"));
11
+
12
+ var _baseCell = require("./base-cell");
13
+
14
+ /**
15
+ * __Head cell__
16
+ *
17
+ * A head cell.
18
+ *
19
+ * @primitive
20
+ */
21
+ var TH = function TH(_ref) {
22
+ var children = _ref.children,
23
+ testId = _ref.testId,
24
+ align = _ref.align,
25
+ scope = _ref.scope,
26
+ backgroundColor = _ref.backgroundColor;
27
+ return (
28
+ /*#__PURE__*/
29
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
30
+ _react.default.createElement(_baseCell.BaseCell, {
31
+ as: "th",
32
+ testId: testId,
33
+ align: align,
34
+ scope: scope,
35
+ backgroundColor: backgroundColor
36
+ }, children)
37
+ );
38
+ };
39
+
40
+ exports.TH = TH;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.THead = void 0;
7
+
8
+ var _react = require("@emotion/react");
9
+
10
+ /** @jsx jsx */
11
+ var baseStyles = (0, _react.css)({
12
+ position: 'sticky',
13
+ zIndex: 1,
14
+ backgroundColor: "var(--ds-surface, white)",
15
+ border: 'none',
16
+ inset: 0,
17
+ '&:after': {
18
+ position: 'absolute',
19
+ boxShadow: "inset 0 -2px 0 0 ".concat("var(--ds-border, #eee)"),
20
+ content: "''",
21
+ inset: 0,
22
+ pointerEvents: 'none'
23
+ }
24
+ });
25
+ /**
26
+ * __THead__
27
+ *
28
+ * A primitive table head container. Applies the HTML native element with minimal styling.
29
+ *
30
+ * @primitive
31
+ */
32
+
33
+ var THead = function THead(_ref) {
34
+ var children = _ref.children;
35
+ return (0, _react.jsx)("thead", {
36
+ css: baseStyles
37
+ }, children);
38
+ };
39
+
40
+ exports.THead = THead;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.TR = void 0;
9
+
10
+ var _react = require("@emotion/react");
11
+
12
+ var _focusRing = _interopRequireDefault(require("@atlaskit/focus-ring"));
13
+
14
+ /** @jsx jsx */
15
+ var baseStyles = (0, _react.css)({
16
+ height: 48,
17
+ position: 'relative',
18
+ border: 'none',
19
+ borderImageWidth: 0,
20
+ borderSpacing: 0
21
+ });
22
+ var selectedStyles = (0, _react.css)({
23
+ backgroundColor: "var(--ds-background-selected, #DEEBFF88)",
24
+ '&:hover': {
25
+ backgroundColor: "var(--ds-background-selected-hovered, #DEEBFF)" // B50
26
+
27
+ }
28
+ });
29
+ var bodyRowStyles = (0, _react.css)({
30
+ '&:hover': {
31
+ backgroundColor: "var(--ds-background-neutral-subtle-hovered, #f8f8f8)"
32
+ },
33
+ '&:focus-visible::after': {
34
+ boxShadow: 'none'
35
+ },
36
+ '&:after': {
37
+ position: 'absolute',
38
+ boxShadow: "inset 0 -1px 0 0 ".concat("var(--ds-border, #eee)"),
39
+ content: "''",
40
+ inset: 0,
41
+ pointerEvents: 'none'
42
+ }
43
+ });
44
+
45
+ /**
46
+ * __Row__
47
+ *
48
+ * A row primitive.
49
+ *
50
+ * - [Examples](https://atlassian.design/components/table/examples)
51
+ */
52
+ var TR = function TR(_ref) {
53
+ var children = _ref.children,
54
+ testId = _ref.testId,
55
+ isSelected = _ref.isSelected,
56
+ _ref$isBodyRow = _ref.isBodyRow,
57
+ isBodyRow = _ref$isBodyRow === void 0 ? true : _ref$isBodyRow;
58
+ return (0, _react.jsx)(_focusRing.default, {
59
+ isInset: true
60
+ }, (0, _react.jsx)("tr", {
61
+ tabIndex: -1,
62
+ "aria-selected": isSelected,
63
+ "data-testid": testId,
64
+ css: [baseStyles, isBodyRow && bodyRowStyles, isSelected && selectedStyles]
65
+ }, children));
66
+ };
67
+
68
+ exports.TR = TR;
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@atlaskit/table",
3
+ "version": "0.1.0",
4
+ "sideEffects": false
5
+ }
@@ -0,0 +1,66 @@
1
+ /* eslint-disable @repo/internal/react/no-clone-element */
2
+
3
+ /** @jsx jsx */
4
+ import { Children, useEffect } from 'react';
5
+ import { jsx } from '@emotion/react';
6
+ import { useSelection } from './hooks/selection-provider';
7
+ import { RowProvider } from './hooks/use-row-id';
8
+ import { useTable } from './hooks/use-table';
9
+ import { TableBodyProvider } from './hooks/use-table-body';
10
+ import * as Primitives from './ui';
11
+
12
+ /**
13
+ * __Table body__
14
+ */
15
+ function TBody({
16
+ rows,
17
+ children
18
+ }) {
19
+ const {
20
+ sortKey,
21
+ sortDirection
22
+ } = useTable();
23
+ const [_state, {
24
+ removeAll,
25
+ setMax
26
+ }] = useSelection(); // TODO this seems like something the user should control
27
+
28
+ useEffect(() => {
29
+ if (removeAll) {
30
+ removeAll();
31
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
32
+
33
+ }, [rows]); // Set data length (via setMax) whenever data changes
34
+
35
+ useEffect(() => {
36
+ const numRows = rows !== undefined ? rows.length : Children.count(children);
37
+ setMax && setMax(numRows); // eslint-disable-next-line react-hooks/exhaustive-deps
38
+ }, [rows === null || rows === void 0 ? void 0 : rows.length, Children.count(children)]);
39
+
40
+ const sortFn = (rowA, rowB) => {
41
+ if (sortKey === 'unset') {
42
+ return 0;
43
+ }
44
+
45
+ const ascendingComparator = rowA[sortKey] < rowB[sortKey] ? -1 : 1;
46
+ return sortDirection === 'ascending' ? ascendingComparator : -ascendingComparator;
47
+ };
48
+
49
+ return jsx(TableBodyProvider, {
50
+ value: true
51
+ }, jsx(Primitives.TBody, null, typeof children === 'function' && rows ? rows.map((row, idx) => ({ ...row,
52
+ idx
53
+ })).sort(sortFn).map(({
54
+ idx,
55
+ ...row
56
+ }) => jsx(RowProvider, {
57
+ key: idx,
58
+ value: idx
59
+ }, // @ts-expect-error
60
+ children(row))) : Children.map(children, (row, idx) => jsx(RowProvider, {
61
+ key: idx,
62
+ value: idx
63
+ }, row))));
64
+ }
65
+
66
+ export default TBody;
@@ -0,0 +1,31 @@
1
+ /* eslint-disable no-unused-vars */
2
+
3
+ /** @jsx jsx */
4
+ import { jsx } from '@emotion/react';
5
+ import { UNSAFE_Text as Text } from '@atlaskit/ds-explorations';
6
+ import { TH } from './ui/th';
7
+ /**
8
+ * __HeadCell__
9
+ *
10
+ * HeadCell element
11
+ */
12
+
13
+ const Column = ({
14
+ children,
15
+ align,
16
+ testId,
17
+ backgroundColor,
18
+ scope = 'col'
19
+ }) => {
20
+ return jsx(TH, {
21
+ scope: scope,
22
+ align: align,
23
+ testId: testId,
24
+ backgroundColor: backgroundColor
25
+ }, jsx(Text, {
26
+ color: "color.text",
27
+ fontWeight: "500"
28
+ }, children));
29
+ };
30
+
31
+ export default Column;
@@ -0,0 +1,33 @@
1
+ import React, { createContext, useContext } from 'react';
2
+ import useSelectionReducer from './use-selectable';
3
+ const SelectionContext = /*#__PURE__*/createContext([{
4
+ checked: [],
5
+ allChecked: false,
6
+ anyChecked: false,
7
+ maxChecked: 0,
8
+ selectionStart: -1,
9
+ previousSelection: []
10
+ }, {}]);
11
+ /**
12
+ * __Selection provider__
13
+ *
14
+ * A selection provider injects selection specific state into the table.
15
+ *
16
+ * - [Examples](https://atlassian.design/components/{packageName}/examples)
17
+ * - [Code](https://atlassian.design/components/{packageName}/code)
18
+ * - [Usage](https://atlassian.design/components/{packageName}/usage)
19
+ */
20
+
21
+ const SelectionProvider = ({
22
+ children
23
+ }) => {
24
+ const reducer = useSelectionReducer();
25
+ return /*#__PURE__*/React.createElement(SelectionContext.Provider, {
26
+ value: reducer
27
+ }, children);
28
+ };
29
+
30
+ export const useSelection = () => {
31
+ return useContext(SelectionContext);
32
+ };
33
+ export default SelectionProvider;
@@ -0,0 +1,13 @@
1
+ import { createContext, useContext } from 'react';
2
+ const RowContext = /*#__PURE__*/createContext(undefined);
3
+ /**
4
+ * @internal
5
+ */
6
+
7
+ export const useRowId = () => useContext(RowContext);
8
+ /**
9
+ * __Row provider__
10
+ * @internal
11
+ */
12
+
13
+ export const RowProvider = RowContext.Provider;
@@ -0,0 +1,158 @@
1
+ import { useCallback, useReducer } from 'react';
2
+ const defaultState = {
3
+ checked: [],
4
+ allChecked: false,
5
+ anyChecked: false,
6
+ maxChecked: 0,
7
+ selectionStart: -1,
8
+ previousSelection: []
9
+ };
10
+
11
+ const arrayFromRange = (from, to) => {
12
+ let startIdx = from;
13
+ let stopIdx = to;
14
+ let increment = 1;
15
+
16
+ if (from > to) {
17
+ startIdx = to;
18
+ stopIdx = from;
19
+ increment = 0;
20
+ } // Create an array with values between `from` and `to` - either ascending or descending
21
+
22
+
23
+ return Array.from({
24
+ length: stopIdx - startIdx
25
+ }, (_, i) => startIdx + i + increment);
26
+ };
27
+
28
+ function reducer({
29
+ checked,
30
+ anyChecked,
31
+ maxChecked,
32
+ selectionStart,
33
+ previousSelection
34
+ }, action) {
35
+ switch (action.type) {
36
+ case 'toggle_selection':
37
+ {
38
+ const {
39
+ value: {
40
+ id,
41
+ shiftHeld
42
+ }
43
+ } = action;
44
+ let updated = checked.slice();
45
+ let newSelectionStart = selectionStart;
46
+ let newPreviousSelection = previousSelection.slice();
47
+
48
+ if (shiftHeld) {
49
+ if (checked.length > 0) {
50
+ const newIds = arrayFromRange(selectionStart, id); // create an array of the new ids
51
+ // Uncheck ids from the previous selection.
52
+ // This is done to maintain consistency with Shift-select behaviour elsewhere (e.g. macOS)
53
+ // TODO: Code could be improved to only remove ids that are not included in the new range, avoiding needing to re-add them below
54
+
55
+ updated = updated.filter(id => !previousSelection.includes(id));
56
+ newIds.forEach(id => updated.indexOf(id) === -1 && updated.push(id) // If the new id is not already checked, check it
57
+ );
58
+ newPreviousSelection = newIds; // Maintain an array of the previous selection to allow for consistent Shift-select behaviour
59
+ }
60
+ } else {
61
+ const checkedIndex = checked.indexOf(id); // is index already checked
62
+
63
+ if (checkedIndex !== -1) {
64
+ updated.splice(checkedIndex, 1); // if index is already checked, uncheck
65
+ } else {
66
+ updated.push(id); // if index is not checked, check
67
+ }
68
+
69
+ newSelectionStart = id; // Reset selection start id to this non-shift-selected id
70
+
71
+ newPreviousSelection = []; // Reset previous selection as it is no longer relevant once a new non-shift-selected id is added
72
+ }
73
+
74
+ const anyChecked = updated.length > 0;
75
+ return {
76
+ checked: updated,
77
+ allChecked: updated.length === maxChecked,
78
+ anyChecked: anyChecked || Boolean(updated[id]),
79
+ maxChecked,
80
+ selectionStart: newSelectionStart,
81
+ previousSelection: newPreviousSelection
82
+ };
83
+ }
84
+
85
+ case 'set_root':
86
+ return {
87
+ checked: action.value ? Array.from(Array(maxChecked).keys()) : [],
88
+ allChecked: action.value,
89
+ anyChecked: Boolean(action.value),
90
+ maxChecked,
91
+ selectionStart,
92
+ previousSelection
93
+ };
94
+
95
+ case 'set_max':
96
+ {
97
+ const {
98
+ value: max
99
+ } = action;
100
+ return {
101
+ maxChecked: max,
102
+ allChecked: checked.length === max,
103
+ anyChecked,
104
+ checked,
105
+ selectionStart,
106
+ previousSelection
107
+ };
108
+ }
109
+
110
+ default:
111
+ throw new Error();
112
+ }
113
+ }
114
+
115
+ const initialiseState = () => {
116
+ return { ...defaultState,
117
+ checked: []
118
+ };
119
+ };
120
+
121
+ function useSelectable() {
122
+ const [state, dispatch] = useReducer(reducer, initialiseState());
123
+ const toggleSelection = useCallback((id, shiftHeld) => {
124
+ dispatch({
125
+ type: 'toggle_selection',
126
+ value: {
127
+ id,
128
+ shiftHeld
129
+ }
130
+ });
131
+ }, []);
132
+ const setAll = useCallback(() => {
133
+ dispatch({
134
+ type: 'set_root',
135
+ value: true
136
+ });
137
+ }, []);
138
+ const removeAll = useCallback(() => {
139
+ dispatch({
140
+ type: 'set_root',
141
+ value: false
142
+ });
143
+ }, []);
144
+ const setMax = useCallback(max => {
145
+ dispatch({
146
+ type: 'set_max',
147
+ value: max
148
+ });
149
+ }, []);
150
+ return [state, {
151
+ setAll,
152
+ removeAll,
153
+ toggleSelection,
154
+ setMax
155
+ }];
156
+ }
157
+
158
+ export default useSelectable;
@@ -0,0 +1,37 @@
1
+ import { useCallback, useState } from 'react';
2
+ export const useSorting = sortKey => {
3
+ const [localSortKey, setLocalSortKey] = useState(sortKey);
4
+ const [localSortDirection, setLocalSortDirection] = useState();
5
+ const toggleSortDirection = useCallback(() => {
6
+ setLocalSortDirection(oldLocalSortDirection => {
7
+ switch (oldLocalSortDirection) {
8
+ case undefined:
9
+ return 'ascending';
10
+
11
+ case 'ascending':
12
+ return 'descending';
13
+
14
+ case 'descending':
15
+ return 'ascending';
16
+ }
17
+ });
18
+ }, []);
19
+ const setSortState = useCallback(key => {
20
+ setLocalSortKey(localSortKey => {
21
+ if (key !== localSortKey) {
22
+ // sorting by different column
23
+ setLocalSortDirection('ascending');
24
+ return key;
25
+ } else {
26
+ toggleSortDirection();
27
+ }
28
+
29
+ return localSortKey;
30
+ });
31
+ }, [toggleSortDirection]);
32
+ return {
33
+ sortKey: localSortKey,
34
+ sortDirection: localSortDirection,
35
+ setSortState
36
+ };
37
+ };
@@ -0,0 +1,13 @@
1
+ import { createContext, useContext } from 'react';
2
+ import invariant from 'tiny-invariant';
3
+ const TableBodyContext = /*#__PURE__*/createContext(false);
4
+ /**
5
+ * __Table body provider__
6
+ * Ensures correct nesting of table elements.
7
+ */
8
+
9
+ export const TableBodyProvider = TableBodyContext.Provider;
10
+ export const useTableBody = () => {
11
+ const hasTableBody = useContext(TableBodyContext);
12
+ invariant(hasTableBody, '<Row /> must be nested inside a <TableBody>');
13
+ };
@@ -0,0 +1,34 @@
1
+ import React, { createContext, useContext } from 'react';
2
+ import __noop from '@atlaskit/ds-lib/noop';
3
+
4
+ function generateContext() {
5
+ return /*#__PURE__*/createContext({
6
+ isSelectable: false,
7
+ sortKey: 'unset',
8
+ setSortState: __noop
9
+ });
10
+ }
11
+
12
+ const TableContext = generateContext();
13
+ /**
14
+ * __Table state provider__
15
+ *
16
+ * The table context provides the data required for more complex functionality.
17
+ *
18
+ * - [Examples](https://atlassian.design/components/table/examples)
19
+ */
20
+
21
+ export function TableProvider({
22
+ children,
23
+ state
24
+ }) {
25
+ return (
26
+ /*#__PURE__*/
27
+ // @ts-expect-error
28
+ React.createElement(TableContext.Provider, {
29
+ value: state
30
+ }, children)
31
+ );
32
+ }
33
+ export const useTable = () => // @ts-expect-error
34
+ useContext(TableContext);