UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

113 lines 5.76 kB
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