@kaizen/components 1.79.8 → 1.79.10
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/cjs/src/Avatar/Avatar.cjs +2 -2
- package/dist/cjs/src/Modal/GenericModal/GenericModal.cjs +3 -5
- package/dist/esm/src/Avatar/Avatar.mjs +2 -2
- package/dist/esm/src/Modal/GenericModal/GenericModal.mjs +3 -5
- package/dist/styles.css +14 -14
- package/locales/de.json +17 -17
- package/package.json +1 -1
- package/src/Avatar/Avatar.spec.tsx +1 -0
- package/src/Avatar/Avatar.tsx +2 -2
- package/src/Modal/GenericModal/GenericModal.tsx +3 -5
- package/src/__next__/Button/_docs/Button--api-specification.mdx +6 -0
- package/src/__next__/Button/_docs/Button.docs.stories.tsx +29 -0
- package/src/__next__/Menu/_docs/Menu--api-specification.mdx +6 -0
- package/src/__next__/Menu/_docs/Menu.stories.tsx +29 -0
|
@@ -109,9 +109,9 @@ var Avatar = function (_a) {
|
|
|
109
109
|
var isOtherUser = isNoneOrError && !isCurrentUser;
|
|
110
110
|
return React__default.default.createElement("span", tslib.__assign({
|
|
111
111
|
className: classnames__default.default(Avatar_module.wrapper, Avatar_module[size], classNameOverride, isCompany && Avatar_module.company, isPersonal && Avatar_module.personal, isOtherUser && Avatar_module.otherUser)
|
|
112
|
-
}, restProps), avatarState !== 'none' && React__default.default.createElement("img", {
|
|
112
|
+
}, restProps), avatarState !== 'none' && avatarState !== 'error' && React__default.default.createElement("img", {
|
|
113
113
|
ref: image,
|
|
114
|
-
className: classnames__default.default(Avatar_module.avatarImage, isCompany && Avatar_module.companyAvatarImage,
|
|
114
|
+
className: classnames__default.default(Avatar_module.avatarImage, isCompany && Avatar_module.companyAvatarImage, avatarState === 'loading' && Avatar_module.loading),
|
|
115
115
|
src: avatarSrc,
|
|
116
116
|
onError: onImageFailure,
|
|
117
117
|
onLoad: onImageSuccess,
|
|
@@ -99,21 +99,19 @@ var GenericModal = function (_a) {
|
|
|
99
99
|
document.addEventListener('keyup', escapeKeyHandler);
|
|
100
100
|
}
|
|
101
101
|
};
|
|
102
|
-
var cleanUpAfterClose = function () {
|
|
102
|
+
var cleanUpAfterClose = React.useCallback(function () {
|
|
103
103
|
if (!isClientReady) return;
|
|
104
104
|
document.documentElement.classList.remove(GenericModal_module.unscrollable, GenericModal_module.pseudoScrollbar);
|
|
105
105
|
if (onEscapeKeyup) {
|
|
106
106
|
document.removeEventListener('keyup', escapeKeyHandler);
|
|
107
107
|
}
|
|
108
|
-
};
|
|
108
|
+
}, [escapeKeyHandler, onEscapeKeyup, isClientReady]);
|
|
109
109
|
/* Ensure sure add-on styles (e.g. unscrollable) and key event is cleaned up when the modal is unmounted*/
|
|
110
|
-
// @todo: Fix if possible - avoiding breaking in eslint upgrade
|
|
111
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
110
|
React.useEffect(function () {
|
|
113
111
|
return function () {
|
|
114
112
|
return cleanUpAfterClose();
|
|
115
113
|
};
|
|
116
|
-
}, []);
|
|
114
|
+
}, [cleanUpAfterClose]);
|
|
117
115
|
var onAfterLeaveHandler = function () {
|
|
118
116
|
cleanUpAfterClose();
|
|
119
117
|
propsOnAfterLeave === null || propsOnAfterLeave === void 0 ? void 0 : propsOnAfterLeave();
|
|
@@ -101,9 +101,9 @@ var Avatar = function (_a) {
|
|
|
101
101
|
var isOtherUser = isNoneOrError && !isCurrentUser;
|
|
102
102
|
return /*#__PURE__*/React.createElement("span", __assign({
|
|
103
103
|
className: classnames(styles.wrapper, styles[size], classNameOverride, isCompany && styles.company, isPersonal && styles.personal, isOtherUser && styles.otherUser)
|
|
104
|
-
}, restProps), avatarState !== 'none' && (/*#__PURE__*/React.createElement("img", {
|
|
104
|
+
}, restProps), avatarState !== 'none' && avatarState !== 'error' && (/*#__PURE__*/React.createElement("img", {
|
|
105
105
|
ref: image,
|
|
106
|
-
className: classnames(styles.avatarImage, isCompany && styles.companyAvatarImage,
|
|
106
|
+
className: classnames(styles.avatarImage, isCompany && styles.companyAvatarImage, avatarState === 'loading' && styles.loading),
|
|
107
107
|
src: avatarSrc,
|
|
108
108
|
onError: onImageFailure,
|
|
109
109
|
onLoad: onImageSuccess,
|
|
@@ -90,21 +90,19 @@ const GenericModal = /*#__PURE__*/function () {
|
|
|
90
90
|
document.addEventListener('keyup', escapeKeyHandler);
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
|
-
var cleanUpAfterClose = function () {
|
|
93
|
+
var cleanUpAfterClose = useCallback(function () {
|
|
94
94
|
if (!isClientReady) return;
|
|
95
95
|
document.documentElement.classList.remove(styles.unscrollable, styles.pseudoScrollbar);
|
|
96
96
|
if (onEscapeKeyup) {
|
|
97
97
|
document.removeEventListener('keyup', escapeKeyHandler);
|
|
98
98
|
}
|
|
99
|
-
};
|
|
99
|
+
}, [escapeKeyHandler, onEscapeKeyup, isClientReady]);
|
|
100
100
|
/* Ensure sure add-on styles (e.g. unscrollable) and key event is cleaned up when the modal is unmounted*/
|
|
101
|
-
// @todo: Fix if possible - avoiding breaking in eslint upgrade
|
|
102
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
103
101
|
useEffect(function () {
|
|
104
102
|
return function () {
|
|
105
103
|
return cleanUpAfterClose();
|
|
106
104
|
};
|
|
107
|
-
}, []);
|
|
105
|
+
}, [cleanUpAfterClose]);
|
|
108
106
|
var onAfterLeaveHandler = function () {
|
|
109
107
|
cleanUpAfterClose();
|
|
110
108
|
propsOnAfterLeave === null || propsOnAfterLeave === void 0 ? void 0 : propsOnAfterLeave();
|
package/dist/styles.css
CHANGED
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
@layer kz-components {
|
|
13
|
+
.ListItem-module_listItem__xGr6A {
|
|
14
|
+
font-family: var(--typography-paragraph-body-font-family);
|
|
15
|
+
font-weight: var(--typography-paragraph-body-font-weight);
|
|
16
|
+
font-size: var(--typography-paragraph-body-font-size);
|
|
17
|
+
line-height: var(--typography-paragraph-body-line-height);
|
|
18
|
+
letter-spacing: var(--typography-paragraph-body-letter-spacing);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
@layer kz-components {
|
|
13
23
|
.ListSection-module_listSectionHeader__bptHg {
|
|
14
24
|
font-family: var(--typography-heading-5-font-family);
|
|
@@ -20,12 +30,10 @@
|
|
|
20
30
|
}
|
|
21
31
|
|
|
22
32
|
@layer kz-components {
|
|
23
|
-
.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
line-height: var(--typography-paragraph-body-line-height);
|
|
28
|
-
letter-spacing: var(--typography-paragraph-body-letter-spacing);
|
|
33
|
+
.List-module_list__bbFPn {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: var(--spacing-16);
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
|
|
@@ -48,14 +56,6 @@
|
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
|
|
51
|
-
@layer kz-components {
|
|
52
|
-
.List-module_list__bbFPn {
|
|
53
|
-
display: flex;
|
|
54
|
-
flex-direction: column;
|
|
55
|
-
gap: var(--spacing-16);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
59
|
@layer kz-components {
|
|
60
60
|
/*
|
|
61
61
|
* This is taken from the Material Symbols CDN
|
package/locales/de.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"date.validation.unavailableDate" : {
|
|
25
25
|
"description" : "Error message when the user tries to select a date that is unavailable",
|
|
26
|
-
"message" : "{inputValue} ist nicht verfügbar.
|
|
26
|
+
"message" : "{inputValue} ist nicht verfügbar. Versuche es mit einem anderen Datum."
|
|
27
27
|
},
|
|
28
28
|
"dateInputDescription.inputFormat" : {
|
|
29
29
|
"description" : "Label for the 'Input format' field",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"datePicker.calendarLabelDescription" : {
|
|
33
33
|
"description" : "Label for the search input",
|
|
34
|
-
"message" : "
|
|
34
|
+
"message" : "Wähle im Kalender ein Datum für:"
|
|
35
35
|
},
|
|
36
36
|
"filterBar.addFiltersMenu.buttonLabel" : {
|
|
37
37
|
"description" : "Menu button label to show additional available filter options",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
},
|
|
88
88
|
"kzErrorPage" : {
|
|
89
89
|
"description" : "Label for contact button",
|
|
90
|
-
"message" : "kontaktieren
|
|
90
|
+
"message" : "Support kontaktieren"
|
|
91
91
|
},
|
|
92
92
|
"kzErrorPage.400.message" : {
|
|
93
93
|
"description" : "Call to action instructions for the user",
|
|
@@ -99,23 +99,23 @@
|
|
|
99
99
|
},
|
|
100
100
|
"kzErrorPage.401.message" : {
|
|
101
101
|
"description" : "Call to action instructions for the user",
|
|
102
|
-
"message" : "Leider können wir nicht überprüfen, ob
|
|
102
|
+
"message" : "Leider können wir nicht überprüfen, ob du diese Seite anzeigen kannst. Gehe zurück und versuche es erneut oder gehe zur Startseite."
|
|
103
103
|
},
|
|
104
104
|
"kzErrorPage.401.title" : {
|
|
105
105
|
"description" : "Main title for page",
|
|
106
|
-
"message" : "
|
|
106
|
+
"message" : "Du kannst diese Seite nicht anzeigen"
|
|
107
107
|
},
|
|
108
108
|
"kzErrorPage.403.message" : {
|
|
109
109
|
"description" : "Call to action instructions for the user",
|
|
110
|
-
"message" : "Offenbar fehlt
|
|
110
|
+
"message" : "Offenbar fehlt dir leider die Berechtigung zum Anzeigen dieser Seite. Gehe zurück und versuche es erneut oder gehe zur Startseite."
|
|
111
111
|
},
|
|
112
112
|
"kzErrorPage.403.title" : {
|
|
113
113
|
"description" : "Main title for page",
|
|
114
|
-
"message" : "
|
|
114
|
+
"message" : "Du kannst diese Seite nicht anzeigen"
|
|
115
115
|
},
|
|
116
116
|
"kzErrorPage.404.message" : {
|
|
117
117
|
"description" : "Call to action instructions for the user",
|
|
118
|
-
"message" : "Leider können wir die von
|
|
118
|
+
"message" : "Leider können wir die von dir gesuchte Seite nicht finden. Gehe zurück und versuche es erneut oder gehe zur Startseite"
|
|
119
119
|
},
|
|
120
120
|
"kzErrorPage.404.title" : {
|
|
121
121
|
"description" : "Main title of page",
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
"kzErrorPage.413" : {
|
|
125
125
|
"description" : "Call to action instructions for the user",
|
|
126
|
-
"message" : "Leider liegt ein Problem mit unserem System vor und diese Seite kann nicht angezeigt werden.
|
|
126
|
+
"message" : "Leider liegt ein Problem mit unserem System vor und diese Seite kann nicht angezeigt werden. Gehe zurück und versuche es erneut oder gehe zur Startseite"
|
|
127
127
|
},
|
|
128
128
|
"kzErrorPage.413.title" : {
|
|
129
129
|
"description" : "Main title of page",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
},
|
|
132
132
|
"kzErrorPage.422.message" : {
|
|
133
133
|
"description" : "Call to action instructions for the user",
|
|
134
|
-
"message" : "
|
|
134
|
+
"message" : "Deine Änderung konnte leider nicht vorgenommen werden. Gehe zurück und versuche es erneut oder gehe zur Startseite."
|
|
135
135
|
},
|
|
136
136
|
"kzErrorPage.422.title" : {
|
|
137
137
|
"description" : "Main title of page",
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
},
|
|
140
140
|
"kzErrorPage.500" : {
|
|
141
141
|
"description" : "Call to action instructions for the user",
|
|
142
|
-
"message" : "Leider liegt ein Problem mit unserem System vor und diese Seite kann nicht angezeigt werden.
|
|
142
|
+
"message" : "Leider liegt ein Problem mit unserem System vor und diese Seite kann nicht angezeigt werden. Gehe zurück und versuche es erneut oder gehe zur Startseite."
|
|
143
143
|
},
|
|
144
144
|
"kzErrorPage.500.title" : {
|
|
145
145
|
"description" : "Main title of page",
|
|
@@ -147,27 +147,27 @@
|
|
|
147
147
|
},
|
|
148
148
|
"kzErrorPage.502.message" : {
|
|
149
149
|
"description" : "Call to action instructions for the user",
|
|
150
|
-
"message" : "Das tut uns leid. Das Beste, was
|
|
150
|
+
"message" : "Das tut uns leid. Das Beste, was du tun kannst, ist, zurückzugehen und es erneut zu versuchen."
|
|
151
151
|
},
|
|
152
152
|
"kzErrorPage.502.title" : {
|
|
153
153
|
"description" : "Main title of page",
|
|
154
|
-
"message" : "
|
|
154
|
+
"message" : "Du kannst diese Seite nicht anzeigen"
|
|
155
155
|
},
|
|
156
156
|
"kzErrorPage.503.message" : {
|
|
157
157
|
"description" : "Call to action instructions for the user",
|
|
158
|
-
"message" : "Das tut uns leid. Das Beste, was
|
|
158
|
+
"message" : "Das tut uns leid. Das Beste, was du tun kannst, ist, zurückzugehen und es erneut zu versuchen."
|
|
159
159
|
},
|
|
160
160
|
"kzErrorPage.503.title" : {
|
|
161
161
|
"description" : "Main title of page",
|
|
162
|
-
"message" : "
|
|
162
|
+
"message" : "Du kannst diese Seite nicht anzeigen"
|
|
163
163
|
},
|
|
164
164
|
"kzErrorPage.504.message" : {
|
|
165
165
|
"description" : "Call to action instructions for the user",
|
|
166
|
-
"message" : "Das tut uns leid. Das Beste, was
|
|
166
|
+
"message" : "Das tut uns leid. Das Beste, was du tun kannst, ist, zurückzugehen und es erneut zu versuchen."
|
|
167
167
|
},
|
|
168
168
|
"kzErrorPage.504.title" : {
|
|
169
169
|
"description" : "Main title of page",
|
|
170
|
-
"message" : "
|
|
170
|
+
"message" : "Du kannst diese Seite nicht anzeigen"
|
|
171
171
|
},
|
|
172
172
|
"kzErrorPage.errorCode" : {
|
|
173
173
|
"message" : "Fehlercode {code}"
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ describe('<Avatar />', () => {
|
|
|
14
14
|
fireEvent.error(screen.getByRole('img'))
|
|
15
15
|
|
|
16
16
|
expect(screen.getByText('JD')).toBeInTheDocument()
|
|
17
|
+
expect(screen.queryByRole('img')).not.toBeInTheDocument()
|
|
17
18
|
})
|
|
18
19
|
|
|
19
20
|
describe('full name provided contains more than two names', () => {
|
package/src/Avatar/Avatar.tsx
CHANGED
|
@@ -156,13 +156,13 @@ export const Avatar = ({
|
|
|
156
156
|
)}
|
|
157
157
|
{...restProps}
|
|
158
158
|
>
|
|
159
|
-
{avatarState !== 'none' && (
|
|
159
|
+
{avatarState !== 'none' && avatarState !== 'error' && (
|
|
160
160
|
<img
|
|
161
161
|
ref={image}
|
|
162
162
|
className={classnames(
|
|
163
163
|
styles.avatarImage,
|
|
164
164
|
isCompany && styles.companyAvatarImage,
|
|
165
|
-
|
|
165
|
+
avatarState === 'loading' && styles.loading,
|
|
166
166
|
)}
|
|
167
167
|
src={avatarSrc}
|
|
168
168
|
onError={onImageFailure}
|
|
@@ -125,7 +125,7 @@ export const GenericModal = ({
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
const cleanUpAfterClose = ()
|
|
128
|
+
const cleanUpAfterClose = useCallback(() => {
|
|
129
129
|
if (!isClientReady) return
|
|
130
130
|
|
|
131
131
|
document.documentElement.classList.remove(styles.unscrollable, styles.pseudoScrollbar)
|
|
@@ -133,12 +133,10 @@ export const GenericModal = ({
|
|
|
133
133
|
if (onEscapeKeyup) {
|
|
134
134
|
document.removeEventListener('keyup', escapeKeyHandler)
|
|
135
135
|
}
|
|
136
|
-
}
|
|
136
|
+
}, [escapeKeyHandler, onEscapeKeyup, isClientReady])
|
|
137
137
|
|
|
138
138
|
/* Ensure sure add-on styles (e.g. unscrollable) and key event is cleaned up when the modal is unmounted*/
|
|
139
|
-
|
|
140
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
141
|
-
useEffect(() => () => cleanUpAfterClose(), [])
|
|
139
|
+
useEffect(() => () => cleanUpAfterClose(), [cleanUpAfterClose])
|
|
142
140
|
|
|
143
141
|
const onAfterLeaveHandler = (): void => {
|
|
144
142
|
cleanUpAfterClose()
|
|
@@ -156,6 +156,12 @@ If a button is statically the full width of a container you can use the `isFullW
|
|
|
156
156
|
|
|
157
157
|
For resizing on smaller screens, consider using the `className` prop to leverage CSS media or container queries, ie: `<Button className="w-full md:w-[initial]">Label</Button>`.
|
|
158
158
|
|
|
159
|
+
## Use a menu to show additional actions
|
|
160
|
+
|
|
161
|
+
Instead of a split button (now a [deprecated component](https://cultureamp.atlassian.net/wiki/spaces/DES/pages/4286611457/Deprecating+Split+Buttons+-+Design+Request+for+Comment+RFC)), use a Button with text followed by a Menu to show any additional actions related to the most critical action.
|
|
162
|
+
|
|
163
|
+
<Canvas className="mb-24" of={exampleStories.ButtonMenuPattern} />
|
|
164
|
+
|
|
159
165
|
## Additional API options
|
|
160
166
|
|
|
161
167
|
The following table is a collection of additional React Aria and native HTML props that are exposed from the React Aria API. These are not required for the implementation of `Button` but can be used to extend its functionality. Refer back to the [overview section](#overview) for the core props that enable most use cases.
|
|
@@ -391,3 +391,32 @@ export const DontExampleTertiaryButtonWithIcons: Story = {
|
|
|
391
391
|
variant: 'tertiary',
|
|
392
392
|
},
|
|
393
393
|
}
|
|
394
|
+
|
|
395
|
+
export const ButtonMenuPattern: Story = {
|
|
396
|
+
name: 'Button + Menu Pattern',
|
|
397
|
+
render: () => (
|
|
398
|
+
<div className="flex gap-4">
|
|
399
|
+
<Button size="large" variant="secondary">
|
|
400
|
+
Edit Survey
|
|
401
|
+
</Button>
|
|
402
|
+
<MenuTrigger>
|
|
403
|
+
<Button
|
|
404
|
+
size="large"
|
|
405
|
+
icon={<Icon name="more_horiz" isPresentational />}
|
|
406
|
+
variant="secondary"
|
|
407
|
+
hasHiddenLabel
|
|
408
|
+
>
|
|
409
|
+
More surveys
|
|
410
|
+
</Button>
|
|
411
|
+
<MenuPopover>
|
|
412
|
+
<Menu>
|
|
413
|
+
<MenuItem>Survey 1</MenuItem>
|
|
414
|
+
<MenuItem>Survey 2</MenuItem>
|
|
415
|
+
<MenuItem>Survey 3</MenuItem>
|
|
416
|
+
<MenuItem>Survey 4</MenuItem>
|
|
417
|
+
</Menu>
|
|
418
|
+
</MenuPopover>
|
|
419
|
+
</MenuTrigger>
|
|
420
|
+
</div>
|
|
421
|
+
),
|
|
422
|
+
}
|
|
@@ -83,3 +83,9 @@ Menu items can be disabled with the `isDisabled` prop.
|
|
|
83
83
|
By default, the open/closed state of the menu is handled under the hood. In cases where you need control over the open state, use the `isOpen` and `onOpenChange` props on the `MenuTrigger` component (both props must be used for this to work).
|
|
84
84
|
|
|
85
85
|
<Canvas className="mb-24" of={exampleStories.Controlled} />
|
|
86
|
+
|
|
87
|
+
## Use a menu to show additional actions
|
|
88
|
+
|
|
89
|
+
Instead of a split button (now a [deprecated component](https://cultureamp.atlassian.net/wiki/spaces/DES/pages/4286611457/Deprecating+Split+Buttons+-+Design+Request+for+Comment+RFC)), use a Button with text followed by a Menu to show any additional actions related to the most critical action.
|
|
90
|
+
|
|
91
|
+
<Canvas className="mb-24" of={exampleStories.ButtonMenuPattern} />
|
|
@@ -128,3 +128,32 @@ export const Sections: Story = {
|
|
|
128
128
|
</MenuTrigger>
|
|
129
129
|
),
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
export const ButtonMenuPattern: Story = {
|
|
133
|
+
name: 'Button + Menu Pattern',
|
|
134
|
+
render: ({ defaultOpen: _, ...args }) => (
|
|
135
|
+
<div className="flex gap-4">
|
|
136
|
+
<Button size="large" variant="secondary">
|
|
137
|
+
Edit Survey
|
|
138
|
+
</Button>
|
|
139
|
+
<MenuTrigger {...args}>
|
|
140
|
+
<Button
|
|
141
|
+
size="large"
|
|
142
|
+
icon={<Icon name="more_horiz" isPresentational />}
|
|
143
|
+
variant="secondary"
|
|
144
|
+
hasHiddenLabel
|
|
145
|
+
>
|
|
146
|
+
More surveys
|
|
147
|
+
</Button>
|
|
148
|
+
<MenuPopover>
|
|
149
|
+
<Menu>
|
|
150
|
+
<MenuItem>Survey 1</MenuItem>
|
|
151
|
+
<MenuItem>Survey 2</MenuItem>
|
|
152
|
+
<MenuItem>Survey 3</MenuItem>
|
|
153
|
+
<MenuItem>Survey 4</MenuItem>
|
|
154
|
+
</Menu>
|
|
155
|
+
</MenuPopover>
|
|
156
|
+
</MenuTrigger>
|
|
157
|
+
</div>
|
|
158
|
+
),
|
|
159
|
+
}
|