aloha-vue 2.59.0 → 2.60.0

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.
@@ -1,176 +1,182 @@
1
- import {
2
- computed,
3
- h,
4
- } from "vue";
5
-
6
- import AButton from "../../AButton/AButton";
7
- import AIcon from "../../AIcon/AIcon";
8
- import ATranslation from "../../ATranslation/ATranslation";
9
-
10
- import IdAPI from "./compositionAPI/IdAPI";
11
-
12
- import ChevronDown from "aloha-svg/dist/js/bootstrap/ChevronDown";
13
- import ChevronUp from "aloha-svg/dist/js/bootstrap/ChevronUp";
14
- import GripVertical from "aloha-svg/dist/js/bootstrap/GripVertical";
15
-
16
- export default {
17
- name: "ATableFormCellDnd",
18
- props: {
19
- canMoveRowDown: {
20
- type: Function,
21
- required: true,
22
- },
23
- canMoveRowUp: {
24
- type: Function,
25
- required: true,
26
- },
27
- id: {
28
- type: String,
29
- required: true,
30
- },
31
- isCreateMode: {
32
- type: Boolean,
33
- required: false,
34
- default: false,
35
- },
36
- isDragAndDrop: {
37
- type: Boolean,
38
- required: false,
39
- default: false,
40
- },
41
- isDndDisabled: {
42
- type: Boolean,
43
- required: false,
44
- default: false,
45
- },
46
- isFooter: {
47
- type: Boolean,
48
- required: false,
49
- default: false,
50
- },
51
- isHeader: {
52
- type: Boolean,
53
- required: false,
54
- default: false,
55
- },
56
- moveRowDown: {
57
- type: Function,
58
- required: true,
59
- },
60
- moveRowUp: {
61
- type: Function,
62
- required: true,
63
- },
64
- onDragend: {
65
- type: Function,
66
- required: true,
67
- },
68
- onDragstart: {
69
- type: Function,
70
- required: true,
71
- },
72
- rowIndex: {
73
- type: Number,
74
- required: true,
75
- },
76
- texts: {
77
- type: Object,
78
- required: false,
79
- default: () => ({}),
80
- },
81
- widths: {
82
- type: Object,
83
- required: false,
84
- default: () => ({}),
85
- },
86
- },
87
- setup(props) {
88
- const {
89
- idBtnDown,
90
- idBtnUp,
91
- } = IdAPI(props);
92
-
93
- return {
94
- columnStyles: computed(() => ({
95
- maxWidth: `${ props.widths.dndColumn }px`,
96
- minWidth: `${ props.widths.dndColumn }px`,
97
- width: `${ props.widths.dndColumn }px`,
98
- })),
99
- idBtnDown,
100
- idBtnUp,
101
- };
102
- },
103
- render() {
104
- const tag = this.isHeader ? "th" : "td";
105
- const isHandleDraggable = this.isDragAndDrop && !this.isDndDisabled;
106
-
107
- return h(tag, {
108
- class: [
109
- "a_table_form__cell",
110
- `a_table_form__cell_${ tag }`,
111
- "a_table_form__cell_reorder",
112
- ],
113
- style: this.columnStyles,
114
- }, [
115
- this.isHeader ?
116
- h("span", {
117
- class: "a_sr_only",
118
- }, [
119
- h(ATranslation, {
120
- tag: "span",
121
- text: this.texts.reorderColumn,
122
- }),
123
- ]) :
124
- this.isCreateMode ?
125
- null :
126
- this.isFooter ?
127
- null :
128
- h("div", {
129
- class: "a_table_form__reorder_actions",
130
- }, [
131
- this.canMoveRowUp(this.rowIndex) && h(AButton, {
132
- id: this.idBtnUp,
133
- class: "a_sr_only_focusable a_btn a_btn_transparent_dark a_table_form__reorder_button",
134
- disabled: this.isDndDisabled,
135
- iconLeft: ChevronUp,
136
- preventKeyboardRepeat: true,
137
- tabindex: this.isDndDisabled ? -1 : undefined,
138
- title: this.texts.reorderUp,
139
- textScreenReader: this.texts.reorderUp,
140
- onClick: () => this.moveRowUp(this.rowIndex),
141
- }),
142
- h("span", {
143
- ariaHidden: true,
144
- class: "a_table_form__reorder_handle",
145
- draggable: isHandleDraggable,
146
- onDragend: isHandleDraggable ? this.onDragend : undefined,
147
- onDragstart: isHandleDraggable ? ($event => this.onDragstart($event, this.rowIndex)) : undefined,
148
- }, [
149
- h(AIcon, {
150
- class: "a_table_form__reorder_icon",
151
- icon: GripVertical,
152
- }),
153
- ]),
154
- h("span", {
155
- class: "a_sr_only",
156
- }, [
157
- h(ATranslation, {
158
- tag: "span",
159
- text: this.texts.reorderHandle,
160
- }),
161
- ]),
162
- this.canMoveRowDown(this.rowIndex) && h(AButton, {
163
- id: this.idBtnDown,
164
- class: "a_sr_only_focusable a_btn a_btn_transparent_dark a_table_form__reorder_button",
165
- disabled: this.isDndDisabled,
166
- iconLeft: ChevronDown,
167
- preventKeyboardRepeat: true,
168
- tabindex: this.isDndDisabled ? -1 : undefined,
169
- title: this.texts.reorderDown,
170
- textScreenReader: this.texts.reorderDown,
171
- onClick: () => this.moveRowDown(this.rowIndex),
172
- }),
173
- ]),
174
- ]);
175
- },
176
- };
1
+ import {
2
+ computed,
3
+ h,
4
+ } from "vue";
5
+
6
+ import AButton from "../../AButton/AButton";
7
+ import AIcon from "../../AIcon/AIcon";
8
+ import ATranslation from "../../ATranslation/ATranslation";
9
+
10
+ import IdAPI from "./compositionAPI/IdAPI";
11
+
12
+ import ChevronDown from "aloha-svg/dist/js/bootstrap/ChevronDown";
13
+ import ChevronUp from "aloha-svg/dist/js/bootstrap/ChevronUp";
14
+ import GripVertical from "aloha-svg/dist/js/bootstrap/GripVertical";
15
+ import LockFill from "aloha-svg/dist/js/bootstrap/LockFill";
16
+
17
+ export default {
18
+ name: "ATableFormCellDnd",
19
+ props: {
20
+ canMoveRowDown: {
21
+ type: Function,
22
+ required: true,
23
+ },
24
+ canMoveRowUp: {
25
+ type: Function,
26
+ required: true,
27
+ },
28
+ id: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ isCreateMode: {
33
+ type: Boolean,
34
+ required: false,
35
+ default: false,
36
+ },
37
+ isDragAndDrop: {
38
+ type: Boolean,
39
+ required: false,
40
+ default: false,
41
+ },
42
+ isDndDisabled: {
43
+ type: Boolean,
44
+ required: false,
45
+ default: false,
46
+ },
47
+ isFooter: {
48
+ type: Boolean,
49
+ required: false,
50
+ default: false,
51
+ },
52
+ isHeader: {
53
+ type: Boolean,
54
+ required: false,
55
+ default: false,
56
+ },
57
+ moveRowDown: {
58
+ type: Function,
59
+ required: true,
60
+ },
61
+ moveRowUp: {
62
+ type: Function,
63
+ required: true,
64
+ },
65
+ onDragend: {
66
+ type: Function,
67
+ required: true,
68
+ },
69
+ onDragstart: {
70
+ type: Function,
71
+ required: true,
72
+ },
73
+ rowIndex: {
74
+ type: Number,
75
+ required: true,
76
+ },
77
+ texts: {
78
+ type: Object,
79
+ required: false,
80
+ default: () => ({}),
81
+ },
82
+ widths: {
83
+ type: Object,
84
+ required: false,
85
+ default: () => ({}),
86
+ },
87
+ },
88
+ setup(props) {
89
+ const {
90
+ idBtnDown,
91
+ idBtnUp,
92
+ } = IdAPI(props);
93
+
94
+ return {
95
+ columnStyles: computed(() => ({
96
+ maxWidth: `${ props.widths.dndColumn }px`,
97
+ minWidth: `${ props.widths.dndColumn }px`,
98
+ width: `${ props.widths.dndColumn }px`,
99
+ })),
100
+ idBtnDown,
101
+ idBtnUp,
102
+ };
103
+ },
104
+ render() {
105
+ const tag = this.isHeader ? "th" : "td";
106
+ const isHandleDraggable = this.isDragAndDrop && !this.isDndDisabled;
107
+
108
+ return h(tag, {
109
+ class: [
110
+ "a_table_form__cell",
111
+ `a_table_form__cell_${ tag }`,
112
+ "a_table_form__cell_reorder",
113
+ ],
114
+ style: this.columnStyles,
115
+ }, [
116
+ this.isHeader ?
117
+ h("span", {
118
+ class: "a_sr_only",
119
+ }, [
120
+ h(ATranslation, {
121
+ tag: "span",
122
+ text: this.texts.reorderColumn,
123
+ }),
124
+ ]) :
125
+ this.isCreateMode ?
126
+ null :
127
+ this.isFooter ?
128
+ null :
129
+ h("div", {
130
+ class: "a_table_form__reorder_actions",
131
+ }, [
132
+ this.canMoveRowUp(this.rowIndex) && h(AButton, {
133
+ id: this.idBtnUp,
134
+ class: "a_sr_only_focusable a_btn a_btn_transparent_dark a_table_form__reorder_button",
135
+ disabled: this.isDndDisabled,
136
+ iconLeft: ChevronUp,
137
+ preventKeyboardRepeat: true,
138
+ tabindex: this.isDndDisabled ? -1 : undefined,
139
+ title: this.texts.reorderUp,
140
+ textScreenReader: this.texts.reorderUp,
141
+ onClick: () => this.moveRowUp(this.rowIndex),
142
+ }),
143
+ h("span", {
144
+ ariaHidden: true,
145
+ class: [
146
+ "a_table_form__reorder_handle",
147
+ {
148
+ a_table_form__reorder_handle_disabled: this.isDndDisabled,
149
+ },
150
+ ],
151
+ draggable: isHandleDraggable,
152
+ onDragend: isHandleDraggable ? this.onDragend : undefined,
153
+ onDragstart: isHandleDraggable ? ($event => this.onDragstart($event, this.rowIndex)) : undefined,
154
+ }, [
155
+ h(AIcon, {
156
+ class: "a_table_form__reorder_icon",
157
+ icon: this.isDndDisabled ? LockFill : GripVertical,
158
+ }),
159
+ ]),
160
+ h("span", {
161
+ class: "a_sr_only",
162
+ }, [
163
+ h(ATranslation, {
164
+ tag: "span",
165
+ text: this.isDndDisabled ? this.texts.reorderDisabled : this.texts.reorderHandle,
166
+ }),
167
+ ]),
168
+ this.canMoveRowDown(this.rowIndex) && h(AButton, {
169
+ id: this.idBtnDown,
170
+ class: "a_sr_only_focusable a_btn a_btn_transparent_dark a_table_form__reorder_button",
171
+ disabled: this.isDndDisabled,
172
+ iconLeft: ChevronDown,
173
+ preventKeyboardRepeat: true,
174
+ tabindex: this.isDndDisabled ? -1 : undefined,
175
+ title: this.texts.reorderDown,
176
+ textScreenReader: this.texts.reorderDown,
177
+ onClick: () => this.moveRowDown(this.rowIndex),
178
+ }),
179
+ ]),
180
+ ]);
181
+ },
182
+ };
@@ -0,0 +1,162 @@
1
+ import {
2
+ computed,
3
+ reactive,
4
+ } from "vue";
5
+ import {
6
+ describe,
7
+ expect,
8
+ it,
9
+ jest,
10
+ } from "@jest/globals";
11
+ import {
12
+ mount,
13
+ } from "@vue/test-utils";
14
+
15
+ import AIcon from "../../AIcon/AIcon";
16
+ import ATableFormCellDnd from "../ATableFormCellDnd/ATableFormCellDnd";
17
+
18
+ import DragAndDropAPI from "../compositionAPI/DragAndDropAPI";
19
+
20
+ import LockFill from "aloha-svg/dist/js/bootstrap/LockFill";
21
+
22
+ jest.mock("../../AButton/AButton", () => {
23
+ const {
24
+ h,
25
+ } = require("vue");
26
+
27
+ return {
28
+ __esModule: true,
29
+ default: {
30
+ name: "AButton",
31
+ inheritAttrs: false,
32
+ props: {
33
+ disabled: Boolean,
34
+ textScreenReader: String,
35
+ },
36
+ render() {
37
+ return h("button", {
38
+ disabled: this.disabled,
39
+ }, this.textScreenReader);
40
+ },
41
+ },
42
+ };
43
+ });
44
+ jest.mock("aloha-svg/dist/js/bootstrap/ChevronDown", () => ({
45
+ __esModule: true,
46
+ default: "ChevronDown",
47
+ }));
48
+ jest.mock("aloha-svg/dist/js/bootstrap/ChevronUp", () => ({
49
+ __esModule: true,
50
+ default: "ChevronUp",
51
+ }));
52
+ jest.mock("aloha-svg/dist/js/bootstrap/GripVertical", () => ({
53
+ __esModule: true,
54
+ default: "GripVertical",
55
+ }));
56
+ jest.mock("aloha-svg/dist/js/bootstrap/LockFill", () => ({
57
+ __esModule: true,
58
+ default: "LockFill",
59
+ }));
60
+
61
+ describe("ATableForm DragAndDropAPI", () => {
62
+ it("prevents dragging, dropping on, and moving across a disabled row", () => {
63
+ const emit = jest.fn();
64
+ const props = reactive({
65
+ dndDisabledCallback: ({ row }) => row.dndDisabled,
66
+ focusAfterMove: false,
67
+ id: "table",
68
+ isDragAndDrop: true,
69
+ rows: [
70
+ { id: 1 },
71
+ { dndDisabled: true, id: 2 },
72
+ { id: 3 },
73
+ { id: 4 },
74
+ ],
75
+ });
76
+ const {
77
+ draggedRowIndex,
78
+ isDndDisabledForRow,
79
+ moveRowDown,
80
+ onDragover,
81
+ onDragstart,
82
+ onDrop,
83
+ } = DragAndDropAPI(props, { emit }, {
84
+ isDndDisabled: computed(() => false),
85
+ });
86
+
87
+ expect(isDndDisabledForRow(0)).toBe(false);
88
+ expect(isDndDisabledForRow(1)).toBe(true);
89
+
90
+ onDragstart({}, 1);
91
+ expect(draggedRowIndex.value).toBeUndefined();
92
+
93
+ onDragstart({}, 0);
94
+ expect(draggedRowIndex.value).toBe(0);
95
+
96
+ const preventDefaultDisabled = jest.fn();
97
+ onDragover({
98
+ preventDefault: preventDefaultDisabled,
99
+ }, 1);
100
+ onDrop({
101
+ preventDefault: preventDefaultDisabled,
102
+ }, 1);
103
+
104
+ expect(preventDefaultDisabled).not.toHaveBeenCalled();
105
+ expect(emit).not.toHaveBeenCalled();
106
+
107
+ const preventDefaultAfterLock = jest.fn();
108
+ onDragover({
109
+ currentTarget: undefined,
110
+ preventDefault: preventDefaultAfterLock,
111
+ }, 2);
112
+ onDrop({
113
+ preventDefault: preventDefaultAfterLock,
114
+ }, 2);
115
+
116
+ expect(preventDefaultAfterLock).toHaveBeenCalledTimes(2);
117
+ expect(emit).not.toHaveBeenCalled();
118
+
119
+ moveRowDown(2);
120
+
121
+ expect(emit).toHaveBeenCalledWith("updateRows", expect.objectContaining({
122
+ fromIndex: 2,
123
+ toIndex: 3,
124
+ trigger: "moveRowDown",
125
+ }));
126
+ });
127
+ });
128
+
129
+ describe("ATableFormCellDnd", () => {
130
+ it("shows a lock and disables move buttons for a disabled row", () => {
131
+ const wrapper = mount(ATableFormCellDnd, {
132
+ props: {
133
+ canMoveRowDown: () => true,
134
+ canMoveRowUp: () => true,
135
+ id: "table_1",
136
+ isDndDisabled: true,
137
+ isDragAndDrop: true,
138
+ moveRowDown: jest.fn(),
139
+ moveRowUp: jest.fn(),
140
+ onDragend: jest.fn(),
141
+ onDragstart: jest.fn(),
142
+ rowIndex: 1,
143
+ texts: {
144
+ reorderDisabled: "Row reordering disabled",
145
+ reorderDown: "Move row down",
146
+ reorderHandle: "Drag row to reorder",
147
+ reorderUp: "Move row up",
148
+ },
149
+ widths: {
150
+ dndColumn: 56,
151
+ },
152
+ },
153
+ });
154
+
155
+ expect(wrapper.findComponent(AIcon).props("icon")).toBe(LockFill);
156
+ expect(wrapper.find(".a_table_form__reorder_handle").attributes("draggable")).toBe("false");
157
+ expect(wrapper.find(".a_table_form__reorder_handle_disabled").exists()).toBe(true);
158
+ expect(wrapper.text()).toContain("Row reordering disabled");
159
+ expect(wrapper.findAll("button")).toHaveLength(2);
160
+ expect(wrapper.findAll("button").every(button => button.attributes("disabled") !== undefined)).toBe(true);
161
+ });
162
+ });