@workday/canvas-kit-preview-react 14.0.0-alpha.1147-next.0 → 14.0.0-alpha.1149-next.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.
- package/dist/commonjs/color-picker/lib/ColorPicker.js +1 -1
- package/dist/commonjs/color-picker/lib/parts/ColorReset.js +1 -1
- package/dist/commonjs/color-picker/lib/parts/SwatchBook.js +1 -1
- package/dist/commonjs/divider/lib/Divider.js +1 -1
- package/dist/commonjs/index.d.ts +0 -1
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +0 -1
- package/dist/commonjs/information-highlight/lib/InformationHighlight.js +7 -7
- package/dist/commonjs/information-highlight/lib/parts/Body.js +1 -1
- package/dist/commonjs/information-highlight/lib/parts/Heading.js +1 -1
- package/dist/commonjs/information-highlight/lib/parts/Link.js +1 -1
- package/dist/commonjs/loading-sparkles/lib/LoadingSparkles.js +2 -2
- package/dist/commonjs/multi-select/lib/MultiSelectInput.js +3 -3
- package/dist/commonjs/pill/lib/Pill.js +3 -3
- package/dist/commonjs/pill/lib/PillAvatar.js +1 -1
- package/dist/commonjs/pill/lib/PillCount.js +1 -1
- package/dist/commonjs/pill/lib/PillIcon.js +1 -1
- package/dist/commonjs/pill/lib/PillIconButton.js +1 -1
- package/dist/commonjs/pill/lib/PillLabel.js +1 -1
- package/dist/commonjs/radio/lib/RadioGroup.js +3 -3
- package/dist/commonjs/radio/lib/RadioLabel.js +1 -1
- package/dist/commonjs/radio/lib/RadioText.js +4 -4
- package/dist/commonjs/radio/lib/StyledRadioButton.js +5 -5
- package/dist/commonjs/segmented-control/lib/SegmentedControlItem.js +16 -16
- package/dist/commonjs/segmented-control/lib/SegmentedControlList.js +4 -4
- package/dist/commonjs/side-panel/lib/SidePanel.js +7 -7
- package/dist/commonjs/side-panel/lib/SidePanelToggleButton.js +11 -11
- package/dist/commonjs/status-indicator/lib/StatusIndicator.js +13 -13
- package/dist/commonjs/status-indicator/lib/StatusIndicatorLabel.js +1 -1
- package/dist/es6/color-picker/lib/ColorPicker.js +1 -1
- package/dist/es6/color-picker/lib/parts/ColorReset.js +1 -1
- package/dist/es6/color-picker/lib/parts/SwatchBook.js +1 -1
- package/dist/es6/divider/lib/Divider.js +1 -1
- package/dist/es6/index.d.ts +0 -1
- package/dist/es6/index.d.ts.map +1 -1
- package/dist/es6/index.js +0 -1
- package/dist/es6/information-highlight/lib/InformationHighlight.js +7 -7
- package/dist/es6/information-highlight/lib/parts/Body.js +1 -1
- package/dist/es6/information-highlight/lib/parts/Heading.js +1 -1
- package/dist/es6/information-highlight/lib/parts/Link.js +1 -1
- package/dist/es6/loading-sparkles/lib/LoadingSparkles.js +2 -2
- package/dist/es6/multi-select/lib/MultiSelectInput.js +3 -3
- package/dist/es6/pill/lib/Pill.js +3 -3
- package/dist/es6/pill/lib/PillAvatar.js +1 -1
- package/dist/es6/pill/lib/PillCount.js +1 -1
- package/dist/es6/pill/lib/PillIcon.js +1 -1
- package/dist/es6/pill/lib/PillIconButton.js +1 -1
- package/dist/es6/pill/lib/PillLabel.js +1 -1
- package/dist/es6/radio/lib/RadioGroup.js +3 -3
- package/dist/es6/radio/lib/RadioLabel.js +1 -1
- package/dist/es6/radio/lib/RadioText.js +4 -4
- package/dist/es6/radio/lib/StyledRadioButton.js +5 -5
- package/dist/es6/segmented-control/lib/SegmentedControlItem.js +16 -16
- package/dist/es6/segmented-control/lib/SegmentedControlList.js +4 -4
- package/dist/es6/side-panel/lib/SidePanel.js +7 -7
- package/dist/es6/side-panel/lib/SidePanelToggleButton.js +11 -11
- package/dist/es6/status-indicator/lib/StatusIndicator.js +13 -13
- package/dist/es6/status-indicator/lib/StatusIndicatorLabel.js +1 -1
- package/index.ts +0 -1
- package/package.json +4 -4
- package/dist/commonjs/menu/index.d.ts +0 -3
- package/dist/commonjs/menu/index.d.ts.map +0 -1
- package/dist/commonjs/menu/index.js +0 -18
- package/dist/commonjs/menu/lib/Menu.d.ts +0 -78
- package/dist/commonjs/menu/lib/Menu.d.ts.map +0 -1
- package/dist/commonjs/menu/lib/Menu.js +0 -277
- package/dist/commonjs/menu/lib/MenuItem.d.ts +0 -75
- package/dist/commonjs/menu/lib/MenuItem.d.ts.map +0 -1
- package/dist/commonjs/menu/lib/MenuItem.js +0 -249
- package/dist/es6/menu/index.d.ts +0 -3
- package/dist/es6/menu/index.d.ts.map +0 -1
- package/dist/es6/menu/index.js +0 -2
- package/dist/es6/menu/lib/Menu.d.ts +0 -78
- package/dist/es6/menu/lib/Menu.d.ts.map +0 -1
- package/dist/es6/menu/lib/Menu.js +0 -247
- package/dist/es6/menu/lib/MenuItem.d.ts +0 -75
- package/dist/es6/menu/lib/MenuItem.d.ts.map +0 -1
- package/dist/es6/menu/lib/MenuItem.js +0 -219
- package/menu/index.ts +0 -2
- package/menu/lib/Menu.tsx +0 -368
- package/menu/lib/MenuItem.tsx +0 -351
- package/menu/package.json +0 -6
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import styled from '@emotion/styled';
|
|
4
|
-
import { colors, commonColors, iconColors, typeColors, space, type, } from '@workday/canvas-kit-react/tokens';
|
|
5
|
-
import { SystemIcon } from '@workday/canvas-kit-react/icon';
|
|
6
|
-
const Item = styled('li')({
|
|
7
|
-
...type.levels.subtext.large,
|
|
8
|
-
padding: `${space.xxs} ${space.s}`,
|
|
9
|
-
height: space.xl,
|
|
10
|
-
boxSizing: 'border-box',
|
|
11
|
-
cursor: 'pointer',
|
|
12
|
-
color: colors.blackPepper300,
|
|
13
|
-
display: 'flex',
|
|
14
|
-
flexDirection: 'row',
|
|
15
|
-
alignItems: 'center',
|
|
16
|
-
transition: 'background-color 80ms, color 80ms',
|
|
17
|
-
'&:focus': {
|
|
18
|
-
outline: 'none',
|
|
19
|
-
},
|
|
20
|
-
}, ({ isHeader }) => {
|
|
21
|
-
return { pointerEvents: isHeader ? 'none' : 'all' };
|
|
22
|
-
}, ({ isFocused, isDisabled }) => {
|
|
23
|
-
if (!isFocused && !isDisabled) {
|
|
24
|
-
return {
|
|
25
|
-
backgroundColor: 'inherit',
|
|
26
|
-
'&:hover': {
|
|
27
|
-
backgroundColor: commonColors.hoverBackground,
|
|
28
|
-
color: colors.blackPepper300,
|
|
29
|
-
'.wd-icon-fill, .wd-icon-accent, .wd-icon-accent2': {
|
|
30
|
-
fill: iconColors.hover,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
else if (isDisabled && !isFocused) {
|
|
36
|
-
return {
|
|
37
|
-
color: colors.licorice100,
|
|
38
|
-
cursor: 'default',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
// Is focused or focused and disabled
|
|
43
|
-
return {
|
|
44
|
-
backgroundColor: isDisabled ? colors.blueberry200 : commonColors.focusBackground,
|
|
45
|
-
color: typeColors.inverse,
|
|
46
|
-
'span .wd-icon-background ~ .wd-icon-accent, .wd-icon-background ~ .wd-icon-accent2': {
|
|
47
|
-
fill: isDisabled ? iconColors.disabled : iconColors.active,
|
|
48
|
-
},
|
|
49
|
-
'&:hover': {
|
|
50
|
-
'span .wd-icon-fill, span .wd-icon-accent, span .wd-icon-accent2': {
|
|
51
|
-
fill: iconColors.inverse,
|
|
52
|
-
},
|
|
53
|
-
'span .wd-icon-background ~ .wd-icon-accent, span .wd-icon-background ~ .wd-icon-accent2': {
|
|
54
|
-
fill: isDisabled ? iconColors.disabled : iconColors.active,
|
|
55
|
-
},
|
|
56
|
-
'span .wd-icon-background': {
|
|
57
|
-
fill: iconColors.inverse,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
[`[data-whatinput='mouse'] &,
|
|
61
|
-
[data-whatinput='touch'] &,
|
|
62
|
-
[data-whatinput='pointer'] &`]: {
|
|
63
|
-
backgroundColor: 'inherit',
|
|
64
|
-
color: colors.blackPepper300,
|
|
65
|
-
'span .wd-icon-background ~ .wd-icon-accent, span .wd-icon-background ~ .wd-icon-accent2': {
|
|
66
|
-
fill: iconColors.standard,
|
|
67
|
-
},
|
|
68
|
-
'&:hover': {
|
|
69
|
-
backgroundColor: commonColors.hoverBackground,
|
|
70
|
-
'span .wd-icon-fill, span .wd-icon-accent, span .wd-icon-accent2': {
|
|
71
|
-
fill: iconColors.hover,
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
'.wd-icon-fill, .wd-icon-accent, .wd-icon-accent2': {
|
|
75
|
-
fill: iconColors.standard,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
const LabelContainer = styled('span')({
|
|
82
|
-
flex: '1 1 auto',
|
|
83
|
-
overflow: 'hidden',
|
|
84
|
-
whiteSpace: 'nowrap',
|
|
85
|
-
textOverflow: 'ellipsis',
|
|
86
|
-
});
|
|
87
|
-
const Divider = styled('hr')({
|
|
88
|
-
display: 'block',
|
|
89
|
-
height: 1,
|
|
90
|
-
border: 0,
|
|
91
|
-
borderTop: `1px solid ${colors.soap400}`,
|
|
92
|
-
margin: `${space.xxs} 0`,
|
|
93
|
-
});
|
|
94
|
-
const iconSize = 24;
|
|
95
|
-
const iconPadding = 16;
|
|
96
|
-
const StyledSystemIcon = styled(SystemIcon)({
|
|
97
|
-
minWidth: iconSize + iconPadding, // gives padding between LabelContainer, no matter the direction
|
|
98
|
-
});
|
|
99
|
-
const SecondaryStyledSystemIcon = styled(SystemIcon)({
|
|
100
|
-
display: `flex`,
|
|
101
|
-
minWidth: iconSize + iconPadding,
|
|
102
|
-
justifyContent: `flex-end`,
|
|
103
|
-
});
|
|
104
|
-
let iconProps = null;
|
|
105
|
-
let secondaryIconProps = null;
|
|
106
|
-
const setIconProps = (icon, isDisabled, isFocused) => {
|
|
107
|
-
if (!icon) {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
let props = {
|
|
111
|
-
icon: icon,
|
|
112
|
-
size: iconSize,
|
|
113
|
-
};
|
|
114
|
-
if (isDisabled) {
|
|
115
|
-
props = {
|
|
116
|
-
...props,
|
|
117
|
-
fill: iconColors.disabled,
|
|
118
|
-
fillHover: iconColors.disabled,
|
|
119
|
-
accent: iconColors.disabled,
|
|
120
|
-
accentHover: iconColors.disabled,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
if (isFocused) {
|
|
124
|
-
props = {
|
|
125
|
-
...props,
|
|
126
|
-
fill: iconColors.inverse,
|
|
127
|
-
fillHover: iconColors.inverse,
|
|
128
|
-
accent: iconColors.inverse,
|
|
129
|
-
accentHover: iconColors.inverse,
|
|
130
|
-
background: iconColors.inverse,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
return props;
|
|
134
|
-
};
|
|
135
|
-
const scrollIntoViewIfNeeded = (elem, centerIfNeeded = true) => {
|
|
136
|
-
const parent = elem.parentElement;
|
|
137
|
-
if (elem && parent) {
|
|
138
|
-
const parentComputedStyle = window.getComputedStyle(parent, null), parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width'), 10), parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width'), 10), overTop = elem.offsetTop - parent.offsetTop < parent.scrollTop, overBottom = elem.offsetTop - parent.offsetTop + elem.clientHeight - parentBorderTopWidth >
|
|
139
|
-
parent.scrollTop + parent.clientHeight, overLeft = elem.offsetLeft - parent.offsetLeft < parent.scrollLeft, overRight = elem.offsetLeft - parent.offsetLeft + elem.clientWidth - parentBorderLeftWidth >
|
|
140
|
-
parent.scrollLeft + parent.clientWidth, alignWithTop = overTop && !overBottom;
|
|
141
|
-
if ((overTop || overBottom) && centerIfNeeded) {
|
|
142
|
-
parent.scrollTop =
|
|
143
|
-
elem.offsetTop -
|
|
144
|
-
parent.offsetTop -
|
|
145
|
-
parent.clientHeight / 2 -
|
|
146
|
-
parentBorderTopWidth +
|
|
147
|
-
elem.clientHeight / 2;
|
|
148
|
-
}
|
|
149
|
-
if ((overLeft || overRight) && centerIfNeeded) {
|
|
150
|
-
parent.scrollLeft =
|
|
151
|
-
elem.offsetLeft -
|
|
152
|
-
parent.offsetLeft -
|
|
153
|
-
parent.clientWidth / 2 -
|
|
154
|
-
parentBorderLeftWidth +
|
|
155
|
-
elem.clientWidth / 2;
|
|
156
|
-
}
|
|
157
|
-
if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
|
|
158
|
-
elem.scrollIntoView(alignWithTop);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
/**
|
|
163
|
-
* `DeprecatedMenuItem` renders an `<li>` element with the correct attributes to ensure it is
|
|
164
|
-
* accessible. If you choose to implement your own custom menu items, be sure to use semantic `<li>`
|
|
165
|
-
* elements with the following attributes:
|
|
166
|
-
*
|
|
167
|
-
* - `role="menuitem"`
|
|
168
|
-
* - `tabindex={-1}`
|
|
169
|
-
* - `id`s following this pattern: `${MenuId}-${index}`
|
|
170
|
-
*
|
|
171
|
-
* Undocumented props are spread to the underlying `<li>` element.
|
|
172
|
-
*
|
|
173
|
-
* @deprecated ⚠️ `DeprecatedMenuItem` has been deprecated and will be removed in a future major version. Please use [Menu in Main](https://workday.github.io/canvas-kit/?path=/docs/components-popups-menu--basic) instead.
|
|
174
|
-
*
|
|
175
|
-
*/
|
|
176
|
-
export class DeprecatedMenuItem extends React.Component {
|
|
177
|
-
constructor() {
|
|
178
|
-
super(...arguments);
|
|
179
|
-
this.ref = React.createRef();
|
|
180
|
-
this.componentDidUpdate = (prevProps) => {
|
|
181
|
-
if (!prevProps.isFocused && this.props.isFocused) {
|
|
182
|
-
if (this.ref.current) {
|
|
183
|
-
scrollIntoViewIfNeeded(this.ref.current);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
this.handleClick = (event) => {
|
|
188
|
-
if (this.props.isDisabled) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (this.props.onClick) {
|
|
192
|
-
this.props.onClick(event);
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
componentDidMount() {
|
|
197
|
-
console.warn(`This component is being deprecated and will be removed in a future major version.\n
|
|
198
|
-
For more information, please see the V8 upgrade guide:\n
|
|
199
|
-
https://workday.github.io/canvas-kit/?path=/docs/guides-upgrade-guides-v8-0--docs#menu-preview
|
|
200
|
-
`);
|
|
201
|
-
}
|
|
202
|
-
render() {
|
|
203
|
-
const { onClick, children, id, icon, secondaryIcon, hasDivider, isDisabled, isFocused, isHeader, role, ...elemProps } = this.props;
|
|
204
|
-
iconProps = setIconProps(icon, isDisabled, isFocused);
|
|
205
|
-
secondaryIconProps = setIconProps(secondaryIcon, isDisabled, isFocused);
|
|
206
|
-
return (_jsxs(_Fragment, { children: [hasDivider && _jsx(Divider, { "aria-hidden": "true" }), _jsxs(Item, { ref: this.ref, tabIndex: -1, id: id, role: isHeader ? 'presentation' : role, "aria-hidden": isHeader ? true : undefined, onClick: this.handleClick, "aria-disabled": isDisabled ? true : undefined, isDisabled: !!isDisabled, isFocused: !!isFocused, isHeader: !!isHeader, ...elemProps, children: [icon && iconProps && _jsx(StyledSystemIcon, { ...iconProps }), _jsx(LabelContainer, { children: children }), secondaryIcon && secondaryIconProps && (_jsx(SecondaryStyledSystemIcon, { ...secondaryIconProps }))] })] }));
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* If we destructure props, shouldClose will be undefined because the value is only applied for the render method only.
|
|
211
|
-
* We have to use defaultProps so that the value of shouldClose is applied for every method and therefore references in the Menu component.
|
|
212
|
-
* For reference: https://github.com/Workday/canvas-kit/blob/f6d4d29e9bb2eb2af0b204e6f4ce2e5ed5a98e57/modules/_labs/menu/react/lib/Menu.tsx#L259,
|
|
213
|
-
*/
|
|
214
|
-
// TODO: Remove this ts-ignore when we convert to a functional component
|
|
215
|
-
// @ts-ignore
|
|
216
|
-
DeprecatedMenuItem.defaultProps = {
|
|
217
|
-
shouldClose: true,
|
|
218
|
-
role: 'menuitem',
|
|
219
|
-
};
|
package/menu/index.ts
DELETED
package/menu/lib/Menu.tsx
DELETED
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import styled from '@emotion/styled';
|
|
3
|
-
|
|
4
|
-
import {DeprecatedMenuItemProps} from './MenuItem';
|
|
5
|
-
import {Card} from '@workday/canvas-kit-react/card';
|
|
6
|
-
import {commonColors, space, borderRadius} from '@workday/canvas-kit-react/tokens';
|
|
7
|
-
import {GrowthBehavior, generateUniqueId} from '@workday/canvas-kit-react/common';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @deprecated ⚠️ `DeprecatedMenuProps` has been deprecated and will be removed in a future major version. Please use [Menu in Main](https://workday.github.io/canvas-kit/?path=/docs/components-popups-menu--basic) instead.
|
|
11
|
-
*/
|
|
12
|
-
export interface DeprecatedMenuProps
|
|
13
|
-
extends GrowthBehavior,
|
|
14
|
-
React.HTMLAttributes<HTMLUListElement> {
|
|
15
|
-
/**
|
|
16
|
-
* The DeprecatedMenuItem children of the DeprecatedMenu (must be at least one). Also accepts other components which share the same interface as `DeprecatedMenuItem`.
|
|
17
|
-
*/
|
|
18
|
-
children?:
|
|
19
|
-
| React.ReactElement<DeprecatedMenuItemProps>
|
|
20
|
-
| React.ReactElement<DeprecatedMenuItemProps>[];
|
|
21
|
-
/**
|
|
22
|
-
* If true, set the DeprecatedMenu to the open state. Useful for showing and hiding the DeprecatedMenu from a parent component such as a menu button.
|
|
23
|
-
* @default true
|
|
24
|
-
*/
|
|
25
|
-
isOpen?: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* The width of the DeprecatedMenu. If no value is provided, the DeprecatedMenu will collapse around its content.
|
|
28
|
-
*/
|
|
29
|
-
width?: number | string;
|
|
30
|
-
/**
|
|
31
|
-
* The function called when a menu item is selected.
|
|
32
|
-
*/
|
|
33
|
-
onSelect?: () => void;
|
|
34
|
-
/**
|
|
35
|
-
* The function called when the DeprecatedMenu should close. This is called after a menu item is selected or if the escape shortcut key is used. This will not fire if the menu item sets `shouldClose` to false.
|
|
36
|
-
*/
|
|
37
|
-
onClose?: () => void;
|
|
38
|
-
/**
|
|
39
|
-
* The zero-based index of the menu item which should initially receive focus.
|
|
40
|
-
*/
|
|
41
|
-
initialSelectedItem?: number;
|
|
42
|
-
/**
|
|
43
|
-
* The unique id of the DeprecatedMenu used for ARIA and HTML `id` attributes.
|
|
44
|
-
*/
|
|
45
|
-
id?: string;
|
|
46
|
-
/**
|
|
47
|
-
* The HTML `id` of the element that labels the DeprecatedMenu. Often used with menu buttons.
|
|
48
|
-
*/
|
|
49
|
-
'aria-labelledby'?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
*
|
|
54
|
-
* @deprecated ⚠️ `DeprecatedMenuState` has been deprecated and will be removed in a future major version. Please use [Menu in Main](https://workday.github.io/canvas-kit/?path=/docs/components-popups-menu--basic) instead.
|
|
55
|
-
*/
|
|
56
|
-
export interface DeprecatedMenuState {
|
|
57
|
-
selectedItemIndex: number;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const List = styled('ul')({
|
|
61
|
-
background: commonColors.background,
|
|
62
|
-
borderRadius: borderRadius.m,
|
|
63
|
-
padding: 0,
|
|
64
|
-
margin: `${space.xxs} 0`,
|
|
65
|
-
'&:focus-visible, &.focus': {
|
|
66
|
-
outline: 'none',
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* `DeprecatedMenu` renders a styled `<ul role="menu">` element within a {@link Card} and follows
|
|
72
|
-
* the [Active Menu
|
|
73
|
-
* pattern](https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-actions-active-descendant.html)
|
|
74
|
-
* using `aria-activedescendant`.
|
|
75
|
-
*
|
|
76
|
-
* Undocumented props are spread to the underlying `<ul>` element.
|
|
77
|
-
*
|
|
78
|
-
* @deprecated ⚠️ Deprecated Menu has been deprecated and will be removed in a future major version. Please use [Menu in Main](https://workday.github.io/canvas-kit/?path=/docs/components-popups-menu--basic) instead.
|
|
79
|
-
*/
|
|
80
|
-
export class DeprecatedMenu extends React.Component<DeprecatedMenuProps, DeprecatedMenuState> {
|
|
81
|
-
private id = generateUniqueId();
|
|
82
|
-
private animateId!: number;
|
|
83
|
-
|
|
84
|
-
private menuRef: React.RefObject<HTMLUListElement>;
|
|
85
|
-
private firstCharacters!: string[];
|
|
86
|
-
|
|
87
|
-
constructor(props: DeprecatedMenuProps) {
|
|
88
|
-
super(props);
|
|
89
|
-
this.menuRef = React.createRef();
|
|
90
|
-
|
|
91
|
-
const selected = this.getInitialSelectedItem();
|
|
92
|
-
|
|
93
|
-
// We track the active menu item by index so we can avoid setting a bunch of refs
|
|
94
|
-
// for doing things like selecting an item by first character (or really calling .focus() at all)
|
|
95
|
-
// It allows us to use the activedescendant design pattern
|
|
96
|
-
// https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-actions-active-descendant.html
|
|
97
|
-
this.state = {
|
|
98
|
-
selectedItemIndex: selected,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
componentDidUpdate(prevProps: DeprecatedMenuProps) {
|
|
103
|
-
if (this.props.children !== prevProps.children) {
|
|
104
|
-
this.setFirstCharacters();
|
|
105
|
-
this.setInitialSelectedItem();
|
|
106
|
-
}
|
|
107
|
-
if (this.props.isOpen && !prevProps.isOpen) {
|
|
108
|
-
this.setInitialSelectedItem();
|
|
109
|
-
}
|
|
110
|
-
this.animateId = requestAnimationFrame(() => {
|
|
111
|
-
if (this.props.isOpen && this.menuRef.current) {
|
|
112
|
-
this.menuRef.current.focus();
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
componentDidMount() {
|
|
118
|
-
console.warn(
|
|
119
|
-
`This component is being deprecated and will be removed in a future major version.\n
|
|
120
|
-
For more information, please see the V8 upgrade guide:\n
|
|
121
|
-
https://workday.github.io/canvas-kit/?path=/docs/guides-upgrade-guides-v8-0--docs#menu-preview
|
|
122
|
-
`
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
this.setFirstCharacters();
|
|
126
|
-
this.setInitialSelectedItem();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
componentWillUnmount() {
|
|
130
|
-
cancelAnimationFrame(this.animateId);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
public render() {
|
|
134
|
-
// TODO: Standardize on prop spread location (see #150)
|
|
135
|
-
const {
|
|
136
|
-
id = this.id,
|
|
137
|
-
isOpen = true,
|
|
138
|
-
children,
|
|
139
|
-
'aria-labelledby': ariaLabelledby,
|
|
140
|
-
grow,
|
|
141
|
-
width,
|
|
142
|
-
onSelect,
|
|
143
|
-
onClose,
|
|
144
|
-
initialSelectedItem,
|
|
145
|
-
...elemProps
|
|
146
|
-
} = this.props;
|
|
147
|
-
const {selectedItemIndex} = this.state;
|
|
148
|
-
const cardWidth = grow ? '100%' : width;
|
|
149
|
-
let interactiveItemIndex: number | null = null;
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<Card display="inline-block" padding={space.zero} width={cardWidth} depth={3}>
|
|
153
|
-
<Card.Body>
|
|
154
|
-
<List
|
|
155
|
-
role="menu"
|
|
156
|
-
tabIndex={0}
|
|
157
|
-
id={id}
|
|
158
|
-
aria-labelledby={ariaLabelledby}
|
|
159
|
-
aria-activedescendant={`${id}-${selectedItemIndex}`}
|
|
160
|
-
onKeyDown={this.handleKeyboardShortcuts}
|
|
161
|
-
ref={this.menuRef}
|
|
162
|
-
{...elemProps}
|
|
163
|
-
>
|
|
164
|
-
{React.Children.map(children, menuItem => {
|
|
165
|
-
if (!React.isValidElement(menuItem)) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
let itemId;
|
|
169
|
-
if (!menuItem.props.isHeader) {
|
|
170
|
-
interactiveItemIndex = (interactiveItemIndex ?? -1) + 1;
|
|
171
|
-
itemId = `${id}-${interactiveItemIndex}`;
|
|
172
|
-
}
|
|
173
|
-
return (
|
|
174
|
-
<React.Fragment key={itemId}>
|
|
175
|
-
{React.cloneElement(menuItem, {
|
|
176
|
-
onClick: (event: React.MouseEvent) => this.handleClick(event, menuItem.props),
|
|
177
|
-
id: itemId,
|
|
178
|
-
isFocused:
|
|
179
|
-
selectedItemIndex === interactiveItemIndex && !menuItem.props.isHeader,
|
|
180
|
-
})}
|
|
181
|
-
</React.Fragment>
|
|
182
|
-
);
|
|
183
|
-
})}
|
|
184
|
-
</List>
|
|
185
|
-
</Card.Body>
|
|
186
|
-
</Card>
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
public getNormalizedItemIndex = (index: number | undefined): number => {
|
|
191
|
-
const itemCount = React.Children.count(this.props.children);
|
|
192
|
-
const firstItem = 0;
|
|
193
|
-
const lastItem = itemCount - 1;
|
|
194
|
-
if (!index) {
|
|
195
|
-
return firstItem;
|
|
196
|
-
}
|
|
197
|
-
return index < 0 ? firstItem : index >= itemCount ? lastItem : index;
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
public setNormalizedItemIndex = (index: number | undefined): void => {
|
|
201
|
-
this.setState({selectedItemIndex: this.getNormalizedItemIndex(index)});
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
private handleKeyboardShortcuts = (event: React.KeyboardEvent): void => {
|
|
205
|
-
if (event.ctrlKey || event.altKey || event.metaKey) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const children = React.Children.toArray(this.props.children);
|
|
209
|
-
let nextSelectedIndex = 0;
|
|
210
|
-
let isShortcut = false;
|
|
211
|
-
const interactiveItems = children.filter(child => {
|
|
212
|
-
return !(child as React.ReactElement<DeprecatedMenuItemProps>)?.props?.isHeader;
|
|
213
|
-
});
|
|
214
|
-
const interactiveItemCount = interactiveItems.length;
|
|
215
|
-
const firstIndex = 0;
|
|
216
|
-
const lastIndex = interactiveItemCount - 1;
|
|
217
|
-
|
|
218
|
-
if (event.key.length === 1 && event.key.match(/\S/)) {
|
|
219
|
-
let start = this.state.selectedItemIndex + 1;
|
|
220
|
-
let searchIndex;
|
|
221
|
-
if (start === children.length) {
|
|
222
|
-
start = 0;
|
|
223
|
-
}
|
|
224
|
-
searchIndex = this.getIndexFirstChars(start, event.key.toLowerCase());
|
|
225
|
-
if (searchIndex === -1) {
|
|
226
|
-
searchIndex = this.getIndexFirstChars(0, event.key.toLowerCase(), start);
|
|
227
|
-
}
|
|
228
|
-
if (searchIndex > -1) {
|
|
229
|
-
isShortcut = true;
|
|
230
|
-
nextSelectedIndex = searchIndex;
|
|
231
|
-
}
|
|
232
|
-
} else {
|
|
233
|
-
switch (event.key) {
|
|
234
|
-
case 'ArrowUp':
|
|
235
|
-
case 'ArrowDown':
|
|
236
|
-
const direction = event.key === 'ArrowUp' ? -1 : 1;
|
|
237
|
-
isShortcut = true;
|
|
238
|
-
const nextIndex = this.state.selectedItemIndex + direction;
|
|
239
|
-
nextSelectedIndex =
|
|
240
|
-
nextIndex < 0 ? lastIndex : nextIndex >= interactiveItemCount ? firstIndex : nextIndex;
|
|
241
|
-
break;
|
|
242
|
-
|
|
243
|
-
case 'Home':
|
|
244
|
-
case 'End':
|
|
245
|
-
const skipTo = event.key === 'Home' ? firstIndex : lastIndex;
|
|
246
|
-
isShortcut = true;
|
|
247
|
-
nextSelectedIndex = skipTo;
|
|
248
|
-
break;
|
|
249
|
-
|
|
250
|
-
case 'Tab':
|
|
251
|
-
if (this.props.onClose) {
|
|
252
|
-
this.props.onClose();
|
|
253
|
-
}
|
|
254
|
-
break;
|
|
255
|
-
|
|
256
|
-
case 'Escape':
|
|
257
|
-
case 'Esc': // IE/Edge specific value
|
|
258
|
-
isShortcut = true;
|
|
259
|
-
if (this.props.onClose) {
|
|
260
|
-
this.props.onClose();
|
|
261
|
-
}
|
|
262
|
-
break;
|
|
263
|
-
|
|
264
|
-
case 'Spacebar':
|
|
265
|
-
case ' ':
|
|
266
|
-
case 'Enter':
|
|
267
|
-
nextSelectedIndex = this.state.selectedItemIndex;
|
|
268
|
-
const child = interactiveItems[
|
|
269
|
-
this.state.selectedItemIndex
|
|
270
|
-
] as React.ReactElement<DeprecatedMenuItemProps>;
|
|
271
|
-
this.handleClick(event, child.props);
|
|
272
|
-
isShortcut = true;
|
|
273
|
-
break;
|
|
274
|
-
|
|
275
|
-
default:
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (isShortcut) {
|
|
279
|
-
this.setNormalizedItemIndex(nextSelectedIndex);
|
|
280
|
-
event.stopPropagation();
|
|
281
|
-
event.preventDefault();
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
private handleClick = (
|
|
286
|
-
event: React.MouseEvent | React.KeyboardEvent,
|
|
287
|
-
menuItemProps: DeprecatedMenuItemProps
|
|
288
|
-
): void => {
|
|
289
|
-
/* istanbul ignore next line for coverage */
|
|
290
|
-
if (menuItemProps.isDisabled) {
|
|
291
|
-
// You should only hit this point if you are using a custom DeprecatedMenuItem implementation.
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
if (menuItemProps.onClick) {
|
|
295
|
-
menuItemProps.onClick(event as React.MouseEvent);
|
|
296
|
-
}
|
|
297
|
-
if (this.props.onSelect) {
|
|
298
|
-
this.props.onSelect();
|
|
299
|
-
}
|
|
300
|
-
if (this.props.onClose) {
|
|
301
|
-
if (menuItemProps.shouldClose) {
|
|
302
|
-
this.props.onClose();
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
private getIndexFirstChars = (
|
|
308
|
-
startIndex: number,
|
|
309
|
-
character: string,
|
|
310
|
-
lastIndex: number = this.firstCharacters.length
|
|
311
|
-
) => {
|
|
312
|
-
for (let i = startIndex; i < lastIndex; i++) {
|
|
313
|
-
if (character === this.firstCharacters[i]) {
|
|
314
|
-
return i;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return -1;
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
private setFirstCharacters = (): void => {
|
|
321
|
-
const getFirstCharacter = (child: React.ReactNode): string => {
|
|
322
|
-
let character = '';
|
|
323
|
-
if (!child || typeof child === 'boolean') {
|
|
324
|
-
character = '';
|
|
325
|
-
} else if (typeof child === 'string' || typeof child === 'number') {
|
|
326
|
-
character = child.toString().trim().substring(0, 1).toLowerCase();
|
|
327
|
-
} else if (Array.isArray(child) && child[0]) {
|
|
328
|
-
// TODO test React.ReactNodeArray
|
|
329
|
-
character = getFirstCharacter(child[0]);
|
|
330
|
-
} else if ('props' in child) {
|
|
331
|
-
const {children} = child.props;
|
|
332
|
-
|
|
333
|
-
if (Array.isArray(children)) {
|
|
334
|
-
character = getFirstCharacter(children[0]);
|
|
335
|
-
} else {
|
|
336
|
-
character = getFirstCharacter(children);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return character;
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
const firstCharacters = React.Children.map(this.props.children, child => {
|
|
343
|
-
if ((child as React.ReactElement<DeprecatedMenuItemProps>)?.props?.isHeader) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
return getFirstCharacter(child);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
this.firstCharacters = firstCharacters as string[];
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
private getInitialSelectedItem = (): number => {
|
|
353
|
-
let selected = this.props.initialSelectedItem || 0;
|
|
354
|
-
selected = selected < 0 ? React.Children.count(this.props.children) + selected : selected;
|
|
355
|
-
if (selected < 0) {
|
|
356
|
-
selected = 0;
|
|
357
|
-
} else if (selected > React.Children.count(this.props.children) - 1) {
|
|
358
|
-
selected = React.Children.count(this.props.children) - 1;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return selected;
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
private setInitialSelectedItem = () => {
|
|
365
|
-
const selected = this.getInitialSelectedItem();
|
|
366
|
-
this.setState({selectedItemIndex: selected});
|
|
367
|
-
};
|
|
368
|
-
}
|