Skip to content

Commit c5d8790

Browse files
committed
refactor(radio-button): replace RadioButtonTemplate with a private component instead
1 parent 7835142 commit c5d8790

File tree

6 files changed

+126
-79
lines changed

6 files changed

+126
-79
lines changed

etc/lime-elements.api.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,13 @@ export namespace Components {
685685
"ui": EditorUiType;
686686
"value": string;
687687
}
688+
export interface LimelRadioButton {
689+
"checked"?: boolean;
690+
"disabled"?: boolean;
691+
"id": string;
692+
"label"?: string;
693+
"onChange"?: (event: Event) => void;
694+
}
688695
// @beta
689696
export interface LimelRadioButtonGroup {
690697
"badgeIcons": boolean;
@@ -1258,6 +1265,8 @@ export namespace JSX {
12581265
//
12591266
// (undocumented)
12601267
"limel-prosemirror-adapter": LimelProsemirrorAdapter;
1268+
// (undocumented)
1269+
"limel-radio-button": LimelRadioButton;
12611270
// 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
12621271
//
12631272
// (undocumented)
@@ -1886,6 +1895,13 @@ export namespace JSX {
18861895
"ui"?: EditorUiType;
18871896
"value"?: string;
18881897
}
1898+
export interface LimelRadioButton {
1899+
"checked"?: boolean;
1900+
"disabled"?: boolean;
1901+
"id": string;
1902+
"label"?: string;
1903+
"onChange"?: (event: Event) => void;
1904+
}
18891905
// @beta
18901906
export interface LimelRadioButtonGroup {
18911907
"badgeIcons"?: boolean;

src/components/list-item/list-item.scss

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
@use '../../style/mixins';
88
@forward '../checkbox/checkbox.scss';
9-
@forward '../radio-button-group/radio-button.scss';
109

1110
*,
1211
*:before,
@@ -169,9 +168,13 @@ limel-list-item {
169168

170169
// ====================
171170
// Checkbox and radios
171+
.boolean-input,
172+
limel-radio-button {
173+
width: var(--limel-boolean-input-box-size) !important;
174+
margin-left: -0.25rem !important;
175+
}
176+
172177
.boolean-input {
173-
width: var(--limel-boolean-input-box-size);
174-
margin-left: -0.25rem;
175178
&.checkbox {
176179
margin-right: 0.25rem;
177180
}
@@ -182,11 +185,11 @@ limel-list-item {
182185
margin-left: 0;
183186
order: 2;
184187
}
185-
}
186188

187-
.boolean-input-label {
188-
@include mixins.truncate-text();
189-
opacity: 0;
190-
width: var(--limel-boolean-input-box-size);
189+
.boolean-input-label {
190+
@include mixins.truncate-text();
191+
opacity: 0;
192+
width: var(--limel-boolean-input-box-size);
193+
}
191194
}
192195
// ====================

src/components/list-item/list-item.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { ListItem } from './list-item.types';
66
import { MenuItem } from '../menu/menu.types';
77
import { ListSeparator } from '../../global/shared-types/separator.types';
88
import { CheckboxTemplate } from '../checkbox/checkbox.template';
9-
import { RadioButtonTemplate } from '../radio-button-group/radio-button.template';
109
import translate from '../../global/translations';
1110
import { Languages } from '../date-picker/date.types';
1211

@@ -309,7 +308,7 @@ export class ListItemComponent implements ListItem {
309308
}
310309

311310
return (
312-
<RadioButtonTemplate
311+
<limel-radio-button
313312
id={`radio_${this.labelId}`}
314313
checked={this.selected}
315314
disabled={this.disabled}

src/components/radio-button-group/radio-button.scss

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/**
22
* :::important
3-
* The `RadioButtonTemplate` can be imported and used in the HTML of
4-
* other components, to render a non-functional and decorative radio button in
3+
* The `limel-radio-button` component can be used inside the HTML of
4+
* other components to render a decorative radio button in
55
* their UI. An example of this is the list component.
6-
* This means the content of `RadioButtonTemplate` will become a part of the
6+
* This means the content of `limel-radio-button` will become a part of the
77
* consumer's DOM structure.
88
*
9-
* Additionally, the consumer components' also need to import the current `.scss`
10-
* file into their own styles file, for the radio button to be rendered correctly!
9+
* Additionally, the consumer components also need to import the current `.scss`
10+
* file into their own styles file for the radio button to be rendered correctly!
1111
* This means, if the styles in this file are not "specific" enough,
1212
* there is a risk that the consumer component's styles are affected by
1313
* our styles here.

src/components/radio-button-group/radio-button.template.tsx

Lines changed: 0 additions & 64 deletions
This file was deleted.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Component, Host, Prop, h } from '@stencil/core';
2+
3+
/**
4+
* This is a low-level private component that renders individual radio button elements.
5+
* It's used internally by the list-item component to render radio buttons when
6+
* `type="radio"` is specified.
7+
*
8+
* ## Usage in the Library
9+
*
10+
* This template is primarily used by:
11+
* - `limel-list` component when `type="radio"`
12+
* - `limel-radio-button-group` component (which wraps `limel-list`)
13+
*
14+
* ## Why This Exists
15+
*
16+
* While we have `limel-radio-button-group` for most use cases, this template provides
17+
* the actual radio button HTML structure with proper MDC classes and accessibility
18+
* attributes. It ensures consistent styling and behavior across all radio button
19+
* implementations in the library.
20+
*
21+
* ## Design Philosophy
22+
*
23+
* This follows the principle that individual radio buttons should not be standalone
24+
* components, as a single radio button is never useful in a UI. Instead, this template
25+
* is used to build groups of radio buttons through higher-level components.
26+
*
27+
* However, since this is a private component, consumers who need to use a radio button
28+
* outside of the context of a list or group, can still use the `limel-radio-button`
29+
* component directly according to in their UI needs.
30+
*
31+
* @private
32+
*/
33+
@Component({
34+
tag: 'limel-radio-button',
35+
shadow: false,
36+
styleUrl: 'radio-button.scss',
37+
})
38+
export class RadioButtonComponent {
39+
/**
40+
* Indicates whether the radio button is checked.
41+
*/
42+
@Prop({ reflect: true })
43+
public checked?: boolean;
44+
45+
/**
46+
* Disables the radio button when set to `true`.
47+
*/
48+
@Prop({ reflect: true })
49+
public disabled?: boolean;
50+
51+
/**
52+
* Associates the internal input with an external label.
53+
*/
54+
@Prop()
55+
public id!: string;
56+
57+
/**
58+
* Visual label shown next to the radio button.
59+
*/
60+
@Prop()
61+
public label?: string;
62+
63+
/**
64+
* Change handler forwarded to the underlying input element.
65+
*/
66+
@Prop()
67+
public onChange?: (event: Event) => void;
68+
69+
public render() {
70+
return (
71+
<Host
72+
class={{
73+
'boolean-input': true,
74+
'radio-button': true,
75+
checked: this.checked,
76+
disabled: this.disabled,
77+
}}
78+
>
79+
<input
80+
type="radio"
81+
id={this.id}
82+
checked={this.checked}
83+
disabled={this.disabled}
84+
onChange={this.onChange}
85+
/>
86+
<div class="box" />
87+
<label class="boolean-input-label" htmlFor={this.id}>
88+
{this.label}
89+
</label>
90+
</Host>
91+
);
92+
}
93+
}

0 commit comments

Comments
 (0)