@orangesk/orange-design-system 2.0.0-beta.25 → 2.0.0-beta.26
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/build/components/AnchorNavigation/style.css +1 -1
- package/build/components/AnchorNavigation/style.css.map +1 -1
- package/build/components/DocumentationSidebar/style.css +1 -1
- package/build/components/DocumentationSidebar/style.css.map +1 -1
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/src/components/Modal/Modal.static.d.ts +2 -0
- package/build/lib/base.css +1 -1
- package/build/lib/base.css.map +1 -1
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/scripts.js +1 -1
- package/build/lib/scripts.js.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/build/lib/tsconfig.tsbuildinfo +1 -1
- package/build/search-index.json +1 -1
- package/package.json +14 -14
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +3 -0
- package/src/components/AnchorNavigation/styles/mixins.scss +3 -6
- package/src/components/DocumentationSidebar/DocumentationSidebar.tsx +56 -7
- package/src/components/DocumentationSidebar/styles/style.scss +6 -0
- package/src/components/Modal/Modal.static.ts +3 -1
- package/src/components/Modal/Modal.tsx +2 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
|
-
import { usePathname } from "next/navigation";
|
|
5
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
6
6
|
import Link from "next/link";
|
|
7
7
|
import MiniSearch from "minisearch";
|
|
8
8
|
import { Image } from "../Image";
|
|
@@ -231,9 +231,12 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
231
231
|
const [isMenuOpenOnMobile, setIsMenuOpenOnMobile] = React.useState(false);
|
|
232
232
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
233
233
|
const [searchResults, setSearchResults] = React.useState<SearchResult[]>([]);
|
|
234
|
+
const [activeSearchIndex, setActiveSearchIndex] = React.useState(0);
|
|
234
235
|
const [miniSearch, setMiniSearch] = React.useState<MiniSearch | null>(null);
|
|
235
236
|
const pathname = usePathname();
|
|
237
|
+
const router = useRouter();
|
|
236
238
|
const sidebarRef = React.useRef<HTMLElement>(null);
|
|
239
|
+
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
|
237
240
|
|
|
238
241
|
// Initialize search on mount
|
|
239
242
|
React.useEffect(() => {
|
|
@@ -274,21 +277,32 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
274
277
|
combineWith: "AND", // Require all terms to match
|
|
275
278
|
}) as unknown as SearchResult[];
|
|
276
279
|
setSearchResults(results.slice(0, 10)); // Limit to 10 results
|
|
280
|
+
setActiveSearchIndex(0); // Reset active index when results change
|
|
277
281
|
} else {
|
|
278
282
|
setSearchResults([]);
|
|
283
|
+
setActiveSearchIndex(0);
|
|
279
284
|
}
|
|
280
285
|
};
|
|
281
286
|
|
|
282
287
|
React.useEffect(() => {
|
|
283
|
-
const
|
|
288
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
289
|
+
// Handle Cmd+K or Ctrl+K to focus search
|
|
290
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "k") {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
searchInputRef.current?.focus();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Handle Escape key
|
|
284
297
|
if (event.key === "Escape") {
|
|
285
298
|
setIsMenuOpenOnMobile(false);
|
|
286
299
|
setSearchQuery("");
|
|
287
300
|
setSearchResults([]);
|
|
301
|
+
setActiveSearchIndex(0);
|
|
288
302
|
}
|
|
289
303
|
};
|
|
290
|
-
document.addEventListener("keydown",
|
|
291
|
-
return () => document.removeEventListener("keydown",
|
|
304
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
305
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
292
306
|
}, []);
|
|
293
307
|
|
|
294
308
|
// Scroll to active item when pathname changes or component mounts
|
|
@@ -311,6 +325,36 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
311
325
|
setIsMenuOpenOnMobile(false);
|
|
312
326
|
setSearchQuery("");
|
|
313
327
|
setSearchResults([]);
|
|
328
|
+
setActiveSearchIndex(0);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// Handle keyboard navigation in search results
|
|
332
|
+
const handleSearchKeyDown = (
|
|
333
|
+
event: React.KeyboardEvent<HTMLInputElement>,
|
|
334
|
+
) => {
|
|
335
|
+
if (searchResults.length === 0) return;
|
|
336
|
+
|
|
337
|
+
switch (event.key) {
|
|
338
|
+
case "ArrowDown":
|
|
339
|
+
event.preventDefault();
|
|
340
|
+
setActiveSearchIndex((prev) =>
|
|
341
|
+
prev < searchResults.length - 1 ? prev + 1 : prev,
|
|
342
|
+
);
|
|
343
|
+
break;
|
|
344
|
+
case "ArrowUp":
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
setActiveSearchIndex((prev) => (prev > 0 ? prev - 1 : 0));
|
|
347
|
+
break;
|
|
348
|
+
case "Enter":
|
|
349
|
+
event.preventDefault();
|
|
350
|
+
if (searchResults[activeSearchIndex]) {
|
|
351
|
+
const href = searchResults[activeSearchIndex].href;
|
|
352
|
+
searchInputRef.current?.blur();
|
|
353
|
+
router.push(href);
|
|
354
|
+
handleSelect(href);
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
314
358
|
};
|
|
315
359
|
|
|
316
360
|
const classes = cx(CLASS_ROOT, className, {
|
|
@@ -341,11 +385,13 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
341
385
|
<TextInput
|
|
342
386
|
id="search-documentation"
|
|
343
387
|
htmlType="search"
|
|
344
|
-
placeholder="
|
|
388
|
+
placeholder="CTRL+K to search..."
|
|
345
389
|
value={searchQuery}
|
|
346
390
|
onChange={(e) => handleSearch(e.currentTarget.value)}
|
|
391
|
+
onKeyDown={handleSearchKeyDown}
|
|
347
392
|
width="fullwidth"
|
|
348
393
|
aria-label="Search documentation"
|
|
394
|
+
ref={searchInputRef}
|
|
349
395
|
/>
|
|
350
396
|
{searchQuery && (
|
|
351
397
|
<button
|
|
@@ -365,11 +411,14 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
365
411
|
{searchResults.length > 0 && (
|
|
366
412
|
<div className={`${CLASS_ROOT}__search-results`}>
|
|
367
413
|
<ul className={`${CLASS_ROOT}__search-list`}>
|
|
368
|
-
{searchResults.map((result) => (
|
|
414
|
+
{searchResults.map((result, index) => (
|
|
369
415
|
<li key={result.id}>
|
|
370
416
|
<Link
|
|
371
417
|
href={result.href}
|
|
372
|
-
className={`${CLASS_ROOT}__search-result-link
|
|
418
|
+
className={cx(`${CLASS_ROOT}__search-result-link`, {
|
|
419
|
+
[`${CLASS_ROOT}__search-result-link--active`]:
|
|
420
|
+
index === activeSearchIndex,
|
|
421
|
+
})}
|
|
373
422
|
onClick={() => handleSelect(result.href)}
|
|
374
423
|
>
|
|
375
424
|
{result.label}
|
|
@@ -268,6 +268,12 @@
|
|
|
268
268
|
color: var(--color-text-default);
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
&--active {
|
|
272
|
+
background-color: var(--color-surface-subtle);
|
|
273
|
+
color: var(--color-text-default);
|
|
274
|
+
font-weight: 600;
|
|
275
|
+
}
|
|
276
|
+
|
|
271
277
|
&:focus-visible {
|
|
272
278
|
outline: 2px solid var(--color-border-accent);
|
|
273
279
|
outline-offset: -2px;
|
|
@@ -10,6 +10,8 @@ interface ModalConfig {
|
|
|
10
10
|
root: string;
|
|
11
11
|
/** Move modal into this element selector (must be unique in DOM) */
|
|
12
12
|
modalsRoot: string;
|
|
13
|
+
/** Disable moving modal into #root-modals */
|
|
14
|
+
disablePortal?: boolean;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
const defaultConfig = (): ModalConfig => ({
|
|
@@ -111,7 +113,7 @@ export default class Modal {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
init(): void {
|
|
114
|
-
if (this.config.modalsRoot) {
|
|
116
|
+
if (this.config.modalsRoot && !this.config.disablePortal) {
|
|
115
117
|
Modal.moveToModalRoot(
|
|
116
118
|
this.element,
|
|
117
119
|
document.querySelector(this.config.modalsRoot),
|
|
@@ -83,7 +83,8 @@ const Modal: React.FC<ModalProps> = ({
|
|
|
83
83
|
disableFooterSpacing,
|
|
84
84
|
...other
|
|
85
85
|
}) => {
|
|
86
|
-
const
|
|
86
|
+
const modalConfig = isActive !== undefined ? { disablePortal: true } : {};
|
|
87
|
+
const [modalRef, instance] = useStatic(ModalStatic, modalConfig);
|
|
87
88
|
|
|
88
89
|
useEffect(() => {
|
|
89
90
|
if (isActive && instance && (instance as any).current) {
|