@processmaker/screen-builder 2.83.11 → 2.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/vue-form-builder.css +1 -1
- package/dist/vue-form-builder.es.js +4504 -4042
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +52 -52
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +18 -2
- package/src/App.vue +34 -56
- package/src/assets/css/custom.css +11 -0
- package/src/assets/css/tabs.css +118 -0
- package/src/bootstrap.js +111 -0
- package/src/components/ScreenToolbar.vue +100 -0
- package/src/components/TabsBar.vue +233 -0
- package/src/components/editor/pagesDropdown.vue +125 -0
- package/src/components/index.js +1 -0
- package/src/components/inspector/color-select.vue +18 -1
- package/src/components/sortable/Sortable.vue +80 -0
- package/src/components/sortable/sortable.scss +25 -0
- package/src/components/sortable/sortableList/SortableList.vue +141 -0
- package/src/components/sortable/sortableList/sortableList.scss +73 -0
- package/src/components/vue-form-builder.vue +342 -253
- package/src/main.js +1 -2
- package/src/mixins/canOpenJsonFile.js +1 -1
- package/src/stories/ColorSelect.stories.js +79 -0
- package/src/stories/Configure.mdx +78 -0
- package/src/stories/DropdownAndPages.stories.js +113 -0
- package/src/stories/PageTabs.stories.js +338 -0
- package/src/stories/PagesDropdown.stories.js +132 -0
- package/src/stories/ScreenToolbar.stories.js +188 -0
- package/src/stories/Sortable.stories.js +236 -0
package/src/main.js
CHANGED
|
@@ -24,7 +24,7 @@ export default {
|
|
|
24
24
|
if (json instanceof Array) {
|
|
25
25
|
screen = { config:json, computed: [], customCSS: null };
|
|
26
26
|
} else if (json && json.screens instanceof Array) {
|
|
27
|
-
screen = json.screens[
|
|
27
|
+
screen = json.screens[0];
|
|
28
28
|
if (window.exampleScreens instanceof Array) {
|
|
29
29
|
window.exampleScreens = json.screens;
|
|
30
30
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import { userEvent, expect } from "@storybook/test";
|
|
3
|
+
import "../bootstrap";
|
|
4
|
+
import ColorSelect from "../components/inspector/color-select.vue";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Components/ColorSelect",
|
|
8
|
+
component: ColorSelect,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
render: (args, { argTypes }) => ({
|
|
11
|
+
props: Object.keys(argTypes),
|
|
12
|
+
components: { ColorSelect },
|
|
13
|
+
template: '<color-select v-bind="$props" v-model="inputValue" />',
|
|
14
|
+
data() {
|
|
15
|
+
return { inputValue: args.value };
|
|
16
|
+
},
|
|
17
|
+
watch: {
|
|
18
|
+
// Updates the value when the property changes in storybook controls
|
|
19
|
+
value(value) {
|
|
20
|
+
this.inputValue = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Stories of the component
|
|
28
|
+
*/
|
|
29
|
+
// Preview the component
|
|
30
|
+
export const Preview = {
|
|
31
|
+
args: {
|
|
32
|
+
label: "Select a color",
|
|
33
|
+
helper: "Helper text",
|
|
34
|
+
options: [
|
|
35
|
+
{ value: "alert alert-primary", content: "primary" },
|
|
36
|
+
{ value: "alert alert-secondary", content: "secondary" },
|
|
37
|
+
{ value: "alert alert-success", content: "success" },
|
|
38
|
+
{ value: "alert alert-danger", content: "danger" },
|
|
39
|
+
{ value: "alert alert-warning", content: "warning" },
|
|
40
|
+
{ value: "alert alert-info", content: "info" },
|
|
41
|
+
{ value: "alert alert-light", content: "light" },
|
|
42
|
+
{ value: "alert alert-dark", content: "dark" }
|
|
43
|
+
],
|
|
44
|
+
value: "alert alert-success"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// A user can change the selected color
|
|
49
|
+
export const ChangeSelectedColor = {
|
|
50
|
+
args: {
|
|
51
|
+
label: "Select a color",
|
|
52
|
+
helper: "Helper text",
|
|
53
|
+
options: [
|
|
54
|
+
{ value: "alert alert-primary", content: "primary" },
|
|
55
|
+
{ value: "alert alert-secondary", content: "secondary" },
|
|
56
|
+
{ value: "alert alert-success", content: "success" },
|
|
57
|
+
{ value: "alert alert-danger", content: "danger" },
|
|
58
|
+
{ value: "alert alert-warning", content: "warning" },
|
|
59
|
+
{ value: "alert alert-info", content: "info" },
|
|
60
|
+
{ value: "alert alert-light", content: "light" },
|
|
61
|
+
{ value: "alert alert-dark", content: "dark" }
|
|
62
|
+
],
|
|
63
|
+
value: "alert alert-success"
|
|
64
|
+
},
|
|
65
|
+
play: async ({ canvasElement }) => {
|
|
66
|
+
const primaryColor = canvasElement.querySelector(".text-primary.fa-check");
|
|
67
|
+
|
|
68
|
+
// check if the default value is the success color
|
|
69
|
+
let selected = canvasElement.querySelector(".text-light");
|
|
70
|
+
expect(selected.parentNode).toHaveClass("bg-success");
|
|
71
|
+
|
|
72
|
+
// change the selected color
|
|
73
|
+
await userEvent.click(primaryColor);
|
|
74
|
+
|
|
75
|
+
// check if the alert is now the primary color
|
|
76
|
+
selected = canvasElement.querySelector(".text-light");
|
|
77
|
+
expect(selected.parentNode).toHaveClass("bg-primary");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import pkg from '../../package.json'; // Adjust the path as necessary
|
|
2
|
+
import { Meta } from "@storybook/blocks";
|
|
3
|
+
|
|
4
|
+
export const RightArrow = () => <svg
|
|
5
|
+
viewBox="0 0 14 14"
|
|
6
|
+
width="8px"
|
|
7
|
+
height="14px"
|
|
8
|
+
style={{
|
|
9
|
+
marginLeft: '4px',
|
|
10
|
+
display: 'inline-block',
|
|
11
|
+
shapeRendering: 'inherit',
|
|
12
|
+
verticalAlign: 'middle',
|
|
13
|
+
fill: 'currentColor',
|
|
14
|
+
'path fill': 'currentColor'
|
|
15
|
+
}}
|
|
16
|
+
>
|
|
17
|
+
<path d="m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z" />
|
|
18
|
+
</svg>
|
|
19
|
+
|
|
20
|
+
<Meta title="ProcessMaker ScreenBuilder" />
|
|
21
|
+
|
|
22
|
+
# ScreenBuilder <strong>v{pkg.version}</strong>
|
|
23
|
+
|
|
24
|
+
<div className="sb-container">
|
|
25
|
+
<div className='sb-section-title'>
|
|
26
|
+
## Introduction
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
Welcome to the ProcessMaker ScreenBuilder Storybook! This interactive library is designed to showcase the components used to render screens within ProcessMaker processes. Built with Vue2, our components provide a versatile and intuitive way to build dynamic forms and interfaces for your business processes.
|
|
30
|
+
|
|
31
|
+
<div className='sb-section-title'>
|
|
32
|
+
## Key Features
|
|
33
|
+
</div>
|
|
34
|
+
<ul>
|
|
35
|
+
<li>**Wide Range of Components**: From basic input fields to complex data grids, our library covers all the components you might need.</li>
|
|
36
|
+
<li>**Vue2 Compatibility**: Fully compatible with Vue2, ensuring seamless integration into your Vue applications.</li>
|
|
37
|
+
<li>**Interactive Examples**: Explore components through interactive examples, allowing you to see how they work in real-time.</li>
|
|
38
|
+
<li>**Customization**: Learn how to customize components to match your specific process requirements.</li>
|
|
39
|
+
</ul>
|
|
40
|
+
|
|
41
|
+
<div className='sb-section-title'>
|
|
42
|
+
## Getting Started
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
To start using the ScreenBuilder components in your ProcessMaker processes, follow these steps:
|
|
46
|
+
|
|
47
|
+
Clone the repository and `cd` into the `screen-builder` directory:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone git@github.com:ProcessMaker/screen-builder.git
|
|
51
|
+
cd screen-builder
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Install dependencies using NPM, then run the local development server:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm i
|
|
58
|
+
npm run serve
|
|
59
|
+
```
|
|
60
|
+
<div className='sb-section-title'>
|
|
61
|
+
## Explore Components
|
|
62
|
+
</div>
|
|
63
|
+
Start exploring the components by selecting them from the sidebar. Each entry provides detailed information about the component, including usage examples and customization options.
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
{`
|
|
68
|
+
.sb-container {
|
|
69
|
+
font-family: 'Arial', sans-serif;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sb-section-title {
|
|
73
|
+
margin-top: 20px;
|
|
74
|
+
font-weight: bold;
|
|
75
|
+
font-size: 20px;
|
|
76
|
+
}
|
|
77
|
+
`}
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import { within, expect, waitFor } from "@storybook/test";
|
|
3
|
+
import "../bootstrap";
|
|
4
|
+
// b-tabs from bootstrap-vue
|
|
5
|
+
import TabsBar from "../components/TabsBar.vue";
|
|
6
|
+
import PagesDropdown from "../components/editor/pagesDropdown.vue";
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: "Components/DropdownAndPages",
|
|
10
|
+
component: [TabsBar, PagesDropdown],
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
render: (args, { argTypes }) => ({
|
|
13
|
+
props: Object.keys(argTypes),
|
|
14
|
+
components: { TabsBar, PagesDropdown },
|
|
15
|
+
template: `
|
|
16
|
+
<tabs-bar ref="tabsBar" v-bind="$props">
|
|
17
|
+
<template v-slot:tabs-start>
|
|
18
|
+
<pages-dropdown
|
|
19
|
+
:data="pages"
|
|
20
|
+
@addPage="onAddPage"
|
|
21
|
+
@clickPage="onClick"
|
|
22
|
+
@seeAllPages="onSeeAllPages"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
25
|
+
<template v-slot="{ currentPage }">
|
|
26
|
+
Here comes content of {{pages[currentPage].name}} (#{{currentPage}})
|
|
27
|
+
</template>
|
|
28
|
+
</tabs-bar>
|
|
29
|
+
`,
|
|
30
|
+
data() {
|
|
31
|
+
return {};
|
|
32
|
+
},
|
|
33
|
+
methods: {
|
|
34
|
+
onAddPage() {
|
|
35
|
+
console.log("Add page clicked");
|
|
36
|
+
},
|
|
37
|
+
onSeeAllPages() {
|
|
38
|
+
console.log("See all pages clicked");
|
|
39
|
+
},
|
|
40
|
+
onClick(page) {
|
|
41
|
+
const index = this.pages.indexOf(page);
|
|
42
|
+
this.$refs.tabsBar.openPageByIndex(index);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Stories of the component
|
|
50
|
+
*/
|
|
51
|
+
// Preview the component
|
|
52
|
+
export const Preview = {
|
|
53
|
+
args: {
|
|
54
|
+
pages: [
|
|
55
|
+
{ name: "Page 1" },
|
|
56
|
+
{ name: "Page 2" },
|
|
57
|
+
{ name: "Page 3" },
|
|
58
|
+
{ name: "Page 4" },
|
|
59
|
+
{ name: "Page 5" }
|
|
60
|
+
],
|
|
61
|
+
initialOpenedPages: [0]
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Open a page using the PageDropdown(index)
|
|
66
|
+
export const OpenPageUsingDropdown = {
|
|
67
|
+
args: {
|
|
68
|
+
pages: [
|
|
69
|
+
{ name: "Page1" },
|
|
70
|
+
{ name: "Page2" },
|
|
71
|
+
{ name: "Page3" },
|
|
72
|
+
{ name: "Page4" },
|
|
73
|
+
{ name: "Page5" }
|
|
74
|
+
],
|
|
75
|
+
initialOpenedPages: [0]
|
|
76
|
+
},
|
|
77
|
+
play: async ({ canvasElement, step }) => {
|
|
78
|
+
const canvas = within(canvasElement);
|
|
79
|
+
const selector = canvasElement.querySelector(
|
|
80
|
+
"[data-test=page-dropdown] button"
|
|
81
|
+
);
|
|
82
|
+
let selectorAddPage = canvasElement.querySelector("[data-test=page-Page3]");
|
|
83
|
+
console.log(selectorAddPage);
|
|
84
|
+
await selector.click(selector);
|
|
85
|
+
await selectorAddPage.click(selectorAddPage);
|
|
86
|
+
// Open Page 3 (index=2)
|
|
87
|
+
await step("Open Page 3 (index=2)", async () => {
|
|
88
|
+
await waitFor(
|
|
89
|
+
() => {
|
|
90
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
91
|
+
"Here comes content of Page3 (#2)"
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
{ timeout: 1000 }
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Open Page 2 (index=1)
|
|
99
|
+
await selector.click(selector);
|
|
100
|
+
selectorAddPage = canvasElement.querySelector("[data-test=page-Page2]");
|
|
101
|
+
await selectorAddPage.click(selectorAddPage);
|
|
102
|
+
await step("Open Page 2 (index=1)", async () => {
|
|
103
|
+
await waitFor(
|
|
104
|
+
() => {
|
|
105
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
106
|
+
"Here comes content of Page2 (#1)"
|
|
107
|
+
);
|
|
108
|
+
},
|
|
109
|
+
{ timeout: 1000 }
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import { within, userEvent, expect, waitFor } from "@storybook/test";
|
|
3
|
+
import "../bootstrap";
|
|
4
|
+
// b-tabs from bootstrap-vue
|
|
5
|
+
import TabsBar from "../components/TabsBar.vue";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "Components/TabsBar",
|
|
9
|
+
component: TabsBar,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
render: (args, { argTypes }) => ({
|
|
12
|
+
props: Object.keys(argTypes),
|
|
13
|
+
components: { TabsBar },
|
|
14
|
+
template: `
|
|
15
|
+
<tabs-bar ref="tabsBar" v-bind="$props">
|
|
16
|
+
<template v-slot:tabs-start>
|
|
17
|
+
<b-form-select :options="pages.map((v,k)=>k)" @change="openPage($event)" data-test="open-page" />
|
|
18
|
+
</template>
|
|
19
|
+
<template v-slot="{ currentPage }">
|
|
20
|
+
Here comes content of {{pages[currentPage].name}} (#{{currentPage}})
|
|
21
|
+
</template>
|
|
22
|
+
</tabs-bar>
|
|
23
|
+
`,
|
|
24
|
+
data() {
|
|
25
|
+
return {};
|
|
26
|
+
},
|
|
27
|
+
methods: {
|
|
28
|
+
openPage(index) {
|
|
29
|
+
this.$refs.tabsBar.openPageByIndex(index);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Stories of the component
|
|
37
|
+
*/
|
|
38
|
+
// Preview the component
|
|
39
|
+
export const Preview = {
|
|
40
|
+
args: {
|
|
41
|
+
pages: [
|
|
42
|
+
{ name: "Page 1" },
|
|
43
|
+
{ name: "Page 2" },
|
|
44
|
+
{ name: "Page 3" },
|
|
45
|
+
{ name: "Page 4" },
|
|
46
|
+
{ name: "Page 5" }
|
|
47
|
+
],
|
|
48
|
+
initialOpenedPages: [0]
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Open a page using openPageByIndex(index)
|
|
53
|
+
export const OpenPageByIndexFunction = {
|
|
54
|
+
args: {
|
|
55
|
+
pages: [
|
|
56
|
+
{ name: "Page 1" },
|
|
57
|
+
{ name: "Page 2" },
|
|
58
|
+
{ name: "Page 3" },
|
|
59
|
+
{ name: "Page 4" },
|
|
60
|
+
{ name: "Page 5" }
|
|
61
|
+
],
|
|
62
|
+
initialOpenedPages: [0]
|
|
63
|
+
},
|
|
64
|
+
play: async ({ canvasElement, step }) => {
|
|
65
|
+
const canvas = within(canvasElement);
|
|
66
|
+
const selector = canvasElement.querySelector("[data-test=open-page]");
|
|
67
|
+
|
|
68
|
+
// Open Page 3 (index=2)
|
|
69
|
+
await step("Open Page 3 (index=2)", async () => {
|
|
70
|
+
userEvent.selectOptions(selector, "2");
|
|
71
|
+
await waitFor(
|
|
72
|
+
() => {
|
|
73
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
74
|
+
"Here comes content of Page 3 (#2)"
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
{ timeout: 1000 }
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Open Page 2 (index=1)
|
|
82
|
+
await step("Open Page 2 (index=1)", async () => {
|
|
83
|
+
userEvent.selectOptions(selector, "1");
|
|
84
|
+
await waitFor(
|
|
85
|
+
() => {
|
|
86
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
87
|
+
"Here comes content of Page 2 (#1)"
|
|
88
|
+
);
|
|
89
|
+
},
|
|
90
|
+
{ timeout: 1000 }
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Close Tab #1 = Page 3 (index=2)
|
|
95
|
+
await step("Close Page 3 (index=2)", async () => {
|
|
96
|
+
canvas.getByTestId("close-tab-2").click();
|
|
97
|
+
await waitFor(
|
|
98
|
+
() => {
|
|
99
|
+
expect(canvas.getByTestId("tab-content")).not.toContainHTML(
|
|
100
|
+
"Here comes content of Page 3 (#2)"
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
{ timeout: 1000 }
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Select Page 1 using dropdown (index=0) (tab=0)
|
|
108
|
+
await step("Select Page 1 (index=0)", async () => {
|
|
109
|
+
userEvent.selectOptions(selector, "0");
|
|
110
|
+
await waitFor(
|
|
111
|
+
() => {
|
|
112
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
113
|
+
"Here comes content of Page 1 (#0)"
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
{ timeout: 1000 }
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Select Page 2 using dropdown (index=1) (tab=1)
|
|
121
|
+
await step("Select Page 2 (index=1)", async () => {
|
|
122
|
+
userEvent.selectOptions(selector, "1");
|
|
123
|
+
await waitFor(
|
|
124
|
+
() => {
|
|
125
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
126
|
+
"Here comes content of Page 2 (#1)"
|
|
127
|
+
);
|
|
128
|
+
},
|
|
129
|
+
{ timeout: 1000 }
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// User navigating through tabs
|
|
136
|
+
export const UserNavigatingThroughTabs = {
|
|
137
|
+
args: {
|
|
138
|
+
pages: [
|
|
139
|
+
{ name: "Page 1" },
|
|
140
|
+
{ name: "Page 2" },
|
|
141
|
+
{ name: "Page 3" },
|
|
142
|
+
{ name: "Page 4" },
|
|
143
|
+
{ name: "Page 5" }
|
|
144
|
+
],
|
|
145
|
+
initialOpenedPages: [0, 1]
|
|
146
|
+
},
|
|
147
|
+
play: async ({ canvasElement, step }) => {
|
|
148
|
+
const canvas = within(canvasElement);
|
|
149
|
+
|
|
150
|
+
// Select Page 2 using tab (data-test=tab-1)
|
|
151
|
+
await step("Select Page 2 using tab", async () => {
|
|
152
|
+
canvas.getByTestId("tab-1").click();
|
|
153
|
+
await waitFor(
|
|
154
|
+
() => {
|
|
155
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
156
|
+
"Here comes content of Page 2 (#1)"
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
{ timeout: 1000 }
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Select Page 1 using tab (data-test=tab-0)
|
|
164
|
+
await step("Select Page 1 using tab", async () => {
|
|
165
|
+
canvas.getByTestId("tab-0").click();
|
|
166
|
+
await waitFor(
|
|
167
|
+
() => {
|
|
168
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
169
|
+
"Here comes content of Page 1 (#0)"
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
{ timeout: 1000 }
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Lots of pages opened
|
|
179
|
+
export const ALotOfPagesOpen = {
|
|
180
|
+
args: {
|
|
181
|
+
pages: [
|
|
182
|
+
{ name: "Page 1" },
|
|
183
|
+
{ name: "Page 2" },
|
|
184
|
+
{ name: "Page 3" },
|
|
185
|
+
{ name: "Page 4" },
|
|
186
|
+
{ name: "Page 5" },
|
|
187
|
+
{ name: "Page 6" },
|
|
188
|
+
{ name: "Page 7" },
|
|
189
|
+
{ name: "Page 8" },
|
|
190
|
+
{ name: "Page 9" },
|
|
191
|
+
{ name: "Page 10" },
|
|
192
|
+
{ name: "Page 11" },
|
|
193
|
+
{ name: "Page 12" },
|
|
194
|
+
{ name: "Page 13" },
|
|
195
|
+
{ name: "Page 14" },
|
|
196
|
+
{ name: "Page 15" },
|
|
197
|
+
{ name: "Page 16" }
|
|
198
|
+
],
|
|
199
|
+
initialOpenedPages: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
200
|
+
},
|
|
201
|
+
play: async ({ canvasElement, step }) => {
|
|
202
|
+
const canvas = within(canvasElement);
|
|
203
|
+
const scrollLeft = canvas.getByTestId("scroll-left");
|
|
204
|
+
const scrollRight = canvas.getByTestId("scroll-right");
|
|
205
|
+
|
|
206
|
+
await waitFor(() => expect(scrollRight).toBeVisible());
|
|
207
|
+
await waitFor(() => expect(scrollLeft).toBeVisible());
|
|
208
|
+
|
|
209
|
+
// Scroll to the right
|
|
210
|
+
await step("Scroll to the right", async () => {
|
|
211
|
+
scrollRight.click();
|
|
212
|
+
await waitFor(() => expect(scrollLeft).toBeVisible());
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Scroll to the left
|
|
216
|
+
await step("Scroll to the left", async () => {
|
|
217
|
+
scrollLeft.click();
|
|
218
|
+
await waitFor(() => expect(scrollLeft).toBeVisible());
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Tab content fill all the available space
|
|
224
|
+
export const TabContentFillAllTheAvailableSpace = {
|
|
225
|
+
args: {
|
|
226
|
+
pages: [
|
|
227
|
+
{ name: "Page 1" },
|
|
228
|
+
{ name: "Page 2" },
|
|
229
|
+
{ name: "Page 3" },
|
|
230
|
+
{ name: "Page 4" },
|
|
231
|
+
{ name: "Page 5" }
|
|
232
|
+
],
|
|
233
|
+
initialOpenedPages: [0, 1]
|
|
234
|
+
},
|
|
235
|
+
parameters: {
|
|
236
|
+
layout: "fullscreen"
|
|
237
|
+
},
|
|
238
|
+
decorators: [
|
|
239
|
+
() => ({
|
|
240
|
+
template: '<div style="height: calc(100vh - 2rem)"><story/></div>'
|
|
241
|
+
})
|
|
242
|
+
],
|
|
243
|
+
play: async ({ canvasElement, step }) => {
|
|
244
|
+
const canvas = within(canvasElement);
|
|
245
|
+
|
|
246
|
+
// Check content position in Page 1
|
|
247
|
+
await step("Check content position in Page 1", async () => {
|
|
248
|
+
const tabContent = canvas.getByTestId("tab-content");
|
|
249
|
+
const tabsBar = canvas.getByRole("tablist").parentElement;
|
|
250
|
+
|
|
251
|
+
// -------------------------------------
|
|
252
|
+
//
|
|
253
|
+
// Check the height of the tab content is the same as the height
|
|
254
|
+
// of the canvas minus height of the tabs bar. This is important
|
|
255
|
+
// to make sure the tab content fill all the available space and
|
|
256
|
+
// the dropzone can be used to drop elements. Also check the top
|
|
257
|
+
// position of the tab content is the same as the height of the
|
|
258
|
+
// tabs bar.
|
|
259
|
+
//
|
|
260
|
+
// -------------------------------------
|
|
261
|
+
await waitFor(() => {
|
|
262
|
+
const canvasHeight = canvasElement.clientHeight;
|
|
263
|
+
const tabsBarHeight = tabsBar.clientHeight;
|
|
264
|
+
const tabContentTop = tabContent.getBoundingClientRect().top;
|
|
265
|
+
expect(tabContentTop).toBe(tabsBarHeight);
|
|
266
|
+
expect(tabContent).toHaveStyle({
|
|
267
|
+
height: `${canvasHeight - tabsBarHeight}px`
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Select Page 2 using tab (data-test=tab-1)
|
|
273
|
+
await step("Select Page 2 using tab", async () => {
|
|
274
|
+
canvas.getByTestId("tab-1").click();
|
|
275
|
+
await waitFor(
|
|
276
|
+
() => {
|
|
277
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
278
|
+
"Here comes content of Page 2 (#1)"
|
|
279
|
+
);
|
|
280
|
+
},
|
|
281
|
+
{ timeout: 1000 }
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Check content position in Page 2
|
|
286
|
+
await step("Check content position in Page 2", async () => {
|
|
287
|
+
const tabContent = canvas.getByTestId("tab-content");
|
|
288
|
+
const tabsBar = canvas.getByRole("tablist").parentElement;
|
|
289
|
+
|
|
290
|
+
// -------------------------------------
|
|
291
|
+
//
|
|
292
|
+
// Check the height of the tab content is the same as the height
|
|
293
|
+
// of the canvas minus height of the tabs bar. This is important
|
|
294
|
+
// to make sure the tab content fill all the available space and
|
|
295
|
+
// the dropzone can be used to drop elements. Also check the top
|
|
296
|
+
// position of the tab content is the same as the height of the
|
|
297
|
+
// tabs bar.
|
|
298
|
+
//
|
|
299
|
+
// -------------------------------------
|
|
300
|
+
await waitFor(() => {
|
|
301
|
+
const canvasHeight = canvasElement.clientHeight;
|
|
302
|
+
const tabsBarHeight = tabsBar.clientHeight;
|
|
303
|
+
const tabContentTop = tabContent.getBoundingClientRect().top;
|
|
304
|
+
expect(tabContentTop).toBe(tabsBarHeight);
|
|
305
|
+
expect(tabContent).toHaveStyle({
|
|
306
|
+
height: `${canvasHeight - tabsBarHeight}px`
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Without any page opened
|
|
314
|
+
export const WithoutAnyPageOpened = {
|
|
315
|
+
args: {
|
|
316
|
+
pages: [
|
|
317
|
+
{ name: "Page 1" },
|
|
318
|
+
{ name: "Page 2" },
|
|
319
|
+
{ name: "Page 3" },
|
|
320
|
+
{ name: "Page 4" },
|
|
321
|
+
{ name: "Page 5" }
|
|
322
|
+
],
|
|
323
|
+
initialOpenedPages: []
|
|
324
|
+
},
|
|
325
|
+
play: async ({ canvasElement }) => {
|
|
326
|
+
const canvas = within(canvasElement);
|
|
327
|
+
|
|
328
|
+
// Check that there is a message when there is no page open.
|
|
329
|
+
await waitFor(
|
|
330
|
+
() => {
|
|
331
|
+
expect(canvas.getByTestId("tab-content")).toContainHTML(
|
|
332
|
+
"There are no open pages."
|
|
333
|
+
);
|
|
334
|
+
},
|
|
335
|
+
{ timeout: 1000 }
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
};
|