@vaadin/grid
Advanced tools
Comparing version 24.5.0 to 24.5.1
{ | ||
"name": "@vaadin/grid", | ||
"version": "24.5.0", | ||
"version": "24.5.1", | ||
"publishConfig": { | ||
@@ -49,14 +49,14 @@ "access": "public" | ||
"@polymer/polymer": "^3.0.0", | ||
"@vaadin/a11y-base": "~24.5.0", | ||
"@vaadin/checkbox": "~24.5.0", | ||
"@vaadin/component-base": "~24.5.0", | ||
"@vaadin/lit-renderer": "~24.5.0", | ||
"@vaadin/text-field": "~24.5.0", | ||
"@vaadin/vaadin-lumo-styles": "~24.5.0", | ||
"@vaadin/vaadin-material-styles": "~24.5.0", | ||
"@vaadin/vaadin-themable-mixin": "~24.5.0", | ||
"@vaadin/a11y-base": "~24.5.1", | ||
"@vaadin/checkbox": "~24.5.1", | ||
"@vaadin/component-base": "~24.5.1", | ||
"@vaadin/lit-renderer": "~24.5.1", | ||
"@vaadin/text-field": "~24.5.1", | ||
"@vaadin/vaadin-lumo-styles": "~24.5.1", | ||
"@vaadin/vaadin-material-styles": "~24.5.1", | ||
"@vaadin/vaadin-themable-mixin": "~24.5.1", | ||
"lit": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@vaadin/chai-plugins": "~24.5.0", | ||
"@vaadin/chai-plugins": "~24.5.1", | ||
"@vaadin/testing-helpers": "^1.0.0", | ||
@@ -69,3 +69,3 @@ "sinon": "^18.0.0" | ||
], | ||
"gitHead": "c69ad692cdd6261518a20ec7aa2d398b8bd84435" | ||
"gitHead": "0cf89edf4f22ee6f71925b86ea38d22f118638c3" | ||
} |
@@ -7,5 +7,19 @@ /** | ||
import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js'; | ||
import { animationFrame } from '@vaadin/component-base/src/async.js'; | ||
import { Debouncer } from '@vaadin/component-base/src/debounce.js'; | ||
import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js'; | ||
import { get } from '@vaadin/component-base/src/path-utils.js'; | ||
function isRow(element) { | ||
return element instanceof HTMLTableRowElement; | ||
} | ||
function isCell(element) { | ||
return element instanceof HTMLTableCellElement; | ||
} | ||
function isDetailsCell(element) { | ||
return element.matches('[part~="details-cell"]'); | ||
} | ||
/** | ||
@@ -88,5 +102,3 @@ * @polymerMixin | ||
get __rowFocusMode() { | ||
return ( | ||
this.__isRow(this._itemsFocusable) || this.__isRow(this._headerFocusable) || this.__isRow(this._footerFocusable) | ||
); | ||
return [this._headerFocusable, this._itemsFocusable, this._footerFocusable].some(isRow); | ||
} | ||
@@ -99,6 +111,6 @@ | ||
const parent = focusable && focusable.parentElement; | ||
if (this.__isCell(focusable)) { | ||
if (isCell(focusable)) { | ||
// Cell itself focusable (default) | ||
this[prop] = parent; | ||
} else if (this.__isCell(parent)) { | ||
} else if (isCell(parent)) { | ||
// Focus button mode is enabled for the column, | ||
@@ -108,3 +120,3 @@ // button element inside the cell is focusable. | ||
} | ||
} else if (!value && this.__isRow(focusable)) { | ||
} else if (!value && isRow(focusable)) { | ||
const cell = focusable.firstElementChild; | ||
@@ -207,3 +219,3 @@ this[prop] = cell._focusButton || cell; | ||
// button element inside the cell is focusable. | ||
if (this.__isCell(parent)) { | ||
if (isCell(parent)) { | ||
cell = parent; | ||
@@ -271,6 +283,6 @@ parent = parent.parentElement; | ||
/** @private */ | ||
_ensureScrolledToIndex(index) { | ||
__ensureFlatIndexInViewport(index) { | ||
const targetRowInDom = [...this.$.items.children].find((child) => child.index === index); | ||
if (!targetRowInDom) { | ||
this.scrollToIndex(index); | ||
this._scrollToFlatIndex(index); | ||
} else { | ||
@@ -295,22 +307,2 @@ this.__scrollIntoViewport(index); | ||
/** @private */ | ||
__isDetailsCell(element) { | ||
return element.matches('[part~="details-cell"]'); | ||
} | ||
/** @private */ | ||
__isCell(element) { | ||
return element instanceof HTMLTableCellElement; | ||
} | ||
/** @private */ | ||
__isRow(element) { | ||
return element instanceof HTMLTableRowElement; | ||
} | ||
/** @private */ | ||
__getIndexOfChildElement(el) { | ||
return Array.prototype.indexOf.call(el.parentNode.children, el); | ||
} | ||
/** @private */ | ||
_onNavigationKeyDown(e, key) { | ||
@@ -320,4 +312,4 @@ e.preventDefault(); | ||
const isRTL = this.__isRTL; | ||
const activeRow = e.composedPath().find((el) => this.__isRow(el)); | ||
const activeCell = e.composedPath().find((el) => this.__isCell(el)); | ||
const activeRow = e.composedPath().find(isRow); | ||
const activeCell = e.composedPath().find(isCell); | ||
@@ -417,3 +409,3 @@ // Handle keyboard interaction as defined in: | ||
const activeRowCells = [...activeRow.children].sort((a, b) => a._order - b._order); | ||
if (activeCell === activeRowCells[0] || this.__isDetailsCell(activeCell)) { | ||
if (activeCell === activeRowCells[0] || isDetailsCell(activeCell)) { | ||
// "If focus is on the first cell in a row and row focus is supported, moves focus to the row." | ||
@@ -457,3 +449,3 @@ this.__rowFocusMode = true; | ||
} | ||
return this.__getIndexOfChildElement(row); | ||
return [...rowGroup.children].indexOf(row); | ||
} | ||
@@ -499,3 +491,3 @@ | ||
if (activeCell) { | ||
const isRowDetails = this.__isDetailsCell(activeCell); | ||
const isRowDetails = isDetailsCell(activeCell); | ||
// Row details navigation logic | ||
@@ -521,3 +513,3 @@ if (activeRowGroup === this.$.items) { | ||
// Ensure correct vertical scroll position, destination row is visible | ||
this._ensureScrolledToIndex(dstRowIndex); | ||
this.__ensureFlatIndexInViewport(dstRowIndex); | ||
@@ -529,4 +521,4 @@ // When scrolling with repeated keydown, sometimes FocusEvent listeners | ||
// This has to be set after scrolling, otherwise it can be removed by | ||
// `_preventScrollerRotatingCellFocus(row, index)` during scrolling. | ||
// Reapply navigating state in case it was removed due to previous item | ||
// being focused with the mouse. | ||
this.toggleAttribute('navigating', true); | ||
@@ -552,3 +544,3 @@ | ||
let columnIndex = this.__getIndexOfChildElement(activeCell); | ||
let columnIndex = [...activeRow.children].indexOf(activeCell); | ||
if (this.$.items.contains(activeCell)) { | ||
@@ -559,3 +551,3 @@ // lazy column rendering may be enabled, so we need use the always visible sizer cells to find the column index | ||
const isCurrentCellRowDetails = this.__isDetailsCell(activeCell); | ||
const isCurrentCellRowDetails = isDetailsCell(activeCell); | ||
const activeRowGroup = activeRow.parentNode; | ||
@@ -578,3 +570,3 @@ const currentRowIndex = this.__getIndexInGroup(activeRow, this._focusedItemIndex); | ||
// Focusing a row details cell on the destination row | ||
const dstCell = [...dstRow.children].find((el) => this.__isDetailsCell(el)); | ||
const dstCell = [...dstRow.children].find(isDetailsCell); | ||
dstCell.focus(); | ||
@@ -756,19 +748,10 @@ } else { | ||
} else if (focusTarget === this._itemsFocusable) { | ||
let itemsFocusTarget = focusTarget; | ||
const targetRow = this.__isRow(focusTarget) ? focusTarget : focusTarget.parentNode; | ||
this._ensureScrolledToIndex(this._focusedItemIndex); | ||
if (targetRow.index !== this._focusedItemIndex && this.__isCell(focusTarget)) { | ||
// The target row, which is about to be focused next, has been | ||
// assigned with a new index since last focus, probably because of | ||
// scrolling. Focus the row for the stored focused item index instead. | ||
const columnIndex = Array.from(targetRow.children).indexOf(this._itemsFocusable); | ||
const focusedItemRow = Array.from(this.$.items.children).find( | ||
(row) => !row.hidden && row.index === this._focusedItemIndex, | ||
); | ||
if (focusedItemRow) { | ||
itemsFocusTarget = focusedItemRow.children[columnIndex]; | ||
} | ||
} | ||
this.__ensureFlatIndexInViewport(this._focusedItemIndex); | ||
// Ensure the correct element is set as focusable after scrolling. | ||
// The virtualizer may use a different element to render the item. | ||
this.__updateItemsFocusable(); | ||
e.preventDefault(); | ||
itemsFocusTarget.focus(); | ||
this._itemsFocusable.focus(); | ||
} else { | ||
@@ -787,8 +770,8 @@ e.preventDefault(); | ||
const element = e.composedPath()[0]; | ||
const isRow = this.__isRow(element); | ||
if (isRow || !element._content || !element._content.firstElementChild) { | ||
const isElementRow = isRow(element); | ||
if (isElementRow || !element._content || !element._content.firstElementChild) { | ||
this.dispatchEvent( | ||
new CustomEvent(isRow ? 'row-activate' : 'cell-activate', { | ||
new CustomEvent(isElementRow ? 'row-activate' : 'cell-activate', { | ||
detail: { | ||
model: this.__getRowModel(isRow ? element : element.parentElement), | ||
model: this.__getRowModel(isElementRow ? element : element.parentElement), | ||
}, | ||
@@ -870,7 +853,9 @@ }), | ||
this._activeRowGroup = section; | ||
if (this.$.header === section) { | ||
if (section === this.$.header) { | ||
this._headerFocusable = this.__getFocusable(row, cell); | ||
} else if (this.$.items === section) { | ||
} else if (section === this.$.items) { | ||
this._itemsFocusable = this.__getFocusable(row, cell); | ||
} else if (this.$.footer === section) { | ||
this._focusedItemIndex = row.index; | ||
} else if (section === this.$.footer) { | ||
this._footerFocusable = this.__getFocusable(row, cell); | ||
@@ -895,4 +880,2 @@ } | ||
} | ||
this._detectFocusedItemIndex(e); | ||
} | ||
@@ -935,10 +918,2 @@ | ||
/** @private */ | ||
_detectFocusedItemIndex(e) { | ||
const { section, row } = this._getGridEventLocation(e); | ||
if (section === this.$.items) { | ||
this._focusedItemIndex = row.index; | ||
} | ||
} | ||
/** | ||
@@ -962,22 +937,41 @@ * Enables or disables the focus target of the containing section of the | ||
/** | ||
* @param {!HTMLTableRowElement} row | ||
* @param {number} index | ||
* @protected | ||
*/ | ||
_preventScrollerRotatingCellFocus(row, index) { | ||
if ( | ||
row.index === this._focusedItemIndex && | ||
this.hasAttribute('navigating') && | ||
this._activeRowGroup === this.$.items | ||
) { | ||
// Focused item has went, hide navigation mode | ||
this._navigatingIsHidden = true; | ||
this.toggleAttribute('navigating', false); | ||
/** @protected */ | ||
_preventScrollerRotatingCellFocus() { | ||
if (this._activeRowGroup !== this.$.items) { | ||
return; | ||
} | ||
if (index === this._focusedItemIndex && this._navigatingIsHidden) { | ||
// Focused item is back, restore navigation mode | ||
this._navigatingIsHidden = false; | ||
this.toggleAttribute('navigating', true); | ||
} | ||
this.__preventScrollerRotatingCellFocusDebouncer = Debouncer.debounce( | ||
this.__preventScrollerRotatingCellFocusDebouncer, | ||
animationFrame, | ||
() => { | ||
const isItemsRowGroupActive = this._activeRowGroup === this.$.items; | ||
const isFocusedItemRendered = this._getRenderedRows().some((row) => row.index === this._focusedItemIndex); | ||
if (isFocusedItemRendered) { | ||
// Ensure the correct element is focused, as the virtualizer | ||
// may use different elements when re-rendering visible items. | ||
this.__updateItemsFocusable(); | ||
// The focused item is visible, so restore the cell focus outline | ||
// and navigation mode. | ||
if (isItemsRowGroupActive && !this.__rowFocusMode) { | ||
this._focusedCell = this._itemsFocusable; | ||
} | ||
if (this._navigatingIsHidden) { | ||
this.toggleAttribute('navigating', true); | ||
this._navigatingIsHidden = false; | ||
} | ||
} else if (isItemsRowGroupActive) { | ||
// The focused item was scrolled out of view and focus is still inside body, | ||
// so remove the cell focus outline and hide navigation mode. | ||
this._focusedCell = null; | ||
if (this.hasAttribute('navigating')) { | ||
this._navigatingIsHidden = true; | ||
this.toggleAttribute('navigating', false); | ||
} | ||
} | ||
}, | ||
); | ||
} | ||
@@ -1042,3 +1036,3 @@ | ||
_scrollHorizontallyToCell(dstCell) { | ||
if (dstCell.hasAttribute('frozen') || dstCell.hasAttribute('frozen-to-end') || this.__isDetailsCell(dstCell)) { | ||
if (dstCell.hasAttribute('frozen') || dstCell.hasAttribute('frozen-to-end') || isDetailsCell(dstCell)) { | ||
// These cells are, by design, always visible, no need to scroll. | ||
@@ -1056,3 +1050,3 @@ return; | ||
const cell = dstRow.children[i]; | ||
if (cell.hasAttribute('hidden') || this.__isDetailsCell(cell)) { | ||
if (cell.hasAttribute('hidden') || isDetailsCell(cell)) { | ||
continue; | ||
@@ -1067,3 +1061,3 @@ } | ||
const cell = dstRow.children[i]; | ||
if (cell.hasAttribute('hidden') || this.__isDetailsCell(cell)) { | ||
if (cell.hasAttribute('hidden') || isDetailsCell(cell)) { | ||
continue; | ||
@@ -1070,0 +1064,0 @@ } |
@@ -147,2 +147,6 @@ /** | ||
[part~='cell'] { | ||
outline: none; | ||
} | ||
[part~='cell'] > [tabindex] { | ||
@@ -149,0 +153,0 @@ display: flex; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
676886
16251