Skip to content

Commit c47cb15

Browse files
authored
Merge 17eb2c4 into 79af062
2 parents 79af062 + 17eb2c4 commit c47cb15

File tree

5 files changed

+175
-63
lines changed

5 files changed

+175
-63
lines changed

.changeset/cyan-hoops-hope.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@navikt/ds-react": patch
3+
---
4+
5+
Darkside: Search now correctly respects 'clearButton'-prop when set to false.

@navikt/core/react/src/form/search/Search.tsx

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,9 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
126126

127127
const { cn } = useRenameCSS();
128128

129-
const themeContext = useThemeInternal(false);
130-
131129
const searchRef = useRef<HTMLInputElement | null>(null);
132130
const mergedRef = useMergeRefs(searchRef, ref);
133-
const translate = useI18n("Search");
131+
134132
const [internalValue, setInternalValue] = useState(defaultValue ?? "");
135133

136134
const handleChange = (newValue: string) => {
@@ -151,33 +149,6 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
151149
const showClearButton =
152150
clearButton && !inputProps.disabled && (value ?? internalValue);
153151

154-
const ClearButton = () =>
155-
themeContext ? (
156-
<Button
157-
className={cn("navds-search__button-clear")}
158-
variant="tertiary"
159-
data-color="neutral"
160-
size={size === "medium" ? "small" : "xsmall"}
161-
icon={<XMarkIcon aria-hidden />}
162-
title={clearButtonLabel || translate("clear")}
163-
hidden={!showClearButton}
164-
onClick={(event) => handleClear({ trigger: "Click", event })}
165-
type="button"
166-
/>
167-
) : (
168-
<button
169-
type="button"
170-
onClick={(event) => handleClear({ trigger: "Click", event })}
171-
className={cn("navds-search__button-clear")}
172-
hidden={!showClearButton}
173-
>
174-
<span className={cn("navds-sr-only")}>
175-
{clearButtonLabel || translate("clear")}
176-
</span>
177-
<XMarkIcon aria-hidden />
178-
</button>
179-
);
180-
181152
return (
182153
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
183154
<div
@@ -246,7 +217,13 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
246217
)}
247218
{...(htmlSize ? { size: Number(htmlSize) } : {})}
248219
/>
249-
<ClearButton />
220+
{showClearButton && (
221+
<ClearButton
222+
handleClear={handleClear}
223+
size={size}
224+
clearButtonLabel={clearButtonLabel}
225+
/>
226+
)}
250227
</div>
251228
<SearchContext.Provider
252229
value={{
@@ -276,6 +253,44 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
276253
},
277254
) as SearchComponent;
278255

256+
type SearchClearButtonProps = Pick<SearchProps, "size" | "clearButtonLabel"> & {
257+
handleClear: (clearEvent: SearchClearEvent) => void;
258+
};
259+
260+
function ClearButton({
261+
size,
262+
clearButtonLabel,
263+
handleClear,
264+
}: SearchClearButtonProps) {
265+
const { cn } = useRenameCSS();
266+
267+
const themeContext = useThemeInternal(false);
268+
const translate = useI18n("Search");
269+
270+
return themeContext ? (
271+
<Button
272+
className={cn("navds-search__button-clear")}
273+
variant="tertiary-neutral"
274+
size={size === "medium" ? "small" : "xsmall"}
275+
icon={<XMarkIcon aria-hidden />}
276+
title={clearButtonLabel || translate("clear")}
277+
onClick={(event) => handleClear({ trigger: "Click", event })}
278+
type="button"
279+
/>
280+
) : (
281+
<button
282+
type="button"
283+
onClick={(event) => handleClear({ trigger: "Click", event })}
284+
className={cn("navds-search__button-clear")}
285+
>
286+
<span className={cn("navds-sr-only")}>
287+
{clearButtonLabel || translate("clear")}
288+
</span>
289+
<XMarkIcon aria-hidden />
290+
</button>
291+
);
292+
}
293+
279294
Search.Button = SearchButton;
280295

281296
export default Search;

aksel.nav.no/website/app/dev/(designsystemet)/_ui/sidebar/Sidebar.module.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
padding-inline: var(--ax-space-8);
77
margin-left: var(--ax-space-16);
88
color: var(--ax-text-neutral);
9+
display: flex;
10+
flex-direction: column;
11+
gap: var(--ax-space-24);
912

1013
&[data-layout="sidebar"] {
1114
width: 16rem;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"use client";
2+
3+
import React, { useMemo, useState } from "react";
4+
import { BodyShort, Search } from "@navikt/ds-react";
5+
import {
6+
DesignsystemSidebarSectionT,
7+
SidebarGroupedPagesT,
8+
SidebarPageT,
9+
} from "@/types";
10+
import { DesignsystemSidebarGroup } from "./Sidebar.group";
11+
import styles from "./Sidebar.module.css";
12+
import { type DesignsystemSidebarDataT } from "./Sidebar.util";
13+
14+
type SidebarNavProps = {
15+
layout?: "sidebar" | "mobile";
16+
sidebarData: DesignsystemSidebarDataT;
17+
};
18+
19+
function DesignsystemSidebarNav(props: SidebarNavProps) {
20+
const { layout = "sidebar", sidebarData } = props;
21+
22+
const [filterText, setFilterText] = useState<string>("");
23+
24+
const filteredSidebarData = useMemo(() => {
25+
if (!filterText) {
26+
return sidebarData;
27+
}
28+
29+
const isValidHit = (value: string): boolean => {
30+
return value.toLowerCase().includes(filterText.toLowerCase());
31+
};
32+
33+
const sections: DesignsystemSidebarDataT = [];
34+
35+
for (const section of sidebarData) {
36+
const pages: SidebarPageT[] = [];
37+
38+
for (const link of section.links) {
39+
if (!itemIsSidebarGroup(link)) {
40+
isValidHit(link.heading) && pages.push(link);
41+
continue;
42+
}
43+
44+
if (isValidHit(link.title)) {
45+
pages.push(...link.pages);
46+
continue;
47+
}
48+
49+
for (const page of link.pages) {
50+
isValidHit(page.heading) &&
51+
pages.push({
52+
...page,
53+
heading:
54+
page.heading === "Oversikt"
55+
? `${page.heading} (${link.title})`
56+
: page.heading,
57+
});
58+
}
59+
}
60+
61+
if (pages.length === 0) {
62+
continue;
63+
}
64+
65+
sections.push({
66+
label: section.label,
67+
links: pages,
68+
});
69+
}
70+
71+
return sections;
72+
}, [filterText, sidebarData]);
73+
74+
return (
75+
<div className={styles.navList} data-layout={layout}>
76+
<Search
77+
variant="simple"
78+
size="small"
79+
label="Filtrer navigasjon"
80+
clearButton={false}
81+
onChange={setFilterText}
82+
autoComplete="off"
83+
/>
84+
<nav aria-label="Sidemeny">
85+
<BodyShort
86+
as="ul"
87+
className={styles.navListUl}
88+
size={layout === "sidebar" ? "small" : "medium"}
89+
>
90+
{filteredSidebarData.map((section, index) => {
91+
return (
92+
<React.Fragment key={section.label}>
93+
<DesignsystemSidebarGroup
94+
key={section.label}
95+
label={section.label}
96+
links={section.links}
97+
layout={layout}
98+
/>
99+
{index !== filteredSidebarData.length - 1 && (
100+
<li aria-hidden className={styles.navListDivider} />
101+
)}
102+
</React.Fragment>
103+
);
104+
})}
105+
</BodyShort>
106+
</nav>
107+
</div>
108+
);
109+
}
110+
111+
function itemIsSidebarGroup(
112+
input: DesignsystemSidebarSectionT[number],
113+
): input is SidebarGroupedPagesT {
114+
return "pages" in input;
115+
}
116+
117+
export { DesignsystemSidebarNav };
118+
export type { SidebarNavProps };

aksel.nav.no/website/app/dev/(designsystemet)/_ui/sidebar/Sidebar.tsx

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,19 @@
1-
import React from "react";
2-
import { BodyShort } from "@navikt/ds-react";
31
import { sanityFetch } from "@/app/_sanity/live";
42
import {
53
DESIGNSYSTEM_OVERVIEW_PAGES_QUERY,
64
DESIGNSYSTEM_SIDEBAR_QUERY,
75
} from "@/app/_sanity/queries";
8-
import { DesignsystemSidebarGroup } from "./Sidebar.group";
9-
import styles from "./Sidebar.module.css";
6+
import { DesignsystemSidebarNav, SidebarNavProps } from "./Sidebar.nav";
107
import { generateSidebar } from "./Sidebar.util";
118

12-
type SidebarProps = {
13-
layout?: "sidebar" | "mobile";
14-
} & React.HTMLAttributes<HTMLDivElement>;
9+
type SidebarProps = Omit<SidebarNavProps, "sidebarData">;
1510

1611
async function DesignsystemSidebar(props: SidebarProps) {
1712
const { layout = "sidebar" } = props;
1813

1914
const sidebarData = await getSidebarData();
2015

21-
return (
22-
<nav aria-label="Sidemeny" className={styles.navList} data-layout={layout}>
23-
<BodyShort
24-
as="ul"
25-
className={styles.navListUl}
26-
size={layout === "sidebar" ? "small" : "medium"}
27-
>
28-
{sidebarData.map((section, index) => {
29-
return (
30-
<React.Fragment key={section.label}>
31-
<DesignsystemSidebarGroup
32-
key={section.label}
33-
label={section.label}
34-
links={section.links}
35-
layout={layout}
36-
/>
37-
{index !== sidebarData.length - 1 && (
38-
<li aria-hidden className={styles.navListDivider} />
39-
)}
40-
</React.Fragment>
41-
);
42-
})}
43-
</BodyShort>
44-
</nav>
45-
);
16+
return <DesignsystemSidebarNav sidebarData={sidebarData} layout={layout} />;
4617
}
4718

4819
async function getSidebarData() {

0 commit comments

Comments
 (0)