Skip to content

Commit

Permalink
feat(Suggestion): ✨ new component
Browse files Browse the repository at this point in the history
  • Loading branch information
Barsnes committed Dec 11, 2024
1 parent 68a8c3d commit e29f4bf
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@navikt/aksel-icons": "^6.14.0",
"@radix-ui/react-slot": "^1.1.0",
"@tanstack/react-virtual": "^3.10.7",
"@u-elements/u-datalist": "^0.0.9",
"@u-elements/u-details": "^0.1.0",
"clsx": "^2.1.1"
},
Expand Down
11 changes: 11 additions & 0 deletions packages/react/src/components/Suggestion/Suggestion.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Meta, Canvas, Controls, Primary } from '@storybook/blocks';
import * as SuggestionStories from './Suggestion.stories';

<Meta of={ToggleGroupStories} />

# ToggleGroup

Med `ToggleGroup` kan brukerne velge alternativer som påvirker innholdet på en side. Komponenten består av en gruppe knapper som henger sammen, der kun én knapp er mulig å velge om gangen.

<Primary />
<Controls />
10 changes: 10 additions & 0 deletions packages/react/src/components/Suggestion/Suggestion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Meta, StoryFn } from '@storybook/react';
import { Suggestion } from './Suggestion';
export default {
title: 'Komponenter/Suggestion',
component: Suggestion,
} as Meta;

export const Preview: StoryFn<typeof Suggestion> = (args) => {
return <Suggestion {...args} />;
};
32 changes: 32 additions & 0 deletions packages/react/src/components/Suggestion/Suggestion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useMergeRefs } from '@floating-ui/react';
import cl from 'clsx/lite';
import { createContext, forwardRef, useId, useRef, useState } from 'react';
import type { DefaultProps } from '../../types';

type SuggestionContextType = {
listId?: string;
setListId?: (id: string) => void;
};

export const SuggestionContext = createContext<SuggestionContextType>({});

export type SuggestionProps =
DefaultProps & {} & React.HTMLAttributes<HTMLDivElement>;

export const Suggestion = forwardRef<HTMLDivElement, SuggestionProps>(
function Suggestion({ className, ...rest }, ref) {
const [listId, setListId] = useState(useId());
const innerRef = useRef<HTMLElement>(null);
const mergedRefs = useMergeRefs([innerRef, ref]);

return (
<SuggestionContext.Provider value={{ listId, setListId }}>
<div
className={cl('ds-suggestion', className)}
ref={mergedRefs}
{...rest}
/>
</SuggestionContext.Provider>
);
},
);
19 changes: 19 additions & 0 deletions packages/react/src/components/Suggestion/SuggestionEmpty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { HTMLAttributes } from 'react';
import { forwardRef } from 'react';
import type { DefaultProps } from '../../types';

export type SuggestionEmptyProps = HTMLAttributes<HTMLDivElement> &
DefaultProps;
export const SuggestionEmpty = forwardRef<HTMLDivElement, SuggestionEmptyProps>(
function SuggestionEmpty(rest, ref) {
return (
<div
aria-disabled='true'
ref={ref}
role='option'
tabIndex={0}
{...rest}
/>
);
},
);
15 changes: 15 additions & 0 deletions packages/react/src/components/Suggestion/SuggestionInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { forwardRef, useContext } from 'react';
import { Input, type InputProps } from '../Input';
import { SuggestionContext } from './Suggestion';

export type SuggestionInputProps = InputProps;

export const SuggestionInput = forwardRef<
HTMLInputElement,
SuggestionInputProps
>(function SuggestionList(rest, ref) {
const { listId } = useContext(SuggestionContext);

/* We need an empty placeholder for the clear button to be able to show/hide */
return <Input ref={ref} list={listId} placeholder='' {...rest} />;
});
29 changes: 29 additions & 0 deletions packages/react/src/components/Suggestion/SuggestionList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { HTMLAttributes } from 'react';
import { forwardRef, useContext, useEffect } from 'react';
import '@u-elements/u-datalist';

import type { DefaultProps } from '../../types';
import { SuggestionContext } from './Suggestion';

export type SuggestionListProps = HTMLAttributes<HTMLDataListElement> &
DefaultProps;

export const SuggestionList = forwardRef<
HTMLDataListElement,
SuggestionListProps
>(function SuggestionList({ className, id, ...rest }, ref) {
const { listId, setListId } = useContext(SuggestionContext);

useEffect(() => {
if (id && listId !== id) setListId?.(id);
}, [listId, id, setListId]);

return (
<u-datalist
class={className} // Using "class" since React does not translate className on custom elements
id={listId}
ref={ref}
{...rest}
/>
);
});
15 changes: 15 additions & 0 deletions packages/react/src/components/Suggestion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Suggestion as SuggestionRoot } from './Suggestion';
import { SuggestionEmpty } from './SuggestionEmpty';
import { SuggestionInput } from './SuggestionInput';
import { SuggestionList } from './SuggestionList';

const Suggestion = Object.assign(SuggestionRoot, {
List: SuggestionList,
Input: SuggestionInput,
Empty: SuggestionEmpty,
});

export { Suggestion, SuggestionList, SuggestionInput, SuggestionEmpty };
export type { SuggestionProps } from './Suggestion';
export type { SuggestionListProps } from './SuggestionList';
export type { SuggestionInputProps } from './SuggestionInput';
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,7 @@ __metadata:
"@testing-library/jest-dom": "npm:^6.4.8"
"@testing-library/react": "npm:^16.0.0"
"@testing-library/user-event": "npm:^14.5.2"
"@u-elements/u-datalist": "npm:^0.0.9"
"@u-elements/u-details": "npm:^0.1.0"
clsx: "npm:^2.1.1"
copyfiles: "npm:^2.4.1"
Expand Down Expand Up @@ -5525,6 +5526,13 @@ __metadata:
languageName: node
linkType: hard

"@u-elements/u-datalist@npm:^0.0.9":
version: 0.0.9
resolution: "@u-elements/u-datalist@npm:0.0.9"
checksum: 10/35e517271bec2c67aaee5806fa90d6f8755ed86cbdc339bb47d1584d8f424668ebe78052828a5a353b1143cff5f91bfb5b3105b5408949468fe33d363d12c439
languageName: node
linkType: hard

"@u-elements/u-details@npm:^0.1.0":
version: 0.1.0
resolution: "@u-elements/u-details@npm:0.1.0"
Expand Down

0 comments on commit e29f4bf

Please sign in to comment.