diff --git a/commitlint.config.js b/commitlint.config.js
index baad2b20b..04e99e16a 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -29,6 +29,7 @@ module.exports = {
'list',
'modal',
'navbar',
+ 'optgroup',
'panel',
'popover',
'progress-bar',
diff --git a/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.css b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.css
new file mode 100644
index 000000000..743230875
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.html b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.html
new file mode 100644
index 000000000..19a28c864
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.html
@@ -0,0 +1,8 @@
+
+
+
+ {{ pokemon.viewValue }}
+
+
+ Mr. Mime
+
diff --git a/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.ts b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.ts
new file mode 100644
index 000000000..a7ec5d78f
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/list/list-groups/list-groups-example.ts
@@ -0,0 +1,47 @@
+import { Component } from '@angular/core';
+
+
+/**
+ * @title Basic list
+ */
+@Component({
+ selector: 'list-groups-example',
+ templateUrl: 'list-groups-example.html',
+ styleUrls: ['list-groups-example.css']
+})
+export class ListGroupsExample {
+ pokemonTypes = [
+ {
+ name: 'Grass',
+ pokemon: [
+ { value: 'bulbasaur-0', viewValue: 'Bulbasaur' },
+ { value: 'oddish-1', viewValue: 'Oddish' },
+ { value: 'bellsprout-2', viewValue: 'Bellsprout' }
+ ]
+ },
+ {
+ name: 'Water',
+ disabled: true,
+ pokemon: [
+ { value: 'squirtle-3', viewValue: 'Squirtle' },
+ { value: 'psyduck-4', viewValue: 'Psyduck' },
+ { value: 'horsea-5', viewValue: 'Horsea' }
+ ]
+ },
+ {
+ name: 'Fire',
+ pokemon: [
+ { value: 'charmander-6', viewValue: 'Charmander' },
+ { value: 'vulpix-7', viewValue: 'Vulpix' },
+ { value: 'flareon-8', viewValue: 'Flareon' }
+ ]
+ },
+ {
+ name: 'Psychic',
+ pokemon: [
+ { value: 'mew-9', viewValue: 'Mew' },
+ { value: 'mewtwo-10', viewValue: 'Mewtwo' }
+ ]
+ }
+ ];
+}
diff --git a/packages/mosaic-examples/mosaic/list/module.ts b/packages/mosaic-examples/mosaic/list/module.ts
index cb45278dc..2d3544d66 100644
--- a/packages/mosaic-examples/mosaic/list/module.ts
+++ b/packages/mosaic-examples/mosaic/list/module.ts
@@ -1,7 +1,9 @@
+import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { McListModule } from '@ptsecurity/mosaic/list';
+import { ListGroupsExample } from './list-groups/list-groups-example';
import { ListMultipleCheckboxExample } from './list-multiple-checkbox/list-multiple-checkbox-example';
import { ListMultipleKeyboardExample } from './list-multiple-keyboard/list-multiple-keyboard-example';
import { ListOverviewExample } from './list-overview/list-overview-example';
@@ -10,11 +12,13 @@ import { ListOverviewExample } from './list-overview/list-overview-example';
const EXAMPLES = [
ListOverviewExample,
ListMultipleCheckboxExample,
- ListMultipleKeyboardExample
+ ListMultipleKeyboardExample,
+ ListGroupsExample
];
@NgModule({
imports: [
+ CommonModule,
FormsModule,
McListModule
],
diff --git a/packages/mosaic-examples/mosaic/select/module.ts b/packages/mosaic-examples/mosaic/select/module.ts
index 752db6703..9a96874c7 100644
--- a/packages/mosaic-examples/mosaic/select/module.ts
+++ b/packages/mosaic-examples/mosaic/select/module.ts
@@ -5,6 +5,7 @@ import { McIconModule } from '@ptsecurity/mosaic/icon';
import { McInputModule } from '@ptsecurity/mosaic/input';
import { McSelectModule } from '@ptsecurity/mosaic/select';
+import { SelectGroupsExample } from './select-groups/select-groups-example';
import { SelectMultipleOverviewExample } from './select-multiple-overview/select-multiple-overview-example';
import { SelectOverviewExample } from './select-overview/select-overview-example';
import { SelectSearchOverviewExample } from './select-search-overview/select-search-overview-example';
@@ -13,7 +14,8 @@ import { SelectSearchOverviewExample } from './select-search-overview/select-sea
const EXAMPLES = [
SelectOverviewExample,
SelectMultipleOverviewExample,
- SelectSearchOverviewExample
+ SelectSearchOverviewExample,
+ SelectGroupsExample
];
@NgModule({
diff --git a/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.css b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.css
new file mode 100644
index 000000000..743230875
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.html b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.html
new file mode 100644
index 000000000..1b78f0d65
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.html
@@ -0,0 +1,8 @@
+
+
+
+ {{ pokemon.viewValue }}
+
+ Mr. Mime
+
+
diff --git a/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.ts b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.ts
new file mode 100644
index 000000000..45b854027
--- /dev/null
+++ b/packages/mosaic-examples/mosaic/select/select-groups/select-groups-example.ts
@@ -0,0 +1,47 @@
+import { Component } from '@angular/core';
+
+
+/**
+ * @title Basic Select
+ */
+@Component({
+ selector: 'select-groups-example',
+ templateUrl: 'select-groups-example.html',
+ styleUrls: ['select-groups-example.css']
+})
+export class SelectGroupsExample {
+ pokemonTypes = [
+ {
+ name: 'Grass',
+ pokemon: [
+ { value: 'bulbasaur-0', viewValue: 'Bulbasaur' },
+ { value: 'oddish-1', viewValue: 'Oddish' },
+ { value: 'bellsprout-2', viewValue: 'Bellsprout' }
+ ]
+ },
+ {
+ name: 'Water',
+ disabled: true,
+ pokemon: [
+ { value: 'squirtle-3', viewValue: 'Squirtle' },
+ { value: 'psyduck-4', viewValue: 'Psyduck' },
+ { value: 'horsea-5', viewValue: 'Horsea' }
+ ]
+ },
+ {
+ name: 'Fire',
+ pokemon: [
+ { value: 'charmander-6', viewValue: 'Charmander' },
+ { value: 'vulpix-7', viewValue: 'Vulpix' },
+ { value: 'flareon-8', viewValue: 'Flareon' }
+ ]
+ },
+ {
+ name: 'Psychic',
+ pokemon: [
+ { value: 'mew-9', viewValue: 'Mew' },
+ { value: 'mewtwo-10', viewValue: 'Mewtwo' }
+ ]
+ }
+ ];
+}
diff --git a/packages/mosaic/core/option/_optgroup-theme.scss b/packages/mosaic/core/option/_optgroup-theme.scss
index 4948b5a9f..7c401a5d8 100644
--- a/packages/mosaic/core/option/_optgroup-theme.scss
+++ b/packages/mosaic/core/option/_optgroup-theme.scss
@@ -10,13 +10,13 @@
color: mc-color($foreground, secondary-text);
}
- .mc-optgroup-disabled .mc-optgroup-label {
- color: mc-color($foreground, hint-text);
+ .mc-disabled .mc-optgroup-label {
+ color: mc-color($foreground, disabled-text);
}
}
@mixin mc-optgroup-typography($config) {
.mc-optgroup-label {
- @include mc-typography-level-to-styles($config, body-2);
+ @include mc-typography-level-to-styles($config, subheading);
}
}
diff --git a/packages/mosaic/core/option/optgroup.html b/packages/mosaic/core/option/optgroup.html
index 7353d5f24..681eabaf6 100644
--- a/packages/mosaic/core/option/optgroup.html
+++ b/packages/mosaic/core/option/optgroup.html
@@ -1,2 +1,2 @@
-
+
diff --git a/packages/mosaic/core/option/optgroup.scss b/packages/mosaic/core/option/optgroup.scss
index f58b4f43a..e9472c2d1 100644
--- a/packages/mosaic/core/option/optgroup.scss
+++ b/packages/mosaic/core/option/optgroup.scss
@@ -2,6 +2,9 @@
.mc-optgroup-label {
+ padding-left: 16px;
+
@include user-select(none);
+
cursor: default;
}
diff --git a/packages/mosaic/core/option/optgroup.ts b/packages/mosaic/core/option/optgroup.ts
index 2a19a3e57..113c9ff2d 100644
--- a/packages/mosaic/core/option/optgroup.ts
+++ b/packages/mosaic/core/option/optgroup.ts
@@ -3,14 +3,12 @@ import { Component, ViewEncapsulation, Input, ChangeDetectionStrategy } from '@a
import { mixinDisabled, CanDisable, CanDisableCtor } from '../common-behaviors/index';
-// Boilerplate for applying mixins to McOptgroup.
/** @docs-private */
export class McOptgroupBase {}
// tslint:disable-next-line: naming-convention
export const McOptgroupMixinBase: CanDisableCtor & typeof McOptgroupBase = mixinDisabled(McOptgroupBase);
-// Counter for unique group ids.
let uniqueOptgroupIdCounter = 0;
/**
@@ -20,20 +18,16 @@ let uniqueOptgroupIdCounter = 0;
selector: 'mc-optgroup',
exportAs: 'mcOptgroup',
templateUrl: 'optgroup.html',
+ styleUrls: ['./optgroup.css'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
inputs: ['disabled'],
- styleUrls: ['optgroup.css'],
host: {
class: 'mc-optgroup',
- role: 'group',
- '[class.mc-optgroup-disabled]': 'disabled',
- '[attr.aria-disabled]': 'disabled.toString()',
- '[attr.aria-labelledby]': 'labelId'
+ '[class.mc-disabled]': 'disabled'
}
})
export class McOptgroup extends McOptgroupMixinBase implements CanDisable {
- /** Label for the option group. */
@Input() label: string;
/** Unique id for the underlying label. */
diff --git a/packages/mosaic/core/styles/typography/_all-typography.scss b/packages/mosaic/core/styles/typography/_all-typography.scss
index 33a3f47fa..27ff28df6 100644
--- a/packages/mosaic/core/styles/typography/_all-typography.scss
+++ b/packages/mosaic/core/styles/typography/_all-typography.scss
@@ -26,6 +26,7 @@
@import '../../../tree/tree-theme';
@import '../../../vertical-navbar/vertical-navbar-theme';
@import '../../option/option-theme';
+@import '../../option/optgroup-theme';
@mixin mosaic-typography($config: null) {
@@ -50,6 +51,7 @@
@include mc-modal-typography($config);
@include mc-navbar-typography($config);
@include mc-option-typography($config);
+ @include mc-optgroup-typography($config);
@include mc-popover-typography($config);
@include mc-radio-typography($config);
@include mc-select-typography($config);
diff --git a/packages/mosaic/core/theming/_all-theme.scss b/packages/mosaic/core/theming/_all-theme.scss
index 51748c9a4..50b24c7c9 100644
--- a/packages/mosaic/core/theming/_all-theme.scss
+++ b/packages/mosaic/core/theming/_all-theme.scss
@@ -33,6 +33,7 @@
@import '../../tree/tree-theme';
@import '../../vertical-navbar/vertical-navbar-theme';
@import '../option/option-theme';
+@import '../option/optgroup-theme';
@import '../highlight/highlight-theme';
@import '../visual/panel-theme';
@@ -57,6 +58,7 @@
@include mc-modal-theme($theme);
@include mc-navbar-theme($theme);
@include mc-option-theme($theme);
+ @include mc-optgroup-theme($theme);
@include mc-panel-theme($theme);
@include mc-popover-theme($theme);
@include mc-progress-bar-theme($theme);
diff --git a/packages/mosaic/list/_list-theme.scss b/packages/mosaic/list/_list-theme.scss
index 5424007f5..8cc99b247 100644
--- a/packages/mosaic/list/_list-theme.scss
+++ b/packages/mosaic/list/_list-theme.scss
@@ -45,6 +45,7 @@
background: mc-color($primary, if($is-dark-theme, 700, 100));
}
+ &.mc-disabled,
&[disabled] {
background: transparent;
diff --git a/packages/mosaic/list/list-selection.component.ts b/packages/mosaic/list/list-selection.component.ts
index 806484e38..1b4d0962e 100644
--- a/packages/mosaic/list/list-selection.component.ts
+++ b/packages/mosaic/list/list-selection.component.ts
@@ -19,7 +19,8 @@ import {
OnDestroy,
OnInit,
ViewChild,
- NgZone
+ NgZone,
+ Optional
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { FocusKeyManager, IFocusableOption } from '@ptsecurity/cdk/a11y';
@@ -44,7 +45,8 @@ import {
HasTabIndexCtor,
mixinTabIndex,
HasTabIndex,
- MultipleMode
+ MultipleMode,
+ McOptgroup
} from '@ptsecurity/mosaic/core';
import { merge, Observable, Subject, Subscription } from 'rxjs';
import { startWith, take, takeUntil } from 'rxjs/operators';
@@ -69,6 +71,7 @@ export interface McOptionEvent {
class: 'mc-list-option',
'[class.mc-selected]': 'selected',
'[class.mc-focused]': 'hasFocus',
+ '[class.mc-disabled]': 'disabled',
'(focus)': 'focus()',
'(blur)': 'blur()',
@@ -97,7 +100,8 @@ export class McListOption implements OnDestroy, OnInit, IFocusableOption {
@Input()
get disabled() {
- return this._disabled || (this.listSelection && this.listSelection.disabled);
+ return (this.listSelection && this.listSelection.disabled) || (this.group && this.group.disabled) ||
+ this._disabled;
}
set disabled(value: any) {
@@ -147,7 +151,8 @@ export class McListOption implements OnDestroy, OnInit, IFocusableOption {
private elementRef: ElementRef,
private changeDetector: ChangeDetectorRef,
private ngZone: NgZone,
- @Inject(forwardRef(() => McListSelection)) public listSelection: McListSelection
+ @Inject(forwardRef(() => McListSelection)) public listSelection: McListSelection,
+ @Optional() readonly group: McOptgroup
) {}
ngOnInit() {
@@ -290,8 +295,7 @@ export class McListSelection extends McListSelectionMixinBase implements CanDisa
keyManager: FocusKeyManager;
- // The option components contained within this selection-list.
- @ContentChildren(McListOption) options: QueryList;
+ @ContentChildren(McListOption, { descendants: true }) options: QueryList;
autoSelect: boolean;
noUnselect: boolean;
diff --git a/packages/mosaic/list/list.md b/packages/mosaic/list/list.md
index ead288d0e..f00bde9ba 100644
--- a/packages/mosaic/list/list.md
+++ b/packages/mosaic/list/list.md
@@ -2,9 +2,13 @@
-### Multiple mode with checkboxes
+#### Multiple mode with checkboxes
-### Multiple mode without checkboxes
-
\ No newline at end of file
+#### Multiple mode without checkboxes
+
+
+
+#### Multiple mode without checkboxes
+
\ No newline at end of file
diff --git a/packages/mosaic/list/list.module.ts b/packages/mosaic/list/list.module.ts
index 7039ecfff..74a6e6f23 100644
--- a/packages/mosaic/list/list.module.ts
+++ b/packages/mosaic/list/list.module.ts
@@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { A11yModule } from '@ptsecurity/cdk/a11y';
-import { McLineModule, McPseudoCheckboxModule } from '@ptsecurity/mosaic/core';
+import { McLineModule, McOptionModule, McPseudoCheckboxModule } from '@ptsecurity/mosaic/core';
import { McListSelection, McListOption } from './list-selection.component';
import { McList, McListItem, McListSubheaderCssStyler } from './list.component';
@@ -12,13 +12,15 @@ import { McList, McListItem, McListSubheaderCssStyler } from './list.component';
CommonModule,
A11yModule,
McPseudoCheckboxModule,
- McLineModule
+ McLineModule,
+ McOptionModule
],
exports: [
McList,
McListSelection,
McListItem,
McListOption,
+ McOptionModule,
McListSubheaderCssStyler
],
declarations: [
diff --git a/packages/mosaic/list/list.scss b/packages/mosaic/list/list.scss
index 4095ece42..b15221333 100644
--- a/packages/mosaic/list/list.scss
+++ b/packages/mosaic/list/list.scss
@@ -45,6 +45,6 @@
}
}
-.mc-list-option:not([disabled]) {
+.mc-list-option:not([disabled]):not(.mc-disabled){
cursor: pointer;
}
diff --git a/packages/mosaic/select/select.component.spec.ts b/packages/mosaic/select/select.component.spec.ts
index 30d3d5a7c..5b13af20c 100644
--- a/packages/mosaic/select/select.component.spec.ts
+++ b/packages/mosaic/select/select.component.spec.ts
@@ -526,8 +526,7 @@ class FalsyValueSelect {
template: `
-
+
{{ pokemon.viewValue }}
@@ -2187,7 +2186,7 @@ describe('McSelect', () => {
expect(panel.scrollTop).toBe(288, 'Expected scroll to be at the 9th option.');
}));
- xit('should skip option group labels', fakeAsync(() => {
+ it('should skip option group labels', fakeAsync(() => {
fixture.destroy();
const groupFixture = TestBed.createComponent(SelectWithGroups);
@@ -2198,7 +2197,7 @@ describe('McSelect', () => {
flush();
host = groupFixture.debugElement.query(By.css('mc-select')).nativeElement;
- panel = overlayContainerElement.querySelector('.mc-select__panel') as HTMLElement;
+ panel = overlayContainerElement.querySelector('.mc-select__content') as HTMLElement;
for (let i = 0; i < 5; i++) {
dispatchKeyboardEvent(host, 'keydown', DOWN_ARROW);
@@ -2206,8 +2205,8 @@ describe('McSelect', () => {
// Note that we press down 5 times, but it will skip
// 3 options because the second group is disabled.
- // <(option index + group labels) * height> - = (9 + 3) * 48 - 256 = 320
- expect(panel.scrollTop).toBe(320, 'Expected scroll to be at the 9th option.');
+ // <(option index + group labels) * height> - = (9 + 3) * 32 - 224 = 160
+ expect(panel.scrollTop).toBe(160, 'Expected scroll to be at the 9th option.');
}));
it('should scroll top the top when pressing HOME', fakeAsync(() => {
@@ -3403,7 +3402,7 @@ describe('McSelect', () => {
groupFixture.detectChanges();
flush();
- const scrollContainer = document.querySelector('.cdk-overlay-pane .mc-select__panel')!;
+ const scrollContainer = document.querySelector('.cdk-overlay-pane .mc-select__content')!;
// The selected option should be scrolled to the center of the panel.
// This will be its original offset from the scrollTop - half the panel height + half the
diff --git a/packages/mosaic/select/select.md b/packages/mosaic/select/select.md
index 858a5b04a..25619e00d 100644
--- a/packages/mosaic/select/select.md
+++ b/packages/mosaic/select/select.md
@@ -6,3 +6,6 @@
#### With search
+
+#### With groups
+