@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
113 lines • 5.76 kB
JavaScript
import { createComponent, Shade } from '@furystack/shades';
import { buildTransition, cssVariableTheme } from '../../services/css-variable-theme.js';
export const DataGridRow = Shade({
customElementName: 'shades-data-grid-row',
css: {
display: 'table-row',
fontFamily: cssVariableTheme.typography.fontFamily,
cursor: 'default',
userSelect: 'none',
transition: buildTransition(['background-color', cssVariableTheme.transitions.duration.fast, 'ease'], ['box-shadow', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.easeInOut], ['transform', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.easeInOut]),
borderLeft: '3px solid transparent',
'&:not([data-selected]):hover': {
backgroundColor: cssVariableTheme.action.hoverBackground,
},
'&[data-selected]': {
backgroundColor: cssVariableTheme.action.selectedBackground,
borderLeft: `3px solid ${cssVariableTheme.palette.primary.main}`,
},
'&[data-focused]': {
boxShadow: `0 0 0 2px ${cssVariableTheme.palette.primary.main} inset, 0 2px 8px 0px rgba(0,0,0,0.15)`,
fontWeight: '500',
transform: 'scale(1.002)',
},
'& td': {
padding: '0.75em 1.2em',
borderBottom: `1px solid ${cssVariableTheme.action.subtleBorder}`,
verticalAlign: 'middle',
fontSize: '0.875rem',
lineHeight: '1.5',
},
},
render: ({ props, useObservable, useHostProps, useRef }) => {
const { entry, rowComponents, columns, service } = props;
const [selection] = useObservable('isSelected', service.selection);
const [focus] = useObservable('focus', service.focusedEntry);
const isSelected = selection.includes(entry);
const isFocused = focus === entry;
const rowStyle = {};
if (props.selectedRowStyle && isSelected) {
Object.assign(rowStyle, props.selectedRowStyle);
}
else if (props.unselectedRowStyle && !isSelected) {
Object.assign(rowStyle, props.unselectedRowStyle);
}
if (isFocused && props.focusedRowStyle) {
Object.assign(rowStyle, props.focusedRowStyle);
}
else if (!isFocused && props.unfocusedRowStyle) {
Object.assign(rowStyle, props.unfocusedRowStyle);
}
useHostProps({
tabIndex: isFocused ? 0 : -1,
'data-spatial-nav-target': '',
'aria-selected': isSelected.toString(),
onpointerdown: () => {
service.setFocusAnchor();
},
onfocus: () => {
if (service.focusedEntry.getValue() !== entry) {
service.focusedEntry.setValue(entry);
}
if (!service.hasFocus.getValue()) {
service.hasFocus.setValue(true);
}
},
...(isSelected ? { 'data-selected': '' } : {}),
...(isFocused ? { 'data-focused': '' } : {}),
...(Object.keys(rowStyle).length > 0 ? { style: rowStyle } : {}),
});
const wrapperRef = useRef('wrapper');
if (isFocused) {
queueMicrotask(() => {
const el = wrapperRef.current;
if (!el)
return;
const hostEl = el.closest('shades-data-grid-row');
if (!hostEl)
return;
if (document.activeElement !== hostEl) {
hostEl.focus({ preventScroll: true });
}
const scrollContainer = hostEl.closest('shade-data-grid');
if (!scrollContainer)
return;
const headerHeight = hostEl.closest('table')?.querySelector('th')?.getBoundingClientRect().height || 42;
const footerHeight = scrollContainer.querySelector('shade-data-grid-footer')?.getBoundingClientRect().height || 42;
const containerRect = scrollContainer.getBoundingClientRect();
const rowRect = hostEl.getBoundingClientRect();
const rowTopInContainer = rowRect.top - containerRect.top;
const rowBottomInContainer = rowRect.bottom - containerRect.top;
if (rowTopInContainer < headerHeight) {
const scrollAdjustment = rowTopInContainer - headerHeight;
scrollContainer.scrollTo({
top: scrollContainer.scrollTop + scrollAdjustment,
behavior: 'instant',
});
}
else if (rowBottomInContainer > scrollContainer.clientHeight - footerHeight) {
const scrollAdjustment = rowBottomInContainer - (scrollContainer.clientHeight - footerHeight);
scrollContainer.scrollTo({
top: scrollContainer.scrollTop + scrollAdjustment,
behavior: 'instant',
});
}
});
}
return (createComponent(createComponent, null, columns.map((column, colIdx) => (createComponent("td", { ...(colIdx === 0 ? { ref: wrapperRef } : {}), onclick: (ev) => props.onRowClick?.(entry, ev), ondblclick: (ev) => props.onRowDoubleClick?.(entry, ev) }, rowComponents?.[column]?.(entry, { selection, focus }) ||
rowComponents?.default?.(entry, { selection, focus }) || (createComponent("span", null, typeof entry === 'object' && entry && column in entry
? entry[column]
: null)))))));
},
});
//# sourceMappingURL=data-grid-row.js.map