import type { Repository } from '../../core/repository'; import type { BadgeShape, BadgeVariant } from '../badge'; import type { ButtonSize, ButtonVariant } from '../button'; import type { IconProp } from '../icon'; import type { Snippet } from 'svelte'; export type WithId = { id: string; }; export type IAnyTableColumn = IOneOfTableColumn; export type IOneOfTableColumn = ITableBadgeColumn | ITableButtonColumn | ITableByColumn | ITableCheckboxColumn | ITableIconColumn | ITableImageColumn | ITableMoveRowColumn | ITableSnippetColumn | ITableTextColumn; export type TableColumnType = 'actions' | 'badge' | 'button' | 'by' | 'checkbox' | 'icon' | 'image' | 'move-row' | 'snippet' | 'text'; interface ITableColumnBase { type: TableColumnType; /** * Preferred column width. Under the table's `table-layout: auto` this is a suggestion: content can push a column wider, and a column with no width of its * own is left with whatever the others do not claim. Use `minCssWidth` for a width the browser must honour. */ cssWidth?: string; /** Floor the column will not shrink below, taken out of columns whose `cssWidth` is merely a suggestion. Use it on the column that must keep space. */ minCssWidth?: string; centered?: boolean; } export interface ITableColumn extends ITableColumnBase { id: keyof T; title: string; onSort?: ((state: TableColumnSortDirection) => Promise) | null; sortDirection?: TableColumnSortDirection; sortLabelsOverride?: { asc: string; desc: string; }; onClick?: ((item: T) => Promise | void) | null; hidden?: boolean; hideable?: boolean; } export interface ITableActionsColumn extends ITableColumnBase { type: 'actions'; } export interface ITableBadgeColumn extends ITableColumn { type: 'badge'; variantFactory?: ((item: T) => BadgeVariant) | null; valueFactory?: ((item: T) => string) | null; /** Stretch the badge to fill the column width. @default false */ fullWidth?: boolean; /** Corner style of the rendered badge. @default 'pill' */ shape?: BadgeShape; } export interface ITableByColumn extends ITableColumn { type: 'by'; /** The "when" — an ISO date string. Return null from the factory to render the person's name instead of a date. */ valueFactory?: ((item: T) => string | null) | null; byValueFactory?: ((item: T) => { id: string; name: string; handle: string; image: string | null; } | null) | null; /** Returns href for the person link — wraps the avatar in date mode, the name in name mode. If not provided, no link is rendered. */ hrefFactory?: ((by: { id: string; handle: string; }) => string) | null; /** Called when the user clicks the person link. Use for SPA navigation. */ onNavigate?: ((by: { id: string; handle: string; }) => void) | null; /** When the person-name link shows its underline: only on hover, permanently, or not at all. @default 'hover' */ underline?: 'hover' | 'always' | 'never'; } export interface ITableButtonColumn extends ITableColumn { type: 'button'; styleFactory?: ((item: T) => ButtonVariant) | null; sizeFactory?: ((item: T) => ButtonSize) | null; valueFactory?: ((item: T) => string) | null; } export interface ITableCheckboxColumn extends ITableColumnBase { type: 'checkbox'; } export interface ITableIconColumn extends ITableColumn { type: 'icon'; iconFactory?: ((item: T) => IconProp) | null; tooltipTextFactory?: ((item: T) => string) | null; } export interface ITableImageColumn extends ITableColumn { type: 'image'; valueFactory?: ((item: T) => string) | null; format?: 'circle' | 'square-contain' | 'square-cover' | 'vertical-cover' | 'horizontal-cover'; coverAspectRatio?: number; sizeCss?: string; } export interface ITableMoveRowColumn extends ITableColumnBase { type: 'move-row'; disableFactory?: (() => boolean) | null; } export interface ITableSnippetColumn extends ITableColumn { type: 'snippet'; /** Render-prop snippet receiving the row item. Use for rich / custom cell composition without creating a separate cell component. */ cell: Snippet<[T]>; } export interface ITableTextColumn extends ITableColumn { type: 'text'; format?: 'text' | 'html' | 'money' | 'date' | 'date-time' | null; /** @default 1 */ maxLines?: number | 'single-line-no-trim' | null; valueFactory?: ((item: T) => string) | null; } export type TableItemAction = { title: string; icon?: IconProp; action: (item: T) => void; visibilityFactory?: (item: T) => boolean; }; export type TableStyles = { /** Stick the table header to the scrolling ancestor. @default false */ stickyHeader?: boolean; /** Show the per-row actions popover above the row instead of below. @default false */ actionsPopoverTopDirection?: boolean; /** Row + cell padding preset. @default 'md' */ size?: 'sm' | 'md'; /** Alternate row backgrounds for readability on long lists. @default false */ zebra?: boolean; /** Visual chrome around the table. `'plain'` blends with surrounding layout; `'card'` adds a bordered, rounded panel. @default 'plain' */ variant?: 'plain' | 'card'; }; export type TableOrderByState = { orderBy: TOrder; ascendingOrder: boolean; }; export type PageQuery = { ascendingOrder: boolean; fetchTotal: boolean; orderBy: TOrder; page: number; perPage: number; }; export type SelectionSettings = { preserveSelection?: boolean; repository?: Repository; }; export type TableColumnSortDirection = 'none' | 'asc' | 'desc'; export type ColumnsConfig = Array<{ id: string; hidden: boolean; }>; export {};