import { FluentComponent } from '../core/fluent-component'
import { createUniversalComponent } from '../core/component-factory'
class FluentTableInternal extends FluentComponent {
static tag = 'fluent-table'
static override get observedAttributes() {
return ['sortable']
}
override connectedCallback() {
super.connectedCallback()
this.addEventListener('click', (e) => {
const path = (e.composedPath && e.composedPath()) || []
const target = path.find((el: any) => el?.matches && el.matches('th[aria-sort]')) as HTMLElement | undefined
if (target && this.hasAttribute('sortable')) {
const slot = this.shadowRootRef.querySelector('slot[name="thead"]') as HTMLSlotElement | null
const headers = slot ? slot.assignedElements() : []
const index = headers.indexOf(target)
const dir = target.getAttribute('aria-sort') === 'ascending' ? 'descending' : 'ascending'
target.setAttribute('aria-sort', dir)
this.sortByIndex(index, dir === 'ascending')
}
})
}
render() {
const sortable = this.hasAttribute('sortable')
this.shadowRootRef.innerHTML = `
`
if (sortable) {
const slot = this.shadowRootRef.querySelector('slot[name="thead"]') as HTMLSlotElement | null
slot?.assignedElements().forEach(el => el.setAttribute('aria-sort', 'none'))
}
}
constructor() {
super()
this.recipe = {
base: { display: 'block', width: '100%' },
selectors: {
'.tbl': { width: '100%', borderCollapse: 'collapse' },
'thead': { position: 'sticky', top: '0', background: 'light-dark(var(--fluent-color-neutral-100), var(--fluent-color-neutral-800))' },
'th, td': { border: '1px solid var(--fluent-color-neutral-300)', padding: '0.5rem', textAlign: 'left' }
}
}
}
private sortByIndex(index: number, asc: boolean) {
const bodySlot = this.shadowRootRef.querySelector('slot[name="tbody"]') as HTMLSlotElement | null
if (!bodySlot) return
const rows = bodySlot.assignedNodes().filter(n => (n as Element).nodeType === 1) as HTMLElement[]
rows.sort((a, b) => {
const ta = a.querySelectorAll('td')[index]?.textContent || ''
const tb = b.querySelectorAll('td')[index]?.textContent || ''
return asc ? ta.localeCompare(tb) : tb.localeCompare(ta)
})
rows.forEach(r => r.parentElement?.appendChild(r))
}
}
export const FluentTable = createUniversalComponent({
tag: 'fluent-table',
class: FluentTableInternal,
events: ['sort-change']
})
if (typeof window !== 'undefined') {
if (!customElements.get(FluentTableInternal.tag)) {
customElements.define(FluentTableInternal.tag, FluentTableInternal)
}
}