Vanilla Example: Basic

ts
import { atom } from 'nanostores'

import {
  type RowData,
  type TableOptions,
  type TableOptionsResolved,
  createTable,
} from '@tanstack/table-core'

export const flexRender = <TProps extends object>(comp: any, props: TProps) => {
  if (typeof comp === 'function') {
    return comp(props)
  }
  return comp
}

export const useTable = <TData extends RowData>(
  options: TableOptions<TData>,
) => {
  // Compose in the generic options to the user options
  const resolvedOptions: TableOptionsResolved<TData> = {
    state: {}, // Dummy state
    onStateChange: () => {}, // noop
    renderFallbackValue: null,
    ...options,
  }

  // Create a new table
  const table = createTable<TData>(resolvedOptions)

  // By default, manage table state here using the table's initial state
  const state = atom(table.initialState)

  // Subscribe to state changes
  state.subscribe((currentState) => {
    table.setOptions((prev) => ({
      ...prev,
      ...options,
      state: {
        ...currentState,
        ...options.state,
      },
      // Similarly, we'll maintain both our internal state and any user-provided state
      onStateChange: (updater) => {
        if (typeof updater === 'function') {
          const newState = updater(currentState)
          state.set(newState)
        } else {
          state.set(updater)
        }
        options.onStateChange?.(updater)
      },
    }))
  })

  return table
}
import { atom } from 'nanostores'

import {
  type RowData,
  type TableOptions,
  type TableOptionsResolved,
  createTable,
} from '@tanstack/table-core'

export const flexRender = <TProps extends object>(comp: any, props: TProps) => {
  if (typeof comp === 'function') {
    return comp(props)
  }
  return comp
}

export const useTable = <TData extends RowData>(
  options: TableOptions<TData>,
) => {
  // Compose in the generic options to the user options
  const resolvedOptions: TableOptionsResolved<TData> = {
    state: {}, // Dummy state
    onStateChange: () => {}, // noop
    renderFallbackValue: null,
    ...options,
  }

  // Create a new table
  const table = createTable<TData>(resolvedOptions)

  // By default, manage table state here using the table's initial state
  const state = atom(table.initialState)

  // Subscribe to state changes
  state.subscribe((currentState) => {
    table.setOptions((prev) => ({
      ...prev,
      ...options,
      state: {
        ...currentState,
        ...options.state,
      },
      // Similarly, we'll maintain both our internal state and any user-provided state
      onStateChange: (updater) => {
        if (typeof updater === 'function') {
          const newState = updater(currentState)
          state.set(newState)
        } else {
          state.set(updater)
        }
        options.onStateChange?.(updater)
      },
    }))
  })

  return table
}