Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SegmentedControl improvements: keyboard interactions, composition, icon #149

Merged
merged 13 commits into from
Feb 17, 2025
10 changes: 8 additions & 2 deletions src/components/actions/Button/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,16 @@
}
}
}
&:not(:disabled, .bk-button--disabled, .bk-button--nonactive):active {
scale: 0.98;
}

@media (prefers-reduced-motion: no-preference) {
transition: none 150ms ease-in-out;
transition-property: border, background, color;
transition:
border 150ms ease-in-out,
background-color 150ms ease-in-out,
color 150ms ease-in-out,
scale 100ms ease-in;
}

/* & > :global(.icon) { font-size: 1.2rem; } */
Expand Down
8 changes: 8 additions & 0 deletions src/components/actions/IconButton/IconButton.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@
&.inline {
display: inline-flex;
}

&:not(:disabled):active {
scale: 0.95;
}

@media (prefers-reduced-motion: no-preference) {
transition: scale 100ms ease-in;
}
}
}
3 changes: 2 additions & 1 deletion src/components/actions/Link/Link.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default {
args: {
unstyled: false,
label: 'Link',
onClick: event => { event.preventDefault(); },
},
render: (args) => <Link {...args}/>,
} satisfies Meta<LinkArgs>;
Expand All @@ -48,7 +49,7 @@ export const Scroll: Story = {
<>
<DummyLink id="anchor">Anchor</DummyLink>
<OverflowTester openDefault/>
<Link {...args} href="#anchor"/>
<Link {...args} href="#anchor" onClick={undefined}/>
<OverflowTester openDefault/>
</>
),
Expand Down
3 changes: 2 additions & 1 deletion src/components/actions/LinkAsButton/LinkAsButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as React from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import { LinkAsButton } from './LinkAsButton.tsx';
import { OverflowTester } from '../../../util/storybook/OverflowTester.tsx';


type LinkAsButtonArgs = React.ComponentProps<typeof LinkAsButton>;
Expand All @@ -26,6 +25,7 @@ export default {
label: 'Link',
href: 'https://fortanix.com',
target: '_blank',
onClick: event => { event.preventDefault(); },
},
render: (args) => <LinkAsButton {...args}/>,
} satisfies Meta<LinkAsButtonArgs>;
Expand Down Expand Up @@ -66,5 +66,6 @@ export const Download: Story = {
download: 'my_file.txt',
label: 'Download',
href: `data:text/plain,Lorem ipsum`,
onClick: undefined,
},
};
9 changes: 5 additions & 4 deletions src/components/containers/Banner/Banner.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,11 @@ export const BannerWithThemedContent: Story = {
</p>
<div style={{ display: 'flex', gap: '2ch', marginTop: '1lh' }}>
<Button nonactive kind="primary" onPress={() => { notify.info('Clicked'); }}>Button</Button>
<SegmentedControl
options={['Test 1', 'Test 2']}
defaultValue="Test 1"
/>
<SegmentedControl size="small" defaultButtonKey="test-1" aria-label="Test segmented control">
<SegmentedControl.Button buttonKey="test-1" label="Test 1"/>
<SegmentedControl.Button buttonKey="test-2" label="Test 2"/>
<SegmentedControl.Button buttonKey="test-3" label="Test 3"/>
</SegmentedControl>
</div>
</article>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
@include bk.component-base(bk-segmented-control);

display: flex;
flex-direction: row;

.bk-segmented-control__toggle {
.bk-segmented-control__button {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-default};
--bk-segmented-control-toggle-border-color: #{bk.$theme-segmented-control-border-unselected};
--bk-segmented-control-toggle-text-color: #{bk.$theme-segmented-control-text-unselected};
Expand All @@ -19,32 +20,34 @@

padding: bk.$spacing-1 bk.$spacing-3;
background-color: var(--bk-segmented-control-toggle-background-color);
border: 1px solid var(--bk-segmented-control-toggle-border-color);
border: bk.rem-from-px(1) solid var(--bk-segmented-control-toggle-border-color);
border-inline-start: 0;

&:first-child {
border-inline-start: bk.rem-from-px(1) solid var(--bk-segmented-control-toggle-border-color);
border-radius: bk.$radius-1 0 0 bk.$radius-1;
}
&:last-child {
border-radius: 0 bk.$radius-1 bk.$radius-1 0;
}

color: var(--bk-segmented-control-toggle-text-color);
font-weight: bk.$font-weight-semibold;
font-size: bk.$font-size-xs;
text-transform: uppercase;
}

.bk-segmented-control__item {
&:first-child {
.bk-segmented-control__toggle {
border-inline-start: 1px solid var(--bk-segmented-control-toggle-border-color);
border-radius: 2px 0 0 2px;
}

&:active {
filter: brightness(90%);
}

&:last-child {
.bk-segmented-control__toggle {
border-radius: 0 2px 2px 0;
}
@media (prefers-reduced-motion: no-preference) {
transition: filter 100ms ease-out;
}
}

/* States */
&:not(.bk-segmented-control--disabled) {
.bk-segmented-control__toggle {
.bk-segmented-control__button:not(:disabled) {
&[aria-checked="true"] {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-selected};
//--bk-segmented-control-toggle-border-color: #{bk.$theme-segmented-control-border-selected};
Expand All @@ -59,22 +62,25 @@
@include bk.focus-outset;
&:is(:focus-visible, :global(.pseudo-focus-visible)) {
position: relative; // Have the focused toggle render over the other toggles so that the focus is fully shown
border-inline-start: 1px solid var(--bk-segmented-control-toggle-border-color);
border-inline-start: bk.rem-from-px(1) solid var(--bk-segmented-control-toggle-border-color);
border-radius: bk.$radius-2;

&:not(:first-child) {
// Workaround for layout shifting on focus
margin-inline-start: bk.rem-from-px(-1);
}
}
}
}

&.bk-segmented-control--disabled {
.bk-segmented-control__toggle {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-disabled-2};
--bk-segmented-control-toggle-border-color: #{bk.$theme-segmented-control-border-disabled};
--bk-segmented-control-toggle-text-color: #{bk.$theme-segmented-control-text-unselected-2};
cursor: not-allowed;

&[aria-checked="true"] {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-disabled};
}
:is(&.bk-segmented-control--disabled .bk-segmented-control__button, .bk-segmented-control__button:disabled) {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-disabled-2};
--bk-segmented-control-toggle-border-color: #{bk.$theme-segmented-control-border-disabled};
--bk-segmented-control-toggle-text-color: #{bk.$theme-segmented-control-text-unselected-2};
cursor: not-allowed;

&[aria-checked="true"] {
--bk-segmented-control-toggle-background-color: #{bk.$theme-segmented-control-background-disabled};
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ export default {
argTypes: {
},
args: {
options: ['Test1', 'Test2', 'Test3'],
'aria-label': 'Choose a color',
defaultButtonKey: 'red',
children: (
<>
<SegmentedControl.Button buttonKey="red" label="Red"/>
<SegmentedControl.Button buttonKey="green" label="Green"/>
<SegmentedControl.Button buttonKey="blue" label="Blue"/>
</>
),
},
render: (args) => <SegmentedControl {...args}/>,
} satisfies Meta<SegmentedControlArgs>;

const BaseStory: Story = {
args: {},
render: (args) => <SegmentedControl {...args}/>,
};

const baseOptions = [
{
value: 'test1',
Expand All @@ -46,47 +49,46 @@ const baseOptions = [
},
];

export const Standard: Story = {
...BaseStory,
name: 'SegmentedControl [standard]',
export const SegmentedControlStandard: Story = {};

export const SegmentedControlHover: Story = {
args: {
children: (
<>
<SegmentedControl.Button buttonKey="red" label="Red" className="pseudo-hover"/>
<SegmentedControl.Button buttonKey="green" label="Green"/>
<SegmentedControl.Button buttonKey="blue" label="Blue"/>
</>
),
},
};

export const StandardHover: Story = {
...BaseStory,
name: 'SegmentedControl [hover]',
export const SegmentedControlFocused: Story = {
args: {
...BaseStory.args,
options: baseOptions.map((option, index) => {
if (index === 1) {
return {
...option,
className: 'pseudo-hover',
}
}
return option;
}),
children: (
<>
<SegmentedControl.Button buttonKey="red" label="Red" className="pseudo-focus-visible"/>
<SegmentedControl.Button buttonKey="green" label="Green"/>
<SegmentedControl.Button buttonKey="blue" label="Blue"/>
</>
),
},
};

export const StandardFocus: Story = {
...BaseStory,
name: 'SegmentedControl [focus]',
export const SegmentedControlDisabled: Story = {
args: {
...BaseStory.args,
options: baseOptions.map((option, index) => {
if (index === 1) {
return {
...option,
className: 'pseudo-focus-visible',
}
}
return option;
}),
disabled: true,
},
};

export const StandardAllDisabled: Story = {
...BaseStory,
name: 'SegmentedControl [disabled]',
args: { ...BaseStory.args, disabled: true },
export const SegmentedControlDisabledOne: Story = {
args: {
children: (
<>
<SegmentedControl.Button buttonKey="red" label="Red"/>
<SegmentedControl.Button buttonKey="green" label="Green" disabled/>
<SegmentedControl.Button buttonKey="blue" label="Blue"/>
</>
),
},
};
Loading