{"version":3,"file":"data-view.cjs","sources":["../../../components/data-view/data-view.tsx"],"sourcesContent":["'use client';\n\nimport {\n  getCoreRowModel,\n  getExpandedRowModel,\n  getSortedRowModel,\n  RowSelectionState,\n  Updater,\n  useReactTable,\n  VisibilityState\n} from '@tanstack/react-table';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { DataViewClearFilters } from './components/clear-filters';\nimport { DataViewCustom } from './components/custom';\nimport { DisplayAccess } from './components/display-access';\nimport { DisplayControls } from './components/display-controls';\nimport { DataViewEmptyState } from './components/empty-state';\nimport { Filters } from './components/filters';\nimport { DataViewList } from './components/list';\nimport { DataViewSearch } from './components/search';\nimport { DataViewTimeline } from './components/timeline';\nimport { Toolbar } from './components/toolbar';\nimport { DataViewZeroState } from './components/zero-state';\nimport { DataViewContext } from './context';\nimport {\n  DataViewContextType,\n  DataViewField,\n  DataViewProps,\n  defaultGroupOption,\n  GroupedData,\n  InternalQuery,\n  TableQueryUpdateFn\n} from './data-view.types';\nimport {\n  hasActiveQuery as computeHasActiveQuery,\n  createRowIdResolver,\n  fieldsToColumnDefs,\n  getDefaultTableQuery,\n  getFilteredRowModelWithFlatRows,\n  getInitialColumnVisibility,\n  groupData,\n  hasQueryChanged,\n  isGroupRowData,\n  queryToTableState,\n  transformToDataViewQuery\n} from './utils';\n\nfunction DataViewRoot<TData>({\n  data = [],\n  fields,\n  query,\n  mode = 'client',\n  isLoading = false,\n  totalRowCount,\n  loadingRowCount = 3,\n  defaultSort,\n  children,\n  onTableQueryChange,\n  onLoadMore,\n  onRowClick,\n  onColumnVisibilityChange,\n  onRowSelectionChange,\n  getRowId,\n  views,\n  defaultView,\n  view,\n  onViewChange,\n  groupByResolvers\n}: React.PropsWithChildren<DataViewProps<TData>>) {\n  const defaultTableQuery = useMemo(\n    () => getDefaultTableQuery(defaultSort, query),\n    [defaultSort, query]\n  );\n\n  // Active view (controlled / uncontrolled).\n  const isViewControlled = view !== undefined;\n  const [internalActiveView, setInternalActiveView] = useState<\n    string | undefined\n  >(defaultView ?? views?.[0]?.value);\n  const activeView = isViewControlled ? view : internalActiveView;\n  const setActiveView = useCallback(\n    (next: string) => {\n      if (!isViewControlled) setInternalActiveView(next);\n      onViewChange?.(next);\n    },\n    [isViewControlled, onViewChange]\n  );\n\n  // Per-view field overrides registered by mounted renderers.\n  const [fieldsByView, setFieldsByView] = useState<\n    Record<string, DataViewField<TData>[]>\n  >({});\n\n  const registerFieldsForView = useCallback(\n    (name: string, override: DataViewField<TData>[]) => {\n      setFieldsByView(prev => {\n        if (prev[name] === override) return prev;\n        return { ...prev, [name]: override };\n      });\n      return () => {\n        setFieldsByView(prev => {\n          if (!(name in prev)) return prev;\n          const next = { ...prev };\n          delete next[name];\n          return next;\n        });\n      };\n    },\n    []\n  );\n\n  const effectiveFields = useMemo(() => {\n    if (activeView && fieldsByView[activeView]) return fieldsByView[activeView];\n    return fields;\n  }, [activeView, fieldsByView, fields]);\n\n  const initialColumnVisibility = useMemo(\n    () => getInitialColumnVisibility(fields),\n    [fields]\n  );\n\n  const [columnVisibility, setColumnVisibilityState] =\n    useState<VisibilityState>(initialColumnVisibility);\n\n  const handleColumnVisibilityChange = useCallback(\n    (value: Updater<VisibilityState>) => {\n      setColumnVisibilityState(prev => {\n        const newValue = typeof value === 'function' ? value(prev) : value;\n        onColumnVisibilityChange?.(newValue);\n        return newValue;\n      });\n    },\n    [onColumnVisibilityChange]\n  );\n\n  // Lifted so a selection change invalidates the memoized context value; the\n  // table instance identity is stable and can't do it.\n  const [rowSelection, setRowSelectionState] = useState<RowSelectionState>({});\n\n  const handleRowSelectionChange = useCallback(\n    (value: Updater<RowSelectionState>) => {\n      setRowSelectionState(prev => {\n        const newValue = typeof value === 'function' ? value(prev) : value;\n        onRowSelectionChange?.(newValue);\n        return newValue;\n      });\n    },\n    [onRowSelectionChange]\n  );\n\n  const [tableQuery, setTableQuery] =\n    useState<InternalQuery>(defaultTableQuery);\n\n  const oldQueryRef = useRef<InternalQuery | null>(null);\n\n  const reactTableState = useMemo(\n    () => queryToTableState(tableQuery),\n    [tableQuery]\n  );\n\n  const onDisplaySettingsReset = useCallback(() => {\n    setTableQuery(prev => ({\n      ...prev,\n      ...defaultTableQuery,\n      sort: [defaultSort],\n      group_by: [defaultGroupOption.id]\n    }));\n    handleColumnVisibilityChange(initialColumnVisibility);\n  }, [\n    defaultSort,\n    defaultTableQuery,\n    initialColumnVisibility,\n    handleColumnVisibilityChange\n  ]);\n\n  const group_by = tableQuery.group_by?.[0];\n\n  // Column defs are derived from EFFECTIVE fields so toolbar + headless filter/\n  // sort/visibility reflect the active view's metadata override.\n  const columnDefs = useMemo(\n    () => fieldsToColumnDefs<TData>(effectiveFields, tableQuery.filters),\n    [effectiveFields, tableQuery.filters]\n  );\n\n  const groupedData = useMemo(\n    () => groupData(data, group_by, effectiveFields, groupByResolvers),\n    [data, group_by, effectiveFields, groupByResolvers]\n  );\n\n  useEffect(() => {\n    if (\n      tableQuery &&\n      onTableQueryChange &&\n      hasQueryChanged(oldQueryRef.current, tableQuery) &&\n      mode === 'server'\n    ) {\n      onTableQueryChange(transformToDataViewQuery(tableQuery));\n      oldQueryRef.current = tableQuery;\n    }\n  }, [tableQuery, onTableQueryChange, mode]);\n\n  const resolveRowId = useMemo(() => createRowIdResolver(getRowId), [getRowId]);\n\n  const table = useReactTable({\n    data: groupedData as unknown as TData[],\n    columns: columnDefs,\n    getRowId: resolveRowId,\n    // Group rows render without cells, so they have no checkbox — keeping them\n    // unselectable keeps `rowSelection` one key per data row.\n    enableRowSelection: row => !isGroupRowData(row.original),\n    getCoreRowModel: getCoreRowModel(),\n    getExpandedRowModel: getExpandedRowModel(),\n    getSubRows: row => (row as unknown as GroupedData<TData>)?.subRows || [],\n    getSortedRowModel: mode === 'server' ? undefined : getSortedRowModel(),\n    getFilteredRowModel:\n      mode === 'server' ? undefined : getFilteredRowModelWithFlatRows(),\n    manualSorting: mode === 'server',\n    manualFiltering: mode === 'server',\n    onColumnVisibilityChange: handleColumnVisibilityChange,\n    onRowSelectionChange: handleRowSelectionChange,\n    globalFilterFn: mode === 'server' ? undefined : 'auto',\n    initialState: { columnVisibility: initialColumnVisibility },\n    filterFromLeafRows: true,\n    state: {\n      ...reactTableState,\n      columnVisibility,\n      rowSelection,\n      expanded:\n        group_by && group_by !== defaultGroupOption.id ? true : undefined\n    }\n  });\n\n  const updateTableQuery = useCallback((fn: TableQueryUpdateFn) => {\n    setTableQuery(prev => fn(prev));\n  }, []);\n\n  const loadMoreData = useCallback(() => {\n    if (mode === 'server' && onLoadMore) onLoadMore();\n  }, [mode, onLoadMore]);\n\n  const searchQuery = query?.search;\n  useEffect(() => {\n    if (searchQuery) {\n      setTableQuery(prev => ({ ...prev, search: searchQuery }));\n    }\n  }, [searchQuery]);\n\n  const rowCount = (() => {\n    try {\n      return table.getRowModel().rows.length;\n    } catch {\n      return data.length;\n    }\n  })();\n\n  const hasData = rowCount > 0 || isLoading;\n\n  const hasActiveQueryFlag = useMemo(\n    () => computeHasActiveQuery(tableQuery, defaultSort),\n    [tableQuery, defaultSort]\n  );\n\n  const isZeroState = !hasData && !hasActiveQueryFlag;\n  const isEmptyState = !hasData && hasActiveQueryFlag;\n\n  // The filter bar shows whenever there's data OR an active query. The pure\n  // zero state (no data + no query) keeps the surface clean.\n  const shouldShowFilters = hasData || hasActiveQueryFlag;\n\n  const contextValue: DataViewContextType<TData> = useMemo(\n    () => ({\n      table,\n      fields: effectiveFields,\n      rootFields: fields,\n      data,\n      mode,\n      isLoading,\n      loadMoreData,\n      tableQuery,\n      updateTableQuery,\n      onDisplaySettingsReset,\n      defaultSort,\n      totalRowCount,\n      loadingRowCount,\n      onRowClick,\n      shouldShowFilters,\n      columnVisibility,\n      setColumnVisibility: handleColumnVisibilityChange,\n      rowSelection,\n      setRowSelection: handleRowSelectionChange,\n      views,\n      activeView,\n      setActiveView,\n      registerFieldsForView,\n      hasData,\n      hasActiveQuery: hasActiveQueryFlag,\n      isZeroState,\n      isEmptyState\n    }),\n    [\n      table,\n      effectiveFields,\n      fields,\n      data,\n      mode,\n      isLoading,\n      loadMoreData,\n      tableQuery,\n      updateTableQuery,\n      onDisplaySettingsReset,\n      defaultSort,\n      totalRowCount,\n      loadingRowCount,\n      onRowClick,\n      shouldShowFilters,\n      columnVisibility,\n      handleColumnVisibilityChange,\n      rowSelection,\n      handleRowSelectionChange,\n      views,\n      activeView,\n      setActiveView,\n      registerFieldsForView,\n      hasData,\n      hasActiveQueryFlag,\n      isZeroState,\n      isEmptyState\n    ]\n  );\n\n  return <DataViewContext value={contextValue}>{children}</DataViewContext>;\n}\n\nDataViewRoot.displayName = 'DataView';\n\n// biome-ignore lint/suspicious/noShadowRestrictedNames: public component name intentionally matches the package export\nexport const DataView = Object.assign(DataViewRoot, {\n  List: DataViewList,\n  Timeline: DataViewTimeline,\n  Custom: DataViewCustom,\n  DisplayAccess: DisplayAccess,\n  EmptyState: DataViewEmptyState,\n  ZeroState: DataViewZeroState,\n  ClearFilters: DataViewClearFilters,\n  Toolbar: Toolbar,\n  Search: DataViewSearch,\n  Filters: Filters,\n  DisplayControls: DisplayControls\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgDA;;;AA4BE;AACA;;AAIA;AAEI;;AACA;AACF;;;;;AAYI;AAA6B;;AAE/B;AACA;;AAEI;AAAqB;AACrB;AACA;AACA;AACF;AACF;;AAKJ;AACE;AAA4C;AAC5C;;AAGF;;AAQA;;AAGM;AACA;AACA;AACF;AACF;;;;AAQF;;AAGM;AACA;AACA;AACF;AACF;;AAOF;AAEA;AAKA;AACE;AACE;AACA;;AAEA;AACD;;AAEH;;;;;AAKC;;;;;AAWD;;AAME;;AAGE;;AAGA;AACA;;;AAIJ;;AAGE;AACA;AACA;;;;;;;AAOA;AACA;;;AAIA;AACA;;AAEA;AACA;AACA;AACE;;;AAGA;AAED;AACF;AAED;;;AAIA;AACE;AAAqC;AACvC;AAEA;;;AAGI;;AAEJ;AAEA;AACE;;;AAEE;;;;AAKJ;;AAOA;AACA;;;AAIA;AAEA;;AAGI;AACA;;;;;;;;;;;;;;AAcA;;AAEA;;;;;;AAMA;;;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA;;AAIL;AAEA;AAEA;;AAEE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACD;;"}