Skip to content

Commit 5a8e266

Browse files
committed
fixup! feat(cdk-experimental/radio): add radio demo to dev-app
1 parent ad5ca9b commit 5a8e266

File tree

11 files changed

+286
-0
lines changed

11 files changed

+286
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
load("//tools:defaults.bzl", "ng_project")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ng_project(
6+
name = "radio",
7+
srcs = glob(["**/*.ts"]),
8+
assets = glob([
9+
"**/*.html",
10+
"**/*.css",
11+
]),
12+
deps = [
13+
"//:node_modules/@angular/core",
14+
"//:node_modules/@angular/forms",
15+
"//src/cdk-experimental/radio",
16+
"//src/material/checkbox",
17+
"//src/material/form-field",
18+
"//src/material/select",
19+
],
20+
)
21+
22+
filegroup(
23+
name = "source-files",
24+
srcs = glob([
25+
"**/*.html",
26+
"**/*.css",
27+
"**/*.ts",
28+
]),
29+
)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
.example-radio-controls {
2+
display: flex;
3+
align-items: center;
4+
gap: 16px;
5+
padding-bottom: 16px;
6+
}
7+
8+
.example-radio-group {
9+
gap: 4px;
10+
margin: 0;
11+
padding: 8px;
12+
max-height: 50vh;
13+
border: 1px solid var(--mat-sys-outline);
14+
border-radius: var(--mat-sys-corner-extra-small);
15+
display: flex;
16+
list-style: none;
17+
flex-direction: column;
18+
overflow: scroll;
19+
user-select: none;
20+
}
21+
22+
.example-radio-group[aria-orientation='horizontal'] {
23+
flex-direction: row;
24+
}
25+
26+
.example-radio-group[aria-disabled='true'] {
27+
background-color: var(--mat-sys-surface-dim);
28+
pointer-events: none;
29+
}
30+
31+
.example-radio-button {
32+
gap: 16px;
33+
padding: 16px;
34+
display: flex;
35+
cursor: pointer;
36+
position: relative;
37+
align-items: center;
38+
border-radius: var(--mat-sys-corner-extra-small);
39+
}
40+
41+
/* Basic visual indicator for the radio button */
42+
.example-radio-indicator {
43+
width: 16px;
44+
height: 16px;
45+
border-radius: 50%;
46+
border: 2px solid var(--mat-sys-outline);
47+
display: inline-block;
48+
position: relative;
49+
}
50+
51+
.example-radio-button[aria-checked='true'] .example-radio-indicator {
52+
border-color: var(--mat-sys-primary);
53+
}
54+
55+
.example-radio-button[aria-checked='true'] .example-radio-indicator::after {
56+
content: '';
57+
display: block;
58+
width: 8px;
59+
height: 8px;
60+
border-radius: 50%;
61+
background-color: var(--mat-sys-primary);
62+
position: absolute;
63+
top: 50%;
64+
left: 50%;
65+
transform: translate(-50%, -50%);
66+
}
67+
68+
.example-radio-button[aria-disabled='true'][aria-checked='true'] .example-radio-indicator::after {
69+
background-color: var(--mat-sys-outline);
70+
}
71+
72+
.example-radio-button.cdk-active,
73+
.example-radio-button[aria-disabled='false']:hover {
74+
outline: 1px solid var(--mat-sys-outline);
75+
background: var(--mat-sys-surface-container);
76+
}
77+
78+
.example-radio-button[aria-disabled='false']:focus-within {
79+
outline: 2px solid var(--mat-sys-primary);
80+
background: var(--mat-sys-surface-container);
81+
}
82+
83+
.example-radio-button.cdk-active[aria-disabled='true'],
84+
.example-radio-button[aria-disabled='true']:focus-within {
85+
outline: 2px solid var(--mat-sys-outline);
86+
}
87+
88+
.example-radio-button[aria-disabled='true'] {
89+
cursor: default;
90+
}
91+
92+
.example-radio-button[aria-disabled='true'] span:not(.example-radio-indicator) {
93+
opacity: 0.3;
94+
}
95+
96+
.example-radio-button[aria-disabled='true']::before {
97+
content: '';
98+
position: absolute;
99+
width: 100%;
100+
height: 100%;
101+
top: 0;
102+
left: 0;
103+
border-radius: var(--mat-sys-corner-extra-small);
104+
background-color: var(--mat-sys-on-surface);
105+
opacity: var(--mat-sys-focus-state-layer-opacity);
106+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<div class="example-radio-controls">
2+
<mat-checkbox [formControl]="disabled">Disabled</mat-checkbox>
3+
<mat-checkbox [formControl]="readonly">Readonly</mat-checkbox>
4+
<mat-checkbox [formControl]="skipDisabled">Skip Disabled</mat-checkbox>
5+
6+
<mat-form-field subscriptSizing="dynamic" appearance="outline">
7+
<mat-label>Selected Flavor</mat-label>
8+
<mat-select [(value)]="selectedValue">
9+
<mat-option [value]="null"><em>None</em></mat-option>
10+
@for (flavor of flavors; track flavor) {
11+
<mat-option [value]="flavor">{{flavor}}</mat-option>
12+
}
13+
</mat-select>
14+
</mat-form-field>
15+
16+
<mat-form-field subscriptSizing="dynamic" appearance="outline">
17+
<mat-label>Disabled Radio Options</mat-label>
18+
<mat-select [(value)]="disabledOptions" multiple>
19+
@for (flavor of flavors; track flavor) {
20+
<mat-option [value]="flavor">{{flavor}}</mat-option>
21+
}
22+
</mat-select>
23+
</mat-form-field>
24+
25+
<mat-form-field subscriptSizing="dynamic" appearance="outline">
26+
<mat-label>Orientation</mat-label>
27+
<mat-select [(value)]="orientation">
28+
<mat-option value="vertical">Vertical</mat-option>
29+
<mat-option value="horizontal">Horizontal</mat-option>
30+
</mat-select>
31+
</mat-form-field>
32+
33+
<mat-form-field subscriptSizing="dynamic" appearance="outline">
34+
<mat-label>Focus strategy</mat-label>
35+
<mat-select [(value)]="focusMode">
36+
<mat-option value="roving">Roving Tabindex</mat-option>
37+
<mat-option value="activedescendant">Active Descendant</mat-option>
38+
</mat-select>
39+
</mat-form-field>
40+
</div>
41+
42+
<!-- #docregion radio-group -->
43+
<ul
44+
cdkRadioGroup
45+
[(value)]="selectedValue"
46+
[disabled]="disabled.value"
47+
[readonly]="readonly.value"
48+
[skipDisabled]="skipDisabled.value"
49+
[orientation]="orientation"
50+
[focusMode]="focusMode"
51+
class="example-radio-group"
52+
aria-label="Select your favorite ice cream flavor"
53+
>
54+
@for (flavor of flavors; track flavor) {
55+
@let optionDisabled = disabledOptions.includes(flavor);
56+
<li cdkRadioButton [value]="flavor" [disabled]="optionDisabled" class="example-radio-button">
57+
<span class="example-radio-indicator"></span>
58+
<span>{{ flavor }}</span>
59+
</li>
60+
}
61+
</ul>
62+
<!-- #enddocregion radio-group -->
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {Component} from '@angular/core';
2+
import {CdkRadioGroup, CdkRadioButton} from '@angular/cdk-experimental/radio';
3+
import {MatCheckboxModule} from '@angular/material/checkbox';
4+
import {MatFormFieldModule} from '@angular/material/form-field';
5+
import {MatSelectModule} from '@angular/material/select';
6+
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
7+
8+
/** @title Basic CDK Radio Group */
9+
@Component({
10+
selector: 'cdk-radio-example',
11+
exportAs: 'cdkRadioExample',
12+
templateUrl: 'cdk-radio-example.html',
13+
styleUrl: 'cdk-radio-example.css',
14+
standalone: true,
15+
imports: [
16+
CdkRadioGroup,
17+
CdkRadioButton,
18+
MatCheckboxModule,
19+
MatFormFieldModule,
20+
MatSelectModule,
21+
FormsModule,
22+
ReactiveFormsModule,
23+
],
24+
})
25+
export class CdkRadioExample {
26+
orientation: 'vertical' | 'horizontal' = 'vertical';
27+
disabled = new FormControl(false, {nonNullable: true});
28+
29+
flavors = ['Vanilla', 'Chocolate', 'Strawberry', 'Mint Chip', 'Cookies & Cream', 'Rocky Road'];
30+
31+
// New controls
32+
readonly = new FormControl(false, {nonNullable: true});
33+
skipDisabled = new FormControl(true, {nonNullable: true});
34+
focusMode: 'roving' | 'activedescendant' = 'roving';
35+
selectedValue: string | null = 'Vanilla'; // To control/reflect the radio group's value
36+
37+
// Control for which radio options are individually disabled
38+
disabledOptions: string[] = ['Chocolate'];
39+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {CdkRadioExample} from './cdk-radio/cdk-radio-example';

src/dev-app/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ng_project(
3636
"//src/dev-app/cdk-experimental-accordion",
3737
"//src/dev-app/cdk-experimental-combobox",
3838
"//src/dev-app/cdk-experimental-listbox",
39+
"//src/dev-app/cdk-experimental-radio",
3940
"//src/dev-app/cdk-experimental-tabs",
4041
"//src/dev-app/cdk-listbox",
4142
"//src/dev-app/cdk-menu",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
load("//tools:defaults.bzl", "ng_project")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ng_project(
6+
name = "cdk-experimental-radio",
7+
srcs = glob(["**/*.ts"]),
8+
assets = ["cdk-radio-demo.html"],
9+
deps = [
10+
"//:node_modules/@angular/core",
11+
"//src/components-examples/cdk-experimental/radio",
12+
],
13+
)
14+
15+
filegroup(
16+
name = "source-files",
17+
srcs = glob([
18+
"**/*.ts",
19+
"**/*.html",
20+
]),
21+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div>
2+
<h4>Radio using UI Patterns</h4>
3+
<cdk-radio-example></cdk-radio-example>
4+
</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {ChangeDetectionStrategy, Component} from '@angular/core';
10+
import {CdkRadioExample} from '@angular/components-examples/cdk-experimental/radio';
11+
12+
@Component({
13+
templateUrl: 'cdk-radio-demo.html',
14+
imports: [CdkRadioExample],
15+
changeDetection: ChangeDetectionStrategy.OnPush,
16+
})
17+
export class CdkExperimentalRadioDemo {}

src/dev-app/dev-app/dev-app-layout.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class DevAppLayout {
6060
{name: 'Examples', route: '/examples'},
6161
{name: 'CDK Dialog', route: '/cdk-dialog'},
6262
{name: 'CDK Experimental Combobox', route: '/cdk-experimental-combobox'},
63+
{name: 'CDK Experimental Radio', route: '/cdk-experimental-radio'},
6364
{name: 'CDK Experimental Listbox', route: '/cdk-experimental-listbox'},
6465
{name: 'CDK Experimental Tabs', route: '/cdk-experimental-tabs'},
6566
{name: 'CDK Experimental Accordion', route: '/cdk-experimental-accordion'},

src/dev-app/routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ export const DEV_APP_ROUTES: Routes = [
5050
loadComponent: () =>
5151
import('./cdk-experimental-listbox/cdk-listbox-demo').then(m => m.CdkExperimentalListboxDemo),
5252
},
53+
{
54+
path: 'cdk-experimental-radio',
55+
loadComponent: () =>
56+
import('./cdk-experimental-radio/cdk-radio-demo').then(m => m.CdkExperimentalRadioDemo),
57+
},
5358
{
5459
path: 'cdk-experimental-tabs',
5560
loadComponent: () =>

0 commit comments

Comments
 (0)