https://github.com/bimdata/areas
A Vue.js Blender style area manager to create custom layouts
https://github.com/bimdata/areas
tiling tiling-layout tiling-managers tiling-window tiling-window-manager vue vuejs
Last synced: 4 months ago
JSON representation
A Vue.js Blender style area manager to create custom layouts
- Host: GitHub
- URL: https://github.com/bimdata/areas
- Owner: bimdata
- License: mit
- Created: 2020-04-22T16:23:01.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2023-03-04T18:52:18.000Z (over 3 years ago)
- Last Synced: 2025-10-26T20:57:46.892Z (8 months ago)
- Topics: tiling, tiling-layout, tiling-managers, tiling-window, tiling-window-manager, vue, vuejs
- Language: JavaScript
- Homepage:
- Size: 2.41 MB
- Stars: 27
- Watchers: 3
- Forks: 1
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README


A Vue.js Blender style area manager to create custom layouts.
Areas aims to provide a flexible and customizable environment to create custom UI layouts using [Vue.js](https://vuejs.org/).
It is possible to **split** (vertical/horizontal), **resize**, **swap** and **delete** areas as needed. The current layout can be **saved** and **loaded** later. Components in areas are **cached** and not rerendered when the layout is edited. Areas width and height are **percentage ratio based** so resizing the viewport resizes areas accordingly. Styles can be customized using [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).

# Install
Use npm:
```
npm i @bimdata/areas
```
# Usage
Import Areas in your Vue.js app:
```javascript
import Areas from "@bimdata/areas";
```
Use it in your component:
```html
```
Configuration example:
```javascript
const areasCfg = {
// The available components that will be used in areas.
components: [
{ render: h => h("div", "Content I") },
{ render: h => h("div", "Content II") },
{ render: h => h("div", "Content III") }
],
// The layout divided in areas, composed by areas or area containers.
layout: {
// area container
direction: "row",
ratios: [20, 80],
children: [
{
// area
componentIndex: 0,
},
{
// area container
direction: "column",
ratios: [40, 60],
children: [
{
// area
componentIndex: 1,
},
{
// area
componentIndex: 2
}
]
}
]
}
};
```
Result:

# API
## Configuration
Areas needs an object as `cfg` props:
### `cfg`:
| Property | Type | Description |
| :--- | :--- | :--- |
| `components` | `array` | **Required**. An array of Vue.js components. |
| `layout` | `array` | **Required**. An [`area`](#area) or an [`area container`](#area-container). |
| `separatorThickness` | `number` | **Optional**. Default to 2. The thickness of separators. |
| `separatorDetectionMargin` | `number` | **Optional**. Default to 10. Margin of the detection region on separators. This helps the user to get the separator with the mouse even if it is small. |
| `areaMinRatio` | `number` | **Optional**. Default to 0. The minimal ratio of an area. |
| `defaultComponent` | `object` | **Optional**. Default to a component that renders nothing. The default component is used when splitting the window or using componentIndex = null. |
| `dragImage` | `object` | **Optional**. An object to customize drag image. Properties are img, xOffset and yOffset and match [setDragImage web API](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setDragImage). |
### `area`:
| Property | Type | Description |
| :--- | :--- | :--- |
| `componentIndex` | `number` | **Required**. A valid index of the `cfg.components` array, or `null` for the default component. |
| `name` | `string` | **Optional**. A name, used to retrieve area content. |
| `cfg` | `object` | **Optional**. A [data object](https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth) used to pass props, event listener,... to the component instance. |
### `area container`:
| Property | Type | Description |
| :--- | :--- | :--- |
| `ratios` | `array` | **Required**. An array of integers representing the percentage of the corresponding children in the container. Length must be > 1. |
| `children` | `array` | **Required**. An array of [`area`](#area) or [`area container`](#area-container). Must have the same length as ratios. |
| `direction` | `string` | **Optional**. Default to `row`. Can be changed to `column`. The way areas is displayed in the container. |
## Modes
Areas component instance can be set with *modes*:
- `split-vertical`: a vertical bar is displayed on top of the hovered (active) area. Clicking splits the area vertically.
- `split-horizontal`: a horizontal bar is displayed on top of the hovered (active) area. Clicking splits the area horizontally.
- `swap`: areas can be dragged and dropped to swap them.
- `delete`: clicking area deletes it. (It is impossible to delete the last remaining area.)
To set a mode, use `setMode` on areas instance: (usage example with [ref](https://vuejs.org/v2/api/#ref))
```javascript
this.$refs.areas.setMode(mode); // mode must be "split-vertical", "split-horizontal", "swap", "delete" or null to exit modes
```
When the mode is different from `null`, overlays is displayed on areas. To change overlays style, use [corresponding css variables](#style).
## Events
Splitting, deletting and swapping fire events that can be listened on areas component.
| Name | Arguments |
| :--- | :--- |
| `area-splitted` | `{ areaId, newAreaId, way, percentage, insertNewAfter }` |
| `area-deletted` | `{ areaId }` |
| `areas-swapped` | `{ areaId1, areaId2 }` |
## Public Methods
Methods on Areas instance:
| Name | Arguments | Description |
| :--- | :--- | :--- |
| `getCurrentLayout()` | none | Get the current layout. |
| `loadLayout(layout)` | `layout`: **Required**. A layout object get by calling getCurrentLayout. | Load a saved layout. |
| `changeAreaContent(areaId, contentCfg)` | `areaId`: **Required**. The id of the area to change the content. `contentCfg`: **Required**. An [`area content`](#area) object. | Change the content of an area. |
| `setMode(mode)` | `mode`: **Required**. See [Modes](#Modes) | Change Areas mode. |
| `deleteArea(areaId)` | `areaId`: **Required**. | Delete area with this id. |
| `splitArea(areaId, way, percentage = 50, insertNewAfter = true)` | `areaId`: **Required**. `way`: **Required**. "vertical" or "horizontal". `percentage`, the percentage from left or top. `insertNewAfter`, if the new area is inserted after or before the splitted one. | Split area. |
| `swapAreas(areaId1, areaId2)` | `areaId1` & `areaId2`: **Required** numbers | Swap areas. |
| `getAreaContentByName(name)` | `name`: **Required** string | Get [`area content`](#area) by name. |
## Style
It is possible to customize areas style declaring CSS variables:
```css
/* Cursors */
--areas-delete-cursor some-valid-cursor;
--areas-vertical-resize-cursor some-valid-cursor;
--areas-horizontal-resize-cursor some-valid-cursor;
--areas-vertical-split-cursor: some-valid-cursor;
--areas-horizontal-split-cursor: some-valid-cursor;
--areas-drag-cursor some-valid-cursor;
--areas-dragging-cursor: some-valid-cursor;
--areas-delete-cursor some-valid-cursor;
/* Areas basics */
--areas-background-color: color;
--areas-separator-color: color;
--areas-split-line-color: color;
--areas-active-box-shadow: box-shadow;
/* Areas modes overlays */
--areas-overlay-color: color;
--areas-overlay-outline-offset: outline-offset-px;
--areas-overlay-outline: css-outline-properties;
--areas-overlay-split-color: color;
--areas-overlay-split-outline-offset: outline-offset-px;
--areas-overlay-split-outline: css-outline-properties;
--areas-overlay-delete-color: color;
--areas-overlay-delete-outline-offset: outline-offset-px;
--areas-overlay-delete-outline: css-outline-properties;
--areas-overlay-swap-color: color;
--areas-overlay-swap-outline-offset: outline-offset-px;
--areas-overlay-swap-outline: css-outline-properties;
--areas-overlay-swapover-color: color;
--areas-overlay-swapover-outline-offset: outline-offset-px;
--areas-overlay-swapover-outline: css-outline-properties;
```
[css-outline-properties](https://developer.mozilla.org/en-US/docs/Web/CSS/outline)
[some-valid-cursor](https://developer.mozilla.org/en-US/docs/Web/CSS/cursor)
## Area injection
Each child component in an area is able to get some area utilities from the area it lives in by [injecting](https://vuejs.org/v2/guide/components-edge-cases.html#Dependency-Injection) $area:
```javascript
{
// Your Vue.js component
inject: ["$area"]
}
```
The `$area` object provides the following properties:
| Property | Description |
| :--- | :--- |
| id | The id of the area. |
| domElement | The domElement of the area. |
| component | The Vue.js component instance of the area. |
| contentComponent | The Vue.js component instance of the first child of the area. (It is different from area.$children[0] due to implementation) |
| areas | The Areas Vue.js component instance. |
| onChange(handler) | A method that accepts a callback (handler) as parameter. The handler is called when area change (swap) with newAreaId and OldAreaId as parameters. |
| offChange(handler) | A method that accepts a callback (handler) as parameter to stop listening to area change with this handler. |
## Size
To know areas size (number of areas) :
```javascript
// The host component
{
data() {
return {
areasSize: null,
}
},
mounted() {
this.$watch(() => this.$refs.areas.size, size => { // ref="areas" must be placed on Areas component
this.areasSize = size;
}, {
immediate: true
});
},
// ...
}
```
# Development
Build on-change for development and serve:
```
npm run dev
```
All Tests:
```
npm run build:prod
npm run test
```
Unit tests:
```
npm run build:prod
npm run test:unit
```
E2e tests:
```
npm run build:prod
npm run test:e2e
```
To e2e test on development (this builds in production mode and open cypress instead of running it):
```
npm run test:e2e-dev
```