Skip to content

Commit

Permalink
fix(Select): panel no longer is positioned away from the trigger
Browse files Browse the repository at this point in the history
Selected option is now always visible on open

ISSUES CLOSED: #1351
  • Loading branch information
benjamincharity committed Feb 14, 2019
1 parent d3d266f commit 19ef6e0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 44 deletions.
16 changes: 8 additions & 8 deletions demo/app/components/select/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ export class SelectComponent implements OnInit {
slug: 'neq',
},
{
foo: 'Foo bar baz foo bar baz foo bar baz',
foo: 'Foo2 bar baz foo bar baz foo bar baz',
slug: 'foo2',
},
{
foo: 'Bar Hic saepe ad sunt temporibus.',
foo: 'Bar2 Hic saepe ad sunt temporibus.',
slug: 'bar2',
},
{
Expand All @@ -115,29 +115,29 @@ export class SelectComponent implements OnInit {
disabled: true,
},
{
foo: 'Eligendi magni quod quas',
foo: 'Eligendi2 magni quod quas',
slug: 'eli2',
},
{
foo: 'Necessitatibus corporis officiis atque sed.',
foo: 'Necessitatibus2 corporis officiis atque sed.',
slug: 'nec2',
disabled: true,
},
{
foo: 'Baz Neque numquam reiciendis',
foo: 'Baz2 Neque numquam reiciendis',
slug: 'baz2',
disabled: true,
},
{
foo: 'Vel eos nam porro. Vel eos nam porro.',
foo: 'Vel2 eos nam porro. Vel eos nam porro.',
slug: 'vel2',
},
{
foo: 'Dolores ducimus magnamomnis.',
foo: 'Dolores2 ducimus magnamomnis.',
slug: 'dol2',
},
{
foo: 'Dolorem neque quae ducimus',
foo: 'Dolorem2 neque quae ducimus',
slug: 'neq2',
},
]);
Expand Down
1 change: 1 addition & 0 deletions terminus-ui/checkbox/src/checkbox.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ $ts-select-item-height: 3em !default;
}

// Target checkboxes inside a TsSelectOptionComponent
.ts-select-panel__toggle-all &,
.ts-select-option & {
.mat-checkbox-layout {
width: 100%;
Expand Down
1 change: 0 additions & 1 deletion terminus-ui/select/src/select.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@
[cdkConnectedOverlayPositions]="positions"
[cdkConnectedOverlayMinWidth]="triggerRect?.width"
[cdkConnectedOverlayWidth]="triggerRect?.width"
[cdkConnectedOverlayOffsetY]="offsetY"
(backdropClick)="close()"
(attach)="onAttached()"
(detach)="close()"
Expand Down
70 changes: 35 additions & 35 deletions terminus-ui/select/src/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,17 +543,15 @@ export class TsSelectComponent implements
}

/**
* Calculates the height of the option's offsetHeight. Fall back to the trigger font size if no options exist.
* Calculates the height of the options
*
* Only called if at least one option exists
*/
private get itemHeight(): number {
if (this.options.length) {
// Try to use the 2nd option in case the first option is blank or a filter etc. Fall back to the first item if needed.
const options = this.options.toArray();
const option = options[1] || options[0];
return option.elementRef.nativeElement.offsetHeight;
} else {
return this.triggerFontSize * SELECT_ITEM_HEIGHT_EM;
}
// Try to use the 2nd option in case the first option is blank or a filter etc. Fall back to the first item if needed.
const options = this.options.toArray();
const option = options[1] || options[0];
return option.elementRef.nativeElement.offsetHeight;
}

/**
Expand Down Expand Up @@ -1666,7 +1664,7 @@ export class TsSelectComponent implements
if (this.autocomplete) {
return;
}
const itemHeight = this.optionRect ? this.optionRect.height /* istanbul ignore next - Unreachable */ : this.itemHeight;
const itemHeight = this.itemHeight;
const items = this.itemCount;
const panelHeight = Math.min(items * itemHeight, SELECT_PANEL_MAX_HEIGHT);
const scrollContainerHeight = items * itemHeight;
Expand All @@ -1693,6 +1691,29 @@ export class TsSelectComponent implements
}


/**
* Calculate the scroll position of the select's overlay panel
*
* This attempts to center the selected option in the panel. If the option is too high or too low in the panel to be scrolled to the
* center, it clamps the scroll position to the min or max scroll positions respectively.
*
* @param selectedIndex - The index of the item to scroll to
* @param scrollBuffer - The amount to buffer the scroll
* @param maxScroll - The maximum amount the panel can scroll
*/
private calculateOverlayScroll(selectedIndex: number, scrollBuffer: number, maxScroll: number): number {
const itemHeight = this.itemHeight;
const optionOffsetFromScrollTop = itemHeight * selectedIndex;
const halfOptionHeight = itemHeight / 2;

// Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the scroll container, then subtracts the scroll
// buffer to scroll the option down to the center of the overlay panel. Half the option height must be re-added to the scrollTop so the
// option is centered based on its middle, not its top edge.
const optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
return Math.min(Math.max(0, optimalScrollPosition), maxScroll);
}


/**
* Calculates the y-offset of the select's overlay panel in relation to the top start corner of the trigger.
* It has to be adjusted in order for the selected option to be aligned over the trigger when the panel opens.
Expand Down Expand Up @@ -1785,7 +1806,8 @@ export class TsSelectComponent implements
// Scrolls the panel up by the distance it was extending past the boundary, then
// adjusts the offset by that amount to move the panel up into the viewport.
this.scrollTop -= distanceBelowViewport;
this.offsetY -= distanceBelowViewport;
// Don't allow the offset to be set below 0
this.offsetY = (this.offsetY - distanceBelowViewport) < 0 ? 0 : this.offsetY - distanceBelowViewport;
this.transformOrigin = this.getOriginBasedOnOption();

// If the panel is scrolled to the very top, it won't be able to fit the panel
Expand Down Expand Up @@ -1813,7 +1835,8 @@ export class TsSelectComponent implements
// Scrolls the panel down by the distance it was extending past the boundary, then
// adjusts the offset by that amount to move the panel down into the viewport.
this.scrollTop += distanceAboveViewport;
this.offsetY += distanceAboveViewport;
// Don't allow the offset to be set below 0
this.offsetY = (this.offsetY + distanceAboveViewport) < 0 ? 0 : this.offsetY + distanceAboveViewport;
this.transformOrigin = this.getOriginBasedOnOption();

// If the panel is scrolled to the very bottom, it won't be able to fit the
Expand Down Expand Up @@ -1856,29 +1879,6 @@ export class TsSelectComponent implements
}


/**
* Calculate the scroll position of the select's overlay panel
*
* This attempts to center the selected option in the panel. If the option is too high or too low in the panel to be scrolled to the
* center, it clamps the scroll position to the min or max scroll positions respectively.
*
* @param selectedIndex - The index of the item to scroll to
* @param scrollBuffer - The amount to buffer the scroll
* @param maxScroll - The maximum amount the panel can scroll
*/
private calculateOverlayScroll(selectedIndex: number, scrollBuffer: number, maxScroll: number): number {
const itemHeight = this.optionRect ? this.optionRect.height : this.itemHeight;
const optionOffsetFromScrollTop = itemHeight * selectedIndex;
const halfOptionHeight = itemHeight / 2;

// Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the scroll container, then subtracts the scroll
// buffer to scroll the option down to the center of the overlay panel. Half the option height must be re-added to the scrollTop so the
// option is centered based on its middle, not its top edge.
const optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
return Math.min(Math.max(0, optimalScrollPosition), maxScroll);
}


/**
* Highlight the selected item.
*
Expand Down

0 comments on commit 19ef6e0

Please sign in to comment.