@veiag/payload-cmdk 1.0.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/README.md +594 -0
- package/dist/components/CommandMenuContext.d.ts +15 -0
- package/dist/components/CommandMenuContext.js +430 -0
- package/dist/components/CommandMenuContext.js.map +1 -0
- package/dist/components/SearchButton.d.ts +8 -0
- package/dist/components/SearchButton.js +106 -0
- package/dist/components/SearchButton.js.map +1 -0
- package/dist/components/SearchButton.scss +133 -0
- package/dist/components/cmdk/command.scss +334 -0
- package/dist/components/cmdk/index.d.ts +12 -0
- package/dist/components/cmdk/index.js +77 -0
- package/dist/components/cmdk/index.js.map +1 -0
- package/dist/components/modal.scss +94 -0
- package/dist/endpoints/customEndpointHandler.d.ts +2 -0
- package/dist/endpoints/customEndpointHandler.js +7 -0
- package/dist/endpoints/customEndpointHandler.js.map +1 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.js +4 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +0 -0
- package/dist/exports/rsc.js +2 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/hooks/useMutationObserver.d.ts +1 -0
- package/dist/hooks/useMutationObserver.js +21 -0
- package/dist/hooks/useMutationObserver.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/translations/index.d.ts +32 -0
- package/dist/translations/index.js +38 -0
- package/dist/translations/index.js.map +1 -0
- package/dist/types.d.ts +223 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +30 -0
- package/dist/utils/index.js +191 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +126 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import './modal.scss';
|
|
4
|
+
import { Modal, useConfig, useModal, useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import { ArrowBigUp, ChevronLeft, Command as CommandIcon, Option } from 'lucide-react';
|
|
6
|
+
import { DynamicIcon } from 'lucide-react/dynamic';
|
|
7
|
+
import { useRouter } from 'next/navigation';
|
|
8
|
+
import { createContext, Fragment, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
9
|
+
import { useHotkeys } from 'react-hotkeys-hook';
|
|
10
|
+
import { createDefaultGroups } from '../utils/index';
|
|
11
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from './cmdk/index';
|
|
12
|
+
const MODAL_SLUG = 'command-menu';
|
|
13
|
+
const CommandMenuContext = /*#__PURE__*/ createContext({
|
|
14
|
+
closeMenu: ()=>{},
|
|
15
|
+
currentPage: 'main',
|
|
16
|
+
groups: [],
|
|
17
|
+
isOpen: false,
|
|
18
|
+
items: [],
|
|
19
|
+
openMenu: ()=>{},
|
|
20
|
+
setPage: ()=>{},
|
|
21
|
+
toggleMenu: ()=>{}
|
|
22
|
+
});
|
|
23
|
+
export const useCommandMenu = ()=>{
|
|
24
|
+
const context = useContext(CommandMenuContext);
|
|
25
|
+
return context;
|
|
26
|
+
};
|
|
27
|
+
const ITEM_SELECTOR = `[cmdk-item=""]`;
|
|
28
|
+
function getSelectedElement(containerRef) {
|
|
29
|
+
return containerRef.current?.querySelector(`${ITEM_SELECTOR}[aria-selected="true"]`);
|
|
30
|
+
}
|
|
31
|
+
const CommandMenuComponent = ({ pluginConfig })=>{
|
|
32
|
+
const [search, setSearch] = useState('');
|
|
33
|
+
const [submenuItems, setSubmenuItems] = useState([]);
|
|
34
|
+
const [isLoadingSubmenu, setIsLoadingSubmenu] = useState(false);
|
|
35
|
+
const [isMac, setIsMac] = useState(false);
|
|
36
|
+
const commandListRef = useRef(null);
|
|
37
|
+
const { closeMenu, currentPage, groups, items, setPage } = useCommandMenu();
|
|
38
|
+
const router = useRouter();
|
|
39
|
+
const { t } = useTranslation();
|
|
40
|
+
useEffect(()=>{
|
|
41
|
+
setIsMac(/Mac|iPhone|iPod|iPad/i.test(navigator.platform));
|
|
42
|
+
}, []);
|
|
43
|
+
const submenuEnabled = pluginConfig?.submenu?.enabled !== false;
|
|
44
|
+
const submenuShortcut = pluginConfig?.submenu?.shortcut || 'shift+enter';
|
|
45
|
+
const blurBg = pluginConfig?.blurBg !== false;
|
|
46
|
+
const formatShortcutKey = (key)=>{
|
|
47
|
+
// Handle compound shortcuts like "Shift + Enter"
|
|
48
|
+
const parts = key.split('+').map((part)=>part.trim());
|
|
49
|
+
const elements = parts.map((part, index)=>{
|
|
50
|
+
const lowerPart = part.toLowerCase();
|
|
51
|
+
let content;
|
|
52
|
+
if (lowerPart === 'ctrl' || lowerPart === 'cmd') {
|
|
53
|
+
content = isMac ? /*#__PURE__*/ _jsx(CommandIcon, {
|
|
54
|
+
size: 12
|
|
55
|
+
}) : 'Ctrl';
|
|
56
|
+
} else if (lowerPart === 'meta') {
|
|
57
|
+
content = isMac ? /*#__PURE__*/ _jsx(CommandIcon, {
|
|
58
|
+
size: 12
|
|
59
|
+
}) : 'Ctrl';
|
|
60
|
+
} else if (lowerPart === 'shift') {
|
|
61
|
+
content = isMac ? /*#__PURE__*/ _jsx(ArrowBigUp, {
|
|
62
|
+
size: 12
|
|
63
|
+
}) : 'Shift';
|
|
64
|
+
} else if (lowerPart === 'alt') {
|
|
65
|
+
content = isMac ? /*#__PURE__*/ _jsx(Option, {
|
|
66
|
+
size: 12
|
|
67
|
+
}) : 'Alt';
|
|
68
|
+
} else {
|
|
69
|
+
content = part;
|
|
70
|
+
}
|
|
71
|
+
return /*#__PURE__*/ _jsxs(Fragment, {
|
|
72
|
+
children: [
|
|
73
|
+
content,
|
|
74
|
+
!isMac && index < parts.length - 1 && ' + '
|
|
75
|
+
]
|
|
76
|
+
}, index);
|
|
77
|
+
});
|
|
78
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
79
|
+
children: elements
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
// Debounced search for submenu
|
|
83
|
+
useEffect(()=>{
|
|
84
|
+
if (currentPage === 'main') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const fetchDocuments = async ()=>{
|
|
88
|
+
if (currentPage.type !== 'collection-search') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
setIsLoadingSubmenu(true);
|
|
92
|
+
try {
|
|
93
|
+
const searchParam = search ? `&where[${currentPage.useAsTitle}][like]=${encodeURIComponent(search)}` : '';
|
|
94
|
+
const response = await fetch(`/api/${currentPage.slug}?limit=10${searchParam}&select[${currentPage.useAsTitle}]=true`);
|
|
95
|
+
const data = await response.json();
|
|
96
|
+
if (data.docs && Array.isArray(data.docs)) {
|
|
97
|
+
const docs = data.docs.map((doc)=>({
|
|
98
|
+
slug: `${currentPage.slug}-${doc.id}`,
|
|
99
|
+
type: 'custom',
|
|
100
|
+
action: {
|
|
101
|
+
type: 'link',
|
|
102
|
+
href: `/admin/collections/${currentPage.slug}/${doc.id}`
|
|
103
|
+
},
|
|
104
|
+
icon: pluginConfig?.submenu?.icons?.[currentPage.slug] ?? undefined,
|
|
105
|
+
label: doc[currentPage.useAsTitle] || doc.id
|
|
106
|
+
}));
|
|
107
|
+
setSubmenuItems(docs);
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
setSubmenuItems([]);
|
|
111
|
+
} finally{
|
|
112
|
+
setIsLoadingSubmenu(false);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const timeoutId = setTimeout(fetchDocuments, 300);
|
|
116
|
+
return ()=>clearTimeout(timeoutId);
|
|
117
|
+
}, [
|
|
118
|
+
search,
|
|
119
|
+
currentPage,
|
|
120
|
+
pluginConfig?.submenu?.icons
|
|
121
|
+
]);
|
|
122
|
+
const handleBack = useCallback(()=>{
|
|
123
|
+
setPage('main');
|
|
124
|
+
setSearch('');
|
|
125
|
+
setSubmenuItems([]);
|
|
126
|
+
}, [
|
|
127
|
+
setPage
|
|
128
|
+
]);
|
|
129
|
+
const executeItemAction = useCallback(async (item)=>{
|
|
130
|
+
// Execute the item's action
|
|
131
|
+
switch(item.action.type){
|
|
132
|
+
case 'api':
|
|
133
|
+
await fetch(item.action.href, {
|
|
134
|
+
body: item.action.body ? JSON.stringify(item.action.body) : undefined,
|
|
135
|
+
headers: {
|
|
136
|
+
'Content-Type': 'application/json'
|
|
137
|
+
},
|
|
138
|
+
method: item.action.method || 'GET'
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
case 'link':
|
|
142
|
+
router.push(item.action.href);
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
closeMenu();
|
|
148
|
+
setSearch('');
|
|
149
|
+
setPage('main');
|
|
150
|
+
}, [
|
|
151
|
+
router,
|
|
152
|
+
closeMenu,
|
|
153
|
+
setPage
|
|
154
|
+
]);
|
|
155
|
+
const openSubmenu = useCallback((item)=>{
|
|
156
|
+
setPage({
|
|
157
|
+
slug: item.slug,
|
|
158
|
+
type: 'collection-search',
|
|
159
|
+
label: item.label,
|
|
160
|
+
useAsTitle: item.useAsTitle || 'id',
|
|
161
|
+
useAsTitleLabel: item.useAsTitleLabel || item.useAsTitle || 'id'
|
|
162
|
+
});
|
|
163
|
+
setSearch('');
|
|
164
|
+
//set isLoadingSubmenu to true to show loading state while fetching
|
|
165
|
+
setIsLoadingSubmenu(true);
|
|
166
|
+
setSubmenuItems([]);
|
|
167
|
+
}, [
|
|
168
|
+
setPage
|
|
169
|
+
]);
|
|
170
|
+
const handleSelect = useCallback(async (item)=>{
|
|
171
|
+
await executeItemAction(item);
|
|
172
|
+
}, [
|
|
173
|
+
executeItemAction
|
|
174
|
+
]);
|
|
175
|
+
// Handle keyboard events for navigation and back
|
|
176
|
+
useEffect(()=>{
|
|
177
|
+
const handleKeyDown = (e)=>{
|
|
178
|
+
// ESC key for back navigation in submenu
|
|
179
|
+
if (e.key === 'Escape' && currentPage !== 'main') {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
e.stopPropagation();
|
|
182
|
+
handleBack();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Enter/Shift+Enter handling for collection submenu
|
|
186
|
+
if (e.key === 'Enter' && currentPage === 'main') {
|
|
187
|
+
const selectedElement = getSelectedElement(commandListRef);
|
|
188
|
+
const itemType = selectedElement?.getAttribute('data-item-type');
|
|
189
|
+
const itemSlug = selectedElement?.getAttribute('data-value');
|
|
190
|
+
if (submenuEnabled && itemType === 'collection' && itemSlug) {
|
|
191
|
+
const isShiftPressed = e.shiftKey;
|
|
192
|
+
const shouldOpenSubmenu = submenuShortcut === 'shift+enter' && isShiftPressed || submenuShortcut === 'enter' && !isShiftPressed;
|
|
193
|
+
if (shouldOpenSubmenu) {
|
|
194
|
+
e.preventDefault();
|
|
195
|
+
e.stopPropagation();
|
|
196
|
+
// Find the item in groups
|
|
197
|
+
const item = groups.flatMap((g)=>g.items).find((i)=>i.slug === itemSlug);
|
|
198
|
+
if (item) {
|
|
199
|
+
openSubmenu(item);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
document.addEventListener('keydown', handleKeyDown, true);
|
|
207
|
+
return ()=>document.removeEventListener('keydown', handleKeyDown, true);
|
|
208
|
+
}, [
|
|
209
|
+
currentPage,
|
|
210
|
+
handleBack,
|
|
211
|
+
submenuEnabled,
|
|
212
|
+
submenuShortcut,
|
|
213
|
+
openSubmenu,
|
|
214
|
+
groups
|
|
215
|
+
]);
|
|
216
|
+
const placeholder = currentPage === 'main' ? t('cmdkPlugin:search') : t('general:searchBy', {
|
|
217
|
+
label: currentPage.useAsTitleLabel
|
|
218
|
+
});
|
|
219
|
+
const shouldDisableFilter = currentPage !== 'main';
|
|
220
|
+
// Static footer shortcuts based on current page
|
|
221
|
+
const footerShortcuts = currentPage === 'main' && submenuEnabled && submenuShortcut === 'shift+enter' ? [
|
|
222
|
+
{
|
|
223
|
+
key: 'Enter',
|
|
224
|
+
label: t('cmdkPlugin:navigate')
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
key: 'Shift + Enter',
|
|
228
|
+
label: t('cmdkPlugin:searchInCollection')
|
|
229
|
+
}
|
|
230
|
+
] : currentPage === 'main' && submenuEnabled && submenuShortcut === 'enter' ? [
|
|
231
|
+
{
|
|
232
|
+
key: 'Enter',
|
|
233
|
+
label: t('cmdkPlugin:searchInCollection')
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
key: 'Shift + Enter',
|
|
237
|
+
label: t('cmdkPlugin:navigate')
|
|
238
|
+
}
|
|
239
|
+
] : currentPage === 'main' ? [
|
|
240
|
+
{
|
|
241
|
+
key: 'Enter',
|
|
242
|
+
label: t('cmdkPlugin:navigate')
|
|
243
|
+
}
|
|
244
|
+
] : [
|
|
245
|
+
{
|
|
246
|
+
key: 'Enter',
|
|
247
|
+
label: t('cmdkPlugin:open')
|
|
248
|
+
}
|
|
249
|
+
];
|
|
250
|
+
const handleBackdropClick = (e)=>{
|
|
251
|
+
// Close modal only if clicking the backdrop (not the command itself)
|
|
252
|
+
if (e.target === e.currentTarget) {
|
|
253
|
+
closeMenu();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
return /*#__PURE__*/ _jsx(Modal, {
|
|
257
|
+
slug: MODAL_SLUG,
|
|
258
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
259
|
+
className: `command-modal ${blurBg ? 'command-modal--blur' : ''}`,
|
|
260
|
+
onClick: handleBackdropClick,
|
|
261
|
+
children: /*#__PURE__*/ _jsxs(Command, {
|
|
262
|
+
label: "Command Menu",
|
|
263
|
+
shouldFilter: !shouldDisableFilter,
|
|
264
|
+
children: [
|
|
265
|
+
currentPage !== 'main' && /*#__PURE__*/ _jsxs("div", {
|
|
266
|
+
className: "command__header",
|
|
267
|
+
children: [
|
|
268
|
+
/*#__PURE__*/ _jsx("button", {
|
|
269
|
+
className: "command__back-button",
|
|
270
|
+
onClick: handleBack,
|
|
271
|
+
type: "button",
|
|
272
|
+
children: /*#__PURE__*/ _jsx(ChevronLeft, {
|
|
273
|
+
size: 16
|
|
274
|
+
})
|
|
275
|
+
}),
|
|
276
|
+
/*#__PURE__*/ _jsx("span", {
|
|
277
|
+
className: "command__header-label",
|
|
278
|
+
children: t('cmdkPlugin:searchIn', {
|
|
279
|
+
label: currentPage.label
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
]
|
|
283
|
+
}),
|
|
284
|
+
/*#__PURE__*/ _jsx(CommandInput, {
|
|
285
|
+
onValueChange: setSearch,
|
|
286
|
+
placeholder: placeholder,
|
|
287
|
+
value: search
|
|
288
|
+
}),
|
|
289
|
+
/*#__PURE__*/ _jsxs(CommandList, {
|
|
290
|
+
ref: commandListRef,
|
|
291
|
+
children: [
|
|
292
|
+
/*#__PURE__*/ _jsx(CommandEmpty, {
|
|
293
|
+
children: isLoadingSubmenu ? t('cmdkPlugin:loading') : t('cmdkPlugin:noResults')
|
|
294
|
+
}),
|
|
295
|
+
currentPage === 'main' && groups.map((group, index)=>{
|
|
296
|
+
if (group.items.length === 0) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
let titleName = group.title;
|
|
300
|
+
if (group.title === 'Collections') {
|
|
301
|
+
titleName = t('general:collections');
|
|
302
|
+
}
|
|
303
|
+
if (group.title === 'Globals') {
|
|
304
|
+
titleName = t('general:globals');
|
|
305
|
+
}
|
|
306
|
+
const isRenderSeparator = !(index === groups.length - 1 && items.length === 0);
|
|
307
|
+
return /*#__PURE__*/ _jsxs(Fragment, {
|
|
308
|
+
children: [
|
|
309
|
+
/*#__PURE__*/ _jsx(CommandGroup, {
|
|
310
|
+
heading: titleName,
|
|
311
|
+
children: group.items.map((item)=>{
|
|
312
|
+
const isDynamicIcon = typeof item.icon === 'string';
|
|
313
|
+
const IconComponent = isDynamicIcon ? null : item.icon;
|
|
314
|
+
return /*#__PURE__*/ _jsxs(CommandItem, {
|
|
315
|
+
"data-action-type": item.action.type,
|
|
316
|
+
"data-item-type": item.type,
|
|
317
|
+
keywords: [
|
|
318
|
+
group.title
|
|
319
|
+
],
|
|
320
|
+
onSelect: ()=>handleSelect(item),
|
|
321
|
+
value: item.slug,
|
|
322
|
+
children: [
|
|
323
|
+
isDynamicIcon ? /*#__PURE__*/ _jsx(DynamicIcon, {
|
|
324
|
+
className: "command__item-icon",
|
|
325
|
+
name: item.icon
|
|
326
|
+
}) : IconComponent && /*#__PURE__*/ _jsx(IconComponent, {
|
|
327
|
+
className: "command__item-icon"
|
|
328
|
+
}),
|
|
329
|
+
item.label,
|
|
330
|
+
submenuEnabled && item.type === 'collection' && /*#__PURE__*/ _jsx(CommandShortcut, {
|
|
331
|
+
children: "›"
|
|
332
|
+
})
|
|
333
|
+
]
|
|
334
|
+
}, item.slug);
|
|
335
|
+
})
|
|
336
|
+
}),
|
|
337
|
+
isRenderSeparator && /*#__PURE__*/ _jsx(CommandSeparator, {})
|
|
338
|
+
]
|
|
339
|
+
}, group.title);
|
|
340
|
+
}),
|
|
341
|
+
currentPage === 'main' && items?.map((item)=>/*#__PURE__*/ _jsx(CommandItem, {
|
|
342
|
+
"data-action-type": item.action.type,
|
|
343
|
+
"data-item-type": item.type,
|
|
344
|
+
onSelect: ()=>handleSelect(item),
|
|
345
|
+
value: item.slug,
|
|
346
|
+
children: item.label
|
|
347
|
+
}, item.slug)),
|
|
348
|
+
currentPage !== 'main' && submenuItems.map((item)=>{
|
|
349
|
+
const isDynamicIcon = typeof item.icon === 'string';
|
|
350
|
+
const IconComponent = isDynamicIcon ? null : item.icon;
|
|
351
|
+
return /*#__PURE__*/ _jsxs(CommandItem, {
|
|
352
|
+
"data-action-type": item.action.type,
|
|
353
|
+
"data-item-type": item.type,
|
|
354
|
+
onSelect: ()=>handleSelect(item),
|
|
355
|
+
value: item.slug,
|
|
356
|
+
children: [
|
|
357
|
+
isDynamicIcon ? /*#__PURE__*/ _jsx(DynamicIcon, {
|
|
358
|
+
className: "command__item-icon",
|
|
359
|
+
name: item.icon
|
|
360
|
+
}) : IconComponent && /*#__PURE__*/ _jsx(IconComponent, {
|
|
361
|
+
className: "command__item-icon"
|
|
362
|
+
}),
|
|
363
|
+
item.label
|
|
364
|
+
]
|
|
365
|
+
}, item.slug);
|
|
366
|
+
})
|
|
367
|
+
]
|
|
368
|
+
}),
|
|
369
|
+
footerShortcuts && footerShortcuts.length > 0 && /*#__PURE__*/ _jsx("div", {
|
|
370
|
+
className: "command__footer",
|
|
371
|
+
children: footerShortcuts.map((shortcut, index)=>/*#__PURE__*/ _jsxs("span", {
|
|
372
|
+
children: [
|
|
373
|
+
/*#__PURE__*/ _jsx("kbd", {
|
|
374
|
+
children: formatShortcutKey(shortcut.key)
|
|
375
|
+
}),
|
|
376
|
+
" ",
|
|
377
|
+
shortcut.label
|
|
378
|
+
]
|
|
379
|
+
}, index))
|
|
380
|
+
})
|
|
381
|
+
]
|
|
382
|
+
})
|
|
383
|
+
})
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
const MemoizedCommandMenuComponent = /*#__PURE__*/ memo(CommandMenuComponent);
|
|
387
|
+
export const CommandMenuProvider = ({ children, pluginConfig })=>{
|
|
388
|
+
const { closeModal, isModalOpen, openModal, toggleModal } = useModal();
|
|
389
|
+
const [currentPage, setCurrentPage] = useState('main');
|
|
390
|
+
useHotkeys(pluginConfig.shortcut || [
|
|
391
|
+
'meta+k',
|
|
392
|
+
'ctrl+k'
|
|
393
|
+
], (event)=>{
|
|
394
|
+
event.preventDefault();
|
|
395
|
+
event.stopPropagation();
|
|
396
|
+
toggleModal(MODAL_SLUG);
|
|
397
|
+
}, [
|
|
398
|
+
toggleModal
|
|
399
|
+
]);
|
|
400
|
+
const { config } = useConfig();
|
|
401
|
+
const { i18n } = useTranslation();
|
|
402
|
+
const currentLang = i18n.language;
|
|
403
|
+
const { groups, items } = useMemo(()=>{
|
|
404
|
+
return createDefaultGroups(config, currentLang, pluginConfig);
|
|
405
|
+
}, [
|
|
406
|
+
config,
|
|
407
|
+
currentLang,
|
|
408
|
+
pluginConfig
|
|
409
|
+
]);
|
|
410
|
+
return /*#__PURE__*/ _jsxs(CommandMenuContext.Provider, {
|
|
411
|
+
value: {
|
|
412
|
+
closeMenu: ()=>closeModal(MODAL_SLUG),
|
|
413
|
+
currentPage,
|
|
414
|
+
groups,
|
|
415
|
+
isOpen: isModalOpen(MODAL_SLUG),
|
|
416
|
+
items,
|
|
417
|
+
openMenu: ()=>openModal(MODAL_SLUG),
|
|
418
|
+
setPage: setCurrentPage,
|
|
419
|
+
toggleMenu: ()=>toggleModal(MODAL_SLUG)
|
|
420
|
+
},
|
|
421
|
+
children: [
|
|
422
|
+
children,
|
|
423
|
+
/*#__PURE__*/ _jsx(MemoizedCommandMenuComponent, {
|
|
424
|
+
pluginConfig: pluginConfig
|
|
425
|
+
})
|
|
426
|
+
]
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
//# sourceMappingURL=CommandMenuContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/CommandMenuContext.tsx"],"sourcesContent":["'use client'\nimport type { LucideIcon } from 'lucide-react'\nimport type { IconName } from 'lucide-react/dynamic'\nimport type { CustomTranslationsKeys, CustomTranslationsObject } from 'src/translations/index'\n\nimport './modal.scss'\n\nimport type {\n CommandMenuContextProps,\n CommandMenuGroup,\n CommandMenuItem,\n CommandMenuPage,\n GenericCollectionDocument,\n PluginCommandMenuConfig,\n} from 'src/types'\n\nimport { Modal, useConfig, useModal, useTranslation } from '@payloadcms/ui'\nimport { ArrowBigUp, ChevronLeft, Command as CommandIcon, Option } from 'lucide-react'\nimport { DynamicIcon } from 'lucide-react/dynamic'\nimport { useRouter } from 'next/navigation'\nimport {\n createContext,\n Fragment,\n memo,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { useHotkeys } from 'react-hotkeys-hook'\n\nimport { createDefaultGroups } from '../utils/index'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from './cmdk/index'\n\nconst MODAL_SLUG = 'command-menu'\n\ninterface CommandMenuContextType {\n closeMenu: () => void\n currentPage: CommandMenuPage\n groups: CommandMenuGroup[]\n isOpen: boolean\n items: CommandMenuItem[]\n openMenu: () => void\n setPage: (page: CommandMenuPage) => void\n toggleMenu: () => void\n}\n\nconst CommandMenuContext = createContext<CommandMenuContextType>({\n closeMenu: () => {},\n currentPage: 'main',\n groups: [],\n isOpen: false,\n items: [],\n openMenu: () => {},\n setPage: () => {},\n toggleMenu: () => {},\n})\n\nexport const useCommandMenu = () => {\n const context = useContext(CommandMenuContext)\n return context\n}\n\nconst ITEM_SELECTOR = `[cmdk-item=\"\"]`\n\nfunction getSelectedElement(containerRef: React.RefObject<HTMLElement | null>) {\n return containerRef.current?.querySelector(`${ITEM_SELECTOR}[aria-selected=\"true\"]`)\n}\n\nconst CommandMenuComponent: React.FC<{\n pluginConfig: PluginCommandMenuConfig\n}> = ({ pluginConfig }) => {\n const [search, setSearch] = useState('')\n const [submenuItems, setSubmenuItems] = useState<CommandMenuItem[]>([])\n const [isLoadingSubmenu, setIsLoadingSubmenu] = useState(false)\n const [isMac, setIsMac] = useState(false)\n\n const commandListRef = useRef<HTMLDivElement>(null)\n\n const { closeMenu, currentPage, groups, items, setPage } = useCommandMenu()\n const router = useRouter()\n const { t } = useTranslation<CustomTranslationsObject, CustomTranslationsKeys>()\n\n useEffect(() => {\n setIsMac(/Mac|iPhone|iPod|iPad/i.test(navigator.platform))\n }, [])\n\n const submenuEnabled = pluginConfig?.submenu?.enabled !== false\n const submenuShortcut = pluginConfig?.submenu?.shortcut || 'shift+enter'\n const blurBg = pluginConfig?.blurBg !== false\n\n const formatShortcutKey = (key: string): React.ReactNode => {\n // Handle compound shortcuts like \"Shift + Enter\"\n const parts = key.split('+').map((part) => part.trim())\n const elements = parts.map((part, index) => {\n const lowerPart = part.toLowerCase()\n let content: React.ReactNode\n\n if (lowerPart === 'ctrl' || lowerPart === 'cmd') {\n content = isMac ? <CommandIcon size={12} /> : 'Ctrl'\n } else if (lowerPart === 'meta') {\n content = isMac ? <CommandIcon size={12} /> : 'Ctrl'\n } else if (lowerPart === 'shift') {\n content = isMac ? <ArrowBigUp size={12} /> : 'Shift'\n } else if (lowerPart === 'alt') {\n content = isMac ? <Option size={12} /> : 'Alt'\n } else {\n content = part\n }\n\n return (\n <Fragment key={index}>\n {content}\n {!isMac && index < parts.length - 1 && ' + '}\n </Fragment>\n )\n })\n\n return <>{elements}</>\n }\n\n // Debounced search for submenu\n useEffect(() => {\n if (currentPage === 'main') {\n return\n }\n\n const fetchDocuments = async () => {\n if (currentPage.type !== 'collection-search') {\n return\n }\n\n setIsLoadingSubmenu(true)\n try {\n const searchParam = search\n ? `&where[${currentPage.useAsTitle}][like]=${encodeURIComponent(search)}`\n : ''\n const response = await fetch(\n `/api/${currentPage.slug}?limit=10${searchParam}&select[${currentPage.useAsTitle}]=true`,\n )\n const data = await response.json()\n\n if (data.docs && Array.isArray(data.docs)) {\n const docs: CommandMenuItem[] = data.docs.map((doc: GenericCollectionDocument) => ({\n slug: `${currentPage.slug}-${doc.id}`,\n type: 'custom' as const,\n action: {\n type: 'link',\n href: `/admin/collections/${currentPage.slug}/${doc.id}`,\n },\n icon: pluginConfig?.submenu?.icons?.[currentPage.slug] ?? undefined,\n label: doc[currentPage.useAsTitle] || doc.id,\n }))\n setSubmenuItems(docs)\n }\n } catch {\n setSubmenuItems([])\n } finally {\n setIsLoadingSubmenu(false)\n }\n }\n\n const timeoutId = setTimeout(fetchDocuments, 300)\n return () => clearTimeout(timeoutId)\n }, [search, currentPage, pluginConfig?.submenu?.icons])\n\n const handleBack = useCallback(() => {\n setPage('main')\n setSearch('')\n setSubmenuItems([])\n }, [setPage])\n\n const executeItemAction = useCallback(\n async (item: CommandMenuItem) => {\n // Execute the item's action\n switch (item.action.type) {\n case 'api':\n await fetch(item.action.href, {\n body: item.action.body ? JSON.stringify(item.action.body) : undefined,\n headers: {\n 'Content-Type': 'application/json',\n },\n method: item.action.method || 'GET',\n })\n break\n case 'link':\n router.push(item.action.href)\n break\n default:\n break\n }\n closeMenu()\n setSearch('')\n setPage('main')\n },\n [router, closeMenu, setPage],\n )\n\n const openSubmenu = useCallback(\n (item: CommandMenuItem) => {\n setPage({\n slug: item.slug,\n type: 'collection-search',\n label: item.label,\n useAsTitle: item.useAsTitle || 'id',\n useAsTitleLabel: item.useAsTitleLabel || item.useAsTitle || 'id',\n })\n setSearch('')\n //set isLoadingSubmenu to true to show loading state while fetching\n setIsLoadingSubmenu(true)\n setSubmenuItems([])\n },\n [setPage],\n )\n\n const handleSelect = useCallback(\n async (item: CommandMenuItem) => {\n await executeItemAction(item)\n },\n [executeItemAction],\n )\n\n // Handle keyboard events for navigation and back\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n // ESC key for back navigation in submenu\n if (e.key === 'Escape' && currentPage !== 'main') {\n e.preventDefault()\n e.stopPropagation()\n handleBack()\n return\n }\n\n // Enter/Shift+Enter handling for collection submenu\n if (e.key === 'Enter' && currentPage === 'main') {\n const selectedElement = getSelectedElement(commandListRef)\n const itemType = selectedElement?.getAttribute('data-item-type')\n const itemSlug = selectedElement?.getAttribute('data-value')\n\n if (submenuEnabled && itemType === 'collection' && itemSlug) {\n const isShiftPressed = e.shiftKey\n const shouldOpenSubmenu =\n (submenuShortcut === 'shift+enter' && isShiftPressed) ||\n (submenuShortcut === 'enter' && !isShiftPressed)\n\n if (shouldOpenSubmenu) {\n e.preventDefault()\n e.stopPropagation()\n\n // Find the item in groups\n const item = groups.flatMap((g) => g.items).find((i) => i.slug === itemSlug)\n if (item) {\n openSubmenu(item)\n }\n return\n }\n }\n }\n }\n\n document.addEventListener('keydown', handleKeyDown, true)\n return () => document.removeEventListener('keydown', handleKeyDown, true)\n }, [currentPage, handleBack, submenuEnabled, submenuShortcut, openSubmenu, groups])\n\n const placeholder =\n currentPage === 'main'\n ? t('cmdkPlugin:search')\n : t('general:searchBy', {\n label: currentPage.useAsTitleLabel,\n })\n\n const shouldDisableFilter = currentPage !== 'main'\n\n // Static footer shortcuts based on current page\n const footerShortcuts = currentPage === 'main' && submenuEnabled && submenuShortcut === 'shift+enter'\n ? [\n { key: 'Enter', label: t('cmdkPlugin:navigate') },\n { key: 'Shift + Enter', label: t('cmdkPlugin:searchInCollection') },\n ]\n : currentPage === 'main' && submenuEnabled && submenuShortcut === 'enter'\n ? [\n { key: 'Enter', label: t('cmdkPlugin:searchInCollection') },\n { key: 'Shift + Enter', label: t('cmdkPlugin:navigate') },\n ]\n : currentPage === 'main'\n ? [{ key: 'Enter', label: t('cmdkPlugin:navigate') }]\n : [{ key: 'Enter', label: t('cmdkPlugin:open') }]\n\n const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {\n // Close modal only if clicking the backdrop (not the command itself)\n if (e.target === e.currentTarget) {\n closeMenu()\n }\n }\n\n return (\n <Modal slug={MODAL_SLUG}>\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}\n <div\n className={`command-modal ${blurBg ? 'command-modal--blur' : ''}`}\n onClick={handleBackdropClick}\n >\n <Command label=\"Command Menu\" shouldFilter={!shouldDisableFilter}>\n {/* Header for submenu navigation */}\n {currentPage !== 'main' && (\n <div className=\"command__header\">\n <button className=\"command__back-button\" onClick={handleBack} type=\"button\">\n <ChevronLeft size={16} />\n </button>\n <span className=\"command__header-label\">\n {t('cmdkPlugin:searchIn', { label: currentPage.label })}\n </span>\n </div>\n )}\n\n <CommandInput onValueChange={setSearch} placeholder={placeholder} value={search} />\n <CommandList ref={commandListRef}>\n <CommandEmpty>\n {isLoadingSubmenu ? t('cmdkPlugin:loading') : t('cmdkPlugin:noResults')}\n </CommandEmpty>\n\n {/* Main page view */}\n {currentPage === 'main' &&\n groups.map((group, index) => {\n if (group.items.length === 0) {\n return null\n }\n\n let titleName = group.title\n if (group.title === 'Collections') {\n titleName = t('general:collections')\n }\n if (group.title === 'Globals') {\n titleName = t('general:globals')\n }\n\n const isRenderSeparator = !(index === groups.length - 1 && items.length === 0)\n return (\n <Fragment key={group.title}>\n <CommandGroup heading={titleName}>\n {group.items.map((item) => {\n const isDynamicIcon = typeof item.icon === 'string'\n const IconComponent = isDynamicIcon ? null : (item.icon as LucideIcon)\n return (\n <CommandItem\n data-action-type={item.action.type}\n data-item-type={item.type}\n key={item.slug}\n keywords={[group.title]}\n onSelect={() => handleSelect(item)}\n value={item.slug}\n >\n {isDynamicIcon ? (\n <DynamicIcon\n className=\"command__item-icon\"\n name={item.icon as IconName}\n />\n ) : (\n IconComponent && <IconComponent className=\"command__item-icon\" />\n )}\n {item.label}\n {submenuEnabled && item.type === 'collection' && (\n <CommandShortcut>›</CommandShortcut>\n )}\n </CommandItem>\n )\n })}\n </CommandGroup>\n {isRenderSeparator && <CommandSeparator />}\n </Fragment>\n )\n })}\n\n {/* Stray items on main page */}\n {currentPage === 'main' &&\n items?.map((item) => (\n <CommandItem\n data-action-type={item.action.type}\n data-item-type={item.type}\n key={item.slug}\n onSelect={() => handleSelect(item)}\n value={item.slug}\n >\n {item.label}\n </CommandItem>\n ))}\n\n {/* Submenu page view */}\n {currentPage !== 'main' &&\n submenuItems.map((item) => {\n const isDynamicIcon = typeof item.icon === 'string'\n const IconComponent = isDynamicIcon ? null : (item.icon as LucideIcon)\n return (\n <CommandItem\n data-action-type={item.action.type}\n data-item-type={item.type}\n key={item.slug}\n onSelect={() => handleSelect(item)}\n value={item.slug}\n >\n {isDynamicIcon ? (\n <DynamicIcon className=\"command__item-icon\" name={item.icon as IconName} />\n ) : (\n IconComponent && <IconComponent className=\"command__item-icon\" />\n )}\n {item.label}\n </CommandItem>\n )\n })}\n </CommandList>\n\n {/* Footer with static shortcuts */}\n {footerShortcuts && footerShortcuts.length > 0 && (\n <div className=\"command__footer\">\n {footerShortcuts.map((shortcut, index) => (\n <span key={index}>\n <kbd>{formatShortcutKey(shortcut.key)}</kbd> {shortcut.label}\n </span>\n ))}\n </div>\n )}\n </Command>\n </div>\n </Modal>\n )\n}\n\nconst MemoizedCommandMenuComponent = memo(CommandMenuComponent)\n\nexport const CommandMenuProvider: React.FC<CommandMenuContextProps> = ({\n children,\n pluginConfig,\n}) => {\n const { closeModal, isModalOpen, openModal, toggleModal } = useModal()\n const [currentPage, setCurrentPage] = useState<CommandMenuPage>('main')\n\n useHotkeys(\n pluginConfig.shortcut || ['meta+k', 'ctrl+k'],\n (event) => {\n event.preventDefault()\n event.stopPropagation()\n toggleModal(MODAL_SLUG)\n },\n [toggleModal],\n )\n const { config } = useConfig()\n const { i18n } = useTranslation()\n const currentLang = i18n.language\n const { groups, items } = useMemo(() => {\n return createDefaultGroups(config, currentLang, pluginConfig)\n }, [config, currentLang, pluginConfig])\n\n return (\n <CommandMenuContext.Provider\n value={{\n closeMenu: () => closeModal(MODAL_SLUG),\n currentPage,\n groups,\n isOpen: isModalOpen(MODAL_SLUG),\n items,\n openMenu: () => openModal(MODAL_SLUG),\n setPage: setCurrentPage,\n toggleMenu: () => toggleModal(MODAL_SLUG),\n }}\n >\n {children}\n <MemoizedCommandMenuComponent pluginConfig={pluginConfig} />\n </CommandMenuContext.Provider>\n )\n}\n"],"names":["Modal","useConfig","useModal","useTranslation","ArrowBigUp","ChevronLeft","Command","CommandIcon","Option","DynamicIcon","useRouter","createContext","Fragment","memo","useCallback","useContext","useEffect","useMemo","useRef","useState","useHotkeys","createDefaultGroups","CommandEmpty","CommandGroup","CommandInput","CommandItem","CommandList","CommandSeparator","CommandShortcut","MODAL_SLUG","CommandMenuContext","closeMenu","currentPage","groups","isOpen","items","openMenu","setPage","toggleMenu","useCommandMenu","context","ITEM_SELECTOR","getSelectedElement","containerRef","current","querySelector","CommandMenuComponent","pluginConfig","search","setSearch","submenuItems","setSubmenuItems","isLoadingSubmenu","setIsLoadingSubmenu","isMac","setIsMac","commandListRef","router","t","test","navigator","platform","submenuEnabled","submenu","enabled","submenuShortcut","shortcut","blurBg","formatShortcutKey","key","parts","split","map","part","trim","elements","index","lowerPart","toLowerCase","content","size","length","fetchDocuments","type","searchParam","useAsTitle","encodeURIComponent","response","fetch","slug","data","json","docs","Array","isArray","doc","id","action","href","icon","icons","undefined","label","timeoutId","setTimeout","clearTimeout","handleBack","executeItemAction","item","body","JSON","stringify","headers","method","push","openSubmenu","useAsTitleLabel","handleSelect","handleKeyDown","e","preventDefault","stopPropagation","selectedElement","itemType","getAttribute","itemSlug","isShiftPressed","shiftKey","shouldOpenSubmenu","flatMap","g","find","i","document","addEventListener","removeEventListener","placeholder","shouldDisableFilter","footerShortcuts","handleBackdropClick","target","currentTarget","div","className","onClick","shouldFilter","button","span","onValueChange","value","ref","group","titleName","title","isRenderSeparator","heading","isDynamicIcon","IconComponent","data-action-type","data-item-type","keywords","onSelect","name","kbd","MemoizedCommandMenuComponent","CommandMenuProvider","children","closeModal","isModalOpen","openModal","toggleModal","setCurrentPage","event","config","i18n","currentLang","language","Provider"],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import './SearchButton.scss';
|
|
4
|
+
import { useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import { ArrowBigUp, Command as CommandIcon, Option, SearchIcon } from 'lucide-react';
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import { useCommandMenu } from './CommandMenuContext';
|
|
8
|
+
const SearchButton = ({ position = 'actions', shortcut = [
|
|
9
|
+
'meta+k',
|
|
10
|
+
'ctrl+k'
|
|
11
|
+
] })=>{
|
|
12
|
+
const { openMenu } = useCommandMenu();
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const [isMac, setIsMac] = useState(false);
|
|
15
|
+
useEffect(()=>{
|
|
16
|
+
setIsMac(/Mac|iPhone|iPod|iPad/i.test(navigator.platform));
|
|
17
|
+
}, []);
|
|
18
|
+
const formatShortcut = (shortcutString)=>{
|
|
19
|
+
const parts = shortcutString.split('+').map((part)=>part.trim().toLowerCase());
|
|
20
|
+
return parts.map((part)=>{
|
|
21
|
+
if (part === 'ctrl' || part === 'cmd') {
|
|
22
|
+
return isMac ? {
|
|
23
|
+
icon: /*#__PURE__*/ _jsx(CommandIcon, {
|
|
24
|
+
size: 12
|
|
25
|
+
})
|
|
26
|
+
} : {
|
|
27
|
+
text: 'Ctrl'
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (part === 'meta') {
|
|
31
|
+
return isMac ? {
|
|
32
|
+
icon: /*#__PURE__*/ _jsx(CommandIcon, {
|
|
33
|
+
size: 12
|
|
34
|
+
})
|
|
35
|
+
} : {
|
|
36
|
+
text: 'Ctrl'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (part === 'shift') {
|
|
40
|
+
return isMac ? {
|
|
41
|
+
icon: /*#__PURE__*/ _jsx(ArrowBigUp, {
|
|
42
|
+
size: 12
|
|
43
|
+
})
|
|
44
|
+
} : {
|
|
45
|
+
text: 'Shift'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (part === 'alt') {
|
|
49
|
+
return isMac ? {
|
|
50
|
+
icon: /*#__PURE__*/ _jsx(Option, {
|
|
51
|
+
size: 12
|
|
52
|
+
})
|
|
53
|
+
} : {
|
|
54
|
+
text: 'Alt'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
text: part.toUpperCase()
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// Select the appropriate shortcut to display based on platform
|
|
63
|
+
const getDisplayShortcut = ()=>{
|
|
64
|
+
if (typeof shortcut === 'string') {
|
|
65
|
+
return shortcut;
|
|
66
|
+
}
|
|
67
|
+
// If array, prefer meta shortcut for Mac, ctrl shortcut for others
|
|
68
|
+
const metaShortcut = shortcut.find((s)=>s.toLowerCase().includes('meta'));
|
|
69
|
+
const ctrlShortcut = shortcut.find((s)=>s.toLowerCase().includes('ctrl'));
|
|
70
|
+
if (isMac && metaShortcut) {
|
|
71
|
+
return metaShortcut;
|
|
72
|
+
}
|
|
73
|
+
if (!isMac && ctrlShortcut) {
|
|
74
|
+
return ctrlShortcut;
|
|
75
|
+
}
|
|
76
|
+
// Fallback to first shortcut
|
|
77
|
+
return shortcut[0] || 'meta+k';
|
|
78
|
+
};
|
|
79
|
+
const shortcutParts = formatShortcut(getDisplayShortcut());
|
|
80
|
+
return /*#__PURE__*/ _jsx("button", {
|
|
81
|
+
className: `search-button ${position === 'nav' ? 'search-button--nav' : 'search-button--actions'}`,
|
|
82
|
+
onClick: openMenu,
|
|
83
|
+
type: "button",
|
|
84
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
85
|
+
className: "search-button__wrapper",
|
|
86
|
+
children: [
|
|
87
|
+
/*#__PURE__*/ _jsx(SearchIcon, {
|
|
88
|
+
className: "search-button__icon"
|
|
89
|
+
}),
|
|
90
|
+
position === 'actions' && /*#__PURE__*/ _jsx("span", {
|
|
91
|
+
className: "search-button__placeholder",
|
|
92
|
+
children: t('cmdkPlugin:searchShort')
|
|
93
|
+
}),
|
|
94
|
+
/*#__PURE__*/ _jsx("div", {
|
|
95
|
+
className: "search-button__shortcuts",
|
|
96
|
+
children: shortcutParts.map((part, index)=>/*#__PURE__*/ _jsx("kbd", {
|
|
97
|
+
children: part.icon ? part.icon : part.text
|
|
98
|
+
}, index))
|
|
99
|
+
})
|
|
100
|
+
]
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
export default SearchButton;
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=SearchButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/SearchButton.tsx"],"sourcesContent":["'use client'\n\nimport './SearchButton.scss'\n\nimport { useTranslation } from '@payloadcms/ui'\nimport { ArrowBigUp, Command as CommandIcon, Option, SearchIcon } from 'lucide-react'\nimport React, { useEffect, useState } from 'react'\n\nimport type { CustomTranslationsKeys, CustomTranslationsObject } from '../translations'\n\nimport { useCommandMenu } from './CommandMenuContext'\n\ninterface SearchButtonProps {\n position?: 'actions' | 'nav'\n shortcut?: string | string[]\n}\n\nconst SearchButton: React.FC<SearchButtonProps> = ({\n position = 'actions',\n shortcut = ['meta+k', 'ctrl+k'],\n}) => {\n const { openMenu } = useCommandMenu()\n const { t } = useTranslation<CustomTranslationsObject, CustomTranslationsKeys>()\n const [isMac, setIsMac] = useState(false)\n\n useEffect(() => {\n setIsMac(/Mac|iPhone|iPod|iPad/i.test(navigator.platform))\n }, [])\n\n const formatShortcut = (\n shortcutString: string,\n ): Array<{ icon?: React.ReactNode; text?: string }> => {\n const parts = shortcutString.split('+').map((part) => part.trim().toLowerCase())\n return parts.map((part) => {\n if (part === 'ctrl' || part === 'cmd') {\n return isMac ? { icon: <CommandIcon size={12} /> } : { text: 'Ctrl' }\n }\n if (part === 'meta') {\n return isMac ? { icon: <CommandIcon size={12} /> } : { text: 'Ctrl' }\n }\n if (part === 'shift') {\n return isMac ? { icon: <ArrowBigUp size={12} /> } : { text: 'Shift' }\n }\n if (part === 'alt') {\n return isMac ? { icon: <Option size={12} /> } : { text: 'Alt' }\n }\n return { text: part.toUpperCase() }\n })\n }\n\n // Select the appropriate shortcut to display based on platform\n const getDisplayShortcut = (): string => {\n if (typeof shortcut === 'string') {\n return shortcut\n }\n // If array, prefer meta shortcut for Mac, ctrl shortcut for others\n const metaShortcut = shortcut.find((s) => s.toLowerCase().includes('meta'))\n const ctrlShortcut = shortcut.find((s) => s.toLowerCase().includes('ctrl'))\n\n if (isMac && metaShortcut) {\n return metaShortcut\n }\n if (!isMac && ctrlShortcut) {\n return ctrlShortcut\n }\n // Fallback to first shortcut\n return shortcut[0] || 'meta+k'\n }\n\n const shortcutParts = formatShortcut(getDisplayShortcut())\n\n return (\n <button\n className={`search-button ${position === 'nav' ? 'search-button--nav' : 'search-button--actions'}`}\n onClick={openMenu}\n type=\"button\"\n >\n <div className=\"search-button__wrapper\">\n <SearchIcon className=\"search-button__icon\" />\n {position === 'actions' && (\n <span className=\"search-button__placeholder\">{t('cmdkPlugin:searchShort')}</span>\n )}\n <div className=\"search-button__shortcuts\">\n {shortcutParts.map((part, index) => (\n <kbd key={index}>{part.icon ? part.icon : part.text}</kbd>\n ))}\n </div>\n </div>\n </button>\n )\n}\n\nexport default SearchButton\n"],"names":["useTranslation","ArrowBigUp","Command","CommandIcon","Option","SearchIcon","React","useEffect","useState","useCommandMenu","SearchButton","position","shortcut","openMenu","t","isMac","setIsMac","test","navigator","platform","formatShortcut","shortcutString","parts","split","map","part","trim","toLowerCase","icon","size","text","toUpperCase","getDisplayShortcut","metaShortcut","find","s","includes","ctrlShortcut","shortcutParts","button","className","onClick","type","div","span","index","kbd"],"mappings":"AAAA;;AAEA,OAAO,sBAAqB;AAE5B,SAASA,cAAc,QAAQ,iBAAgB;AAC/C,SAASC,UAAU,EAAEC,WAAWC,WAAW,EAAEC,MAAM,EAAEC,UAAU,QAAQ,eAAc;AACrF,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAIlD,SAASC,cAAc,QAAQ,uBAAsB;AAOrD,MAAMC,eAA4C,CAAC,EACjDC,WAAW,SAAS,EACpBC,WAAW;IAAC;IAAU;CAAS,EAChC;IACC,MAAM,EAAEC,QAAQ,EAAE,GAAGJ;IACrB,MAAM,EAAEK,CAAC,EAAE,GAAGd;IACd,MAAM,CAACe,OAAOC,SAAS,GAAGR,SAAS;IAEnCD,UAAU;QACRS,SAAS,wBAAwBC,IAAI,CAACC,UAAUC,QAAQ;IAC1D,GAAG,EAAE;IAEL,MAAMC,iBAAiB,CACrBC;QAEA,MAAMC,QAAQD,eAAeE,KAAK,CAAC,KAAKC,GAAG,CAAC,CAACC,OAASA,KAAKC,IAAI,GAAGC,WAAW;QAC7E,OAAOL,MAAME,GAAG,CAAC,CAACC;YAChB,IAAIA,SAAS,UAAUA,SAAS,OAAO;gBACrC,OAAOV,QAAQ;oBAAEa,oBAAM,KAACzB;wBAAY0B,MAAM;;gBAAO,IAAI;oBAAEC,MAAM;gBAAO;YACtE;YACA,IAAIL,SAAS,QAAQ;gBACnB,OAAOV,QAAQ;oBAAEa,oBAAM,KAACzB;wBAAY0B,MAAM;;gBAAO,IAAI;oBAAEC,MAAM;gBAAO;YACtE;YACA,IAAIL,SAAS,SAAS;gBACpB,OAAOV,QAAQ;oBAAEa,oBAAM,KAAC3B;wBAAW4B,MAAM;;gBAAO,IAAI;oBAAEC,MAAM;gBAAQ;YACtE;YACA,IAAIL,SAAS,OAAO;gBAClB,OAAOV,QAAQ;oBAAEa,oBAAM,KAACxB;wBAAOyB,MAAM;;gBAAO,IAAI;oBAAEC,MAAM;gBAAM;YAChE;YACA,OAAO;gBAAEA,MAAML,KAAKM,WAAW;YAAG;QACpC;IACF;IAEA,+DAA+D;IAC/D,MAAMC,qBAAqB;QACzB,IAAI,OAAOpB,aAAa,UAAU;YAChC,OAAOA;QACT;QACA,mEAAmE;QACnE,MAAMqB,eAAerB,SAASsB,IAAI,CAAC,CAACC,IAAMA,EAAER,WAAW,GAAGS,QAAQ,CAAC;QACnE,MAAMC,eAAezB,SAASsB,IAAI,CAAC,CAACC,IAAMA,EAAER,WAAW,GAAGS,QAAQ,CAAC;QAEnE,IAAIrB,SAASkB,cAAc;YACzB,OAAOA;QACT;QACA,IAAI,CAAClB,SAASsB,cAAc;YAC1B,OAAOA;QACT;QACA,6BAA6B;QAC7B,OAAOzB,QAAQ,CAAC,EAAE,IAAI;IACxB;IAEA,MAAM0B,gBAAgBlB,eAAeY;IAErC,qBACE,KAACO;QACCC,WAAW,CAAC,cAAc,EAAE7B,aAAa,QAAQ,uBAAuB,0BAA0B;QAClG8B,SAAS5B;QACT6B,MAAK;kBAEL,cAAA,MAACC;YAAIH,WAAU;;8BACb,KAACnC;oBAAWmC,WAAU;;gBACrB7B,aAAa,2BACZ,KAACiC;oBAAKJ,WAAU;8BAA8B1B,EAAE;;8BAElD,KAAC6B;oBAAIH,WAAU;8BACZF,cAAcd,GAAG,CAAC,CAACC,MAAMoB,sBACxB,KAACC;sCAAiBrB,KAAKG,IAAI,GAAGH,KAAKG,IAAI,GAAGH,KAAKK,IAAI;2BAAzCe;;;;;AAMtB;AAEA,eAAenC,aAAY"}
|