import { LoadOptions } from '../limeobject'; /** * Layout configuration for a view * * ViewLayout defines how data should be organized and displayed in a view * component. It combines sorting options from {@link LoadOptions} with * custom layout-specific configuration. * * The layout object can be extended with custom properties to support * view-specific settings such as grouping, display mode, active filters, or * anything else a view has to remember between renders. * * @example Extended layout with custom properties * ```ts * import { ViewLayout } from '@limetech/lime-web-components'; * * // The generic parameter adds view-specific settings on top of `order`. It * // has to be a type alias rather than an interface, because `ViewLayout` * // constrains it to `Record`. * type ListDisplayOptions = { * displayMode: 'list' | 'grid' | 'compact'; * groupBy?: string; * showThumbnails: boolean; * }; * * const layout: ViewLayout = { * order: [{ name: 'createdtime', direction: 'DESC' }], * displayMode: 'list', * groupBy: 'category', * showThumbnails: true, * }; * ``` * * @example Using layout with LoadOptions * ```ts * import { PlatformServiceName, ViewLayout } from '@limetech/lime-web-components'; * * const layout: ViewLayout = { * order: [ * { name: 'priority', direction: 'DESC' }, * { name: 'name', direction: 'ASC' }, * ], * }; * * const repository = platform.get(PlatformServiceName.LimeObjectRepository); * * // `order` is shaped for LoadOptions, so it goes straight to the repository. * const response = await repository.loadObjects('company', { * order: layout.order, * limit: 50, * }); * * const companies = response.objects; * ``` * * @beta * @group Views */ export type ViewLayout = Record> = { /** * The order to sort objects by for this layout * * Defines one or more sort criteria that determine how items are ordered * in the view. Each criterion specifies a field name and sort direction. * When multiple criteria are provided, they are applied in sequence. * * The order is compatible with {@link LoadOptions} and can be passed * directly to repository load methods. * * @example Sorting by several properties * ```ts * import { ViewLayout } from '@limetech/lime-web-components'; * * // Criteria apply in sequence: objects are sorted by status first, then by * // priority within each status, and finally by creation time. * const layout: ViewLayout = { * order: [ * { name: 'status', direction: 'DESC' }, * { name: 'priority', direction: 'DESC' }, * { name: 'createdtime', direction: 'ASC' }, * ], * }; * ``` */ order?: LoadOptions['order']; } & T; /** * Interface for components that render a configuration UI for a {@link ViewLayout} * * This interface defines the contract for layout configuration components, * which allow users to customize how a view displays data. A configuration * component receives the current layout, shows controls for the settings it * supports, and emits `changeLayout` with the whole updated layout when the * user changes something. The parent replaces its layout state with what the * event carries. * * @example A configuration component * ```ts * import { * ViewLayout, * ViewLayoutConfigurationComponent, * } from '@limetech/lime-web-components'; * * type ListDisplayOptions = { * displayMode: 'list' | 'grid' | 'compact'; * groupBy?: string; * showThumbnails: boolean; * }; * * class DisplayConfiguration * implements ViewLayoutConfigurationComponent * { * public layout: ViewLayout; * public changeLayout: ViewLayoutConfigurationComponent['changeLayout']; * * private setDisplayMode(displayMode: ListDisplayOptions['displayMode']) { * this.changeLayout.emit({ ...this.layout, displayMode }); * } * * private toggleThumbnails() { * this.changeLayout.emit({ * ...this.layout, * showThumbnails: !this.layout.showThumbnails, * }); * } * * private groupBy(field: string | undefined) { * this.changeLayout.emit({ ...this.layout, groupBy: field }); * } * } * ``` * * @example Handling layout changes in the parent view * ```ts * import { ViewLayout } from '@limetech/lime-web-components'; * * type ListDisplayOptions = { * displayMode: 'list' | 'grid'; * }; * * let layout: ViewLayout = { * order: [{ name: 'name', direction: 'ASC' }], * displayMode: 'list', * }; * * // The configuration component hands the whole updated layout back on * // `detail`, so the view replaces its state rather than patching it. * const handleChangeLayout = ( * event: CustomEvent> * ) => { * layout = event.detail; * }; * ``` * * @beta * @group Views */ export interface ViewLayoutConfigurationComponent = Record> { /** * The current layout configuration * * This property receives the current layout state from the parent component. * The configuration UI should reflect these values and allow users to modify them. */ layout: ViewLayout; /** * Event emitter to emit layout change events * * When the user modifies layout settings, emit a new layout object through * this event emitter. The parent component will listen for these events and * update its layout state accordingly. * * The emitter's `emit()` method returns a CustomEvent that can be cancelled * by the parent if needed. * * @example Emitting a layout change * ```ts * import { * ViewLayout, * ViewLayoutConfigurationComponent, * } from '@limetech/lime-web-components'; * * class SortConfiguration implements ViewLayoutConfigurationComponent { * // The parent supplies the current layout and listens for the event. * public layout: ViewLayout; * public changeLayout: ViewLayoutConfigurationComponent['changeLayout']; * * private sortBy(name: string, direction: 'ASC' | 'DESC') { * this.changeLayout.emit({ * ...this.layout, * order: [{ name, direction }], * }); * } * } * ``` */ changeLayout: { emit: (data?: ViewLayout) => CustomEvent>; }; }