aloha-vue 2.68.0 → 2.70.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.68.0",
3
+ "version": "2.70.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",
@@ -88,11 +88,16 @@ export default {
88
88
  required: false,
89
89
  default: undefined,
90
90
  },
91
- focusAfterMove: {
92
- type: Boolean,
93
- required: false,
94
- default: true,
95
- },
91
+ focusAfterMove: {
92
+ type: Boolean,
93
+ required: false,
94
+ default: true,
95
+ },
96
+ fullWidthRowCallback: {
97
+ type: Function,
98
+ required: false,
99
+ default: undefined,
100
+ },
96
101
  icons: {
97
102
  type: Object,
98
103
  required: false,
@@ -466,9 +471,10 @@ export default {
466
471
  draggedRowIndex: this.draggedRowIndex,
467
472
  editModel: this.activeEditRowKey === rowKey ? this.activeEditModel : undefined,
468
473
  editFocusColumnId: this.activeEditRowKey === rowKey ? this.activeEditFocusColumnId : undefined,
469
- errorIcon: this.errorIcon,
470
- extra: this.extra,
471
- hasActionsColumn: this.hasActionsColumn,
474
+ errorIcon: this.errorIcon,
475
+ extra: this.extra,
476
+ fullWidthRowCallback: this.fullWidthRowCallback,
477
+ hasActionsColumn: this.hasActionsColumn,
472
478
  hasActiveEditRow: this.hasActiveEditRow,
473
479
  isActionsSticky: this.isActionsSticky,
474
480
  isActiveEditMode: this.activeEditRowKey === rowKey,
@@ -589,8 +595,9 @@ export default {
589
595
  columns: this.columnsVisible,
590
596
  columnsStylesGrow: this.columnsStylesGrow,
591
597
  draggedRowIndex: this.draggedRowIndex,
592
- extra: this.extra,
593
- hasActionsColumn: this.hasActionsColumn,
598
+ extra: this.extra,
599
+ fullWidthRowCallback: this.fullWidthRowCallback,
600
+ hasActionsColumn: this.hasActionsColumn,
594
601
  hasActiveEditRow: this.hasActiveEditRow,
595
602
  isActionsSticky: this.isActionsSticky,
596
603
  isActiveEditMode: false,
@@ -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,
@@ -140,11 +140,16 @@ export default {
140
140
  required: false,
141
141
  default: undefined,
142
142
  },
143
- extra: {
144
- type: Object,
145
- required: false,
146
- default: undefined,
147
- },
143
+ extra: {
144
+ type: Object,
145
+ required: false,
146
+ default: undefined,
147
+ },
148
+ fullWidthRowCallback: {
149
+ type: Function,
150
+ required: false,
151
+ default: undefined,
152
+ },
148
153
  hasActionsColumn: {
149
154
  type: Boolean,
150
155
  required: false,
@@ -357,11 +362,12 @@ export default {
357
362
  };
358
363
  },
359
364
  computed: {
360
- canEditOnRowClick() {
361
- if (
362
- !this.isEditOnRowClick ||
363
- !this.isEditable ||
364
- this.isActiveEditMode ||
365
+ canEditOnRowClick() {
366
+ if (
367
+ !this.isEditOnRowClick ||
368
+ !this.isEditable ||
369
+ this.isFullWidthRow ||
370
+ this.isActiveEditMode ||
365
371
  this.isCreateMode ||
366
372
  this.isFooter ||
367
373
  this.isHeader ||
@@ -387,10 +393,26 @@ export default {
387
393
  })) {
388
394
  return false;
389
395
  }
390
-
391
- return true;
392
- },
393
- currentRowData() {
396
+
397
+ return true;
398
+ },
399
+ isFullWidthRow() {
400
+ if (
401
+ this.isHeader ||
402
+ this.isCreateMode ||
403
+ this.isActiveEditMode ||
404
+ !isFunction(this.fullWidthRowCallback)
405
+ ) {
406
+ return false;
407
+ }
408
+
409
+ return !!this.$slots.fullWidthRow && !!this.fullWidthRowCallback({
410
+ isFooter: this.isFooter,
411
+ row: this.row,
412
+ rowIndex: this.rowIndex,
413
+ });
414
+ },
415
+ currentRowData() {
394
416
  return this.isActiveEditMode && this.modelLocal ? this.modelLocal : this.row;
395
417
  },
396
418
  },
@@ -438,8 +460,8 @@ export default {
438
460
  },
439
461
  },
440
462
  },
441
- render() {
442
- const rows = [];
463
+ render() {
464
+ const rows = [];
443
465
 
444
466
  if (this.isActiveEditMode && this.texts.editInfoText) {
445
467
  rows.push(h("tr", {
@@ -460,7 +482,20 @@ export default {
460
482
  ]));
461
483
  }
462
484
 
463
- rows.push(h("tr", {
485
+ let fullWidthRowCells;
486
+ if (this.isFullWidthRow) {
487
+ fullWidthRowCells = [h("td", {
488
+ class: "a_table_form__cell a_table_form__cell_full_width",
489
+ colspan: this.allColumnsLength,
490
+ }, this.$slots.fullWidthRow({
491
+ isFooter: this.isFooter,
492
+ row: this.row,
493
+ rowIndex: this.rowIndex,
494
+ rows: this.rows,
495
+ }))];
496
+ }
497
+
498
+ rows.push(h("tr", {
464
499
  id: this.idTr,
465
500
  "aria-grabbed": !this.isHeader && !this.isFooter ? this.draggedRowIndex === this.rowIndex : undefined,
466
501
  class: [
@@ -474,98 +509,98 @@ export default {
474
509
  onDragleave: this.onDragleave && ($event => this.onDragleave($event, this.rowIndex)),
475
510
  onDragover: this.onDragover && ($event => this.onDragover($event, this.rowIndex)),
476
511
  onDrop: this.onDrop && ($event => this.onDrop($event, this.rowIndex)),
477
- }, [
478
- this.isDragAndDrop ?
479
- h(ATableFormCellDnd, {
480
- id: this.idTr,
481
- canMoveRowDown: this.canMoveRowDown,
482
- canMoveRowUp: this.canMoveRowUp,
483
- isCreateMode: this.isCreateMode,
484
- isDndDisabled: this.isDndDisabled,
485
- isDndLocked: this.isDndLocked,
486
- isDragAndDrop: this.isDragAndDrop,
487
- isFooter: this.isFooter,
488
- isHeader: this.isHeader,
489
- moveRowDown: this.moveRowDown,
490
- moveRowUp: this.moveRowUp,
491
- onDragend: this.onDragend,
492
- onDragstart: this.onDragstart,
493
- rowIndex: this.rowIndex,
494
- texts: this.texts,
495
- widths: this.widths,
496
- }) :
497
- null,
498
- ...(this.rowView === "list" && !this.isHeader ?
499
- [h(ATableFormCellList, {
500
- id: this.idTr,
501
- columns: this.columns,
502
- errors: this.errorsLocal,
503
- isCreateMode: this.isCreateMode,
504
- isEditable: this.isEditable,
505
- isEditMode: this.isActiveEditMode,
506
- isFooter: this.isFooter,
507
- onUpdateRowData: this.updateModelLocal,
508
- row: this.row,
509
- rowData: this.currentRowData,
510
- rowIndex: this.rowIndex,
511
- rows: this.rows,
512
- }, this.$slots)] :
513
- this.columns.map((column, columnIndex) => {
514
- if (this.isHeader) {
515
- return h(ATableFormTh, {
516
- column,
517
- columnStyle: this.columnsStylesGrow[column.id],
518
- isEditable: this.isEditable,
519
- }, this.$slots);
520
- }
521
-
522
- return h(ATableFormCell, {
523
- id: this.idTr,
524
- column,
525
- columnIndex,
526
- columnStyle: this.columnsStylesGrow[column.id],
527
- errorIcon: this.errorIcon,
528
- errors: this.errorsLocal,
529
- isCreateMode: this.isCreateMode,
530
- isEditable: this.isEditable,
531
- isEditMode: this.isActiveEditMode,
532
- isFooter: this.isFooter,
533
- onUpdateRowData: this.updateModelLocal,
534
- row: this.row,
535
- rowData: this.currentRowData,
536
- rowIndex: this.rowIndex,
537
- rows: this.rows,
538
- tag: this.cellTag,
539
- }, this.$slots);
540
- })),
541
- this.hasActionsColumn ?
542
- h(ATableFormCellAction, {
543
- id: this.idTr,
544
- actionsClasses: this.actionsClasses,
545
- actionsDisabledCallback: this.actionsDisabledCallback,
546
- actionsHideCallback: this.actionsHideCallback,
547
- actionsTitleCallback: this.actionsTitleCallback,
548
- extra: this.extra,
549
- hasActiveEditRow: this.hasActiveEditRow,
550
- isActionsSticky: this.isActionsSticky,
551
- isActiveEditMode: this.isActiveEditMode,
552
- isDeletable: this.isDeletable,
553
- isDeletableConfirm: this.isDeletableConfirm,
554
- isEditable: this.isEditable,
555
- isFooter: this.isFooter,
556
- isHeader: this.isHeader,
557
- isSaving: this.isSaving,
558
- onCancelEditRow: this.cancelEditRow,
559
- onDeleteRow: this.onDeleteRow,
560
- onEditRow: this.onEditRow,
561
- onSaveEditRow: this.saveEditRow,
562
- row: this.row,
563
- rowIndex: this.rowIndex,
564
- texts: this.texts,
565
- widths: this.widths,
566
- }) :
567
- null,
568
- ]));
512
+ }, fullWidthRowCells || [
513
+ this.isDragAndDrop ?
514
+ h(ATableFormCellDnd, {
515
+ id: this.idTr,
516
+ canMoveRowDown: this.canMoveRowDown,
517
+ canMoveRowUp: this.canMoveRowUp,
518
+ isCreateMode: this.isCreateMode,
519
+ isDndDisabled: this.isDndDisabled,
520
+ isDndLocked: this.isDndLocked,
521
+ isDragAndDrop: this.isDragAndDrop,
522
+ isFooter: this.isFooter,
523
+ isHeader: this.isHeader,
524
+ moveRowDown: this.moveRowDown,
525
+ moveRowUp: this.moveRowUp,
526
+ onDragend: this.onDragend,
527
+ onDragstart: this.onDragstart,
528
+ rowIndex: this.rowIndex,
529
+ texts: this.texts,
530
+ widths: this.widths,
531
+ }) :
532
+ null,
533
+ ...(this.rowView === "list" && !this.isHeader ?
534
+ [h(ATableFormCellList, {
535
+ id: this.idTr,
536
+ columns: this.columns,
537
+ errors: this.errorsLocal,
538
+ isCreateMode: this.isCreateMode,
539
+ isEditable: this.isEditable,
540
+ isEditMode: this.isActiveEditMode,
541
+ isFooter: this.isFooter,
542
+ onUpdateRowData: this.updateModelLocal,
543
+ row: this.row,
544
+ rowData: this.currentRowData,
545
+ rowIndex: this.rowIndex,
546
+ rows: this.rows,
547
+ }, this.$slots)] :
548
+ this.columns.map((column, columnIndex) => {
549
+ if (this.isHeader) {
550
+ return h(ATableFormTh, {
551
+ column,
552
+ columnStyle: this.columnsStylesGrow[column.id],
553
+ isEditable: this.isEditable,
554
+ }, this.$slots);
555
+ }
556
+
557
+ return h(ATableFormCell, {
558
+ id: this.idTr,
559
+ column,
560
+ columnIndex,
561
+ columnStyle: this.columnsStylesGrow[column.id],
562
+ errorIcon: this.errorIcon,
563
+ errors: this.errorsLocal,
564
+ isCreateMode: this.isCreateMode,
565
+ isEditable: this.isEditable,
566
+ isEditMode: this.isActiveEditMode,
567
+ isFooter: this.isFooter,
568
+ onUpdateRowData: this.updateModelLocal,
569
+ row: this.row,
570
+ rowData: this.currentRowData,
571
+ rowIndex: this.rowIndex,
572
+ rows: this.rows,
573
+ tag: this.cellTag,
574
+ }, this.$slots);
575
+ })),
576
+ this.hasActionsColumn ?
577
+ h(ATableFormCellAction, {
578
+ id: this.idTr,
579
+ actionsClasses: this.actionsClasses,
580
+ actionsDisabledCallback: this.actionsDisabledCallback,
581
+ actionsHideCallback: this.actionsHideCallback,
582
+ actionsTitleCallback: this.actionsTitleCallback,
583
+ extra: this.extra,
584
+ hasActiveEditRow: this.hasActiveEditRow,
585
+ isActionsSticky: this.isActionsSticky,
586
+ isActiveEditMode: this.isActiveEditMode,
587
+ isDeletable: this.isDeletable,
588
+ isDeletableConfirm: this.isDeletableConfirm,
589
+ isEditable: this.isEditable,
590
+ isFooter: this.isFooter,
591
+ isHeader: this.isHeader,
592
+ isSaving: this.isSaving,
593
+ onCancelEditRow: this.cancelEditRow,
594
+ onDeleteRow: this.onDeleteRow,
595
+ onEditRow: this.onEditRow,
596
+ onSaveEditRow: this.saveEditRow,
597
+ row: this.row,
598
+ rowIndex: this.rowIndex,
599
+ texts: this.texts,
600
+ widths: this.widths,
601
+ }) :
602
+ null,
603
+ ]));
569
604
 
570
605
  if (this.rowView === "table" && this.isActiveEditMode && this.hasErrors) {
571
606
  rows.push(h("tr", {
@@ -1,6 +1,7 @@
1
- import {
2
- computed,
3
- nextTick,
1
+ import {
2
+ computed,
3
+ h,
4
+ nextTick,
4
5
  reactive,
5
6
  ref,
6
7
  } from "vue";
@@ -443,7 +444,7 @@ describe("ATableForm list view", () => {
443
444
  expect(wrapper.findComponent(AForm).props("readonly")).toBe(false);
444
445
  });
445
446
 
446
- it("allows DND but not row-click editing when rows are not editable", async() => {
447
+ it("allows DND but not row-click editing when rows are not editable", async() => {
447
448
  const wrapper = mount(ATableForm, {
448
449
  props: {
449
450
  columns: [
@@ -465,8 +466,112 @@ describe("ATableForm list view", () => {
465
466
 
466
467
  await wrapper.find("tbody tr.a_table_form__row").trigger("click");
467
468
 
468
- expect(wrapper.find("tbody button[id$='_save']").exists()).toBe(false);
469
- });
469
+ expect(wrapper.find("tbody button[id$='_save']").exists()).toBe(false);
470
+ });
471
+
472
+ it("renders a matching row as one full-width cell", async() => {
473
+ const rows = [
474
+ {
475
+ id: 1,
476
+ name: "Section",
477
+ type: "separator",
478
+ },
479
+ {
480
+ id: 2,
481
+ name: "Regular row",
482
+ type: "data",
483
+ },
484
+ ];
485
+ const fullWidthRowCallback = jest.fn(({ row }) => row.type === "separator");
486
+ const wrapper = mount(ATableForm, {
487
+ props: {
488
+ columns: [
489
+ {
490
+ id: "id",
491
+ label: "ID",
492
+ },
493
+ {
494
+ id: "name",
495
+ label: "Name",
496
+ },
497
+ ],
498
+ fullWidthRowCallback,
499
+ isDragAndDrop: true,
500
+ isEditable: true,
501
+ isEditOnRowClick: true,
502
+ keyId: "id",
503
+ rows,
504
+ },
505
+ slots: {
506
+ fullWidthRow: ({ isFooter, row, rowIndex, rows: rowsSlot }) => h("strong", {
507
+ class: "full-width-row-content",
508
+ "data-is-footer": `${ isFooter }`,
509
+ "data-row-index": rowIndex,
510
+ "data-rows-length": rowsSlot.length,
511
+ }, row.name),
512
+ },
513
+ });
514
+
515
+ const bodyRows = wrapper.findAll("tbody tr.a_table_form__row");
516
+ const fullWidthCell = bodyRows[0].find(".a_table_form__cell_full_width");
517
+
518
+ expect(bodyRows).toHaveLength(2);
519
+ expect(bodyRows[0].findAll("td")).toHaveLength(1);
520
+ expect(fullWidthCell.attributes("colspan")).toBe("4");
521
+ expect(fullWidthCell.text()).toBe("Section");
522
+ expect(fullWidthCell.find(".full-width-row-content").attributes()).toEqual(expect.objectContaining({
523
+ "data-is-footer": "false",
524
+ "data-row-index": "0",
525
+ "data-rows-length": "2",
526
+ }));
527
+ expect(bodyRows[0].find(".a_table_form__cell_reorder").exists()).toBe(false);
528
+ expect(bodyRows[0].find(".a_table_form__cell_actions").exists()).toBe(false);
529
+ expect(bodyRows[0].classes()).not.toContain("a_table_form__row_edit_on_click");
530
+ expect(bodyRows[1].findAll("td")).toHaveLength(4);
531
+ expect(bodyRows[1].classes()).toContain("a_table_form__row_edit_on_click");
532
+ expect(fullWidthRowCallback).toHaveBeenCalledWith({
533
+ isFooter: false,
534
+ row: rows[0],
535
+ rowIndex: 0,
536
+ });
537
+
538
+ await bodyRows[0].trigger("click");
539
+
540
+ expect(wrapper.find("tbody button[id$='_save']").exists()).toBe(false);
541
+ });
542
+
543
+ it("renders matching footer rows through the full-width slot", () => {
544
+ const footerRow = {
545
+ label: "Summary",
546
+ type: "summary",
547
+ };
548
+ const wrapper = mount(ATableForm, {
549
+ props: {
550
+ columns: [
551
+ {
552
+ id: "name",
553
+ label: "Name",
554
+ },
555
+ {
556
+ id: "value",
557
+ label: "Value",
558
+ },
559
+ ],
560
+ fullWidthRowCallback: ({ row }) => row.type === "summary",
561
+ rows: [{ name: "Item", value: 1 }],
562
+ rowsFooter: [footerRow],
563
+ },
564
+ slots: {
565
+ fullWidthRow: ({ isFooter, row }) => h("span", `${ isFooter }:${ row.label }`),
566
+ },
567
+ });
568
+
569
+ const footerCells = wrapper.findAll("tfoot td");
570
+
571
+ expect(footerCells).toHaveLength(1);
572
+ expect(footerCells[0].attributes("colspan")).toBe("2");
573
+ expect(footerCells[0].text()).toBe("true:Summary");
574
+ });
470
575
 
471
576
  it("enters edit mode by row click only when enabled and row edit is available", async() => {
472
577
  const rows = [
@@ -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,