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

Introduce horizontally scrollable segmented control setting #2282

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Component, OnInit } from '@angular/core';

import { SegmentItem } from '@kirbydesign/designsystem';

const config = {
template: `<div style="width: 100%; max-width: 500px; overflow-x: scroll; display: flex; align-items: center; --kirby-segmented-control-overflow-x: visible; --kirby-segmented-control-overflow-y: visible;">
<button kirby-button>Option 1</button>
<button kirby-button [attentionLevel]="'2'">Option 2</button>
<kirby-segmented-control
[items]="items"
[value]="selectedSegment"
[scrollable]="true"
></kirby-segmented-control>
</div>`,
};

@Component({
selector: 'cookbook-segmented-control-example-inside-scrollable',
template: config.template,
})
export class SegmentedControlExampleInsideScrollableComponent implements OnInit {
selectedSegment: SegmentItem;
template: string = config.template;

items: SegmentItem[] = [
{
text: 'First item',
id: 'first',
},
{
text: 'Second item',
id: 'second',
},
{
text: 'Third item',
id: 'third',
},
{
text: 'Fourth item',
id: 'fourth',
},
{
text: 'Fifth item',
id: 'fifth',
},
{
text: 'Sixth item',
id: 'sixth',
},
{
text: 'Seventh item',
id: 'seventh',
},
{
text: 'Eighth item',
id: 'eighth',
},
];

ngOnInit(): void {
this.selectedSegment = this.items[0];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Component, OnInit } from '@angular/core';

import { SegmentItem } from '@kirbydesign/designsystem';

const config = {
template: `<div style="width: 100%; max-width: 500px;">
<kirby-segmented-control
[items]="items"
[value]="selectedSegment"
[scrollable]="true"
></kirby-segmented-control>
</div>`,
};

@Component({
selector: 'cookbook-segmented-control-example-scrollable',
template: config.template,
})
export class SegmentedControlExampleScrollableComponent implements OnInit {
selectedSegment: SegmentItem;
template: string = config.template;

items: SegmentItem[] = [
{
text: 'First item',
id: 'first',
},
{
text: 'Second item',
id: 'second',
},
{
text: 'Third item',
id: 'third',
},
{
text: 'Fourth item',
id: 'fourth',
},
{
text: 'Fifth item',
id: 'fifth',
},
{
text: 'Sixth item',
id: 'sixth',
},
{
text: 'Seventh item',
id: 'seventh',
},
{
text: 'Eighth item',
id: 'eighth',
},
];

ngOnInit(): void {
this.selectedSegment = this.items[0];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ <h3>Segmented Control (Default) with Badge</h3>
<cookbook-segmented-control-example-with-badge
class="example"
></cookbook-segmented-control-example-with-badge>

<h3>Scrollable</h3>
<cookbook-segmented-control-example-scrollable
class="example"
></cookbook-segmented-control-example-scrollable>

<h3>Inside Scrollable Element</h3>
<cookbook-segmented-control-example-inside-scrollable
class="example"
></cookbook-segmented-control-example-inside-scrollable>
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { KirbyModule } from '@kirbydesign/designsystem';

import { SegmentedControlExampleDefaultComponent } from './default/default';
import { SegmentedControlExampleGroupedComponent } from './grouped/grouped';
import { SegmentedControlExampleInsideScrollableComponent } from './scrollable/inside-scrollable-element';
import { SegmentedControlExampleScrollableComponent } from './scrollable/scrollable';
import { SegmentedControlExampleWithBadgeComponent } from './with-badge/with-badge';

const COMPONENT_DECLARATIONS = [
SegmentedControlExampleDefaultComponent,
SegmentedControlExampleGroupedComponent,
SegmentedControlExampleScrollableComponent,
SegmentedControlExampleInsideScrollableComponent,
SegmentedControlExampleWithBadgeComponent,
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,36 @@ <h3>Grouped</h3>
></cookbook-segmented-control-example-grouped>
</cookbook-example-viewer>

<h3>Scrollable</h3>
<p>
If the Segmented Control should be horizontally scrollable when there are more segments than can
be shown in its full width, <code>[scrollable]="true"</code> can be set.
</p>
<p>This will also ensure that swiping and dragging will not select the underlying segment.</p>
<cookbook-example-viewer [html]="scrollableExample.template">
<cookbook-segmented-control-example-scrollable
#scrollableExample
></cookbook-segmented-control-example-scrollable>
</cookbook-example-viewer>

<br />

<p>
In situations where the Segmented Control is placed inside other scrollable elements, you can
still set <code>[scrollable]="true"</code> to avoid interactions when swiping and dragging.
</p>
<p>
To remove the scrolling from the Segmented Control itself, you can use
<code>--kirby-segmented-control-overflow-x</code> and
<code>--kirby-segmented-control-overflow-y</code>, to take control of the behavior.
</p>

<cookbook-example-viewer [html]="insideScrollableExample.template">
<cookbook-segmented-control-example-inside-scrollable
#insideScrollableExample
></cookbook-segmented-control-example-inside-scrollable>
</cookbook-example-viewer>

<h3>Default - with Badge</h3>
<p>
Badges can be applied to a Segmented Control when the mode is 'default'. A badge can be added to
Expand All @@ -42,7 +72,7 @@ <h3>Default - with Badge</h3>
></cookbook-segmented-control-example-with-badge>
</cookbook-example-viewer>

<h2>Properties:</h2>
<h2>Properties</h2>
<cookbook-api-description-properties
[properties]="properties"
></cookbook-api-description-properties>
Expand All @@ -52,4 +82,10 @@ <h2>Properties:</h2>
44px. If chip/segment is smaller than this, the surrounding area will still be clickable, to
preserve accessibility.
</p>

<h2>CSS Custom Properties</h2>
<cookbook-api-description-properties
[properties]="_cssCustomProperties"
[columns]="_cssCustomPropertiesColumns"
></cookbook-api-description-properties>
</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Component } from '@angular/core';
import { ApiDescriptionProperty } from '~/app/shared/api-description/api-description-properties/api-description-properties.component';
import {
ApiDescriptionProperty,
ApiDescriptionPropertyColumns,
} from '~/app/shared/api-description/api-description-properties/api-description-properties.component';

@Component({
selector: 'cookbook-segmented-control-showcase',
Expand All @@ -16,7 +19,7 @@ export class SegmentedControlShowcaseComponent {
},
{
name: 'size',
description: 'Sets the size of the segmented control. Only applies to `default` mode.',
description: 'Sets the size of the segmented control. Only applies to default mode.',
defaultValue: 'md',
type: ['sm', 'md'],
},
Expand All @@ -41,16 +44,44 @@ export class SegmentedControlShowcaseComponent {
{
name: 'value',
description:
'Gets/sets the selected segment. Returns the selected segment if there is one, otherwise `undefined``.',
'Gets/sets the selected segment. Returns the selected segment if there is one, otherwise undefined.',
defaultValue: 'undefined',
type: ['SegmentItem'],
},
{
name: 'selectedIndex',
description:
'Gets/sets the index of the selected segment within the `segmentItems` array. The value -1 indicates no element is selected.',
'Gets/sets the index of the selected segment within the segmentItems array. The value -1 indicates no element is selected.',
defaultValue: 'undefined',
type: ['number'],
},
{
name: 'scrollable',
description:
'Makes the segmented control horizontally scrollable when its segments take up more space than the width of the segmented control. It will also prevent selecting a segment while swiping.',
defaultValue: 'false',
type: ['boolean'],
},
];

_cssCustomPropertiesColumns: ApiDescriptionPropertyColumns = {
name: 'Name',
description: 'Description',
default: 'Default',
};

_cssCustomProperties: ApiDescriptionProperty[] = [
{
name: '--kirby-segmented-control-overflow-x',
description:
'Sets the overflow-x property of the Segmented Control. Only usable when the scrollable is set to true.',
defaultValue: 'scroll',
},
{
name: '--kirby-segmented-control-overflow-y',
description:
'Sets the overflow-y property of the Segmented Control. Only usable when the scrollable is set to true.',
defaultValue: 'hidden',
},
];
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<ion-segment
*ngIf="mode === 'default'"
[value]="value?.id"
[scrollable]="scrollable"
(ionChange)="onSegmentSelect($event.detail.value)"
(click)="preventWrapperClick($event)"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@
}
}
}

&.scrollable {
overflow-x: var(--kirby-segmented-control-overflow-x, scroll);
overflow-y: var(
--kirby-segmented-control-overflow-y,
hidden
); // segment touch area height is bigger than segmented control height

@include utils.touch {
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none;
}
}
}
}

ion-segment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export class SegmentedControlComponent {

@Input() mode: SegmentedControlMode | `${SegmentedControlMode}` = SegmentedControlMode.default;

@HostBinding('class.scrollable')
@Input()
scrollable: boolean;

@HostBinding('class')
get _modeCssClass() {
return {
Expand Down