import { Component, HTMLAttributes, MaybeRef, MaybeRefOrGetter, Ref, TdHTMLAttributes, ThHTMLAttributes, VNode, VNodeProps, WatchSource } from 'vue'; import { OnyxI18n } from '../../../i18n/index.js'; import { Nullable } from '../../../types/index.js'; import { Orderable, OrderableMapping } from '../../../utils/feature.js'; import { OnyxMenuItem } from '../../OnyxNavBar/modules/index.js'; import { OnyxTableSlots, TableColumnGroup } from '../../OnyxTable/types.js'; import { DataGridRendererCell, DataGridRendererColumn, DataGridRendererRow } from '../OnyxDataGridRenderer/types.js'; import { ColumnTypesFromFeatures, DataGridEntry, DataGridMetadata } from '../types.js'; import { BASE_FEATURE } from './base/base.js'; import { DataGridAction } from './dataGridActions/types.js'; /** * Function type for modifying the normalized column configuration. */ export type ModifyColumns = OrderableMapping[]>; export type HeaderCellProps = { label: string; typeOptions?: TOptions; }; export type TypeRendererHeaderDef = Omit>, "key" | "props">; export type CellMetadata = { typeOptions?: TOptions; editable?: Nullable; }; export type TypeRendererCell = Omit>, "props">; /** * Defines how a specific column type should be rendered. */ export type TypeRenderer = { header?: TypeRendererHeaderDef; cell: TypeRendererCell; }; /** * Maps a "type" key to a column renderer. * `symbol` keys are intended for internal/helper columns. */ export type TypeRenderMap = Partial>>>; /** * ColumnConfig as it can be defined by the user. */ export type ColumnConfig, TTypes extends ColumnConfigTypeOption = never> = keyof TEntry | PublicNormalizedColumnConfig>>; export type DefaultSupportedTypes = keyof ReturnType>["typeRenderer"]; /** * Configuration for the column groupings. */ export type ColumnGroupConfig = Record; /** * Column config used internally and by the `modifyColumns` functions. */ export type InternalColumnConfig = Omit, "label" | "type"> & { type: ColumnTypeNormalized; /** * Attributes that should be set on all `td` elements */ tdAttributes?: TdHTMLAttributes; /** * Attributes that should be set on all `th` elements */ thAttributes?: ThHTMLAttributes; /** * After normalization the label is always defined. */ label: string; }; export type ColumnTypeNormalized = { name: TKey; options?: TOptions; }; export type ColumnConfigTypeOption = TKey | ColumnTypeNormalized; /** * Normalized column config for public/external usage. */ export type PublicNormalizedColumnConfig> = Pick, "width" | "key"> & { /** * The `label` is displayed in the data grid as column header. * If not defined, the key is used instead. */ label?: string; /** * The `type` of the column. It defines how the header and cells of a column is rendered. * If not defined the values are displayed as plain strings. */ type?: TTypes; /** * Key of the ColumnGroup that this column should be visually grouped in. * The columns have to be defined in the correct order. * So columns that should be grouped together have to actually be defined after each other. * * The label for the column group can be configured via the `columnGroups` prop. */ columnGroupKey?: keyof TColumnGroup; }; /** * Context that is passed to a feature when it is set up by the `useDataGridFeatures` composable. */ export type DataGridFeatureContext = { /** * Ref for the `async` state of the `OnyxDataGrid`. If `true` data mutations should be skipped, if they are expected to be handled by a backend. */ async: Readonly>; /** * The `i18n` object, which can be used to access messages, formatters and the current locale. */ i18n: OnyxI18n; /** * Whether the data grid should be shows as skeleton. */ skeleton: Readonly>; }; /** * Complete Type for a single data grid feature. */ export type DataGridFeature = TypeRenderMap, TFeatureName extends symbol = symbol> = (ctx: DataGridFeatureContext) => DataGridFeatureDescription; export type DataGridFeatureMutation = { func: (state: Readonly[]) => Readonly[] | void; } & Orderable; /** * Object that describes the hooks and properties of a datagrid feature. */ export type DataGridFeatureDescription = TypeRenderMap, TFeatureName extends symbol = symbol> = { /** * Unique name and identifier of the datagrid feature */ name: TFeatureName; /** * An array of reactive states that should trigger a datagrid re-generation */ watch?: WatchSource[]; /** * Use mutations to modify the dataset before it is mapped to the rendered rows and cells. */ mutation?: DataGridFeatureMutation; /** * With `enhanceCell` the render details for a cell can be modified. * The provided function is called for every cell, after the matching typeRenderer was applied. * */ enhanceCells?: { func: (cell: Readonly>, entry: Readonly, index: number) => { component?: DataGridRendererCell["component"]; props?: Partial["props"]>; tdAttributes?: Partial["tdAttributes"]>; }; } & Orderable; /** * Use `enhanceRow` the render details for a complete row can be modified. * The provided function is called for every row that is supposed to be rendered. */ enhanceRow?: { func: (row: Readonly>, entry: Readonly, index: number) => Partial>; } & Orderable; /** * Allows defining actions that are displayed in the "action" slot above the data grid. * Will be automatically wrapped into a "more" flyout if not all actions fit * into the available width. */ actions?: () => DataGridAction[]; /** * Defines a renderer for a column type. */ typeRenderer?: TTypeRenderer; /** * Allows modification of the normalized column configuration. * While the entries are passed as readonly, but the array itself can be modified. * To change entries, you need to clone them first: * * @example * ```ts * { * modifyColumns: [ { func: (config) => configs.map(column => ({ ...column, type: "newType" })) } ]; * } * ``` */ modifyColumns?: ModifyColumns; /** * Allows modification of the column groups. * * @example * ```ts * { * modifyColumnGroups: { * func: (groups, columns) => { * return groups.flatMap(group => { * return [ { ...group, class: 'my-custom-group-class' } ]; * }); * } * } * } * ``` */ modifyColumnGroups?: ModifyColumnGroups; /** * Allows the modification of the headers. */ header?: { /** * Adds header icon button(s). * `iconComponent` of an action is shown after the header label. * The components must be ARIA-conform buttons. */ actions?: (column: InternalColumnConfig, index: number, all: InternalColumnConfig[]) => { iconComponent?: Component | { iconComponent: Component; /** * Will force the icon component to be always shown in the header and not be put into the menu */ alwaysShowInHeader?: boolean; }; menuItems?: Component[]; showFlyoutMenu?: boolean; }[]; wrapper?: (column: InternalColumnConfig, index: number, all: InternalColumnConfig[]) => Component; }; scrollContainerAttributes?: () => DataGridScrollContainerAttributes; tableAttributes?: () => DataGridTableAttributes; /** * Optional table slots. */ slots?: DataGridFeatureSlots; }; export type DataGridScrollContainerAttributes = HTMLAttributes & Pick; export type DataGridTableAttributes = HTMLAttributes & Pick; export type DataGridFeatureSlots = Partial<{ [TSlotName in keyof Pick]: (slotContent: () => VNode[]) => Nullable[]; }>; export type InternalDataGridSlots = Partial VNode[]>>; export type DataGridFeatureOptions>, TWithAsync extends boolean = false> = { /** * Whether the feature is enabled by default. Can be overridden per column. * * @default true */ enabled?: MaybeRef; /** * Options for each column. Will override default/global options of the feature. */ columns?: MaybeRef<{ [TKey in keyof TEntry]?: TColumnOptions[TKey] & { /** * Whether the feature is enabled for this column. If unset, the default/global `enabled` option of this feature will be used. */ enabled?: boolean; }; } | undefined>; } & (TWithAsync extends true ? { /** * When async is `true`, then the internal data transformations of this feature are disabled and have to be performed manually. */ async?: boolean; } : unknown); /** * Helper function that checks the generics of the DataGridFeature type, without breaking type inference. * @example * ```ts * * const MY_FEATURE = Symbol("TABLE_HEADER_BUTTON"); * export const useDataGridHeaderButton = createFeature(() => { * return { * name: MY_FEATURE, * header: { * actions: (column) => [ * { * iconComponent: h('button', { onClick: (column) => console.log(`Clicked on ${column}`) },), * }, * ], * }, * }; * }); * ``` */ export declare function createFeature, T extends CheckDataGridFeature>(featureDefinition: T): T; type CheckDataGridFeature = T extends DataGridFeature, infer C> ? DataGridFeature, C> : never; export type UseDataGridFeaturesOptions> = { columnConfig: MaybeRefOrGetter[]>; i18n: OnyxI18n; columnGroups: MaybeRefOrGetter; async: Readonly>; skeleton: DataGridFeatureContext["skeleton"]; }; export declare const createTableColumnGroups: (columns?: InternalColumnConfig[], columnGroups?: ColumnGroupConfig) => TableColumnGroup[] | undefined; export type ModifyColumnGroups = { func: (groups: TableColumnGroup[], columns: InternalColumnConfig[]) => TableColumnGroup[]; }; /** * Uses the defined datagrid features to provide factory functions. * These factories are to be used to map data and configuration to `OnyxDataGridRenderer` properties. * The properties are then used to render the data grid. * * Make use of the `watchSources` to trigger re-rendering when state changes occur. * @example * ```vue * * * ``` */ export declare const useDataGridFeatures: , TColumnGroup extends ColumnGroupConfig, TTypes extends ColumnConfigTypeOption, T extends DataGridFeature[] | []>(featureDefinitions: T, { i18n, columnConfig, columnGroups, async, skeleton, }: UseDataGridFeaturesOptions) => { /** * Returns the merged attributes that should be applied to the tables scroll-container. */ createScrollContainerAttributes: () => never; /** * Returns the merged attributes that should be applied to the native element. */ createTableAttributes: () => never; /** Uses the column definition and available column group config to generate the column groups for the underlying OnyxTable */ createRendererColumnGroups: () => TableColumnGroup[]; /** Takes the column definition and maps all, calls mutation func and maps at the end to RendererCell */ createRendererRows: (entries: TEntry[]) => DataGridRendererRow[]; /** Takes the column definition and creates a RenderHeader for each, adds actions from features */ createRendererColumns: () => DataGridRendererColumn[]; /** Uses all features and generates the content of the additional table slots (headline, pagination etc.) for the underlying OnyxTable */ createSlots: () => Partial VNode[]>>; watchSources: WatchSource[]; }; export declare const useFeatureContext: (ctx: DataGridFeatureContext, options?: DataGridFeatureOptions) => { /** * Checks whether a data grid feature is enabled for a given column. * Considers the feature defaults as well as column-specific overrides. * * @default true */ isEnabled: import('vue').ComputedRef<(column?: PropertyKey) => boolean>; /** * Whether the feature only or all features have data transformations enabled. */ isAsync: import('vue').ComputedRef; }; export {};