Skip to content

Commit

Permalink
fix(ToggleGroup): align with new css and api principles (#2424)
Browse files Browse the repository at this point in the history
Part of #2295 and #2221
  • Loading branch information
eirikbacker authored Sep 17, 2024
1 parent f71185c commit c2b78ed
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 107 deletions.
6 changes: 6 additions & 0 deletions .changeset/red-queens-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@digdir/designsystemet-css": patch
"@digdir/designsystemet-react": patch
---

ToggleGroup: Rename ToggleGroup.Root to ToggleGroup
4 changes: 2 additions & 2 deletions apps/theme/components/Previews/Components/Components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,11 @@ export const Components = () => {
Svar under så finner vi flyreise
</Paragraph>
<div className={classes.toggleCombo}>
<ToggleGroup.Root defaultValue='norway' size='sm'>
<ToggleGroup defaultValue='norway' size='sm'>
<ToggleGroup.Item value='norway'>Norge</ToggleGroup.Item>
<ToggleGroup.Item value='sweden'>Sverige</ToggleGroup.Item>
<ToggleGroup.Item value='utlandet'>Utlandet</ToggleGroup.Item>
</ToggleGroup.Root>
</ToggleGroup>
</div>
<Heading size='xs' spacing className={classes.chipsHeading}>
Filtrer på språk
Expand Down
4 changes: 4 additions & 0 deletions packages/css/button.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
text-align: inherit;
text-decoration: none;

&:focus-visible {
position: relative; /* Place focusring on top */
}

&:not([hidden]) {
display: flex;
}
Expand Down
25 changes: 7 additions & 18 deletions packages/css/togglegroup.css
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
.ds-togglegroup {
--dsc-togglegroup-padding: var(--ds-spacing-1);
--dsc-togglegroup-background: var(--ds-color-neutral-background-default);
--dsc-togglegroup-border-color: var(--ds-color-neutral-border-default);
--dsc-togglegroup-border: var(--ds-border-width-default) solid var(--ds-color-neutral-border-default);
--dsc-togglegroup-padding: var(--ds-spacing-1);

background-color: var(--dsc-togglegroup-background);
border: var(--dsc-togglegroup-border-color) solid var(--ds-border-width-default);
background: var(--dsc-togglegroup-background);
border-radius: calc(var(--ds-border-radius-md) + var(--dsc-togglegroup-padding));
width: fit-content;
height: fit-content;
}

.ds-togglegroup__content {
display: inline-grid;
border: var(--dsc-togglegroup-border);
display: grid;
gap: var(--dsc-togglegroup-padding);
grid-auto-columns: 1fr;
grid-auto-flow: column;
height: fit-content;
padding: var(--dsc-togglegroup-padding);
}

.ds-togglegroup__input {
display: none;
}

.ds-togglegroup__item:focus-visible {
z-index: 1;
width: fit-content;
}
6 changes: 3 additions & 3 deletions packages/react/src/components/ToggleGroup/ToggleGroup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Plasser helst innholdet du skal styre rett etter `ToggleGroup` i DOM-en. Hvis ik
```tsx
import { ToggleGroup } from '@digdir/designsystemet-react';

<ToggleGroup.Root defaultValue='value1'>
<ToggleGroup defaultValue='value1'>
<ToggleGroup.Item value='value1'>Option 1</ToggleGroup.Item>
<ToggleGroup.Item value='value2'>Option 2</ToggleGroup.Item>
<ToggleGroup.Item value='value3'>Option 3</ToggleGroup.Item>
</ToggleGroup.Root>;
</ToggleGroup>;
```

## Eksempler
Expand All @@ -44,7 +44,7 @@ Alternativet "Bare ikon" brukes kun når du vet at brukerne vil forstå ikonet.
<Canvas of={ToggleGroupStories.OnlyIcons} />

### Kontrollert
Bruk `value``ToggleGroup.Item` og `ToggleGroup.Root` for å kontrollere verdiene selv.
Bruk `value``ToggleGroup.Item` og `ToggleGroup` for å kontrollere verdiene selv.

<Canvas of={ToggleGroupStories.Kontrollert} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ import { Tooltip } from '../Tooltip';

export default {
title: 'Komponenter/ToggleGroup',
component: ToggleGroup.Root,
component: ToggleGroup,
} as Meta;

export const Preview: StoryFn<typeof ToggleGroup.Root> = (args) => {
export const Preview: StoryFn<typeof ToggleGroup> = (args) => {
return (
<ToggleGroup.Root {...args}>
<ToggleGroup {...args}>
<ToggleGroup.Item value='innboks'>Innboks</ToggleGroup.Item>
<ToggleGroup.Item value='utkast'>Utkast</ToggleGroup.Item>
<ToggleGroup.Item value='arkiv'>Arkiv</ToggleGroup.Item>
<ToggleGroup.Item value='sendt'>Sendt</ToggleGroup.Item>
</ToggleGroup.Root>
</ToggleGroup>
);
};

Expand All @@ -40,7 +40,7 @@ Preview.args = {

export const OnlyIcons: StoryFn<typeof ToggleGroup> = () => {
return (
<ToggleGroup.Root defaultValue={'option-1'}>
<ToggleGroup defaultValue={'option-1'}>
<Tooltip content='Venstrestilt'>
<ToggleGroup.Item value='option-1' icon>
<AlignLeftIcon title='AlignLeftIcon' fontSize='1.5rem' />
Expand All @@ -56,7 +56,7 @@ export const OnlyIcons: StoryFn<typeof ToggleGroup> = () => {
<AlignRightIcon title='AlignRightIcon' fontSize='1.5rem' />
</ToggleGroup.Item>
</Tooltip>
</ToggleGroup.Root>
</ToggleGroup>
);
};

Expand All @@ -70,7 +70,7 @@ export const Kontrollert: StoryFn<typeof ToggleGroup> = () => {
</Button>
</div>
<br />
<ToggleGroup.Root value={value} size='md' onChange={setValue}>
<ToggleGroup value={value} size='md' onChange={setValue}>
<ToggleGroup.Item value='innboks'>
<EnvelopeClosedIcon fontSize='1.5rem' />
Innboks
Expand All @@ -87,7 +87,7 @@ export const Kontrollert: StoryFn<typeof ToggleGroup> = () => {
<PaperplaneIcon fontSize='1.5rem' />
Sendt
</ToggleGroup.Item>
</ToggleGroup.Root>
</ToggleGroup>
<br />
<Paragraph>Du har valgt: {value}</Paragraph>
</>
Expand Down
40 changes: 20 additions & 20 deletions packages/react/src/components/ToggleGroup/ToggleGroup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ const user = userEvent.setup();
describe('ToggleGroup', () => {
test('has generated name for ToggleGroupItem children', () => {
render(
<ToggleGroup.Root>
<ToggleGroup>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item = screen.getByRole('radio');
Expand All @@ -20,9 +20,9 @@ describe('ToggleGroup', () => {

test('has passed name to ToggleGroupItem children', (): void => {
render(
<ToggleGroup.Root name='my name'>
<ToggleGroup name='my name'>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item = screen.getByRole<HTMLButtonElement>('radio');
Expand All @@ -31,11 +31,11 @@ describe('ToggleGroup', () => {

test('can navigate with tab and arrow keys', async () => {
render(
<ToggleGroup.Root>
<ToggleGroup>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
<ToggleGroup.Item value='test2'>test2</ToggleGroup.Item>
<ToggleGroup.Item value='test3'>test3</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item1 = screen.getByRole<HTMLButtonElement>('radio', {
Expand All @@ -58,11 +58,11 @@ describe('ToggleGroup', () => {
});
test('has correct ToggleGroupItem defaultChecked & checked when defaultValue is used', () => {
render(
<ToggleGroup.Root defaultValue='test2'>
<ToggleGroup defaultValue='test2'>
<ToggleGroup.Item value='test1'>test1</ToggleGroup.Item>
<ToggleGroup.Item value='test2'>test2</ToggleGroup.Item>
<ToggleGroup.Item value='test3'>test3</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item = screen.getByRole<HTMLButtonElement>('radio', {
Expand All @@ -74,10 +74,10 @@ describe('ToggleGroup', () => {
const onChangeMock = vi.fn();

render(
<ToggleGroup.Root onChange={onChangeMock}>
<ToggleGroup onChange={onChangeMock}>
<ToggleGroup.Item value='test1'>test1</ToggleGroup.Item>
<ToggleGroup.Item value='test2value'>test2</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item = screen.getByRole<HTMLButtonElement>('radio', {
Expand All @@ -95,10 +95,10 @@ describe('ToggleGroup', () => {
const onChangeMock = vi.fn();

render(
<ToggleGroup.Root defaultValue='test1' onChange={onChangeMock}>
<ToggleGroup defaultValue='test1' onChange={onChangeMock}>
<ToggleGroup.Item value='test1'>test1</ToggleGroup.Item>
<ToggleGroup.Item value='test2'>test2</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const item1 = screen.getByRole<HTMLButtonElement>('radio', {
Expand All @@ -120,9 +120,9 @@ describe('ToggleGroup', () => {
test('if we pass a name, we should have a hidden input with that name', () => {
const name = 'my-name';
const { container } = render(
<ToggleGroup.Root name={name}>
<ToggleGroup name={name}>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const input = container.querySelector(`input[name="${name}"]`);
Expand All @@ -132,9 +132,9 @@ describe('ToggleGroup', () => {
test('if we pass a name, we should have a hidden input with that name and value', () => {
const name = 'my-name';
const { container } = render(
<ToggleGroup.Root name='my-name' defaultValue='test'>
<ToggleGroup name='my-name' defaultValue='test'>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const input = container.querySelector(`input[name="${name}"]`);
Expand All @@ -150,10 +150,10 @@ describe('ToggleGroup', () => {

render(
<form onSubmit={handleSubmit}>
<ToggleGroup.Root name='test' defaultValue='test2'>
<ToggleGroup name='test' defaultValue='test2'>
<ToggleGroup.Item value='test1'>test1</ToggleGroup.Item>
<ToggleGroup.Item value='test2'>test2</ToggleGroup.Item>
</ToggleGroup.Root>
</ToggleGroup>
<button type='submit'>Submit</button>
</form>,
);
Expand All @@ -168,9 +168,9 @@ describe('ToggleGroup', () => {

test('if we dont pass a name, we should not have a hidden input', () => {
render(
<ToggleGroup.Root>
<ToggleGroup>
<ToggleGroup.Item value='test'>test</ToggleGroup.Item>
</ToggleGroup.Root>,
</ToggleGroup>,
);

const input = document.querySelector('input[type="hidden"]');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ export type ToggleGroupProps = {
/**
* Display a group of buttons that can be toggled between.
* @example
* <ToggleGroup.Root onChange={(value) => console.log(value)}>
* <ToggleGroup onChange={(value) => console.log(value)}>
* <ToggleGroup.Item value='1'>Toggle 1</ToggleGroup.Item>
* <ToggleGroup.Item value='2'>Toggle 2</ToggleGroup.Item>
* <ToggleGroup.Item value='3'>Toggle 3</ToggleGroup.Item>
* </ToggleGroup.Root>
* </ToggleGroup>
*/
export const ToggleGroupRoot = forwardRef<HTMLDivElement, ToggleGroupProps>(
(
export const ToggleGroup = forwardRef<HTMLDivElement, ToggleGroupProps>(
function ToggleGroup(
{
size = 'md',
children,
Expand All @@ -53,7 +53,7 @@ export const ToggleGroupRoot = forwardRef<HTMLDivElement, ToggleGroupProps>(
...rest
},
ref,
) => {
) {
const nameId = useId();
const isControlled = value !== undefined;
const [uncontrolledValue, setUncontrolledValue] = useState<
Expand All @@ -70,32 +70,27 @@ export const ToggleGroupRoot = forwardRef<HTMLDivElement, ToggleGroupProps>(
}

return (
<div className={cl('ds-togglegroup', className)} ref={ref} {...rest}>
<ToggleGroupContext.Provider
value={{
value,
defaultValue,
name: name ?? `togglegroup-name-${nameId}`,
onChange: onValueChange,
size,
}}
>
{name && (
<input
className='ds-togglegroup__input'
name={name}
value={value}
/>
)}
<RovingFocusRoot asChild activeValue={value} orientation='ambiguous'>
<div className='ds-togglegroup__content' role='radiogroup'>
{children}
</div>
</RovingFocusRoot>
</ToggleGroupContext.Provider>
</div>
<ToggleGroupContext.Provider
value={{
value,
defaultValue,
name: name ?? `togglegroup-name-${nameId}`,
onChange: onValueChange,
size,
}}
>
<RovingFocusRoot asChild activeValue={value} orientation='ambiguous'>
<div
className={cl('ds-togglegroup', className)}
role='radiogroup'
ref={ref}
{...rest}
>
{name && <input type='hidden' name={name} value={value} />}
{children}
</div>
</RovingFocusRoot>
</ToggleGroupContext.Provider>
);
},
);

ToggleGroupRoot.displayName = 'ToggleGroupRoot';
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import cl from 'clsx/lite';
import { forwardRef } from 'react';

import { RovingFocusItem } from '../../../utilities/RovingFocus/RovingFocusItem';
import type { ButtonProps } from '../../Button';
import { Button } from '../../Button';
import { RovingFocusItem } from '../../utilities/RovingFocus/RovingFocusItem';
import { Button, type ButtonProps } from '../Button';

import { useToggleGroupItem } from './useToggleGroupitem';

Expand All @@ -23,13 +22,12 @@ export type ToggleGroupItemProps = {
export const ToggleGroupItem = forwardRef<
HTMLButtonElement,
ToggleGroupItemProps
>(function ToggleGroupItem({ className, ...rest }, ref) {
>(function ToggleGroupItem(rest, ref) {
const { active, size = 'md', buttonProps, value } = useToggleGroupItem(rest);

return (
<RovingFocusItem asChild value={value}>
<Button
className={cl('ds-togglegroup__item', className)}
variant={active ? 'primary' : 'tertiary'}
size={size}
ref={ref}
Expand Down
Loading

0 comments on commit c2b78ed

Please sign in to comment.