-
Notifications
You must be signed in to change notification settings - Fork 4
Tile Manager Specification
- Tile Manager Specification
Team name: CodeX
Developer names: Maria Tsvyatkova, Ivaylo Barakov
Designer name: Silvia Ivanova
- Damyan Petev
- Svilen Dimchevski
- Radoslav Karaivanov
- Radoslav Mirchev
Version | Author | Date | Notes |
---|---|---|---|
1 | Maria Tsvyatkova | 2024-09-19 | Initial draft |
1.1 | Maria Tsvyatkova | 2024-10-09 | Updated user stories |
1.2 | Ivaylo Barakov | 2025-02-03 | Update Functionality with resizing draft |
1.3 | Galina Edinakova | 2025-02-07 | IgcTileManagerComponent API update |
1.4 | Radoslav Karaivanov | 2025-02-27 | Updated with latest implementation changes |
The igc-tile-manager component enables developers to layout different content inside of tile containers. The tile manager will try to position and arrange those tile containers based on either user provided configuration or its default one. Additional features such a tile drag rearrangement, resizing of tiles, maximized and fullscreen states can be enabled for users to interact with.
Typical use-cases for the tile manager are product and image galleries, dashboards for reports or metrics and bespoke UI scenarios.
The tile manager provides a base tile layout behavior based on the native CSS Grid specification. Tiles accept slotted content and the manager will arrange them based on its and their configuration. Each tile can be configured and sized independently of each other. Features such as rearranging and resizing tiles are also available after configuration. Additional states such as maximized and fullscreen mode can be enabled/disabled per tile, with a default UI that can be customized.
The igc-tile-manager
component must:
- support rendering user-provided tiles and content inside those tiles.
- expose an API to configure the underlying CSS Grid in order to accommodate specific user scenarios.
- expose an API to enable dragging and rearrangement of tiles.
- expose and API to enable resizing of tiles.
- expose an API to serialize the configuration of its tiles into a standard JSON format, so it can be saved either locally or remotely.
- expose an API to deserialize a previously exported configuration and apply it to its current tile descendants.
- follow WAI-ARIA best practices.
The igc-tile
component must:
- expose an API to configure its initial position and layout inside the tile manager.
- support customization of the its content and DOM parts. Users must be able to customize different parts of the tile (header, action buttons, etc) with slots.
- provide a default UI for maximized and fullscreen states as well as expose API to control those states and modify the default UI associated with them.
- participate in tile drag rearrangement when configured by the tile manager.
- participate in tile resizing when configured by the tile manager.
- expose an API to disable resize behavior per tile.
As an end-user I expect to be able to:
- resize a tile by dragging its corner, in order to better view its content or highlight the importance of its content.
- reorder tiles via drag and drop, in order to control the layout and information flow in the tile manager.
- see a preview of a drag and drop operation, in order to understand the impact of placing the tile at the position.
- maximize a tile, in order to focus attention on its content.
- have the tiles inside the tile manager rearrange themselves when the tile manager or the viewport dimensions are changed so I can have a responsive view of the content.
As a developer I expect to be able to:
- declaratively define tiles and their content inside the tile manager.
- define the number of columns, so that I can control the maximum number of tiles which can be displayed in a given row.
- specify how many rows and columns a tile should span, so that I can display tiles with different sizes.
- have an option to allow tile dragging only by their header, so that I can let users interact with the tile's content.
- have an option to allow tile dragging by initiating a drag operation on the tile itself (header + content).
- add/remove tile with different sizes dynamically and the tiles should rearrange minimizing the empty space between them, so that I can have a compact layout.
- save the current layout, so that I can reload it when needed.
- restrict the end user from resizing a specific tile, so that I can ensure it is always displayed as I intended.
- have a completely customizable tile header, so that I can modify its content based on my application logic.
- expose a mode where the layout has a maximized tile and a list of minimized tiles beside it.
- set the size and position of the maximized tile and minimized tiles list, so that I can control the arrangement of tiles in the layout. Default maximized left.
- define the content displayed in each tile based on its current state, so that I can customize the appearance of tiles in minimized, minimized-expanded, maximized, and normal states.
- use a custom style for the tile drag preview, so that I can provide a customized view of a tile while being dragged.
- be able to drill into a minimized tile without making it the maximized tile, so that I can see tile's content without changing the currently maximized tile. (This is applicable if we have both minimized and minimized-expanded states)
The tile manager wraps its projected tile components into an internal
Dragging behavior in the tile manager is enabled by setting the dragMode property ot one of the following values:
- none - Dragging of tiles is disabled.
- tile-header - Dragging is initiated by a click inside the title slot of the tile header.
- tile - Dragging is initiated by a click inside the tile.
Important
Since both drag & resize operations are based on the native PointerEvent API, in order to keep user interaction consistent between resize and drag, when a click is initiated on a resize adorner it will take precedence over the dragging behavior.
Dragging is also ignored on pointer interaction with any elements inside the tile actions slot which includes the default UI for maximize and fullscreen as well as any user provided content.
When initiating a drag operation a ghost copy of the dragged tile is created while the original element is transitioned into a drag state. While dragging the ghost copy around the tile manager for each pointer enter event into a tile, the original copy will switch position and relevant properties (colStart, rowStart) with the touched tile.
This will be valid for all tiles along the path of the drag operation and since the CSS Grid container is set to dense there could be general shift between the a group of tiles if the dragged tile cannot fit into the new position.
Additionllay
Important
asdsa
- While the tile is in maximized or fullscreen states, the tile cannot be dragged.
Resizing in the tile manager is a functionality that allows tiles to be resized using three different resize adorners.
- Side Adorner - Adjusts width by modifying the column span.
- Bottom Adorner - Adjusts height by modifying the row span.
- Corner Adorner - Adjusts both width and height simultaneously.
To achieve smooth resizing, a ghost element is used instead of directly modifying the tile's dimensions. It appears on top of the original tile with it's current dimensions when resizing starts and updates in real time as the user drags any of the resize handles. This approach is known as deferred resizing, meaning that no changes are applied to the actual tile until resizing is complete.
Tiles always resize in alignment with the CSS grid, meaning they can only expand or shrink in full grid units. When resizing horizontally or vertically, the ghost will snap to the next column or row once it reaches the halfway point of that unit. If the resize remains below the halfway threshold when resizing is completed, the tile maintains its current span. This prevents partial resizing and ensures that tiles conform to the grid's structure.
Additionally, grid gaps (grid-gap values) are taken into account during resizing, ensuring that the spacing between tiles remains consistent.
Once the user releases the resize handle, the final grid-row and grid-column spans are calculated based on the ghost's position and size. At this point, the ghost element is removed, and the actual tile is updated to reflect its new size.
Note
If the ghost exceeds the available grid space, it will be resized to the largest possible span within the grid's limits.
The CSS grid automatically rearranges itself when a tile changes size, ensuring that there is minimal empty space. Thats why expanding a tile may push adjacent tiles into new positions, while shrinking creates gaps that other tiles may fill dynamically. This ensures that the tile manager remains as compact as possible without any overlapping tiles and all movements remain within the defined grid structure.
The resize process emits three key events corresponding to pointer interactions:
- igcResizeStart - fired on pointerdown when the user initiates resizing by clicking any of the resize handles
- igcResize - fired on pointermove, continuously updating the ghost element’s size as the user resizes
- igcResizeEnd - fired on lostpointercapture when resizing ends, applying the new dimensions to the tile and removing the ghost element
- igcResizeCancel - fired on pressing Escape during a resize operation. Doing so will cancel the current resize operation, remove the ghost element and leave the state of the tile as it was before the start of the operation.
- Developers can override a tile resize behavior by setting disableResizing to true.
- While the tile is in maximized or fullscreen states, the tile cannot be resized.
- The resize adorners of the tile can be customized through their slots. See the API table below for information.
There are several constraints and limitations in the resizing process:
- A tile cannot be resized smaller than the tile manager's defined minimum column and row values (
minColWidth
,minRowHeight
) - A tile cannot be resized beyond the maximum available space in the CSS grid. If a tile starts at a certain column/row and the user attempts to resize it beyond the visible grid area, it will only expand up to the maximum available columns/rows from its starting position.
Note
E.g. if there are 7 columns and a tile starts at column 4, resizing it to 2000px width will not extend beyond column 7, as that is the maximum available space.
No specific implementation details are required. Tiles and their content are user controlled, so localization handling is left to the user as an application scenario.
Note
This may not be entirely true, since the tile headers have default icon-buttons which should have an aria-label.
Key | Description |
---|---|
Escape | Applicable only during drag and resize interactions. Cancels the current interaction. |
- Pressing Escape during resize will cancel the current resize operation, remove the ghost element and leave the state of the tile as it was before the start of the operation.
- Pressing Escape during drag will unwind all the rearranged tiles during the operation back to their initial state and remove the ghost element.
Property | Attribute | Reflected | Property Type | Default | Description |
---|---|---|---|---|---|
columnCount | column-count | No | number | 0 | Sets the number of columns in the tile manager. Settings this to 0 or a negative value |
minColumnWidth | min-column-width | No | string | - | Sets the minimum width for a column in the tile manager |
minRowHeight | min-row-height | No | string | - | Sets the minimum height for a row in the tile manager |
gap | gap | No | string | - | Sets the CSS Grid gap size |
tiles | - | No | readonly Array<IgcTileComponent> | - | Get the underlying tiles sorted by their position |
dragMode | drag-mode | No | none | tile-header | tile | none | |
resizeMode | resize-mode | No | none | hover | always | none |
Name | Type signature | Description |
---|---|---|
saveLayout | (): string | Returns the current tiles layout configuration an properties serialized as a JSON string |
loadLayout | (data: string): void | Loads a previously serialized configuration and attempts to restore the state to the current tiles |
? setFullscreen ? | (tile: string | IgcTileComponent): void |
Name | Cancellable | Parameters | Description |
---|---|---|---|
igcTileDragStart | true | IgcTileComponent | Emitted when a drag operation is initiated |
igcTileDragEnd | false | IgcTileComponent | Emitted when a drag operation is completed |
igcTileDragCancel | false | IgcTileComponent | Emitted when a drag operation is discarded |
igcTileResizeStart | true | IgcTileComponent | Emitted when a resize operation is initiated |
igcTileResizeEnd | false | IgcTileComponent | Emitted when a resize operation is completed |
igcTileResizeCancel | false | IgcTileComponent | Emitted when a resize operation is discarded |
igcTileFullscreen | true | { IgcTileComponent, state: boolean} | Emitted when a tile is entering into fullscreen state through the default tile header UI |
igcTileMaximized | true | { IgcTileComponent state: boolean } | Emitted a a tile maximized state i toggled through the default tile header UI |
Note
Possibly stop the internal event from propagating up the DOM tree.
Name | Description |
---|---|
(default) | Default slot for slotting tile components into the manager |
Name | Description |
---|---|
base | The tile manager internal CSS Grid container |
Name | Description |
---|
Property | Attribute | Reflected | Property Type | Default | Description |
---|---|---|---|---|---|
tileId | tile-id | Yes | string | - | A unique identifier for the tile. Used for serialization and deserialization. Autogenerated if not set |
colStart | col-start | No | number | - | The column in the CSS Grid container where the tile will start. If not set, it implicitly fallbacks to 'auto' |
colSpan | col-span | No | number | 1 | The number of CSS columns the tile will span. Setting values which are less than 1 are rejected and coerced to 1 |
rowStart | row-start | No | number | - | The row in the CSS Grid container where the tile will start. If not set, it implicitly fallbacks to 'auto' |
rowSpan | row-span | No | number | 1 | The number of CSS rows the tile will span. Setting values which are less than 1 are rejected and coerced to 1 |
position | position | No | number | -1 | |
disableFullscreen | disable-fullscreen | Yes | boolean | false | When set hides the default fullscreen action button |
disableMaximize | disable-maximize | Yes | boolean | false | When set hides the default maximize toggle action button |
disableResize | disable-resize | Yes | boolean | false | When set, resize behavior is disabled for the tile regardless of the parent tile manager configuration |
fullscreen | - | - | readonly boolean | false | Whether the tile current state is fullscreen |
Name | Cancellable | Parameters | Description |
---|---|---|---|
igcTileDragStarted | true | IgcTileComponent | Emitted when a drag operation is initiated |
igcTileDragEnded | false | IgcTileComponent | Emitted when a drag operation is completed |
igcTileDragCancel | false | IgcTileComponent | Emitted when a drag operation is discarded |
igcTileResizeStart | true | IgcTileComponent | Emitted when a resize operation is initiated |
igcTileResizeEnd | false | IgcTileComponent | Emitted when a resize operation is completed |
igcTileResizeCancel | false | IgcTileComponent | Emitted when a resize operation is discarded |
igcTileFullscreen | true | { IgcTileComponent, state: boolean} | Emitted when a tile is entering into fullscreen state through the default tile header UI |
igcTileMaximized | true | { IgcTileComponent state: boolean } | Emitted a a tile maximized state i toggled through the default tile header UI |
Name | Description |
---|---|
(default) | Default slot for slotting content into the tile |
title | Content for the tile header |
fullscreen-action | Overwrite the default fullscreen action content |
maximize-action | Overwrite the default maximize action content |
actions | Custom content rendered after the default actions |
side-adorner | Overwrite the default horizontal resize adorner |
corner-adorner | Overwrite the default diagonal resize adorner |
bottom-adorner | Overwrite the default vertical resize adorner |
Name | Description |
---|---|
base | The wrapping container of the tile component |
header | The header container of the tile, including title and actions parts. |
title | The title container |
actions | The actions container |
content-container | The container wrapping the tile default slot |
trigger-side | Horizontal adorner. |
trigger | Diagonal adorner |
trigger-bottom | Vertical adorner |
Name | Description |
---|
- is defined and rendered
- is initialized with proper default state
- passes the default WAI-ARIA automated tests
- accepts and renders only slotted
igc-tile
component(s) - correct rendering state of slotted tiles
- correct rendering state of slotted content inside a tile
- correct rendering state of slotted content inside the tile header
- DOM and internal state are correct when a tile is added dynamically
- DOM and internal state are correct when a tile is removed dynamically
- correctly serializes tiles collection properties to a JSON string
- correctly deserializes a serialized tiles collection and assign back the properties to the tiles
In general the tile manager and the tile components do not describe explicit ARIA roles.
There is a limitation around the use of the CSS order property which means that the viewport layout may differ from the DOM hierarchy. In that case default keyboard focus behavior may seem weird since the position in the viewport could be different from the actual DOM hierarchy position.