vueless 1.3.9-beta.8 → 1.4.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/composables/useUI.ts +187 -155
- package/composables/useVirtualScroll.ts +100 -0
- package/package.json +2 -2
- package/types.ts +11 -0
- package/ui.button-link/ULink.vue +18 -2
- package/ui.data-table/UTable.vue +597 -198
- package/ui.data-table/UTableRow.vue +372 -168
- package/ui.data-table/config.ts +33 -5
- package/ui.data-table/storybook/stories.ts +163 -0
- package/ui.data-table/tests/UTable.test.ts +456 -20
- package/ui.data-table/tests/UTableRow.test.ts +35 -104
- package/ui.data-table/types.ts +57 -0
- package/ui.data-table/utilTable.ts +16 -10
- package/ui.form-checkbox/UCheckbox.vue +3 -7
- package/ui.text-notify/config.ts +1 -1
- package/ui.text-number/UNumber.vue +36 -2
- package/ui.text-number/config.ts +1 -0
- package/ui.text-number/storybook/stories.ts +11 -0
- package/ui.text-number/tests/UNumber.test.ts +90 -0
- package/ui.text-number/types.ts +5 -0
- package/utils/node/mergeConfigs.d.ts +2 -2
- package/utils/node/mergeConfigs.js +240 -121
- package/utils/node/vuelessConfig.d.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { flushPromises, mount } from "@vue/test-utils";
|
|
2
2
|
import { describe, it, expect, vi } from "vitest";
|
|
3
|
-
import { ref } from "vue";
|
|
3
|
+
import { ref, nextTick } from "vue";
|
|
4
4
|
|
|
5
5
|
import UTableRow from "../UTableRow.vue";
|
|
6
6
|
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
@@ -36,6 +36,10 @@ describe("UTableRow.vue", () => {
|
|
|
36
36
|
bodyRowAttrs: ref({ class: "row-base" }),
|
|
37
37
|
bodyCellStickyLeftAttrs: ref({ class: "sticky-left" }),
|
|
38
38
|
bodyCellStickyRightAttrs: ref({ class: "sticky-right" }),
|
|
39
|
+
bodyCellSearchMatchAttrs: ref({ class: "search-match" }),
|
|
40
|
+
bodyCellSearchMatchTextAttrs: ref({ class: "search-match-text" }),
|
|
41
|
+
bodyCellSearchMatchActiveAttrs: ref({ class: "search-match-active" }),
|
|
42
|
+
bodyCellSearchMatchTextActiveAttrs: ref({ class: "search-match-active-text" }),
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
const defaultConfig = {
|
|
@@ -64,6 +68,7 @@ describe("UTableRow.vue", () => {
|
|
|
64
68
|
config: defaultConfig,
|
|
65
69
|
isChecked: false,
|
|
66
70
|
isExpanded: false,
|
|
71
|
+
isVisible: true,
|
|
67
72
|
columnPositions,
|
|
68
73
|
...overrides,
|
|
69
74
|
};
|
|
@@ -260,14 +265,17 @@ describe("UTableRow.vue", () => {
|
|
|
260
265
|
}),
|
|
261
266
|
});
|
|
262
267
|
|
|
263
|
-
|
|
268
|
+
let icon = component.findComponent(UIcon);
|
|
264
269
|
|
|
265
270
|
expect(icon.props("name")).toBe(defaultConfig.defaults.expandIcon);
|
|
266
271
|
|
|
267
|
-
component.setProps({ isExpanded: true });
|
|
268
|
-
|
|
272
|
+
await component.setProps({ isExpanded: true });
|
|
273
|
+
await nextTick();
|
|
269
274
|
await flushPromises();
|
|
270
275
|
|
|
276
|
+
// Re-query the icon after props update
|
|
277
|
+
icon = component.findComponent(UIcon);
|
|
278
|
+
|
|
271
279
|
expect(icon.props("name")).toBe(defaultConfig.defaults.collapseIcon);
|
|
272
280
|
});
|
|
273
281
|
|
|
@@ -286,106 +294,8 @@ describe("UTableRow.vue", () => {
|
|
|
286
294
|
});
|
|
287
295
|
});
|
|
288
296
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const component = mount(UTableRow, {
|
|
292
|
-
props: getDefaultProps(),
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
await component.get("tr").trigger("click");
|
|
296
|
-
|
|
297
|
-
expect(component.emitted("click")).toBeTruthy();
|
|
298
|
-
expect(component.emitted("click")![0][0]).toEqual(defaultRow);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it("Double Click – emits dblclick event when row is double-clicked", async () => {
|
|
302
|
-
const component = mount(UTableRow, {
|
|
303
|
-
props: getDefaultProps(),
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
await component.get("tr").trigger("dblclick");
|
|
307
|
-
|
|
308
|
-
expect(component.emitted("dblclick")).toBeTruthy();
|
|
309
|
-
expect(component.emitted("dblclick")![0][0]).toEqual(defaultRow);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it("Click Cell – emits clickCell event when cell is clicked", async () => {
|
|
313
|
-
const component = mount(UTableRow, {
|
|
314
|
-
props: getDefaultProps(),
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
const firstCell = component.find("td");
|
|
318
|
-
|
|
319
|
-
await firstCell.trigger("click");
|
|
320
|
-
|
|
321
|
-
expect(component.emitted("clickCell")).toBeTruthy();
|
|
322
|
-
expect(component.emitted("clickCell")![0]).toEqual(["John Doe", defaultRow, "name"]);
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
it("Toggle Expand – emits toggleExpand event when expand icon is clicked", async () => {
|
|
326
|
-
const expandableRow: FlatRow = {
|
|
327
|
-
...defaultRow,
|
|
328
|
-
row: [{ id: "2", name: "Child", nestedLeveL: 1 }],
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
const component = mount(UTableRow, {
|
|
332
|
-
props: getDefaultProps({ row: expandableRow }),
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
const expandIcon = component.find("[data-row-toggle-icon='1']");
|
|
336
|
-
|
|
337
|
-
await expandIcon.trigger("click");
|
|
338
|
-
|
|
339
|
-
expect(component.emitted("toggleExpand")).toBeTruthy();
|
|
340
|
-
expect(component.emitted("toggleExpand")![0][0]).toEqual(expandableRow);
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
it("Toggle Checkbox – emits toggleCheckbox event when checkbox is changed", async () => {
|
|
344
|
-
const component = mount(UTableRow, {
|
|
345
|
-
props: getDefaultProps({ selectable: true }),
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
const checkbox = component.getComponent(UCheckbox);
|
|
349
|
-
|
|
350
|
-
await checkbox.vm.$emit("input", defaultRow);
|
|
351
|
-
|
|
352
|
-
expect(component.emitted("toggleCheckbox")).toBeTruthy();
|
|
353
|
-
expect(component.emitted("toggleCheckbox")![0][0]).toEqual(defaultRow);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it("Checkbox Cell – prevents row click events when checkbox cell is clicked", async () => {
|
|
357
|
-
const component = mount(UTableRow, {
|
|
358
|
-
props: getDefaultProps({ selectable: true }),
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
const checkboxCell = component.find("td");
|
|
362
|
-
|
|
363
|
-
await checkboxCell.trigger("click");
|
|
364
|
-
await checkboxCell.trigger("dblclick");
|
|
365
|
-
|
|
366
|
-
expect(component.emitted("click")).toBeFalsy();
|
|
367
|
-
expect(component.emitted("dblclick")).toBeFalsy();
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
it("Expand Icon – prevents row click events when expand icon is clicked", async () => {
|
|
371
|
-
const expandableRow: FlatRow = {
|
|
372
|
-
...defaultRow,
|
|
373
|
-
row: [{ id: "2", name: "Child", nestedLeveL: 1 }],
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
const component = mount(UTableRow, {
|
|
377
|
-
props: getDefaultProps({ row: expandableRow }),
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
const expandIcon = component.find("[data-row-toggle-icon='1']");
|
|
381
|
-
|
|
382
|
-
await expandIcon.trigger("click");
|
|
383
|
-
await expandIcon.trigger("dblclick");
|
|
384
|
-
|
|
385
|
-
expect(component.emitted("click")).toBeFalsy();
|
|
386
|
-
expect(component.emitted("dblclick")).toBeFalsy();
|
|
387
|
-
});
|
|
388
|
-
});
|
|
297
|
+
// Events are now handled by UTable via event delegation
|
|
298
|
+
// UTableRow no longer emits click, dblclick, clickCell, toggleExpand, or toggleCheckbox events
|
|
389
299
|
|
|
390
300
|
describe("Slots", () => {
|
|
391
301
|
it("Cell Slot – renders custom content from cell slot", () => {
|
|
@@ -550,5 +460,26 @@ describe("UTableRow.vue", () => {
|
|
|
550
460
|
|
|
551
461
|
expect(iconWrapper.exists()).toBe(true);
|
|
552
462
|
});
|
|
463
|
+
|
|
464
|
+
it("isVisible – shows row when isVisible is true", () => {
|
|
465
|
+
const component = mount(UTableRow, {
|
|
466
|
+
props: getDefaultProps({ isVisible: true }),
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
const row = component.find("tr");
|
|
470
|
+
const style = row.attributes("style") || "";
|
|
471
|
+
|
|
472
|
+
expect(style).not.toContain("display: none");
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it("isVisible – hides row when isVisible is false", () => {
|
|
476
|
+
const component = mount(UTableRow, {
|
|
477
|
+
props: getDefaultProps({ isVisible: false }),
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const row = component.find("tr");
|
|
481
|
+
|
|
482
|
+
expect(row.attributes("style")).toContain("display: none");
|
|
483
|
+
});
|
|
553
484
|
});
|
|
554
485
|
});
|
package/ui.data-table/types.ts
CHANGED
|
@@ -16,6 +16,12 @@ export type RowId = string | number;
|
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
17
|
export type Cell = CellObject & any;
|
|
18
18
|
|
|
19
|
+
export interface SearchMatch {
|
|
20
|
+
rowId: RowId;
|
|
21
|
+
columnKey: string;
|
|
22
|
+
indices: number[];
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
export interface RowData {
|
|
20
26
|
[key: string]: Cell;
|
|
21
27
|
}
|
|
@@ -111,6 +117,41 @@ export interface Props {
|
|
|
111
117
|
*/
|
|
112
118
|
loading?: boolean;
|
|
113
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Enable virtual scrolling for large datasets.
|
|
122
|
+
*/
|
|
123
|
+
virtualScroll?: boolean;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Fixed row height in pixels (used for virtual scroll calculations).
|
|
127
|
+
*/
|
|
128
|
+
rowHeight?: number;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Height of the scroll container (CSS value).
|
|
132
|
+
*/
|
|
133
|
+
scrollHeight?: string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Number of extra rows to render above/below viewport.
|
|
137
|
+
*/
|
|
138
|
+
bufferSize?: number;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Search string to highlight in table cells.
|
|
142
|
+
*/
|
|
143
|
+
search?: string;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Index of the current search match to highlight (0-based).
|
|
147
|
+
*/
|
|
148
|
+
searchMatch?: number;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Enable text ellipsis for table cells (renders div wrapper for overflow handling).
|
|
152
|
+
*/
|
|
153
|
+
textEllipsis?: boolean;
|
|
154
|
+
|
|
114
155
|
/**
|
|
115
156
|
* Component config object.
|
|
116
157
|
*/
|
|
@@ -135,11 +176,20 @@ export interface UTableRowAttrs {
|
|
|
135
176
|
bodyRowAttrs: Ref<UnknownObject>;
|
|
136
177
|
bodyCellStickyLeftAttrs: Ref<UnknownObject>;
|
|
137
178
|
bodyCellStickyRightAttrs: Ref<UnknownObject>;
|
|
179
|
+
bodyCellSearchMatchAttrs: Ref<UnknownObject>;
|
|
180
|
+
bodyCellSearchMatchTextAttrs: Ref<UnknownObject>;
|
|
181
|
+
bodyCellSearchMatchActiveAttrs: Ref<UnknownObject>;
|
|
182
|
+
bodyCellSearchMatchTextActiveAttrs: Ref<UnknownObject>;
|
|
138
183
|
}
|
|
139
184
|
|
|
140
185
|
export interface UTableRowProps {
|
|
141
186
|
row: FlatRow;
|
|
142
187
|
columns: ColumnObject[];
|
|
188
|
+
/**
|
|
189
|
+
* Row index in the parent table (used for slot params).
|
|
190
|
+
* Optional to keep UTableRow mountable standalone in tests/internal usage.
|
|
191
|
+
*/
|
|
192
|
+
rowIndex?: number;
|
|
143
193
|
emptyCellLabel?: string;
|
|
144
194
|
selectable: boolean;
|
|
145
195
|
nestedLevel: number;
|
|
@@ -149,5 +199,12 @@ export interface UTableRowProps {
|
|
|
149
199
|
config: Config;
|
|
150
200
|
isChecked: boolean;
|
|
151
201
|
isExpanded: boolean;
|
|
202
|
+
isVisible: boolean;
|
|
152
203
|
columnPositions: Map<string, number>;
|
|
204
|
+
search?: string;
|
|
205
|
+
searchMatchColumns?: Set<string>;
|
|
206
|
+
activeSearchMatchColumn?: string;
|
|
207
|
+
textEllipsis?: boolean;
|
|
208
|
+
onToggleExpand?: (row: Row) => void;
|
|
209
|
+
onToggleCheckbox?: (row: Row) => void;
|
|
153
210
|
}
|
|
@@ -7,24 +7,30 @@ export function normalizeColumns(columns: Column[]): ColumnObject[] {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function mapRowColumns(row: Row, columns: ColumnObject[]): RowData {
|
|
10
|
-
const
|
|
11
|
-
return columns.some((column) => column.key === item[0] && column.isShown !== false);
|
|
12
|
-
});
|
|
10
|
+
const visibleKeys = new Set(columns.filter((col) => col.isShown !== false).map((col) => col.key));
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
const result: RowData = {};
|
|
13
|
+
|
|
14
|
+
for (const key of Object.keys(row)) {
|
|
15
|
+
if (visibleKeys.has(key)) {
|
|
16
|
+
result[key] = row[key];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
export function getFlatRows(tableRows: Row[]) {
|
|
18
24
|
const rows: FlatRow[] = [];
|
|
19
25
|
|
|
20
26
|
function addRow(row: Row, nestedLevel: number, parentRowId?: string | number) {
|
|
21
|
-
|
|
22
|
-
row
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
const flatRow: FlatRow = {
|
|
28
|
+
...row,
|
|
29
|
+
nestedLevel,
|
|
30
|
+
...(parentRowId !== undefined ? { parentRowId } : {}),
|
|
31
|
+
};
|
|
26
32
|
|
|
27
|
-
rows.push(
|
|
33
|
+
rows.push(flatRow);
|
|
28
34
|
|
|
29
35
|
if (row.row && !Array.isArray(row.row)) {
|
|
30
36
|
addRow(row.row, nestedLevel + 1, row.id);
|
|
@@ -121,10 +121,6 @@ function onChange() {
|
|
|
121
121
|
emit("input", newModelValue);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function onIconClick() {
|
|
125
|
-
document.getElementById(elementId)?.click();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
124
|
/**
|
|
129
125
|
* Get element / nested component attributes for each config token ✨
|
|
130
126
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
@@ -185,10 +181,10 @@ const {
|
|
|
185
181
|
@change="onChange"
|
|
186
182
|
/>
|
|
187
183
|
|
|
188
|
-
<
|
|
184
|
+
<label
|
|
189
185
|
v-if="isChecked"
|
|
190
186
|
v-bind="partial ? partiallyCheckedAttrs : checkedAttrs"
|
|
191
|
-
|
|
187
|
+
:for="elementId"
|
|
192
188
|
>
|
|
193
189
|
<UIcon
|
|
194
190
|
v-if="partial"
|
|
@@ -198,7 +194,7 @@ const {
|
|
|
198
194
|
/>
|
|
199
195
|
|
|
200
196
|
<UIcon v-else :name="config.defaults.checkedIcon" color="inherit" v-bind="checkedIconAttrs" />
|
|
201
|
-
</
|
|
197
|
+
</label>
|
|
202
198
|
|
|
203
199
|
<template #bottom>
|
|
204
200
|
<!-- @slot Use it to add something below the checkbox. -->
|
package/ui.text-notify/config.ts
CHANGED
|
@@ -15,7 +15,7 @@ export default /*tw*/ {
|
|
|
15
15
|
bodyWarning: "{>body} bg-radial-[circle_at_0%_50%] from-warning/25 from-2.17% to-transparent",
|
|
16
16
|
bodyError: "{>body} bg-radial-[circle_at_0%_50%] from-error/25 from-2.17% to-transparent",
|
|
17
17
|
bodyInfo: "{>body} bg-radial-[circle_at_0%_50%] from-info/25 from-2.17% to-transparent",
|
|
18
|
-
content: "w-full flex flex-col max-w-full text-medium text-inverted",
|
|
18
|
+
content: "w-full flex flex-col max-w-full text-medium text-inverted break-all text-wrap",
|
|
19
19
|
label: "mb-0.5 font-medium",
|
|
20
20
|
description: "wrap-break-word font-normal",
|
|
21
21
|
statusIcon: "{UIcon} brightness-125 dark:brightness-75",
|
|
@@ -48,6 +48,38 @@ const preparedNumber = computed(() => {
|
|
|
48
48
|
);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
const formattedNumber = computed(() => {
|
|
52
|
+
let result = "";
|
|
53
|
+
|
|
54
|
+
if (props.currencyAlign === "left" && props.currency) {
|
|
55
|
+
result += props.currency;
|
|
56
|
+
|
|
57
|
+
if (props.currencySpace) {
|
|
58
|
+
result += " ";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (props.value) {
|
|
63
|
+
result += mathSign.value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
result += preparedNumber.value.integer;
|
|
67
|
+
|
|
68
|
+
if (props.maxFractionDigits > 0) {
|
|
69
|
+
result += preparedNumber.value.decimalSeparator + preparedNumber.value.fraction;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (props.currencyAlign === "right" && props.currency) {
|
|
73
|
+
if (props.currencySpace) {
|
|
74
|
+
result += " ";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
result += props.currency;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return result;
|
|
81
|
+
});
|
|
82
|
+
|
|
51
83
|
defineExpose({
|
|
52
84
|
/**
|
|
53
85
|
* A reference to the component's wrapper element for direct DOM manipulation.
|
|
@@ -76,10 +108,12 @@ const {
|
|
|
76
108
|
<!-- @slot Use it to add something before the number. -->
|
|
77
109
|
<slot name="left" />
|
|
78
110
|
|
|
79
|
-
<
|
|
111
|
+
<template v-if="raw">{{ formattedNumber }}</template>
|
|
112
|
+
|
|
113
|
+
<div v-else v-bind="numberAttrs" :data-test="getDataTest()">
|
|
80
114
|
<span v-if="currencyAlign === 'left' && currency" v-bind="currencyAttrs" v-text="currency" />
|
|
81
115
|
|
|
82
|
-
<span v-if="value" v-bind="mathSignAttrs" v-text="mathSign" />
|
|
116
|
+
<span v-if="value && mathSign" v-bind="mathSignAttrs" v-text="mathSign" />
|
|
83
117
|
|
|
84
118
|
<span v-bind="integerAttrs" v-text="preparedNumber.integer" />
|
|
85
119
|
|
package/ui.text-number/config.ts
CHANGED
|
@@ -92,6 +92,17 @@ Sizes.args = { enum: "size" };
|
|
|
92
92
|
export const CurrencyAlign = EnumTemplate.bind({});
|
|
93
93
|
CurrencyAlign.args = { enum: "currencyAlign", currency: "USD", currencySpace: true };
|
|
94
94
|
|
|
95
|
+
export const Raw = DefaultTemplate.bind({});
|
|
96
|
+
Raw.args = { raw: true, currency: "USD", currencySpace: true };
|
|
97
|
+
Raw.parameters = {
|
|
98
|
+
docs: {
|
|
99
|
+
description: {
|
|
100
|
+
story:
|
|
101
|
+
"When `raw` is enabled, the number is displayed without formatting and html tags, showing only the raw value.",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
95
106
|
export const LimitFractionDigits: StoryFn<UNumberArgs> = (args: UNumberArgs) => ({
|
|
96
107
|
components: { UNumber, UCol },
|
|
97
108
|
setup: () => ({ args }),
|
|
@@ -192,6 +192,96 @@ describe("UNumber.vue", () => {
|
|
|
192
192
|
});
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
+
it("Raw – renders formatted number as plain text without HTML elements when raw is true", () => {
|
|
196
|
+
const component = mount(UNumber, {
|
|
197
|
+
props: {
|
|
198
|
+
value,
|
|
199
|
+
raw: true,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Should render plain text without the number div structure
|
|
204
|
+
expect(component.find("[vl-key='number']").exists()).toBe(false);
|
|
205
|
+
expect(component.text()).toContain("1 234,56");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("Raw – renders with currency when raw is true and currency is set", () => {
|
|
209
|
+
const currency = "$";
|
|
210
|
+
|
|
211
|
+
const component = mount(UNumber, {
|
|
212
|
+
props: {
|
|
213
|
+
value,
|
|
214
|
+
currency,
|
|
215
|
+
currencyAlign: "left",
|
|
216
|
+
raw: true,
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
expect(component.text()).toBe("$1 234,56");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("Raw – renders with currency and space when raw is true, currency is set, and currencySpace is true", () => {
|
|
224
|
+
const currency = "$";
|
|
225
|
+
|
|
226
|
+
const component = mount(UNumber, {
|
|
227
|
+
props: {
|
|
228
|
+
value,
|
|
229
|
+
currency,
|
|
230
|
+
currencyAlign: "left",
|
|
231
|
+
currencySpace: true,
|
|
232
|
+
raw: true,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(component.text()).toBe("$ 1 234,56");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("Raw – renders with currency on right when raw is true and currencyAlign is right", () => {
|
|
240
|
+
const currency = "$";
|
|
241
|
+
|
|
242
|
+
const component = mount(UNumber, {
|
|
243
|
+
props: {
|
|
244
|
+
value,
|
|
245
|
+
currency,
|
|
246
|
+
currencyAlign: "right",
|
|
247
|
+
raw: true,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(component.text()).toBe("1 234,56$");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// eslint-disable-next-line vue/max-len
|
|
255
|
+
it("Raw – renders with currency on right and space when raw is true, currencyAlign is right, and currencySpace is true", () => {
|
|
256
|
+
const currency = "$";
|
|
257
|
+
|
|
258
|
+
const component = mount(UNumber, {
|
|
259
|
+
props: {
|
|
260
|
+
value,
|
|
261
|
+
currency,
|
|
262
|
+
currencyAlign: "right",
|
|
263
|
+
currencySpace: true,
|
|
264
|
+
raw: true,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(component.text()).toBe("1 234,56 $");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("Raw – renders with sign when raw is true and sign is set", () => {
|
|
272
|
+
const testNegativeValue = -123;
|
|
273
|
+
|
|
274
|
+
const component = mount(UNumber, {
|
|
275
|
+
props: {
|
|
276
|
+
value: testNegativeValue,
|
|
277
|
+
sign: MATH_SIGN_TYPE.auto as Props["sign"],
|
|
278
|
+
raw: true,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
expect(component.text()).toContain(MATH_SIGN.MINUS);
|
|
283
|
+
});
|
|
284
|
+
|
|
195
285
|
it("MinFractionDigits – adds zeros to meet the minimum fraction digits requirement", () => {
|
|
196
286
|
const value = 123;
|
|
197
287
|
const minFractionDigits = 2;
|
package/ui.text-number/types.ts
CHANGED
|
@@ -48,6 +48,11 @@ export interface Props {
|
|
|
48
48
|
*/
|
|
49
49
|
currencySpace?: boolean;
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Show formatted number as plain text without HTML elements.
|
|
53
|
+
*/
|
|
54
|
+
raw?: boolean;
|
|
55
|
+
|
|
51
56
|
/**
|
|
52
57
|
* Minimal number of signs after the decimal separator (fractional part of a number).
|
|
53
58
|
*/
|
|
@@ -4,10 +4,10 @@ export function createMergeConfigs(cx: any): ({ defaultConfig, globalConfig, pro
|
|
|
4
4
|
propsConfig: any;
|
|
5
5
|
config?: {} | undefined;
|
|
6
6
|
isVariants?: boolean | undefined;
|
|
7
|
-
}) =>
|
|
7
|
+
}) => any;
|
|
8
8
|
export function createGetMergedConfig(cx: any): ({ defaultConfig, globalConfig, propsConfig, unstyled }: {
|
|
9
9
|
defaultConfig: any;
|
|
10
10
|
globalConfig: any;
|
|
11
11
|
propsConfig: any;
|
|
12
12
|
unstyled: any;
|
|
13
|
-
}) =>
|
|
13
|
+
}) => any;
|