@workday/canvas-kit-react 9.0.0-alpha.411-next.13 → 9.0.0-alpha.413-next.15
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.
- package/collection/lib/useBaseListModel.tsx +24 -12
- package/collection/lib/useCursorListModel.tsx +102 -78
- package/dialog/lib/Dialog.tsx +66 -0
- package/dist/commonjs/action-bar/lib/ActionBar.d.ts +104 -0
- package/dist/commonjs/action-bar/lib/ActionBar.d.ts.map +1 -1
- package/dist/commonjs/action-bar/lib/ActionBarItem.d.ts +3 -0
- package/dist/commonjs/action-bar/lib/ActionBarItem.d.ts.map +1 -1
- package/dist/commonjs/action-bar/lib/ActionBarList.d.ts +3 -0
- package/dist/commonjs/action-bar/lib/ActionBarList.d.ts.map +1 -1
- package/dist/commonjs/action-bar/lib/ActionBarOverflowButton.d.ts +4 -0
- package/dist/commonjs/action-bar/lib/ActionBarOverflowButton.d.ts.map +1 -1
- package/dist/commonjs/action-bar/lib/useActionBarModel.d.ts +55 -0
- package/dist/commonjs/action-bar/lib/useActionBarModel.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/Breadcrumbs.d.ts +107 -0
- package/dist/commonjs/breadcrumbs/lib/Breadcrumbs.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsCurrentItem.d.ts +4 -0
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsCurrentItem.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsItem.d.ts +3 -0
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsItem.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsList.d.ts +2 -0
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsList.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsMenu.d.ts +49 -0
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsMenu.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsOverflowButton.d.ts +4 -0
- package/dist/commonjs/breadcrumbs/lib/BreadcrumbsOverflowButton.d.ts.map +1 -1
- package/dist/commonjs/breadcrumbs/lib/hooks/useBreadcrumbsModel.d.ts +55 -0
- package/dist/commonjs/breadcrumbs/lib/hooks/useBreadcrumbsModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/ListBox.d.ts +39 -0
- package/dist/commonjs/collection/lib/ListBox.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useBaseListModel.d.ts +20 -10
- package/dist/commonjs/collection/lib/useBaseListModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useBaseListModel.js +21 -10
- package/dist/commonjs/collection/lib/useCursorListModel.d.ts +171 -10
- package/dist/commonjs/collection/lib/useCursorListModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useCursorListModel.js +97 -64
- package/dist/commonjs/collection/lib/useGridModel.d.ts +39 -0
- package/dist/commonjs/collection/lib/useGridModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useListItemRegister.d.ts +1 -0
- package/dist/commonjs/collection/lib/useListItemRegister.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useListItemRovingFocus.d.ts +1 -0
- package/dist/commonjs/collection/lib/useListItemRovingFocus.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useListItemSelect.d.ts +1 -0
- package/dist/commonjs/collection/lib/useListItemSelect.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useListModel.d.ts +39 -0
- package/dist/commonjs/collection/lib/useListModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useListResetCursorOnBlur.d.ts +1 -0
- package/dist/commonjs/collection/lib/useListResetCursorOnBlur.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useOverflowListItemMeasure.d.ts +1 -0
- package/dist/commonjs/collection/lib/useOverflowListItemMeasure.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useOverflowListMeasure.d.ts +1 -0
- package/dist/commonjs/collection/lib/useOverflowListMeasure.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useOverflowListModel.d.ts +51 -0
- package/dist/commonjs/collection/lib/useOverflowListModel.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useOverflowListTarget.d.ts +1 -0
- package/dist/commonjs/collection/lib/useOverflowListTarget.d.ts.map +1 -1
- package/dist/commonjs/collection/lib/useSelectionListModel.d.ts +39 -0
- package/dist/commonjs/collection/lib/useSelectionListModel.d.ts.map +1 -1
- package/dist/commonjs/dialog/lib/Dialog.d.ts +65 -0
- package/dist/commonjs/dialog/lib/Dialog.d.ts.map +1 -1
- package/dist/commonjs/dialog/lib/Dialog.js +65 -0
- package/dist/commonjs/menu/lib/Menu.d.ts +48 -0
- package/dist/commonjs/menu/lib/Menu.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuCard.d.ts +2 -0
- package/dist/commonjs/menu/lib/MenuCard.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuContextTarget.d.ts +3 -0
- package/dist/commonjs/menu/lib/MenuContextTarget.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuItem.d.ts +2 -0
- package/dist/commonjs/menu/lib/MenuItem.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuList.d.ts +2 -0
- package/dist/commonjs/menu/lib/MenuList.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuPopper.d.ts +1 -0
- package/dist/commonjs/menu/lib/MenuPopper.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/MenuTarget.d.ts +5 -0
- package/dist/commonjs/menu/lib/MenuTarget.d.ts.map +1 -1
- package/dist/commonjs/menu/lib/useMenuModel.d.ts +45 -0
- package/dist/commonjs/menu/lib/useMenuModel.d.ts.map +1 -1
- package/dist/commonjs/popup/lib/Popup.d.ts +1 -81
- package/dist/commonjs/popup/lib/Popup.d.ts.map +1 -1
- package/dist/commonjs/popup/lib/Popup.js +1 -1
- package/dist/commonjs/tabs/lib/Tabs.d.ts +158 -7
- package/dist/commonjs/tabs/lib/Tabs.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsItem.d.ts +4 -0
- package/dist/commonjs/tabs/lib/TabsItem.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsList.d.ts +4 -0
- package/dist/commonjs/tabs/lib/TabsList.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsMenuPopper.d.ts +1 -0
- package/dist/commonjs/tabs/lib/TabsMenuPopper.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsOverflowButton.d.ts +4 -0
- package/dist/commonjs/tabs/lib/TabsOverflowButton.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsPanel.d.ts +4 -0
- package/dist/commonjs/tabs/lib/TabsPanel.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/TabsPanels.d.ts +2 -0
- package/dist/commonjs/tabs/lib/TabsPanels.d.ts.map +1 -1
- package/dist/commonjs/tabs/lib/useTabsModel.d.ts +143 -12
- package/dist/commonjs/tabs/lib/useTabsModel.d.ts.map +1 -1
- package/dist/es6/action-bar/lib/ActionBar.d.ts +104 -0
- package/dist/es6/action-bar/lib/ActionBar.d.ts.map +1 -1
- package/dist/es6/action-bar/lib/ActionBarItem.d.ts +3 -0
- package/dist/es6/action-bar/lib/ActionBarItem.d.ts.map +1 -1
- package/dist/es6/action-bar/lib/ActionBarList.d.ts +3 -0
- package/dist/es6/action-bar/lib/ActionBarList.d.ts.map +1 -1
- package/dist/es6/action-bar/lib/ActionBarOverflowButton.d.ts +4 -0
- package/dist/es6/action-bar/lib/ActionBarOverflowButton.d.ts.map +1 -1
- package/dist/es6/action-bar/lib/useActionBarModel.d.ts +55 -0
- package/dist/es6/action-bar/lib/useActionBarModel.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/Breadcrumbs.d.ts +107 -0
- package/dist/es6/breadcrumbs/lib/Breadcrumbs.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsCurrentItem.d.ts +4 -0
- package/dist/es6/breadcrumbs/lib/BreadcrumbsCurrentItem.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsItem.d.ts +3 -0
- package/dist/es6/breadcrumbs/lib/BreadcrumbsItem.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsList.d.ts +2 -0
- package/dist/es6/breadcrumbs/lib/BreadcrumbsList.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsMenu.d.ts +49 -0
- package/dist/es6/breadcrumbs/lib/BreadcrumbsMenu.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/BreadcrumbsOverflowButton.d.ts +4 -0
- package/dist/es6/breadcrumbs/lib/BreadcrumbsOverflowButton.d.ts.map +1 -1
- package/dist/es6/breadcrumbs/lib/hooks/useBreadcrumbsModel.d.ts +55 -0
- package/dist/es6/breadcrumbs/lib/hooks/useBreadcrumbsModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/ListBox.d.ts +39 -0
- package/dist/es6/collection/lib/ListBox.d.ts.map +1 -1
- package/dist/es6/collection/lib/useBaseListModel.d.ts +20 -10
- package/dist/es6/collection/lib/useBaseListModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useBaseListModel.js +22 -11
- package/dist/es6/collection/lib/useCursorListModel.d.ts +171 -10
- package/dist/es6/collection/lib/useCursorListModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useCursorListModel.js +97 -64
- package/dist/es6/collection/lib/useGridModel.d.ts +39 -0
- package/dist/es6/collection/lib/useGridModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useListItemRegister.d.ts +1 -0
- package/dist/es6/collection/lib/useListItemRegister.d.ts.map +1 -1
- package/dist/es6/collection/lib/useListItemRovingFocus.d.ts +1 -0
- package/dist/es6/collection/lib/useListItemRovingFocus.d.ts.map +1 -1
- package/dist/es6/collection/lib/useListItemSelect.d.ts +1 -0
- package/dist/es6/collection/lib/useListItemSelect.d.ts.map +1 -1
- package/dist/es6/collection/lib/useListModel.d.ts +39 -0
- package/dist/es6/collection/lib/useListModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useListResetCursorOnBlur.d.ts +1 -0
- package/dist/es6/collection/lib/useListResetCursorOnBlur.d.ts.map +1 -1
- package/dist/es6/collection/lib/useOverflowListItemMeasure.d.ts +1 -0
- package/dist/es6/collection/lib/useOverflowListItemMeasure.d.ts.map +1 -1
- package/dist/es6/collection/lib/useOverflowListMeasure.d.ts +1 -0
- package/dist/es6/collection/lib/useOverflowListMeasure.d.ts.map +1 -1
- package/dist/es6/collection/lib/useOverflowListModel.d.ts +51 -0
- package/dist/es6/collection/lib/useOverflowListModel.d.ts.map +1 -1
- package/dist/es6/collection/lib/useOverflowListTarget.d.ts +1 -0
- package/dist/es6/collection/lib/useOverflowListTarget.d.ts.map +1 -1
- package/dist/es6/collection/lib/useSelectionListModel.d.ts +39 -0
- package/dist/es6/collection/lib/useSelectionListModel.d.ts.map +1 -1
- package/dist/es6/dialog/lib/Dialog.d.ts +65 -0
- package/dist/es6/dialog/lib/Dialog.d.ts.map +1 -1
- package/dist/es6/dialog/lib/Dialog.js +65 -0
- package/dist/es6/menu/lib/Menu.d.ts +48 -0
- package/dist/es6/menu/lib/Menu.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuCard.d.ts +2 -0
- package/dist/es6/menu/lib/MenuCard.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuContextTarget.d.ts +3 -0
- package/dist/es6/menu/lib/MenuContextTarget.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuItem.d.ts +2 -0
- package/dist/es6/menu/lib/MenuItem.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuList.d.ts +2 -0
- package/dist/es6/menu/lib/MenuList.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuPopper.d.ts +1 -0
- package/dist/es6/menu/lib/MenuPopper.d.ts.map +1 -1
- package/dist/es6/menu/lib/MenuTarget.d.ts +5 -0
- package/dist/es6/menu/lib/MenuTarget.d.ts.map +1 -1
- package/dist/es6/menu/lib/useMenuModel.d.ts +45 -0
- package/dist/es6/menu/lib/useMenuModel.d.ts.map +1 -1
- package/dist/es6/popup/lib/Popup.d.ts +1 -81
- package/dist/es6/popup/lib/Popup.d.ts.map +1 -1
- package/dist/es6/popup/lib/Popup.js +1 -1
- package/dist/es6/tabs/lib/Tabs.d.ts +158 -7
- package/dist/es6/tabs/lib/Tabs.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsItem.d.ts +4 -0
- package/dist/es6/tabs/lib/TabsItem.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsList.d.ts +4 -0
- package/dist/es6/tabs/lib/TabsList.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsMenuPopper.d.ts +1 -0
- package/dist/es6/tabs/lib/TabsMenuPopper.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsOverflowButton.d.ts +4 -0
- package/dist/es6/tabs/lib/TabsOverflowButton.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsPanel.d.ts +4 -0
- package/dist/es6/tabs/lib/TabsPanel.d.ts.map +1 -1
- package/dist/es6/tabs/lib/TabsPanels.d.ts +2 -0
- package/dist/es6/tabs/lib/TabsPanels.d.ts.map +1 -1
- package/dist/es6/tabs/lib/useTabsModel.d.ts +143 -12
- package/dist/es6/tabs/lib/useTabsModel.d.ts.map +1 -1
- package/package.json +3 -3
- package/popup/lib/Popup.tsx +1 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {useVirtual} from './react-virtual';
|
|
3
3
|
|
|
4
|
-
import {useUniqueId,
|
|
4
|
+
import {useUniqueId, createModelHook, Generic} from '@workday/canvas-kit-react/common';
|
|
5
5
|
|
|
6
6
|
export type Orientation = 'horizontal' | 'vertical';
|
|
7
7
|
|
|
8
8
|
export const defaultGetId = (item: any): string => {
|
|
9
|
-
|
|
10
|
-
return item.id;
|
|
9
|
+
return item.id || '';
|
|
11
10
|
};
|
|
12
11
|
|
|
13
12
|
export const defaultGetTextValue = (item: any): string => {
|
|
@@ -79,14 +78,18 @@ export const useBaseListModel = createModelHook({
|
|
|
79
78
|
/** IDREF of the list. Children ids can be derived from this id */
|
|
80
79
|
id: '',
|
|
81
80
|
/**
|
|
82
|
-
* Optional function to return an id of an item. If not provided, the default function will
|
|
83
|
-
* the `id` property from the object of each item. If you did not provide `items`, do not
|
|
84
|
-
* this function. If you don't provided `items` and instead provide static items via
|
|
85
|
-
* will create an internal array of items where `id` is the only property and the
|
|
86
|
-
* will return the desired result.
|
|
81
|
+
* Optional function to return an id of an item. If not provided, the default function will
|
|
82
|
+
* return the `id` property from the object of each item. If you did not provide `items`, do not
|
|
83
|
+
* override this function. If you don't provided `items` and instead provide static items via
|
|
84
|
+
* JSX, the list will create an internal array of items where `id` is the only property and the
|
|
85
|
+
* default `getId` will return the desired result.
|
|
87
86
|
*/
|
|
88
87
|
getId: (item: Generic) => item.id as string,
|
|
89
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Optional function to return the text representation of an item. If not provided, the default
|
|
90
|
+
* function will return the `text` property of the object of each item or an empty string if
|
|
91
|
+
* there is no `text` property. If you did not provide `items`, do not override this function.
|
|
92
|
+
*/
|
|
90
93
|
getTextValue: (item: Generic) => (item.text || '') as string,
|
|
91
94
|
/**
|
|
92
95
|
* Array of all ids which are currently disabled. This is used for navigation to skip over items
|
|
@@ -112,8 +115,17 @@ export const useBaseListModel = createModelHook({
|
|
|
112
115
|
})(config => {
|
|
113
116
|
const id = useUniqueId(config.id);
|
|
114
117
|
|
|
118
|
+
// Optimization to not redo items when `getId` and `getTextValue` references change. They will not
|
|
119
|
+
// likely change during the lifecycle and we don't want to recalculate items when a lamba is
|
|
120
|
+
// passed instead of a stable reference.
|
|
121
|
+
const getIdRef = React.useRef(defaultGetId);
|
|
122
|
+
const getTextValueRef = React.useRef(defaultGetTextValue);
|
|
123
|
+
|
|
115
124
|
const getId = config.getId || defaultGetId;
|
|
116
125
|
const getTextValue = config.getTextValue || defaultGetTextValue;
|
|
126
|
+
getIdRef.current = getId;
|
|
127
|
+
getTextValueRef.current = getTextValue;
|
|
128
|
+
|
|
117
129
|
const [orientation] = React.useState(config.orientation || 'vertical');
|
|
118
130
|
const [UNSTABLE_defaultItemHeight, setDefaultItemHeight] = React.useState(
|
|
119
131
|
config.defaultItemHeight
|
|
@@ -125,13 +137,13 @@ export const useBaseListModel = createModelHook({
|
|
|
125
137
|
() =>
|
|
126
138
|
(config.items || []).map((item, index) => {
|
|
127
139
|
return {
|
|
128
|
-
id:
|
|
140
|
+
id: getIdRef.current(item),
|
|
129
141
|
index,
|
|
130
142
|
value: item,
|
|
131
|
-
textValue:
|
|
143
|
+
textValue: getTextValueRef.current(item),
|
|
132
144
|
};
|
|
133
145
|
}),
|
|
134
|
-
[config.items
|
|
146
|
+
[config.items]
|
|
135
147
|
);
|
|
136
148
|
const [staticItems, setStaticItems] = React.useState<Item<Generic>[]>([]);
|
|
137
149
|
const UNSTABLE_virtual = useVirtual({
|
|
@@ -18,7 +18,7 @@ export interface NavigationManager {
|
|
|
18
18
|
* and `Ctrl+End` for Grids. */
|
|
19
19
|
getLast: NavigationRequestor;
|
|
20
20
|
/** Get an item with the provided `id`. */
|
|
21
|
-
getItem:
|
|
21
|
+
getItem: (id: string, model: NavigationInput) => Item<Generic>;
|
|
22
22
|
/** Get the next item after the provided `id`. This will be called when the `Right` arrow key is
|
|
23
23
|
* pressed for RTL languages and when the `Left` arrow is pressed for LTR languages. */
|
|
24
24
|
getNext: NavigationRequestor;
|
|
@@ -69,90 +69,89 @@ export const createNavigationManager = (manager: NavigationManager) => manager;
|
|
|
69
69
|
/**
|
|
70
70
|
* Given an id and a model, return an item from the collection
|
|
71
71
|
*/
|
|
72
|
-
export type NavigationRequestor = (
|
|
72
|
+
export type NavigationRequestor = (index: number, model: NavigationInput) => number;
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* Get the first item in a list regardless of column count
|
|
76
76
|
*/
|
|
77
|
-
export const getFirst: NavigationRequestor = (_, {state}) =>
|
|
77
|
+
export const getFirst: NavigationRequestor = (_, {state}) => 0;
|
|
78
78
|
/**
|
|
79
79
|
* Get the last item in a list regardless of column count
|
|
80
80
|
*/
|
|
81
|
-
export const getLast: NavigationRequestor = (_, {state}) => state.items
|
|
81
|
+
export const getLast: NavigationRequestor = (_, {state}) => state.items.length - 1;
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
* Get the first item in a row. If column count is 0, it will return the results of `getFirst`
|
|
85
85
|
*/
|
|
86
|
-
export const getFirstOfRow: NavigationRequestor = (
|
|
86
|
+
export const getFirstOfRow: NavigationRequestor = (index, {state}) => {
|
|
87
87
|
if (state.columnCount) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
const offset = currentIndex % state.columnCount;
|
|
91
|
-
return state.items[currentIndex - offset];
|
|
88
|
+
const offset = index % state.columnCount;
|
|
89
|
+
return index - offset;
|
|
92
90
|
}
|
|
93
|
-
return getFirst(
|
|
91
|
+
return getFirst(index, {state});
|
|
94
92
|
};
|
|
95
93
|
|
|
96
94
|
/**
|
|
97
95
|
* get the last item in a row - if column count is 0, it will return the results of `getLast`
|
|
98
96
|
*/
|
|
99
|
-
export const getLastOfRow: NavigationRequestor = (
|
|
97
|
+
export const getLastOfRow: NavigationRequestor = (index, {state}) => {
|
|
100
98
|
if (state.columnCount) {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const offset = (currentIndex % state.columnCount) - state.columnCount + 1;
|
|
104
|
-
let nextIndex = currentIndex - offset;
|
|
99
|
+
const offset = (index % state.columnCount) - state.columnCount + 1;
|
|
100
|
+
let nextIndex = index - offset;
|
|
105
101
|
if (nextIndex >= state.items.length) {
|
|
106
102
|
nextIndex = state.items.length - 1;
|
|
107
103
|
}
|
|
108
|
-
return
|
|
104
|
+
return nextIndex;
|
|
109
105
|
}
|
|
110
|
-
return getLast(
|
|
106
|
+
return getLast(index, {state});
|
|
111
107
|
};
|
|
112
108
|
|
|
113
109
|
/**
|
|
114
110
|
* get the item in the previous page. This can be author defined. By default it will return the
|
|
115
111
|
* first item for a list, and the first item in the same column for a grid.
|
|
116
112
|
*/
|
|
117
|
-
export const getPreviousPage: NavigationRequestor = (
|
|
113
|
+
export const getPreviousPage: NavigationRequestor = (index, {state}) => {
|
|
118
114
|
if (state.columnCount) {
|
|
119
|
-
|
|
120
|
-
const currentIndex = item.index;
|
|
121
|
-
return state.items[currentIndex % state.columnCount];
|
|
115
|
+
return index % state.columnCount;
|
|
122
116
|
}
|
|
123
|
-
return getFirst(
|
|
117
|
+
return getFirst(index, {state});
|
|
124
118
|
};
|
|
125
119
|
|
|
126
120
|
/**
|
|
127
121
|
* get the item in the next page. This can be author defined. By default, it will return the last
|
|
128
122
|
* item for a list, and the last item in the same column for a grid.
|
|
129
123
|
*/
|
|
130
|
-
export const getNextPage: NavigationRequestor = (
|
|
124
|
+
export const getNextPage: NavigationRequestor = (index, {state}) => {
|
|
131
125
|
if (state.columnCount) {
|
|
132
|
-
const item = getItem(id, {state});
|
|
133
|
-
const currentIndex = item.index;
|
|
134
126
|
const lastRowIndex = state.items.length - state.columnCount;
|
|
135
|
-
return
|
|
127
|
+
return lastRowIndex + (index % state.columnCount);
|
|
136
128
|
}
|
|
137
|
-
return getLast(
|
|
129
|
+
return getLast(index, {state});
|
|
138
130
|
};
|
|
139
131
|
|
|
140
|
-
const getItem:
|
|
141
|
-
const item = id ? state.items.find(item =>
|
|
132
|
+
const getItem: (id: string, model: NavigationInput) => Item<Generic> = (id, {state}) => {
|
|
133
|
+
const item = id ? state.items.find(item => item.id === id) : state.items[0]; // no id, return first item
|
|
142
134
|
assert(item, `Item not found: ${id}`);
|
|
143
135
|
return item;
|
|
144
136
|
};
|
|
145
137
|
|
|
146
138
|
export const getWrappingOffsetItem = (offset: number) => (
|
|
147
|
-
|
|
139
|
+
index: number,
|
|
148
140
|
{state}: NavigationInput,
|
|
149
141
|
tries = state.items.length
|
|
150
|
-
):
|
|
142
|
+
): number => {
|
|
143
|
+
if (Number.isNaN(index)) {
|
|
144
|
+
// we have no valid index. If the offset is positive, we'll return the first item
|
|
145
|
+
if (offset === 1) {
|
|
146
|
+
return getFirst(index, {state});
|
|
147
|
+
}
|
|
148
|
+
if (offset === -1) {
|
|
149
|
+
return getLast(index, {state});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
151
152
|
const items = state.items;
|
|
152
|
-
const item = getItem(id, {state});
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
let nextIndex = currentIndex + offset;
|
|
154
|
+
let nextIndex = index + offset;
|
|
156
155
|
|
|
157
156
|
// calculate idealLength as in if the grid was a perfect rectangle
|
|
158
157
|
const rows = Math.ceil(items.length / state.columnCount);
|
|
@@ -185,34 +184,32 @@ export const getWrappingOffsetItem = (offset: number) => (
|
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
if (state.nonInteractiveIds.includes(
|
|
187
|
+
if (state.nonInteractiveIds.includes(items[nextIndex].id) && tries > 0) {
|
|
189
188
|
// The next item is disabled, try again, but only if we haven't already tried everything.
|
|
190
189
|
// Avoid an infinite loop with `tries`
|
|
191
|
-
return getWrappingOffsetItem(offset)(
|
|
190
|
+
return getWrappingOffsetItem(offset)(nextIndex, {state}, tries - 1);
|
|
192
191
|
}
|
|
193
192
|
|
|
194
|
-
return
|
|
193
|
+
return nextIndex;
|
|
195
194
|
};
|
|
196
195
|
|
|
197
196
|
export const getOffsetItem = (offset: number) => (
|
|
198
|
-
|
|
197
|
+
index: number,
|
|
199
198
|
{state}: NavigationInput,
|
|
200
199
|
tries = state.items.length
|
|
201
|
-
):
|
|
200
|
+
): number => {
|
|
202
201
|
const {items, columnCount} = state;
|
|
203
|
-
const item = getItem(id, {state});
|
|
204
202
|
|
|
205
|
-
|
|
206
|
-
let nextIndex = currentIndex + offset;
|
|
203
|
+
let nextIndex = index + offset;
|
|
207
204
|
|
|
208
205
|
if (Math.abs(offset) < columnCount) {
|
|
209
206
|
// if we're here, the columnCount is non-zero and the absolute value of offset is less than the
|
|
210
207
|
// column count. We don't want to wrap, so we'll bound within the row
|
|
211
208
|
|
|
212
|
-
const currentIndexInRow =
|
|
213
|
-
const nextIndexInRow = nextIndex -
|
|
209
|
+
const currentIndexInRow = index % columnCount;
|
|
210
|
+
const nextIndexInRow = nextIndex - index + currentIndexInRow;
|
|
214
211
|
if (nextIndexInRow >= columnCount || nextIndexInRow < 0) {
|
|
215
|
-
nextIndex =
|
|
212
|
+
nextIndex = index;
|
|
216
213
|
}
|
|
217
214
|
} else if (columnCount) {
|
|
218
215
|
// if we're here, there's a column count, but the offset will move into another row. We need to
|
|
@@ -220,12 +217,12 @@ export const getOffsetItem = (offset: number) => (
|
|
|
220
217
|
const nextRow = Math.floor(nextIndex / columnCount);
|
|
221
218
|
|
|
222
219
|
if (nextRow < 0 || nextRow >= columnCount) {
|
|
223
|
-
nextIndex =
|
|
220
|
+
nextIndex = index;
|
|
224
221
|
}
|
|
225
222
|
|
|
226
223
|
// make sure we don't go out of bounds if the grid isn't a perfect rectangle
|
|
227
224
|
if (nextIndex > items.length - 1) {
|
|
228
|
-
nextIndex =
|
|
225
|
+
nextIndex = index;
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
228
|
|
|
@@ -236,13 +233,13 @@ export const getOffsetItem = (offset: number) => (
|
|
|
236
233
|
nextIndex = items.length - 1;
|
|
237
234
|
}
|
|
238
235
|
|
|
239
|
-
if (state.nonInteractiveIds.includes(
|
|
236
|
+
if (state.nonInteractiveIds.includes(items[nextIndex].id) && tries > 0) {
|
|
240
237
|
// The next item is disabled, try again, but only if we haven't already tried everything.
|
|
241
238
|
// Avoid an infinite loop with `tries`
|
|
242
|
-
return getOffsetItem(offset)(
|
|
239
|
+
return getOffsetItem(offset)(nextIndex, {state}, tries - 1);
|
|
243
240
|
}
|
|
244
241
|
|
|
245
|
-
return
|
|
242
|
+
return nextIndex;
|
|
246
243
|
};
|
|
247
244
|
|
|
248
245
|
/**
|
|
@@ -255,9 +252,9 @@ export const wrappingNavigationManager = createNavigationManager({
|
|
|
255
252
|
getLast,
|
|
256
253
|
getItem,
|
|
257
254
|
getNext: getWrappingOffsetItem(1),
|
|
258
|
-
getNextRow: (
|
|
255
|
+
getNextRow: (index, {state}) => getWrappingOffsetItem(state.columnCount)(index, {state}),
|
|
259
256
|
getPrevious: getWrappingOffsetItem(-1),
|
|
260
|
-
getPreviousRow: (
|
|
257
|
+
getPreviousRow: (index, {state}) => getWrappingOffsetItem(-state.columnCount)(index, {state}),
|
|
261
258
|
getPreviousPage,
|
|
262
259
|
getNextPage,
|
|
263
260
|
getFirstOfRow,
|
|
@@ -273,9 +270,9 @@ export const navigationManager = createNavigationManager({
|
|
|
273
270
|
getLast,
|
|
274
271
|
getItem,
|
|
275
272
|
getNext: getOffsetItem(1),
|
|
276
|
-
getNextRow: (
|
|
273
|
+
getNextRow: (index, {state}) => getOffsetItem(state.columnCount)(index, {state}),
|
|
277
274
|
getPrevious: getOffsetItem(-1),
|
|
278
|
-
getPreviousRow: (
|
|
275
|
+
getPreviousRow: (index, {state}) => getOffsetItem(-state.columnCount)(index, {state}),
|
|
279
276
|
getPreviousPage,
|
|
280
277
|
getNextPage,
|
|
281
278
|
getFirstOfRow,
|
|
@@ -312,16 +309,35 @@ export const useCursorListModel = createModelHook({
|
|
|
312
309
|
* well as left/right keys to give a more consistent experience to all users.
|
|
313
310
|
*/
|
|
314
311
|
navigation: wrappingNavigationManager,
|
|
312
|
+
/**
|
|
313
|
+
* Controls how much a pageUp/pageDown navigation request will jump. If not provided, the size
|
|
314
|
+
* of the list and number of items rendered will determine this value.
|
|
315
|
+
*/
|
|
316
|
+
pageSize: 0,
|
|
315
317
|
},
|
|
316
318
|
requiredConfig: useBaseListModel.requiredConfig,
|
|
319
|
+
contextOverride: useBaseListModel.Context,
|
|
317
320
|
})(config => {
|
|
318
321
|
const [cursorId, setCursorId] = React.useState(config.initialCursorId);
|
|
322
|
+
const pageSizeRef = React.useRef(config.pageSize);
|
|
319
323
|
const columnCount = config.columnCount || 0;
|
|
320
324
|
const list = useBaseListModel(config);
|
|
321
325
|
const initialCurrentRef = React.useRef(
|
|
322
|
-
config.initialCursorId || (config.items?.length ?
|
|
326
|
+
config.initialCursorId || (config.items?.length ? list.state.items![0].id : '')
|
|
323
327
|
);
|
|
324
328
|
const navigation = config.navigation;
|
|
329
|
+
const cursorIndexRef = React.useRef(-1);
|
|
330
|
+
const setCursor = (index: number) => {
|
|
331
|
+
const id = state.items[index]?.id || '';
|
|
332
|
+
setCursorId(id);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// Keep the cursorIndex up to date with the cursor ID
|
|
336
|
+
if (cursorId && list.state.items[cursorIndexRef.current]?.id !== cursorId) {
|
|
337
|
+
cursorIndexRef.current = list.state.items.findIndex(item => item.id === cursorId);
|
|
338
|
+
} else if (!cursorId) {
|
|
339
|
+
cursorIndexRef.current = -1;
|
|
340
|
+
}
|
|
325
341
|
|
|
326
342
|
const state = {
|
|
327
343
|
...list.state,
|
|
@@ -333,6 +349,11 @@ export const useCursorListModel = createModelHook({
|
|
|
333
349
|
* @private Use useGridModel instead to make a grid instead of a list
|
|
334
350
|
*/
|
|
335
351
|
columnCount,
|
|
352
|
+
/**
|
|
353
|
+
* A React.Ref of the current page size. Either provided as config, or determined at runtime
|
|
354
|
+
* based on the size of the list container and the number of items fitting within the container.
|
|
355
|
+
*/
|
|
356
|
+
pageSizeRef,
|
|
336
357
|
};
|
|
337
358
|
|
|
338
359
|
const events = {
|
|
@@ -351,7 +372,8 @@ export const useCursorListModel = createModelHook({
|
|
|
351
372
|
},
|
|
352
373
|
/** Directly sets the cursor to the list item by its identifier. */
|
|
353
374
|
goTo(data: {id: string}) {
|
|
354
|
-
|
|
375
|
+
const index = state.items.findIndex(item => item.id === data.id);
|
|
376
|
+
setCursor(index);
|
|
355
377
|
},
|
|
356
378
|
/**
|
|
357
379
|
* Set the cursor to the "next" item in the list. This event delegates to the `getNext` method of
|
|
@@ -360,14 +382,16 @@ export const useCursorListModel = createModelHook({
|
|
|
360
382
|
* item in a row.
|
|
361
383
|
*/
|
|
362
384
|
goToNext() {
|
|
363
|
-
|
|
385
|
+
const index = navigation.getNext(cursorIndexRef.current, {state});
|
|
386
|
+
setCursor(index);
|
|
364
387
|
},
|
|
365
388
|
/**
|
|
366
389
|
* Set the cursor to the "previous" item in the list. If the beginning of the list is detected,
|
|
367
390
|
* it will wrap to the last item
|
|
368
391
|
*/
|
|
369
392
|
goToPrevious() {
|
|
370
|
-
|
|
393
|
+
const index = navigation.getPrevious(cursorIndexRef.current, {state});
|
|
394
|
+
setCursor(index);
|
|
371
395
|
},
|
|
372
396
|
/**
|
|
373
397
|
* Previous item perpendicular to the orientation of a list, or the previous row in a grid. For
|
|
@@ -376,13 +400,10 @@ export const useCursorListModel = createModelHook({
|
|
|
376
400
|
* this would be the previous row (current position - column count).
|
|
377
401
|
*/
|
|
378
402
|
goToPreviousRow() {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
})
|
|
384
|
-
)
|
|
385
|
-
);
|
|
403
|
+
const index = navigation.getPreviousRow(cursorIndexRef.current, {
|
|
404
|
+
state,
|
|
405
|
+
});
|
|
406
|
+
setCursor(index);
|
|
386
407
|
},
|
|
387
408
|
/**
|
|
388
409
|
* Next item perpendicular to the orientation of a list, or the next row in a grid. For example,
|
|
@@ -391,33 +412,36 @@ export const useCursorListModel = createModelHook({
|
|
|
391
412
|
* next row (current position + column count).
|
|
392
413
|
*/
|
|
393
414
|
goToNextRow() {
|
|
394
|
-
|
|
415
|
+
const index = navigation.getNextRow(cursorIndexRef.current, {state});
|
|
416
|
+
setCursor(index);
|
|
395
417
|
},
|
|
396
418
|
/** Set the cursor to the first item in the list */
|
|
397
419
|
goToFirst() {
|
|
398
|
-
|
|
420
|
+
const index = navigation.getFirst(cursorIndexRef.current, {state});
|
|
421
|
+
setCursor(index);
|
|
399
422
|
},
|
|
400
423
|
/** Set the cursor to the last item in the list */
|
|
401
424
|
goToLast() {
|
|
402
|
-
|
|
425
|
+
const index = navigation.getLast(cursorIndexRef.current, {state});
|
|
426
|
+
setCursor(index);
|
|
403
427
|
},
|
|
404
428
|
goToFirstOfRow() {
|
|
405
|
-
|
|
429
|
+
const index = navigation.getFirstOfRow(cursorIndexRef.current, {state});
|
|
430
|
+
setCursor(index);
|
|
406
431
|
},
|
|
407
432
|
goToLastOfRow() {
|
|
408
|
-
|
|
433
|
+
const index = navigation.getLastOfRow(cursorIndexRef.current, {state});
|
|
434
|
+
setCursor(index);
|
|
409
435
|
},
|
|
410
436
|
goToNextPage() {
|
|
411
|
-
|
|
437
|
+
const index = navigation.getNextPage(cursorIndexRef.current, {state});
|
|
438
|
+
setCursor(index);
|
|
412
439
|
},
|
|
413
440
|
goToPreviousPage() {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
})
|
|
419
|
-
)
|
|
420
|
-
);
|
|
441
|
+
const index = navigation.getPreviousPage(cursorIndexRef.current, {
|
|
442
|
+
state,
|
|
443
|
+
});
|
|
444
|
+
setCursor(index);
|
|
421
445
|
},
|
|
422
446
|
};
|
|
423
447
|
|
package/dialog/lib/Dialog.tsx
CHANGED
|
@@ -14,16 +14,82 @@ export interface DialogProps {
|
|
|
14
14
|
children: React.ReactNode;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* This component is the container component and does not render any semantic elements. It provides
|
|
19
|
+
* a React Context model for the `Dialog` subcomponents. If you manually pass a `model` to all
|
|
20
|
+
* subcomponents, this container component isn't needed. If you do not pass a `model`, the `Dialog`
|
|
21
|
+
* container component will build a default one using `useDialogModel`. `Dialog` is a composition of a
|
|
22
|
+
* {@link Popup} component and has a similar structure to `Popup`.
|
|
23
|
+
*/
|
|
17
24
|
export const Dialog = createContainer()({
|
|
18
25
|
displayName: 'Dialog',
|
|
19
26
|
modelHook: useDialogModel,
|
|
20
27
|
subComponents: {
|
|
28
|
+
/**
|
|
29
|
+
* A `Dialog.Body` is a thin wrapper around {@link CardBody Card.Body} and doesn't actually take
|
|
30
|
+
* a model. It adds `body` styling and nothing else.
|
|
31
|
+
*/
|
|
21
32
|
Body: Popup.Body,
|
|
33
|
+
/**
|
|
34
|
+
* A `Dialog.Card` is a wrapper around the {@link Card} component, but hooked up to a
|
|
35
|
+
* {@link DialogModel}. By default, this element has a `role=dialog`, `aria-labelledby` and an `id`.
|
|
36
|
+
* The behavior hook used is called {@link useDialogCard}.
|
|
37
|
+
*/
|
|
22
38
|
Card: DialogCard,
|
|
39
|
+
/**
|
|
40
|
+
* A `Dialog.CloseIcon` is an icon button that is the `X` at the top of a dialog. It will hide a
|
|
41
|
+
* dialog when clicked. The behavior hook used is called {@link usePopupCloseButton}.
|
|
42
|
+
*/
|
|
23
43
|
CloseIcon: Popup.CloseIcon,
|
|
44
|
+
/**
|
|
45
|
+
* A `Dialog.Target` is any element that is meant to show the Dialog. The default component
|
|
46
|
+
* rendered by this component is a {@link SecondaryButton} element. You can override this by
|
|
47
|
+
* passing the desired component via `as`. Many examples above use `as={DeleteButton}`. If you
|
|
48
|
+
* want to render a {@link TertiaryButton} instead, use `as={TertiaryButton}`. The behavior hook
|
|
49
|
+
* used is called {@link usePopupTarget}.
|
|
50
|
+
*
|
|
51
|
+
* ```tsx
|
|
52
|
+
* const model = useDialogModel();
|
|
53
|
+
*
|
|
54
|
+
* // using this component
|
|
55
|
+
* <Dialog.Target>Show Dialog</Dialog.Target>
|
|
56
|
+
*
|
|
57
|
+
* // using props instead
|
|
58
|
+
* const dialogTargetButtonProps = useDialogTarget(model);
|
|
59
|
+
* <SecondaryButton {...dialogTargetButtonProps}>Show Dialog</SecondaryButton>
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* `Dialog.Target` doesn't provide any styling by default. All styling comes from the default
|
|
63
|
+
* component used, which is {@link SecondaryButton}. If you don't want any styling, you can do
|
|
64
|
+
* the following:
|
|
65
|
+
*
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <Dialog.Target as="button">Open</Dialog.Target>
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* To add your own styling, you could either add a `css` prop, or make a styled button and pass
|
|
71
|
+
* that styled component via the `as` prop.
|
|
72
|
+
*/
|
|
24
73
|
Target: Popup.Target,
|
|
74
|
+
/**
|
|
75
|
+
* A `Dialog.Heading` is a wrapper around {@link CardHeading Card.Heading} that connect the
|
|
76
|
+
* heading to a {@link DialogModel}. It will add an `id` to the element that match the
|
|
77
|
+
* `aria-labelledby` that is applied to the `Dialog.Card` element for accessibility. The behavior
|
|
78
|
+
* hook used is called {@link usePopupHeading}.
|
|
79
|
+
*/
|
|
25
80
|
Heading: Popup.Heading,
|
|
81
|
+
/**
|
|
82
|
+
* A `Dialog.Popper` is a wrapper around {@link PopupPopper Popup.Popper}. The behavior
|
|
83
|
+
* hook used is called {@link useDialogPopper}.
|
|
84
|
+
*/
|
|
85
|
+
|
|
26
86
|
Popper: DialogPopper,
|
|
87
|
+
/**
|
|
88
|
+
* A `Dialog.CloseButton` is a button that will hide a dialog. By default, this is a
|
|
89
|
+
* {@link SecondaryButton} component, but `as` can be used to render any button element (i.e
|
|
90
|
+
* {@link DeleteButton} or {@link PrimaryButton}). The behavior hook used is called
|
|
91
|
+
* {@link usePopupCloseButton}.
|
|
92
|
+
*/
|
|
27
93
|
CloseButton: Popup.CloseButton,
|
|
28
94
|
},
|
|
29
95
|
})(({children}: DialogProps) => {
|