Skip to content
Merged
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
31 changes: 31 additions & 0 deletions etc/lime-elements.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,14 @@ export namespace Components {
"ui": EditorUiType;
"value": string;
}
// @beta
export interface LimelRadioButtonGroup {
"badgeIcons": boolean;
"disabled": boolean;
"items": Array<ListItem | ListSeparator>;
"maxLinesSecondaryText": number;
"selectedItem"?: ListItem<string | number>;
}
// (undocumented)
export interface LimelSelect {
"disabled": boolean;
Expand Down Expand Up @@ -1186,6 +1194,10 @@ export namespace JSX {
//
// (undocumented)
"limel-prosemirror-adapter": LimelProsemirrorAdapter;
// Warning: (ae-incompatible-release-tags) The symbol ""limel-radio-button-group"" is marked as @public, but its signature references "JSX" which is marked as @beta
//
// (undocumented)
"limel-radio-button-group": LimelRadioButtonGroup;
// (undocumented)
"limel-select": LimelSelect;
// (undocumented)
Expand Down Expand Up @@ -1762,6 +1774,15 @@ export namespace JSX {
"ui"?: EditorUiType;
"value"?: string;
}
// @beta
export interface LimelRadioButtonGroup {
"badgeIcons"?: boolean;
"disabled"?: boolean;
"items"?: Array<ListItem | ListSeparator>;
"maxLinesSecondaryText"?: number;
"onChange"?: (event: LimelRadioButtonGroupCustomEvent<ListItem<string | number | undefined>>) => void;
"selectedItem"?: ListItem<string | number>;
}
// (undocumented)
export interface LimelSelect {
"disabled"?: boolean;
Expand Down Expand Up @@ -2288,6 +2309,16 @@ export interface LimelProsemirrorAdapterCustomEvent<T> extends CustomEvent<T> {
target: HTMLLimelProsemirrorAdapterElement;
}

// Warning: (ae-missing-release-tag) "LimelRadioButtonGroupCustomEvent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export interface LimelRadioButtonGroupCustomEvent<T> extends CustomEvent<T> {
// (undocumented)
detail: T;
// (undocumented)
target: HTMLLimelRadioButtonGroupElement;
}

// Warning: (ae-missing-release-tag) "LimelSelectCustomEvent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down
2 changes: 1 addition & 1 deletion src/components/list/list-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MenuItem } from '../menu/menu.types';
import { h } from '@stencil/core';
import { CheckboxTemplate } from '../checkbox/checkbox.template';
import { ListRendererConfig } from './list-renderer-config';
import { RadioButtonTemplate } from './radio-button/radio-button.template';
import { RadioButtonTemplate } from '../radio-button-group/radio-button.template';
import {
getIconColor,
getIconName,
Expand Down
2 changes: 1 addition & 1 deletion src/components/list/list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ img {

@import '../checkbox/checkbox.scss';

@import './radio-button/radio-button.scss';
@import '../radio-button-group/radio-button.scss';

@import './partial-styles/custom-styles.scss';
@import './partial-styles/enable-multiline-text.scss';
Expand Down
36 changes: 0 additions & 36 deletions src/components/list/radio-button/radio-button.template.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
ListItem,
LimelRadioButtonGroupCustomEvent,
ListSeparator,
} from '@limetech/lime-elements';
import { Component, h, State } from '@stencil/core';

/**
* Basic radio button group
*
* :::note
* Individual options can also be disabled while keeping others interactive.
* :::
*/
@Component({ tag: 'limel-example-radio-button-group-basic', shadow: true })
export class RadioButtonBasicExample {
@State()
private selectedItem: ListItem<string>;

@State()
private disabled = false;

public componentWillLoad() {
this.selectedItem = this.items.find((item) => item.selected);
}

private items: Array<ListItem | ListSeparator> = [
{ text: 'First Option', value: 'option1', selected: false },
{ text: 'Second Option', value: 'option2', selected: true },
{ separator: true },
{ text: 'Third Option', value: 'option3', selected: false },
{ text: 'Disabled Option', value: 'option4', disabled: true },
];

public render() {
return [
<limel-radio-button-group
items={this.items}
selectedItem={this.selectedItem}
disabled={this.disabled}
onChange={this.handleChange}
/>,
<limel-example-controls>
<limel-checkbox
checked={this.disabled}
label="Disabled"
onChange={this.setDisabled}
/>
</limel-example-controls>,
<limel-example-value
label="Selected value"
value={this.selectedItem?.value}
/>,
];
}

private handleChange = (
event: LimelRadioButtonGroupCustomEvent<ListItem<string | number>>
) => {
const item = event.detail;
if (item.selected) {
this.selectedItem = item;
}
};

private setDisabled = (event: CustomEvent<boolean>) => {
event.stopPropagation();
this.disabled = event.detail;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
ListItem,
LimelRadioButtonGroupCustomEvent,
} from '@limetech/lime-elements';
import { Component, h, Host, State } from '@stencil/core';

/**
* Allowing to deselect a selected radio button
*
* In native radio button groups, users cannot deselect an already selected radio button.
* This is the standard behavior across most implementations; which we also showcased in the
* "Basic example", before this one. However, this interaction design comes with a
* significant user experience drawback. Once a user selects one choice, they cannot regret their choice.
* This could be problematic in some designs such as forms or survey.
* This is because a user cannot first answer a single choice question,
* and then decide to skip that question and leave it unanswered.
*
* As a developer, for such scenarios you always have to remember to provide a N/A choice or similar,
* to enable the user or respondents to skip that question.
* However, having a radio button group in a survey that allows respondents to leave it
* unanswered means that the question cannot be marked as "Required" or "Compulsory".
* A required question works best, when user has to select an option, and cannot unselect it.
*
* See how `handleChange` is implemented in this example, and compare it to the Basic example
* which does not allow deselecting the currently selected option.
*/
@Component({
tag: 'limel-example-radio-button-group-deselect-selected',
shadow: true,
})
export class RadioButtonDeselectSelectedExample {
@State()
private selectedItem: ListItem<string>;

@State()
private disabled: boolean = false;

private items: Array<ListItem<string>> = [
{ text: 'Very satisfied', value: 'very-satisfied' },
{ text: 'Satisfied', value: 'satisfied', selected: true },
{ text: 'Neutral', value: 'neutral' },
{ text: 'Dissatisfied', value: 'dissatisfied' },
{ text: 'Very dissatisfied', value: 'very-dissatisfied' },
];

public componentWillLoad() {
this.selectedItem = this.items.find((item) => item.selected);
}

public render() {
return (
<Host>
<p>How satisfied are you with our product?</p>
<limel-radio-button-group
items={this.items}
selectedItem={this.selectedItem}
disabled={this.disabled}
onChange={this.handleChange}
/>
<limel-example-controls>
<limel-checkbox
checked={this.disabled}
label="Disabled"
onChange={this.setDisabled}
/>
</limel-example-controls>
<limel-example-value
label="Selected answer"
value={this.selectedItem?.value}
/>
</Host>
);
}

private handleChange = (
event: LimelRadioButtonGroupCustomEvent<ListItem<string>>
) => {
const item = event.detail;
this.selectedItem = item.selected === false ? undefined : item;
};

private setDisabled = (event: CustomEvent<boolean>) => {
event.stopPropagation();
this.disabled = event.detail;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
ListItem,
LimelRadioButtonGroupCustomEvent,
} from '@limetech/lime-elements';
import { Component, h, State } from '@stencil/core';

/**
* Items with icons
*/
@Component({ tag: 'limel-example-radio-button-group-icons', shadow: true })
export class RadioButtonIconsExample {
@State()
private selectedItem: ListItem<string>;

private items: Array<ListItem<string>> = [
{
text: 'Sunny',
value: 'weather_sunny',
icon: { name: 'sun', color: 'rgb(var(--color-orange-default))' },
},
{
text: 'Partly Cloudy',
value: 'weather_partly_cloudy',
selected: true,
icon: {
name: 'partly_cloudy_day',
color: 'rgb(var(--color-gray-default))',
},
},
{
text: 'Rainy',
value: 'weather_rainy',
icon: { name: 'rain', color: 'rgb(var(--color-blue-default))' },
},
{
text: 'Snowy',
value: 'weather_snowy',
icon: { name: 'snowflake', color: 'rgb(var(--color-cyan-light))' },
},
];

public componentWillLoad() {
this.selectedItem = this.items.find((item) => item.selected);
}

public render() {
return [
<limel-radio-button-group
items={this.items}
selectedItem={this.selectedItem}
badgeIcons={true}
onChange={this.handleChange}
/>,
<limel-example-value
label="Selected weather"
value={this.selectedItem?.value}
/>,
];
}

private handleChange = (
event: LimelRadioButtonGroupCustomEvent<ListItem<string>>
) => {
const item = event.detail;
this.selectedItem = item.selected === false ? undefined : item;
};
}
Loading