vueless 0.0.673 → 0.0.675
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/bin/commands/create.js +77 -0
- package/bin/commands/index.js +2 -0
- package/bin/commands/init.js +4 -8
- package/bin/constants.js +2 -5
- package/bin/index.js +1 -1
- package/bin/utils/dataUtils.js +53 -0
- package/bin/utils/formatUtil.js +48 -0
- package/constants.js +7 -0
- package/package.json +2 -2
- package/plugin-vite.js +3 -1
- package/types.ts +2 -0
- package/ui.boilerplate/storybook/stories.ts +1 -1
- package/ui.text-badge/storybook/stories.ts +1 -1
- package/ui.text-empty/storybook/stories.ts +1 -1
- package/ui.text-file/storybook/stories.ts +1 -1
- package/ui.text-files/storybook/stories.ts +1 -1
- package/ui.text-money/UMoney.vue +23 -67
- package/ui.text-money/config.ts +12 -32
- package/ui.text-money/storybook/stories.ts +49 -52
- package/ui.text-money/types.ts +1 -1
- package/ui.text-notify/storybook/stories.ts +1 -1
- package/ui.text-number/UNumber.vue +76 -0
- package/ui.text-number/config.ts +42 -0
- package/ui.text-number/constants.ts +5 -0
- package/ui.text-number/storybook/docs.mdx +16 -0
- package/ui.text-number/storybook/stories.ts +105 -0
- package/ui.text-number/types.ts +82 -0
- package/{ui.text-money/utilMoney.ts → ui.text-number/utilNumber.ts} +13 -14
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { cwd } from "node:process";
|
|
5
|
+
import { cp, readFile, writeFile, rename } from "node:fs/promises";
|
|
6
|
+
import { styleText } from "node:util";
|
|
7
|
+
|
|
8
|
+
import { getDirFiles } from "../../utils/node/helper.js";
|
|
9
|
+
import { replaceRelativeImports } from "../utils/formatUtil.js";
|
|
10
|
+
import { getLastStorybookId } from "../utils/dataUtils.js";
|
|
11
|
+
|
|
12
|
+
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
13
|
+
|
|
14
|
+
import { COMPONENTS, VUELESS_DIR, VUELESS_LOCAL_DIR } from "../../constants.js";
|
|
15
|
+
|
|
16
|
+
const boilerplateName = "UBoilerplate";
|
|
17
|
+
const boilerplatePath = path.join(cwd(), VUELESS_DIR, "ui.boilerplate");
|
|
18
|
+
|
|
19
|
+
export async function createVuelessComponent(options) {
|
|
20
|
+
const [componentName] = options;
|
|
21
|
+
|
|
22
|
+
if (!componentName) {
|
|
23
|
+
throw new Error("Component name is required");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isSrcDir = existsSync(path.join(cwd(), VUELESS_LOCAL_DIR));
|
|
27
|
+
const destPath = isSrcDir
|
|
28
|
+
? path.join(cwd(), SRC_COMPONENTS_PATH, componentName)
|
|
29
|
+
: path.join(cwd(), COMPONENTS_PATH, componentName);
|
|
30
|
+
|
|
31
|
+
const isComponentExists = componentName in COMPONENTS || existsSync(destPath);
|
|
32
|
+
|
|
33
|
+
if (isComponentExists) {
|
|
34
|
+
throw new Error(`Component with name ${componentName} alrady exists`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await cp(boilerplatePath, destPath, { recursive: true });
|
|
38
|
+
|
|
39
|
+
await modifyCreatedComponent(destPath, componentName);
|
|
40
|
+
|
|
41
|
+
const successMessage = styleText(
|
|
42
|
+
"green",
|
|
43
|
+
`Success: ${componentName} was created in ${destPath} directory`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
console.log(successMessage);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function modifyCreatedComponent(destPath, componentName) {
|
|
50
|
+
const destFiles = await getDirFiles(destPath, "");
|
|
51
|
+
const lastStorybookId = await getLastStorybookId();
|
|
52
|
+
|
|
53
|
+
for await (const filePath of destFiles) {
|
|
54
|
+
const fileContent = await readFile(filePath, "utf-8");
|
|
55
|
+
|
|
56
|
+
let updatedContent = replaceRelativeImports(componentName, filePath, fileContent);
|
|
57
|
+
let targetPath = filePath;
|
|
58
|
+
|
|
59
|
+
if (filePath.endsWith("constants.ts")) {
|
|
60
|
+
updatedContent = updatedContent.replace(boilerplateName, componentName);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (filePath.endsWith("stories.ts")) {
|
|
64
|
+
updatedContent = updatedContent
|
|
65
|
+
.replaceAll(boilerplateName, componentName)
|
|
66
|
+
.replace("{{component_id}}", String(lastStorybookId + 10));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (targetPath.endsWith(`${boilerplateName}.vue`)) {
|
|
70
|
+
targetPath = targetPath.replace(boilerplateName, componentName);
|
|
71
|
+
|
|
72
|
+
await rename(filePath, targetPath);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await writeFile(targetPath, updatedContent);
|
|
76
|
+
}
|
|
77
|
+
}
|
package/bin/commands/index.js
CHANGED
package/bin/commands/init.js
CHANGED
|
@@ -5,14 +5,10 @@ import path from "node:path";
|
|
|
5
5
|
import { writeFile } from "node:fs/promises";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
JAVASCRIPT_EXT,
|
|
13
|
-
} from "../constants.js";
|
|
14
|
-
|
|
15
|
-
const destPath = path.join(cwd(), DEFAULT_VUELESS_CONFIG_NAME);
|
|
8
|
+
import { DEFAULT_VUELESS_CONFIG_CONTNET } from "../constants.js";
|
|
9
|
+
import { JAVASCRIPT_EXT, TYPESCRIPT_EXT, VUELESS_CONFIG_FILE_NAME } from "../../constants.js";
|
|
10
|
+
|
|
11
|
+
const destPath = path.join(cwd(), VUELESS_CONFIG_FILE_NAME);
|
|
16
12
|
|
|
17
13
|
const vuelessInitOptions = ["--ts", "--js"];
|
|
18
14
|
|
package/bin/constants.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
3
|
-
export const FAILURE_CODE = 1;
|
|
4
|
-
export const TYPESCRIPT_EXT = ".ts";
|
|
5
|
-
export const JAVASCRIPT_EXT = ".js";
|
|
1
|
+
export const SRC_COMPONENTS_PATH = "/src/components";
|
|
2
|
+
export const COMPONENTS_PATH = "/components";
|
|
6
3
|
export const DEFAULT_VUELESS_CONFIG_CONTNET = `
|
|
7
4
|
export default {
|
|
8
5
|
/**
|
package/bin/index.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { cwd } from "node:process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
import { getDirFiles } from "../../utils/node/helper.js";
|
|
7
|
+
|
|
8
|
+
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
9
|
+
import { VUELESS_DIR } from "../../constants.js";
|
|
10
|
+
|
|
11
|
+
const storiesName = "stories.ts";
|
|
12
|
+
|
|
13
|
+
export async function getLastStorybookId() {
|
|
14
|
+
const srcComponentsDir = path.join(cwd(), SRC_COMPONENTS_PATH);
|
|
15
|
+
const componentsDir = path.join(cwd(), COMPONENTS_PATH);
|
|
16
|
+
const vuelessPackagePath = path.join(cwd(), VUELESS_DIR);
|
|
17
|
+
const isSrcComponentsDir = existsSync(srcComponentsDir);
|
|
18
|
+
const isComponentsDir = existsSync(componentsDir);
|
|
19
|
+
|
|
20
|
+
const stories = await getDirFiles(vuelessPackagePath, storiesName);
|
|
21
|
+
|
|
22
|
+
if (isSrcComponentsDir) {
|
|
23
|
+
const srcComponentsDirStories = await getDirFiles(srcComponentsDir, storiesName);
|
|
24
|
+
|
|
25
|
+
stories.push(...srcComponentsDirStories);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (isComponentsDir) {
|
|
29
|
+
const componentsDirStories = await getDirFiles(componentsDir, storiesName);
|
|
30
|
+
|
|
31
|
+
stories.push(...componentsDirStories);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let id = 200000;
|
|
35
|
+
|
|
36
|
+
for await (const storyPath of stories) {
|
|
37
|
+
const storyContent = await readFile(storyPath, "utf-8");
|
|
38
|
+
|
|
39
|
+
const storyIdLine = storyContent.split("\n").find((line, idx, array) => {
|
|
40
|
+
return line.includes("id:") && idx && array[idx - 1].includes("export default");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!storyIdLine) continue;
|
|
44
|
+
|
|
45
|
+
const currentId = parseInt(storyIdLine.split(" ").at(-1).replaceAll('"', ""));
|
|
46
|
+
|
|
47
|
+
if (currentId > id && !Number.isNaN(currentId)) {
|
|
48
|
+
id = currentId;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return id;
|
|
53
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
export function replaceRelativeImports(componentName, filePath, fileContent) {
|
|
4
|
+
const isTopLevelFile = path.dirname(filePath).endsWith(componentName);
|
|
5
|
+
const contentLines = fileContent.split("\n");
|
|
6
|
+
|
|
7
|
+
return contentLines.map((line) => replaceRelativeLineImports(line, isTopLevelFile)).join("\n");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function replaceRelativeLineImports(line, isTopLevelFile) {
|
|
11
|
+
const importRegex = /import\s+(?:[\w\s{},*]+)\s+from\s+(['"])(\.\.?\/.*?)(\.[tj]s)?\1(?!\?)/g;
|
|
12
|
+
|
|
13
|
+
const isTopLevelLocalImport = isTopLevelFile && !line.includes("../");
|
|
14
|
+
const isInnerLocalImport =
|
|
15
|
+
!isTopLevelFile && (line.includes("../") || line.includes("./")) && !line.includes("../../");
|
|
16
|
+
|
|
17
|
+
if (isTopLevelLocalImport || isInnerLocalImport) {
|
|
18
|
+
return line;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return line.replace(importRegex, (match, quote, oldPath, ext) => {
|
|
22
|
+
const isDefaultImport = match.includes("{");
|
|
23
|
+
|
|
24
|
+
if (!isDefaultImport) {
|
|
25
|
+
match = defaultToNamedImport(match);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return match.replace(oldPath + (ext || ""), "vueless");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function defaultToNamedImport(importString) {
|
|
33
|
+
const splittedImport = importString.split(" ");
|
|
34
|
+
|
|
35
|
+
return splittedImport
|
|
36
|
+
.map((importStringToken) => {
|
|
37
|
+
if (importStringToken.includes("import")) {
|
|
38
|
+
return `${importStringToken} { `;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (importStringToken.includes("from")) {
|
|
42
|
+
return ` } ${importStringToken} `;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return importStringToken;
|
|
46
|
+
})
|
|
47
|
+
.join("");
|
|
48
|
+
}
|
package/constants.js
CHANGED
|
@@ -119,6 +119,7 @@ export const COMPONENTS = {
|
|
|
119
119
|
UFiles: "ui.text-files",
|
|
120
120
|
UEmpty: "ui.text-empty",
|
|
121
121
|
UBadge: "ui.text-badge",
|
|
122
|
+
UNumber: "ui.text-number",
|
|
122
123
|
|
|
123
124
|
/* Containers */
|
|
124
125
|
UDivider: "ui.container-divider",
|
|
@@ -220,6 +221,10 @@ export const VUELESS_ICONS_LOCAL_DIR = `src/${ICONS_DIR}`;
|
|
|
220
221
|
export const VUELESS_ICONS_CACHED_DIR = `${VUELESS_CACHE_DIR}/${ICONS_DIR}`;
|
|
221
222
|
export const VUELESS_CONFIGS_CACHED_DIR = `${VUELESS_CACHE_DIR}/configs`;
|
|
222
223
|
|
|
224
|
+
/* System error codes */
|
|
225
|
+
export const DEFAULT_EXIT_CODE = 0;
|
|
226
|
+
export const FAILURE_CODE = 1;
|
|
227
|
+
|
|
223
228
|
/* Other */
|
|
224
229
|
export const PX_IN_REM = 16;
|
|
225
230
|
export const NESTED_COMPONENT_PATTERN_REG_EXP = /\{(U[^}]*)}/;
|
|
@@ -228,3 +233,5 @@ export const DYNAMIC_COLOR_PATTERN = "{color}";
|
|
|
228
233
|
export const TAILWIND_COLOR_OPACITY_DELIMITER = "/";
|
|
229
234
|
export const TAILWIND_VARIANT_DELIMITER = ":";
|
|
230
235
|
export const TAILWIND_VARIANT_DELIMITER_REG_EXP = /:(?![^[]*])/;
|
|
236
|
+
export const JAVASCRIPT_EXT = ".js";
|
|
237
|
+
export const TYPESCRIPT_EXT = ".ts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.675",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"build": "npm run pre:start && storybook build --docs",
|
|
34
34
|
"preview": "vite preview --host --outDir=storybook-static",
|
|
35
35
|
"ts:check": "vue-tsc --build --force",
|
|
36
|
-
"release:prepare": "npm run pre:start && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/
|
|
36
|
+
"release:prepare": "npm run pre:start && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/",
|
|
37
37
|
"release:beta": "release-it --ci --npm.publish --preRelease=beta --increment=prerelease",
|
|
38
38
|
"release:patch": "release-it patch --ci --npm.publish",
|
|
39
39
|
"release:minor": "release-it minor --ci --npm.publish --git.tag --github.release",
|
package/plugin-vite.js
CHANGED
|
@@ -14,6 +14,8 @@ import { setCustomPropTypes, removeCustomPropTypes } from "./utils/node/dynamicP
|
|
|
14
14
|
import { buildWebTypes } from "./utils/node/webTypes.js";
|
|
15
15
|
import { hideHiddenStories, showHiddenStories } from "./utils/node/dynamicStories.js";
|
|
16
16
|
|
|
17
|
+
import { DEFAULT_EXIT_CODE } from "./constants.js";
|
|
18
|
+
|
|
17
19
|
/* Automatically importing Vueless components on demand */
|
|
18
20
|
export const VuelessUnpluginComponents = (options) =>
|
|
19
21
|
UnpluginVueComponents({
|
|
@@ -48,7 +50,7 @@ export const Vueless = function (options = {}) {
|
|
|
48
50
|
clearTailwindSafelist(debug);
|
|
49
51
|
|
|
50
52
|
/* stop command line process */
|
|
51
|
-
process.exit(
|
|
53
|
+
process.exit(DEFAULT_EXIT_CODE);
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
return {
|
package/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import UFilesDefaultConfig from "./ui.text-files/config.ts";
|
|
|
6
6
|
import UMoneyDefaultConfig from "./ui.text-money/config.ts";
|
|
7
7
|
import UHeaderDefaultConfig from "./ui.text-header/config.ts";
|
|
8
8
|
import UNotifyDefaultConfig from "./ui.text-notify/config.ts";
|
|
9
|
+
import UNumberDefaultConfig from "./ui.text-number/config.ts";
|
|
9
10
|
import UDotDefaultConfig from "./ui.other-dot/config.ts";
|
|
10
11
|
import UButtonDefaultConfig from "./ui.button/config.ts";
|
|
11
12
|
import ULinkDefaultConfig from "./ui.button-link/config.ts";
|
|
@@ -194,6 +195,7 @@ export interface Components {
|
|
|
194
195
|
UMoney: Partial<typeof UMoneyDefaultConfig>;
|
|
195
196
|
UHeader: Partial<typeof UHeaderDefaultConfig>;
|
|
196
197
|
UNotify: Partial<typeof UNotifyDefaultConfig>;
|
|
198
|
+
UNumber: Partial<typeof UNumberDefaultConfig>;
|
|
197
199
|
UDot: Partial<typeof UDotDefaultConfig>;
|
|
198
200
|
UButton: Partial<typeof UButtonDefaultConfig>;
|
|
199
201
|
ULink: Partial<typeof ULinkDefaultConfig>;
|
package/ui.text-money/UMoney.vue
CHANGED
|
@@ -3,11 +3,11 @@ import { computed } from "vue";
|
|
|
3
3
|
|
|
4
4
|
import useUI from "../composables/useUI.ts";
|
|
5
5
|
import { getDefaults } from "../utils/ui.ts";
|
|
6
|
-
import { hasSlotContent } from "../utils/helper.ts";
|
|
7
6
|
|
|
8
7
|
import { COMPONENT_NAME } from "./constants.ts";
|
|
9
8
|
import defaultConfig from "./config.ts";
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
import UNumber from "../ui.text-number/UNumber.vue";
|
|
11
11
|
|
|
12
12
|
import type { Props, Config } from "./types.ts";
|
|
13
13
|
|
|
@@ -24,81 +24,37 @@ const currencySymbolPosition = computed(() => {
|
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
const currencySpace = computed(() => {
|
|
28
|
-
return props.symbolDivided ? " " : "";
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const mathSign = computed(() => {
|
|
32
|
-
let type = "";
|
|
33
|
-
|
|
34
|
-
if (props.sign === MONEY_SIGN_TYPE.unsigned) type = "";
|
|
35
|
-
if (props.sign === MONEY_SIGN_TYPE.positive) type = MATH_SIGN.PLUS;
|
|
36
|
-
if (props.sign === MONEY_SIGN_TYPE.negative) type = MATH_SIGN.MINUS;
|
|
37
|
-
if (props.sign === MONEY_SIGN_TYPE.auto && props.value < 0) type = MATH_SIGN.MINUS;
|
|
38
|
-
|
|
39
|
-
return type;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const preparedMoney = computed(() => {
|
|
43
|
-
return separatedMoney(
|
|
44
|
-
Math.abs(props.value || 0),
|
|
45
|
-
props.minFractionDigits,
|
|
46
|
-
props.maxFractionDigits,
|
|
47
|
-
props.decimalSeparator,
|
|
48
|
-
props.thousandsSeparator,
|
|
49
|
-
);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
27
|
/**
|
|
53
28
|
* Get element / nested component attributes for each config token ✨
|
|
54
29
|
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
55
30
|
*/
|
|
56
|
-
const {
|
|
57
|
-
moneyAttrs,
|
|
58
|
-
sumAttrs,
|
|
59
|
-
mathSignAttrs,
|
|
60
|
-
integerAttrs,
|
|
61
|
-
pennyAttrs,
|
|
62
|
-
slotLeftAttrs,
|
|
63
|
-
symbolAttrs,
|
|
64
|
-
slotRightAttrs,
|
|
65
|
-
} = useUI<Config>(defaultConfig);
|
|
31
|
+
const { moneyNumberAttrs, symbolAttrs } = useUI<Config>(defaultConfig);
|
|
66
32
|
</script>
|
|
67
33
|
|
|
68
34
|
<template>
|
|
69
|
-
<
|
|
70
|
-
|
|
35
|
+
<UNumber
|
|
36
|
+
:value="value"
|
|
37
|
+
:size="size"
|
|
38
|
+
:color="color"
|
|
39
|
+
:sign="sign"
|
|
40
|
+
:align="align"
|
|
41
|
+
:min-fraction-digits="minFractionDigits"
|
|
42
|
+
:max-fraction-digits="maxFractionDigits"
|
|
43
|
+
:decimal-separator="decimalSeparator"
|
|
44
|
+
:thousands-separator="thousandsSeparator"
|
|
45
|
+
v-bind="moneyNumberAttrs"
|
|
46
|
+
:data-test="dataTest"
|
|
47
|
+
>
|
|
48
|
+
<template #left>
|
|
71
49
|
<!-- @slot Use it to add something before money amount. -->
|
|
72
50
|
<slot name="left" />
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<div v-bind="sumAttrs" :data-test="dataTest">
|
|
76
|
-
<span
|
|
77
|
-
v-if="currencySymbolPosition.left && symbol"
|
|
78
|
-
v-bind="symbolAttrs"
|
|
79
|
-
v-text="symbol + currencySpace"
|
|
80
|
-
/>
|
|
81
|
-
|
|
82
|
-
<span v-if="value" v-bind="mathSignAttrs" v-text="mathSign" />
|
|
83
|
-
|
|
84
|
-
<span v-bind="integerAttrs" v-text="preparedMoney.integer" />
|
|
85
|
-
|
|
86
|
-
<span
|
|
87
|
-
v-if="maxFractionDigits > 0"
|
|
88
|
-
v-bind="pennyAttrs"
|
|
89
|
-
v-text="preparedMoney.decimalSeparator + preparedMoney.penny"
|
|
90
|
-
/>
|
|
91
|
-
|
|
92
|
-
<span
|
|
93
|
-
v-if="currencySymbolPosition.right && symbol"
|
|
94
|
-
v-bind="symbolAttrs"
|
|
95
|
-
v-text="currencySpace + symbol"
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
51
|
+
<span v-if="currencySymbolPosition.left && symbol" v-bind="symbolAttrs" v-text="symbol" />
|
|
52
|
+
</template>
|
|
98
53
|
|
|
99
|
-
<
|
|
54
|
+
<template #right>
|
|
55
|
+
<span v-if="currencySymbolPosition.right && symbol" v-bind="symbolAttrs" v-text="symbol" />
|
|
100
56
|
<!-- @slot Use it to add something after money amount. -->
|
|
101
57
|
<slot name="right" />
|
|
102
|
-
</
|
|
103
|
-
</
|
|
58
|
+
</template>
|
|
59
|
+
</UNumber>
|
|
104
60
|
</template>
|
package/ui.text-money/config.ts
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
|
|
3
|
-
base: "
|
|
2
|
+
moneyNumber: {
|
|
3
|
+
base: "{UNumber}",
|
|
4
4
|
variants: {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
grayscale: "text-gray-900",
|
|
8
|
-
},
|
|
9
|
-
align: {
|
|
10
|
-
left: "justify-start",
|
|
11
|
-
right: "justify-end",
|
|
5
|
+
planned: {
|
|
6
|
+
true: "opacity-75 before:content-['('] after:content-[')']",
|
|
12
7
|
},
|
|
13
8
|
},
|
|
14
9
|
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
sum: {
|
|
10
|
+
symbol: {
|
|
11
|
+
base: "text-{color}-600 mx-1",
|
|
18
12
|
variants: {
|
|
19
13
|
size: {
|
|
20
14
|
xs: "text-xs",
|
|
@@ -26,27 +20,13 @@ export default /*tw*/ {
|
|
|
26
20
|
"3xl": "text-3xl",
|
|
27
21
|
"4xl": "text-4xl",
|
|
28
22
|
},
|
|
29
|
-
planned: {
|
|
30
|
-
true: "opacity-75 before:content-['('] after:content-[')']",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
symbol: "",
|
|
35
|
-
mathSign: "",
|
|
36
|
-
integer: "",
|
|
37
|
-
penny: {
|
|
38
|
-
variants: {
|
|
39
|
-
size: {
|
|
40
|
-
xs: "text-2xs",
|
|
41
|
-
sm: "text-xs",
|
|
42
|
-
md: "text-sm",
|
|
43
|
-
lg: "text-base",
|
|
44
|
-
xl: "text-lg",
|
|
45
|
-
"2xl": "text-xl",
|
|
46
|
-
"3xl": "text-2xl",
|
|
47
|
-
"4xl": "text-3xl",
|
|
48
|
-
},
|
|
49
23
|
},
|
|
24
|
+
compoundVariants: [
|
|
25
|
+
{ symbolDivided: false, symbolAlign: "left", class: "mr-0" },
|
|
26
|
+
{ symbolDivided: false, symbolAlign: "right", class: "ml-0" },
|
|
27
|
+
{ planned: true, symbolAlign: "left", class: "ml-0" },
|
|
28
|
+
{ planned: true, symbolAlign: "right", class: "mr-0" },
|
|
29
|
+
],
|
|
50
30
|
},
|
|
51
31
|
defaults: {
|
|
52
32
|
color: "grayscale",
|
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
import UMoney from "../../ui.text-money/UMoney.vue";
|
|
9
9
|
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
10
10
|
import URow from "../../ui.container-row/URow.vue";
|
|
11
|
+
import UText from "../../ui.text-block/UText.vue";
|
|
12
|
+
import UDivider from "../../ui.container-divider/UDivider.vue";
|
|
13
|
+
|
|
11
14
|
import DebitIcon from "../../ui.text-money/assets/debit.svg?component";
|
|
12
15
|
import CreditIcon from "../../ui.text-money/assets/credit.svg?component";
|
|
13
16
|
|
|
@@ -16,17 +19,15 @@ import type { Props } from "../types.ts";
|
|
|
16
19
|
|
|
17
20
|
interface UMoneyArgs extends Props {
|
|
18
21
|
slotTemplate?: string;
|
|
19
|
-
enum: "color" | "size" | "sign" | "symbolAlign"
|
|
22
|
+
enum: "color" | "size" | "sign" | "symbolAlign";
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
const COMPONENT_CLASSES = "flex justify-center w-1/6";
|
|
23
|
-
|
|
24
25
|
export default {
|
|
25
|
-
id: "
|
|
26
|
+
id: "4060",
|
|
26
27
|
title: "Text & Content / Money",
|
|
27
28
|
component: UMoney,
|
|
28
29
|
args: {
|
|
29
|
-
value:
|
|
30
|
+
value: -14.24,
|
|
30
31
|
symbol: "$",
|
|
31
32
|
sign: "auto",
|
|
32
33
|
},
|
|
@@ -45,24 +46,17 @@ const DefaultTemplate: StoryFn<UMoneyArgs> = (args: UMoneyArgs) => ({
|
|
|
45
46
|
setup() {
|
|
46
47
|
const slots = getSlotNames(UMoney.__name);
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
Debit: DebitIcon,
|
|
50
|
-
Credit: CreditIcon,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return { args, slots, icons };
|
|
49
|
+
return { args, slots };
|
|
54
50
|
},
|
|
55
51
|
template: `
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
</UMoney>
|
|
60
|
-
</div>
|
|
52
|
+
<UMoney v-bind="args">
|
|
53
|
+
${args.slotTemplate || getSlotsFragment("")}
|
|
54
|
+
</UMoney>
|
|
61
55
|
`,
|
|
62
56
|
});
|
|
63
57
|
|
|
64
58
|
const EnumVariantTemplate: StoryFn<UMoneyArgs> = (args: UMoneyArgs, { argTypes }) => ({
|
|
65
|
-
components: { UMoney, URow },
|
|
59
|
+
components: { UMoney, URow, UText, UDivider },
|
|
66
60
|
setup() {
|
|
67
61
|
const slots = getSlotNames(UMoney.__name);
|
|
68
62
|
|
|
@@ -74,29 +68,26 @@ const EnumVariantTemplate: StoryFn<UMoneyArgs> = (args: UMoneyArgs, { argTypes }
|
|
|
74
68
|
},
|
|
75
69
|
template: `
|
|
76
70
|
<URow>
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
<UMoney
|
|
72
|
+
v-for="(option, index) in options"
|
|
73
|
+
:key="index"
|
|
74
|
+
v-bind="args"
|
|
75
|
+
:[args.enum]="option"
|
|
76
|
+
>
|
|
77
|
+
<template #right v-if="args.enum === 'sign'">
|
|
78
|
+
<UText size="lg" class="ml-1">{{ option }}</UText>
|
|
79
|
+
<UDivider vertical variant="dark" class="h-5" />
|
|
80
|
+
</template>
|
|
81
|
+
</UMoney>
|
|
80
82
|
</URow>
|
|
81
83
|
`,
|
|
82
|
-
created() {
|
|
83
|
-
this.mxArgTypes = argTypes;
|
|
84
|
-
},
|
|
85
84
|
});
|
|
86
85
|
|
|
87
86
|
export const Default = DefaultTemplate.bind({});
|
|
88
87
|
Default.args = {};
|
|
89
88
|
|
|
90
|
-
export const OtherValues = DefaultTemplate.bind({});
|
|
91
|
-
OtherValues.args = { value: 10, symbol: "$", sign: "negative" };
|
|
92
|
-
|
|
93
89
|
export const Colors = EnumVariantTemplate.bind({});
|
|
94
|
-
Colors.args = {
|
|
95
|
-
enum: "color",
|
|
96
|
-
value: 0,
|
|
97
|
-
symbol: "$",
|
|
98
|
-
sign: "auto",
|
|
99
|
-
};
|
|
90
|
+
Colors.args = { enum: "color" };
|
|
100
91
|
|
|
101
92
|
export const Sizes = EnumVariantTemplate.bind({});
|
|
102
93
|
Sizes.args = { enum: "size" };
|
|
@@ -110,26 +101,32 @@ SymbolAlign.args = { enum: "symbolAlign" };
|
|
|
110
101
|
export const Planned = DefaultTemplate.bind({});
|
|
111
102
|
Planned.args = { planned: true };
|
|
112
103
|
|
|
113
|
-
export const
|
|
114
|
-
|
|
104
|
+
export const MinFractionDigits4 = DefaultTemplate.bind({});
|
|
105
|
+
MinFractionDigits4.args = { minFractionDigits: 4, maxFractionDigits: 4 };
|
|
106
|
+
|
|
107
|
+
export const Slots: StoryFn<UMoneyArgs> = (args) => ({
|
|
108
|
+
components: { UMoney, UIcon, URow },
|
|
109
|
+
setup() {
|
|
110
|
+
const icons = {
|
|
111
|
+
Debit: DebitIcon,
|
|
112
|
+
Credit: CreditIcon,
|
|
113
|
+
};
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
return { args, icons };
|
|
116
|
+
},
|
|
117
|
+
template: `
|
|
118
|
+
<URow>
|
|
119
|
+
<UMoney v-bind="args">
|
|
120
|
+
<template #left>
|
|
121
|
+
<UIcon :src="icons.Debit" size="3xs" />
|
|
122
|
+
</template>
|
|
123
|
+
</UMoney>
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</
|
|
125
|
-
`,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export const SlotRight = DefaultTemplate.bind({});
|
|
129
|
-
SlotRight.args = {
|
|
130
|
-
slotTemplate: `
|
|
131
|
-
<template #right>
|
|
132
|
-
<UIcon :src="icons.Credit" size="3xs" />
|
|
133
|
-
</template>
|
|
125
|
+
<UMoney v-bind="args">
|
|
126
|
+
<template #right>
|
|
127
|
+
<UIcon :src="icons.Credit" size="3xs" />
|
|
128
|
+
</template>
|
|
129
|
+
</UMoney>
|
|
130
|
+
</URow>
|
|
134
131
|
`,
|
|
135
|
-
};
|
|
132
|
+
});
|
package/ui.text-money/types.ts
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
|
|
4
|
+
import useUI from "../composables/useUI.ts";
|
|
5
|
+
import { getDefaults } from "../utils/ui.ts";
|
|
6
|
+
|
|
7
|
+
import { COMPONENT_NAME } from "./constants.ts";
|
|
8
|
+
import defaultConfig from "./config.ts";
|
|
9
|
+
import { separatedNumber, MATH_SIGN_TYPE, MATH_SIGN } from "./utilNumber.ts";
|
|
10
|
+
|
|
11
|
+
import type { Props, Config } from "./types.ts";
|
|
12
|
+
|
|
13
|
+
defineOptions({ inheritAttrs: false });
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
+
...getDefaults<Props, Config>(defaultConfig, COMPONENT_NAME),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const numericValue = computed(() => {
|
|
20
|
+
if (typeof props.value === "string") {
|
|
21
|
+
return parseFloat(props.value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return props.value;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const mathSign = computed(() => {
|
|
28
|
+
let type = "";
|
|
29
|
+
|
|
30
|
+
if (props.sign === MATH_SIGN_TYPE.unsigned) type = "";
|
|
31
|
+
if (props.sign === MATH_SIGN_TYPE.positive) type = MATH_SIGN.PLUS;
|
|
32
|
+
if (props.sign === MATH_SIGN_TYPE.negative) type = MATH_SIGN.MINUS;
|
|
33
|
+
if (props.sign === MATH_SIGN_TYPE.auto && numericValue.value < 0) type = MATH_SIGN.MINUS;
|
|
34
|
+
|
|
35
|
+
return type;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const preparedNumber = computed(() => {
|
|
39
|
+
return separatedNumber(
|
|
40
|
+
Math.abs(numericValue.value || 0),
|
|
41
|
+
props.minFractionDigits,
|
|
42
|
+
props.maxFractionDigits,
|
|
43
|
+
props.decimalSeparator,
|
|
44
|
+
props.thousandsSeparator,
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get element / nested component attributes for each config token ✨
|
|
50
|
+
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
|
|
51
|
+
*/
|
|
52
|
+
const { numberAttrs, sumAttrs, mathSignAttrs, integerAttrs, decimalAttrs } =
|
|
53
|
+
useUI<Config>(defaultConfig);
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div v-bind="numberAttrs">
|
|
58
|
+
<!-- @slot Use it to add something before the number. -->
|
|
59
|
+
<slot name="left" />
|
|
60
|
+
|
|
61
|
+
<div v-bind="sumAttrs" :data-test="dataTest">
|
|
62
|
+
<span v-if="value" v-bind="mathSignAttrs" v-text="mathSign" />
|
|
63
|
+
|
|
64
|
+
<span v-bind="integerAttrs" v-text="preparedNumber.integer" />
|
|
65
|
+
|
|
66
|
+
<span
|
|
67
|
+
v-if="maxFractionDigits > 0"
|
|
68
|
+
v-bind="decimalAttrs"
|
|
69
|
+
v-text="preparedNumber.decimalSeparator + preparedNumber.decimal"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<!-- @slot Use it to add something after the number. -->
|
|
74
|
+
<slot name="right" />
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export default /*tw*/ {
|
|
2
|
+
number: {
|
|
3
|
+
base: "whitespace-nowrap flex items-center text-{color}-600",
|
|
4
|
+
variants: {
|
|
5
|
+
color: {
|
|
6
|
+
white: "text-white",
|
|
7
|
+
grayscale: "text-gray-900",
|
|
8
|
+
},
|
|
9
|
+
align: {
|
|
10
|
+
left: "justify-start",
|
|
11
|
+
right: "justify-end",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
sum: {
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
xs: "text-xs",
|
|
19
|
+
sm: "text-sm",
|
|
20
|
+
md: "text-base",
|
|
21
|
+
lg: "text-lg",
|
|
22
|
+
xl: "text-xl",
|
|
23
|
+
"2xl": "text-2xl",
|
|
24
|
+
"3xl": "text-3xl",
|
|
25
|
+
"4xl": "text-4xl",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
mathSign: "",
|
|
30
|
+
integer: "",
|
|
31
|
+
decimal: "",
|
|
32
|
+
defaults: {
|
|
33
|
+
color: "grayscale",
|
|
34
|
+
size: "md",
|
|
35
|
+
sign: "auto",
|
|
36
|
+
align: "left",
|
|
37
|
+
minFractionDigits: 0,
|
|
38
|
+
maxFractionDigits: 2,
|
|
39
|
+
decimalSeparator: ",",
|
|
40
|
+
thousandsSeparator: " ",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
|
|
2
|
+
import { getSource } from "../../utils/storybook.ts";
|
|
3
|
+
|
|
4
|
+
import * as stories from "./stories.ts";
|
|
5
|
+
import defaultConfig from "../config.ts?raw"
|
|
6
|
+
|
|
7
|
+
<Meta of={stories} />
|
|
8
|
+
<Title of={stories} />
|
|
9
|
+
<Subtitle of={stories} />
|
|
10
|
+
<Description of={stories} />
|
|
11
|
+
<Primary of={stories} />
|
|
12
|
+
<Controls of={stories.Default} />
|
|
13
|
+
<Stories of={stories} />
|
|
14
|
+
|
|
15
|
+
## Default config
|
|
16
|
+
<Source code={getSource(defaultConfig)} language="jsx" dark />
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { getArgTypes, getSlotNames, getSlotsFragment } from "../../utils/storybook.ts";
|
|
2
|
+
|
|
3
|
+
import UNumber from "../../ui.text-number/UNumber.vue";
|
|
4
|
+
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
5
|
+
import URow from "../../ui.container-row/URow.vue";
|
|
6
|
+
import UText from "../../ui.text-block/UText.vue";
|
|
7
|
+
import UBadge from "../../ui.text-badge/UBadge.vue";
|
|
8
|
+
import UDivider from "../../ui.container-divider/UDivider.vue";
|
|
9
|
+
|
|
10
|
+
import type { Meta, StoryFn } from "@storybook/vue3";
|
|
11
|
+
import type { Props } from "../types.ts";
|
|
12
|
+
|
|
13
|
+
interface UNumberArgs extends Props {
|
|
14
|
+
slotTemplate?: string;
|
|
15
|
+
enum: "color" | "size" | "sign";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
id: "4050",
|
|
20
|
+
title: "Text & Content / Number",
|
|
21
|
+
component: UNumber,
|
|
22
|
+
args: {
|
|
23
|
+
value: -14.24,
|
|
24
|
+
sign: "auto",
|
|
25
|
+
},
|
|
26
|
+
argTypes: {
|
|
27
|
+
...getArgTypes(UNumber.__name),
|
|
28
|
+
},
|
|
29
|
+
} as Meta;
|
|
30
|
+
|
|
31
|
+
const DefaultTemplate: StoryFn<UNumberArgs> = (args: UNumberArgs) => ({
|
|
32
|
+
components: { UNumber, UIcon, UBadge },
|
|
33
|
+
setup() {
|
|
34
|
+
const slots = getSlotNames(UNumber.__name);
|
|
35
|
+
|
|
36
|
+
return { args, slots };
|
|
37
|
+
},
|
|
38
|
+
template: `
|
|
39
|
+
<UNumber v-bind="args">
|
|
40
|
+
${args.slotTemplate || getSlotsFragment("")}
|
|
41
|
+
</UNumber>
|
|
42
|
+
`,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const EnumVariantTemplate: StoryFn<UNumberArgs> = (args: UNumberArgs, { argTypes }) => ({
|
|
46
|
+
components: { UNumber, URow, UText, UDivider },
|
|
47
|
+
setup() {
|
|
48
|
+
return { args, options: argTypes?.[args.enum]?.options };
|
|
49
|
+
},
|
|
50
|
+
template: `
|
|
51
|
+
<URow>
|
|
52
|
+
<UNumber
|
|
53
|
+
v-for="(option, index) in options"
|
|
54
|
+
:key="index"
|
|
55
|
+
v-bind="args"
|
|
56
|
+
:[args.enum]="option"
|
|
57
|
+
>
|
|
58
|
+
<template #right v-if="args.enum === 'sign'">
|
|
59
|
+
<UText size="lg" class="ml-1">{{ option }}</UText>
|
|
60
|
+
<UDivider vertical variant="dark" class="h-5" />
|
|
61
|
+
</template>
|
|
62
|
+
</UNumber>
|
|
63
|
+
</URow>
|
|
64
|
+
`,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export const Default = DefaultTemplate.bind({});
|
|
68
|
+
Default.args = {};
|
|
69
|
+
|
|
70
|
+
export const Colors = EnumVariantTemplate.bind({});
|
|
71
|
+
Colors.args = {
|
|
72
|
+
enum: "color",
|
|
73
|
+
sign: "auto",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const Sizes = EnumVariantTemplate.bind({});
|
|
77
|
+
Sizes.args = { enum: "size" };
|
|
78
|
+
|
|
79
|
+
export const Sign = EnumVariantTemplate.bind({});
|
|
80
|
+
Sign.args = { enum: "sign" };
|
|
81
|
+
|
|
82
|
+
export const MinFractionDigits4 = DefaultTemplate.bind({});
|
|
83
|
+
MinFractionDigits4.args = { minFractionDigits: 4, maxFractionDigits: 4 };
|
|
84
|
+
|
|
85
|
+
export const Slots: StoryFn<UNumberArgs> = (args) => ({
|
|
86
|
+
components: { UNumber, UIcon, URow, UBadge },
|
|
87
|
+
setup() {
|
|
88
|
+
return { args };
|
|
89
|
+
},
|
|
90
|
+
template: `
|
|
91
|
+
<URow>
|
|
92
|
+
<UNumber v-bind="args">
|
|
93
|
+
<template #left>
|
|
94
|
+
<UIcon name="confirmation_number" color="green" />
|
|
95
|
+
</template>
|
|
96
|
+
</UNumber>
|
|
97
|
+
|
|
98
|
+
<UNumber v-bind="args">
|
|
99
|
+
<template #right>
|
|
100
|
+
<UBadge label="Quantity" color="green" />
|
|
101
|
+
</template>
|
|
102
|
+
</UNumber>
|
|
103
|
+
</URow>
|
|
104
|
+
`,
|
|
105
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import defaultConfig from "./config.ts";
|
|
2
|
+
import type { ComponentConfig } from "../types.ts";
|
|
3
|
+
|
|
4
|
+
export type Config = typeof defaultConfig;
|
|
5
|
+
|
|
6
|
+
export interface Props {
|
|
7
|
+
/**
|
|
8
|
+
* Number value.
|
|
9
|
+
*/
|
|
10
|
+
value?: number | string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Number size.
|
|
14
|
+
*/
|
|
15
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Number color.
|
|
19
|
+
*/
|
|
20
|
+
color?:
|
|
21
|
+
| "grayscale"
|
|
22
|
+
| "red"
|
|
23
|
+
| "orange"
|
|
24
|
+
| "amber"
|
|
25
|
+
| "yellow"
|
|
26
|
+
| "lime"
|
|
27
|
+
| "green"
|
|
28
|
+
| "emerald"
|
|
29
|
+
| "teal"
|
|
30
|
+
| "cyan"
|
|
31
|
+
| "sky"
|
|
32
|
+
| "blue"
|
|
33
|
+
| "indigo"
|
|
34
|
+
| "violet"
|
|
35
|
+
| "purple"
|
|
36
|
+
| "fuchsia"
|
|
37
|
+
| "pink"
|
|
38
|
+
| "rose"
|
|
39
|
+
| "gray"
|
|
40
|
+
| "white"
|
|
41
|
+
| "brand";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Number sign.
|
|
45
|
+
*/
|
|
46
|
+
sign?: "auto" | "positive" | "negative" | "unsigned";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Minimal number of signs after the decimal separator (fractional part of a number).
|
|
50
|
+
*/
|
|
51
|
+
minFractionDigits?: number;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Maximal number of signs after the decimal separator (fractional part of a number).
|
|
55
|
+
*/
|
|
56
|
+
maxFractionDigits?: number;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A symbol used to separate the integer part from the fractional part of a number.
|
|
60
|
+
*/
|
|
61
|
+
decimalSeparator?: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A symbol used to separate the thousand parts of a number.
|
|
65
|
+
*/
|
|
66
|
+
thousandsSeparator?: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Number align.
|
|
70
|
+
*/
|
|
71
|
+
align?: "right" | "left";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Component config object.
|
|
75
|
+
*/
|
|
76
|
+
config?: ComponentConfig<Config>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Data-test attribute for automated testing.
|
|
80
|
+
*/
|
|
81
|
+
dataTest?: string;
|
|
82
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const MATH_SIGN_TYPE = {
|
|
2
2
|
auto: "auto",
|
|
3
3
|
positive: "positive",
|
|
4
4
|
negative: "negative",
|
|
@@ -10,12 +10,11 @@ export const MATH_SIGN = {
|
|
|
10
10
|
MINUS: "-",
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export const ADD_SPACE_IN_MONEY_REG_EX = /(\d)(?=(\d{3})+(\D|$))/g;
|
|
14
13
|
export const SINGLE_ZERO = "0";
|
|
15
14
|
export const DOUBLE_ZERO = "00";
|
|
16
15
|
|
|
17
|
-
export function
|
|
18
|
-
|
|
16
|
+
export function separatedNumber(
|
|
17
|
+
value: number,
|
|
19
18
|
minFractionDigits = 0,
|
|
20
19
|
maxFractionDigits = 2,
|
|
21
20
|
decimalSeparator = ",",
|
|
@@ -26,28 +25,28 @@ export function separatedMoney(
|
|
|
26
25
|
maximumFractionDigits: Number(maxFractionDigits),
|
|
27
26
|
};
|
|
28
27
|
|
|
29
|
-
const
|
|
30
|
-
|
|
28
|
+
const formattedNumber =
|
|
29
|
+
value !== undefined && value !== null ? Number(value).toLocaleString("en-US", options) : "0";
|
|
31
30
|
|
|
32
|
-
let [integer,
|
|
31
|
+
let [integer, decimal = ""] = formattedNumber.split(".");
|
|
33
32
|
|
|
34
33
|
integer = integer.replace(/,/g, thousandsSeparator);
|
|
35
34
|
|
|
36
|
-
if (!
|
|
35
|
+
if (!value && value !== 0) {
|
|
37
36
|
integer = SINGLE_ZERO;
|
|
38
|
-
|
|
37
|
+
decimal = DOUBLE_ZERO;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
if (
|
|
40
|
+
if (decimal === "") {
|
|
42
41
|
decimalSeparator = "";
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
if (minFractionDigits === 0 && maxFractionDigits === 0) {
|
|
46
45
|
decimalSeparator = "";
|
|
47
|
-
|
|
48
|
-
} else if (
|
|
49
|
-
|
|
46
|
+
decimal = "";
|
|
47
|
+
} else if (decimal.length < minFractionDigits) {
|
|
48
|
+
decimal = decimal.padEnd(minFractionDigits, "0");
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
return { integer,
|
|
51
|
+
return { integer, decimal, decimalSeparator };
|
|
53
52
|
}
|