aloha-vue 2.67.0 → 2.69.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aloha-vue",
3
- "version": "2.67.0",
3
+ "version": "2.69.0",
4
4
  "description": "Aloha-vue is a JavaScript library that provides a wide range of accessible components and directives for Vue.js. Accessibility is of paramount importance to us, and we have designed all our components to meet accessibility compliance criteria. This library is a valuable tool for frontend developers and has already been used in three projects, including two large-scale ones",
5
5
  "keywords": [
6
6
  "accessibility compliance criteria",
@@ -161,8 +161,16 @@ export default {
161
161
  } = this.formElementLocal;
162
162
 
163
163
  const slotProps = {
164
+ change: this.updateRowData,
164
165
  column: this.column,
165
166
  columnIndex: this.columnIndex,
167
+ errorIcon: this.errorIcon,
168
+ errors: this.errors,
169
+ id: this.id,
170
+ isCreateMode: this.isCreateMode,
171
+ isEditMode: this.isEditMode,
172
+ isFooter: this.isFooter,
173
+ modelValue: get(this.rowDataLocal, this.column.id),
166
174
  row: this.row,
167
175
  rowIndex: this.rowIndex,
168
176
  rows: this.rows,
@@ -88,12 +88,17 @@ export default {
88
88
  required: false,
89
89
  default: undefined,
90
90
  },
91
- dataExtra: {
92
- type: Array,
93
- required: false,
94
- default: () => [],
95
- },
96
- dependencies: {
91
+ dataExtra: {
92
+ type: Array,
93
+ required: false,
94
+ default: () => [],
95
+ },
96
+ mergeData: {
97
+ type: Boolean,
98
+ required: false,
99
+ default: false,
100
+ },
101
+ dependencies: {
97
102
  type: [Array, Object],
98
103
  required: false,
99
104
  default: undefined,
@@ -353,9 +353,10 @@ export default {
353
353
  } = VerifyAPI(props);
354
354
 
355
355
  const {
356
- clearModel,
357
- displayValue,
358
- initLocalVars,
356
+ clearModel,
357
+ displayValue,
358
+ displayValueReadonly,
359
+ initLocalVars,
359
360
  isInternalChange,
360
361
  localModel,
361
362
  modelNumber,
@@ -415,9 +416,10 @@ export default {
415
416
  attributesToExcludeFromRender,
416
417
  clearModel,
417
418
  componentStyleHide,
418
- decrease,
419
- displayValue,
420
- errorsId,
419
+ decrease,
420
+ displayValue,
421
+ displayValueReadonly,
422
+ errorsId,
421
423
  hasErrorIcon,
422
424
  handleInput,
423
425
  handleKeydown,
@@ -452,7 +454,7 @@ export default {
452
454
  label: this.label,
453
455
  labelClass: this.labelClass,
454
456
  labelScreenReader: this.labelScreenReader,
455
- modelValue: this.displayValue,
457
+ modelValue: this.displayValueReadonly,
456
458
  readonlyDefault: this.readonlyDefault,
457
459
  required: this.required,
458
460
  style: this.componentStyleHide,
@@ -0,0 +1,73 @@
1
+ import {
2
+ reactive,
3
+ } from "vue";
4
+ import {
5
+ describe,
6
+ expect,
7
+ it,
8
+ } from "@jest/globals";
9
+
10
+ import ModelAPI from "../compositionAPI/ModelAPI";
11
+
12
+ const getModelAPI = () => {
13
+ const props = reactive({
14
+ currencySymbol: "€",
15
+ currencySymbolPosition: "right",
16
+ decimalDivider: ",",
17
+ decimalPartLength: 2,
18
+ disabled: false,
19
+ modelType: "number",
20
+ modelUndefined: undefined,
21
+ modelValue: 1234.5,
22
+ required: false,
23
+ skipRequiredModelInit: false,
24
+ thousandDivider: ".",
25
+ });
26
+ const modelAPI = ModelAPI(props, {
27
+ adjustFloatPartAndDivider: () => "1.234,50",
28
+ });
29
+
30
+ modelAPI.initLocalVars();
31
+
32
+ return {
33
+ modelAPI,
34
+ props,
35
+ };
36
+ };
37
+
38
+ describe("AInputCurrency ModelAPI", () => {
39
+ it("adds the currency symbol to the readonly display value at the configured position", () => {
40
+ const {
41
+ modelAPI,
42
+ props,
43
+ } = getModelAPI();
44
+
45
+ expect(modelAPI.displayValueReadonly.value).toBe("1.234,50 €");
46
+
47
+ props.currencySymbol = "$";
48
+ props.currencySymbolPosition = "left";
49
+
50
+ expect(modelAPI.displayValueReadonly.value).toBe("$ 1.234,50");
51
+ });
52
+
53
+ it("does not add the currency symbol to an empty readonly display value", () => {
54
+ const {
55
+ modelAPI,
56
+ } = getModelAPI();
57
+
58
+ modelAPI.displayValue.value = "";
59
+
60
+ expect(modelAPI.displayValueReadonly.value).toBe("");
61
+ });
62
+
63
+ it("keeps the readonly display value unchanged when the currency symbol is empty", () => {
64
+ const {
65
+ modelAPI,
66
+ props,
67
+ } = getModelAPI();
68
+
69
+ props.currencySymbol = "";
70
+
71
+ expect(modelAPI.displayValueReadonly.value).toBe("1.234,50");
72
+ });
73
+ });
@@ -13,20 +13,32 @@ export default function ModelAPI(props, {
13
13
  adjustFloatPartAndDivider = () => {},
14
14
  changeModel = () => {},
15
15
  }) {
16
- const required = toRef(props, "required");
17
- const modelValue = toRef(props, "modelValue");
16
+ const currencySymbol = toRef(props, "currencySymbol");
17
+ const currencySymbolPosition = toRef(props, "currencySymbolPosition");
18
+ const decimalDivider = toRef(props, "decimalDivider");
19
+ const decimalPartLength = toRef(props, "decimalPartLength");
20
+ const disabled = toRef(props, "disabled");
18
21
  const modelType = toRef(props, "modelType");
19
22
  const modelUndefined = toRef(props, "modelUndefined");
23
+ const modelValue = toRef(props, "modelValue");
24
+ const required = toRef(props, "required");
20
25
  const skipRequiredModelInit = toRef(props, "skipRequiredModelInit");
21
- const decimalDivider = toRef(props, "decimalDivider");
22
- const disabled = toRef(props, "disabled");
23
- const decimalPartLength = toRef(props, "decimalPartLength");
24
26
  const thousandDivider = toRef(props, "thousandDivider");
25
27
 
26
28
  const displayValue = ref(undefined);
27
29
  const isInternalChange = ref(false);
28
30
  const localModel = ref(undefined);
29
31
 
32
+ const displayValueReadonly = computed(() => {
33
+ if (isNil(displayValue.value) || displayValue.value === "" || !currencySymbol.value) {
34
+ return displayValue.value;
35
+ }
36
+
37
+ return currencySymbolPosition.value === "left" ?
38
+ `${ currencySymbol.value } ${ displayValue.value }` :
39
+ `${ displayValue.value } ${ currencySymbol.value }`;
40
+ });
41
+
30
42
  const initLocalVars = () => {
31
43
  displayValue.value = adjustFloatPartAndDivider(modelValue.value);
32
44
  localModel.value = modelValue.value;
@@ -78,6 +90,7 @@ export default function ModelAPI(props, {
78
90
  return {
79
91
  clearModel,
80
92
  displayValue,
93
+ displayValueReadonly,
81
94
  initLocalVars,
82
95
  isInternalChange,
83
96
  localModel,
@@ -119,12 +119,17 @@ export default {
119
119
  required: false,
120
120
  default: undefined,
121
121
  },
122
- dataExtra: {
123
- type: Array,
124
- required: false,
125
- default: () => [],
126
- },
127
- dependencies: {
122
+ dataExtra: {
123
+ type: Array,
124
+ required: false,
125
+ default: () => [],
126
+ },
127
+ mergeData: {
128
+ type: Boolean,
129
+ required: false,
130
+ default: false,
131
+ },
132
+ dependencies: {
128
133
  type: [Array, Object],
129
134
  required: false,
130
135
  default: undefined,
@@ -88,12 +88,17 @@ export default {
88
88
  required: false,
89
89
  default: undefined,
90
90
  },
91
- dataExtra: {
92
- type: Array,
93
- required: false,
94
- default: () => [],
95
- },
96
- dependencies: {
91
+ dataExtra: {
92
+ type: Array,
93
+ required: false,
94
+ default: () => [],
95
+ },
96
+ mergeData: {
97
+ type: Boolean,
98
+ required: false,
99
+ default: false,
100
+ },
101
+ dependencies: {
97
102
  type: [Array, Object],
98
103
  required: false,
99
104
  default: undefined,
@@ -122,12 +122,17 @@ export default {
122
122
  required: false,
123
123
  default: undefined,
124
124
  },
125
- dataExtra: {
126
- type: Array,
127
- required: false,
128
- default: () => ASelectPluginOptions.propsDefault.dataExtra,
129
- },
130
- dependencies: {
125
+ dataExtra: {
126
+ type: Array,
127
+ required: false,
128
+ default: () => ASelectPluginOptions.propsDefault.dataExtra,
129
+ },
130
+ mergeData: {
131
+ type: Boolean,
132
+ required: false,
133
+ default: false,
134
+ },
135
+ dependencies: {
131
136
  type: [Array, Object],
132
137
  required: false,
133
138
  default: undefined,
@@ -31,9 +31,10 @@ export default function UiDataWithKeyIdAndLabelAPI(props) {
31
31
  const data = toRef(props, "data");
32
32
  const dataExtra = toRef(props, "dataExtra");
33
33
  const isDataSimpleArray = toRef(props, "isDataSimpleArray");
34
- const keyId = toRef(props, "keyId");
35
- const keyLabel = toRef(props, "keyLabel");
36
- const keyLabelCallback = toRef(props, "keyLabelCallback");
34
+ const keyId = toRef(props, "keyId");
35
+ const keyLabel = toRef(props, "keyLabel");
36
+ const keyLabelCallback = toRef(props, "keyLabelCallback");
37
+ const mergeData = toRef(props, "mergeData");
37
38
  const searchTextInHtml = toRef(props, "searchTextInHtml");
38
39
  const translateData = toRef(props, "translateData");
39
40
 
@@ -156,7 +157,14 @@ export default function UiDataWithKeyIdAndLabelAPI(props) {
156
157
  let DATA_LOCAL = data.value || [];
157
158
 
158
159
  if (dataFromServer.value.length) {
159
- DATA_LOCAL = dataFromServer.value;
160
+ if (mergeData.value) {
161
+ DATA_LOCAL = uniqBy([
162
+ ...dataFromServer.value,
163
+ ...DATA_LOCAL,
164
+ ], item => get(item, keyId.value, item));
165
+ } else {
166
+ DATA_LOCAL = dataFromServer.value;
167
+ }
160
168
  }
161
169
 
162
170
  if (!dataFromRetrieve.value.length) {
@@ -0,0 +1,128 @@
1
+ import {
2
+ createApp,
3
+ defineComponent,
4
+ } from "vue";
5
+ import {
6
+ describe,
7
+ expect,
8
+ it,
9
+ jest,
10
+ } from "@jest/globals";
11
+
12
+ import UiDataWithKeyIdAndLabelAPI from "../UiDataWithKeyIdAndLabelAPI";
13
+
14
+ import {
15
+ AKeyId,
16
+ AKeyLabel,
17
+ } from "../../../const/AKeys";
18
+
19
+ jest.mock("../../../index", () => ({
20
+ AKeyId: "_a_id",
21
+ AKeyLabel: "_a_label",
22
+ AKeyLabelSearch: "_a_label_search",
23
+ extractTextFromHtml: value => value,
24
+ getTranslatedText: ({ placeholder }) => placeholder,
25
+ isArrayOfArrays: value => Array.isArray(value) && value.every(Array.isArray),
26
+ isPlaceholderTranslate: () => false,
27
+ }));
28
+
29
+ const createProps = ({
30
+ data,
31
+ isDataSimpleArray = false,
32
+ mergeData = false,
33
+ }) => ({
34
+ alwaysTranslate: false,
35
+ data,
36
+ dataExtra: [],
37
+ isDataSimpleArray,
38
+ keyId: "id",
39
+ keyLabel: "label",
40
+ keyLabelCallback: undefined,
41
+ mergeData,
42
+ searchTextInHtml: false,
43
+ translateData: false,
44
+ });
45
+
46
+ const useDataAPI = props => {
47
+ let result;
48
+ const app = createApp(defineComponent({
49
+ name: "TestUiDataWithKeyIdAndLabelAPI",
50
+ setup() {
51
+ result = UiDataWithKeyIdAndLabelAPI(props);
52
+ return () => null;
53
+ },
54
+ }));
55
+
56
+ app.mount(document.createElement("div"));
57
+ return result;
58
+ };
59
+
60
+ describe("UiDataWithKeyIdAndLabelAPI", () => {
61
+ it("keeps replacing prop data with internally loaded data by default", () => {
62
+ const {
63
+ dataFromServer,
64
+ dataLocal,
65
+ } = useDataAPI(createProps({
66
+ data: [
67
+ { id: 1, label: "Prop one" },
68
+ { id: 3, label: "Prop three" },
69
+ ],
70
+ }));
71
+
72
+ dataFromServer.value = [
73
+ { id: 1, label: "Internal one" },
74
+ { id: 2, label: "Internal two" },
75
+ ];
76
+
77
+ expect(dataLocal.value.map(item => item[AKeyLabel])).toEqual([
78
+ "Internal one",
79
+ "Internal two",
80
+ ]);
81
+ });
82
+
83
+ it("merges prop and internally loaded data by ID with internal items taking precedence", () => {
84
+ const {
85
+ dataFromServer,
86
+ dataLocal,
87
+ } = useDataAPI(createProps({
88
+ data: [
89
+ { id: 1, label: "Prop one" },
90
+ { id: 3, label: "Prop three" },
91
+ ],
92
+ mergeData: true,
93
+ }));
94
+
95
+ dataFromServer.value = [
96
+ { id: 1, label: "Internal one" },
97
+ { id: 2, label: "Internal two" },
98
+ ];
99
+
100
+ expect(dataLocal.value.map(item => ({
101
+ id: item[AKeyId],
102
+ label: item[AKeyLabel],
103
+ }))).toEqual([
104
+ { id: 1, label: "Internal one" },
105
+ { id: 2, label: "Internal two" },
106
+ { id: 3, label: "Prop three" },
107
+ ]);
108
+ });
109
+
110
+ it("merges simple arrays by their values", () => {
111
+ const {
112
+ dataFromServer,
113
+ dataLocal,
114
+ } = useDataAPI(createProps({
115
+ data: ["one", "three"],
116
+ isDataSimpleArray: true,
117
+ mergeData: true,
118
+ }));
119
+
120
+ dataFromServer.value = ["one", "two"];
121
+
122
+ expect(dataLocal.value.map(item => item[AKeyId])).toEqual([
123
+ "one",
124
+ "two",
125
+ "three",
126
+ ]);
127
+ });
128
+ });