@caipira/tamandua 0.0.1 → 0.0.2
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/.storybook/main.ts +0 -3
- package/README.md +4 -0
- package/components/Form/Form.vue +1 -1
- package/components/InputMultiplier/InputMultiplier.vue +21 -46
- package/components/InputMultiplier/input-multiplier.story.ts +30 -0
- package/components/InputMultiplier/types.ts +16 -0
- package/components/InputPassword/InputPassword.vue +32 -30
- package/components/InputText/InputText.vue +2 -2
- package/components/ModalForm/ModalForm.vue +1 -1
- package/components/Table/Table.story.ts +7 -9
- package/components/Table/Table.vue +13 -40
- package/components/Table/index.ts +1 -1
- package/components/Table/types.ts +14 -0
- package/components/Tag/Tag.vue +2 -14
- package/components/Tag/types.ts +15 -0
- package/form/convertors.ts +31 -0
- package/{services/form → form}/form-data-transformers.ts +14 -14
- package/{services/form → form}/form-transformer.ts +2 -2
- package/{services/form → form}/form-value-transformers.ts +1 -4
- package/{services/form → form}/form.test.ts +1 -3
- package/{services/form/form-json-transformers.ts → form/json-transformers.ts} +8 -8
- package/index.css +0 -86
- package/package.json +2 -2
- package/types/form.ts +7 -7
- package/vite.config.mts +10 -34
- package/vitest.setup.ts +2 -2
- package/services/form/form.ts +0 -80
- /package/{services/form → form}/crud.ts +0 -0
package/.storybook/main.ts
CHANGED
package/README.md
CHANGED
package/components/Form/Form.vue
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ValidationResult,
|
|
10
10
|
} from "@/types/form";
|
|
11
11
|
|
|
12
|
-
import { transformForm } from "@/
|
|
12
|
+
import { transformForm } from "@/form/form-transformer";
|
|
13
13
|
import { ref, provide, reactive, watch } from "vue";
|
|
14
14
|
|
|
15
15
|
defineOptions({ name: "TForm" });
|
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { SocialDirectory } from "@/types/social-network";
|
|
3
|
-
|
|
4
2
|
import { ref, watch, inject } from "vue";
|
|
3
|
+
import { InputMultiplierEvents, InputMultiplierProps } from "./types";
|
|
5
4
|
|
|
6
5
|
defineOptions({ name: "TInputMultiplier" });
|
|
7
6
|
|
|
8
|
-
const props = withDefaults(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
type: "",
|
|
17
|
-
label: "",
|
|
18
|
-
inputProps: {},
|
|
19
|
-
},
|
|
20
|
-
);
|
|
7
|
+
const props = withDefaults(defineProps<InputMultiplierProps>(), {
|
|
8
|
+
type: "t-input-text",
|
|
9
|
+
label: "",
|
|
10
|
+
listeners: () => ({}),
|
|
11
|
+
inputProps: () => ({}),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const emit = defineEmits<InputMultiplierEvents>();
|
|
21
15
|
|
|
22
16
|
const values = ref<any[]>([]);
|
|
23
17
|
const formStyle = inject("formStyle", { label: "", input: "" });
|
|
24
18
|
|
|
25
|
-
const
|
|
26
|
-
(e: "update:modelValue", val: any): void;
|
|
27
|
-
(e: "on-fetch-directory", val: SocialDirectory): void;
|
|
28
|
-
}>();
|
|
29
|
-
|
|
30
|
-
const add = () => {
|
|
19
|
+
const addNewItem = () => {
|
|
31
20
|
// @todo: Add an switch case that adds an value according to the input type
|
|
32
21
|
values.value.push({});
|
|
33
22
|
};
|
|
@@ -49,31 +38,10 @@ const getItemKey = (value: any, index: number): string | number => {
|
|
|
49
38
|
}
|
|
50
39
|
};
|
|
51
40
|
|
|
52
|
-
const onFetchDirectory = (directory: SocialDirectory) => {
|
|
53
|
-
values.value = [
|
|
54
|
-
...values.value,
|
|
55
|
-
...directory.social_networks
|
|
56
|
-
.filter(
|
|
57
|
-
(network) =>
|
|
58
|
-
!!!values.value.find(
|
|
59
|
-
(value) =>
|
|
60
|
-
value.network === network.network &&
|
|
61
|
-
value.profile === network.path,
|
|
62
|
-
),
|
|
63
|
-
)
|
|
64
|
-
.map((network) => ({
|
|
65
|
-
network: network.network,
|
|
66
|
-
profile: network.path,
|
|
67
|
-
})),
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
emit("on-fetch-directory", directory);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
41
|
watch(
|
|
74
42
|
values,
|
|
75
43
|
(newValues: any[]) => {
|
|
76
|
-
emit("update:
|
|
44
|
+
emit("update:model-value", newValues);
|
|
77
45
|
},
|
|
78
46
|
{ deep: true },
|
|
79
47
|
);
|
|
@@ -101,7 +69,7 @@ watch(
|
|
|
101
69
|
:is-outline="true"
|
|
102
70
|
icon="plus"
|
|
103
71
|
size="sm"
|
|
104
|
-
@click="
|
|
72
|
+
@click="addNewItem"
|
|
105
73
|
/>
|
|
106
74
|
</div>
|
|
107
75
|
<div
|
|
@@ -111,7 +79,14 @@ watch(
|
|
|
111
79
|
class="flex items-center justify-start mt-1 ml-2"
|
|
112
80
|
>
|
|
113
81
|
<div :class="{ [formStyle.label]: true }" />
|
|
114
|
-
<
|
|
82
|
+
<component
|
|
83
|
+
:is="props.component"
|
|
84
|
+
v-model="values[index]"
|
|
85
|
+
v-bind="props.inputProps"
|
|
86
|
+
v-on="props.listeners"
|
|
87
|
+
class="my-1"
|
|
88
|
+
/>
|
|
89
|
+
<!-- <t-input-social
|
|
115
90
|
v-if="type === 'social'"
|
|
116
91
|
v-model="values[index]"
|
|
117
92
|
class="my-1"
|
|
@@ -132,7 +107,7 @@ watch(
|
|
|
132
107
|
v-model="values[index]"
|
|
133
108
|
v-bind="props.inputProps"
|
|
134
109
|
class="my-1"
|
|
135
|
-
/>
|
|
110
|
+
/> -->
|
|
136
111
|
<t-icon-button
|
|
137
112
|
icon="close"
|
|
138
113
|
size="sm"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const story = {
|
|
2
|
+
title: "Form/Input multiplier",
|
|
3
|
+
args: {
|
|
4
|
+
label: "Name",
|
|
5
|
+
component: "t-input-text",
|
|
6
|
+
listeners: {
|
|
7
|
+
"update:model-value": (newValue: string) => {
|
|
8
|
+
console.log("new value from child: ", newValue);
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
argTypes: {
|
|
13
|
+
component: {
|
|
14
|
+
options: ["t-input-text", "t-input-phone"],
|
|
15
|
+
control: "radio",
|
|
16
|
+
description: "Set component",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const Template = (args: any) => ({
|
|
22
|
+
setup() {
|
|
23
|
+
return { args };
|
|
24
|
+
},
|
|
25
|
+
template: `<t-input-multiplier v-bind="args" />`,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const Default: any = Template.bind({});
|
|
29
|
+
|
|
30
|
+
export { story as default, Default };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ComponentType = "t-input-text" | "t-input-phone";
|
|
2
|
+
|
|
3
|
+
export type InputMultiplierProps = {
|
|
4
|
+
component?: ComponentType;
|
|
5
|
+
inputProps?: any;
|
|
6
|
+
label?: string;
|
|
7
|
+
listeners?: {
|
|
8
|
+
[key: string]: (...args: any[]) => void;
|
|
9
|
+
};
|
|
10
|
+
modelValue?: any[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type InputMultiplierEvents = {
|
|
14
|
+
/** Fired when the input value changes */
|
|
15
|
+
(event: "update:model-value", value: any[]): void;
|
|
16
|
+
};
|
|
@@ -8,29 +8,29 @@ import { inject, ref, watch } from "vue";
|
|
|
8
8
|
import InputText from "@/components/InputText/InputText.vue";
|
|
9
9
|
import ButtonCopy from "@/components/ButtonCopy/ButtonCopy.vue";
|
|
10
10
|
|
|
11
|
+
export type InputPasswordProps = {
|
|
12
|
+
autocomplete?: string;
|
|
13
|
+
canCopy?: boolean;
|
|
14
|
+
encryptor?: (value: string) => Promise<string>;
|
|
15
|
+
keyup?: any;
|
|
16
|
+
modelValue?: InputPasswordModel;
|
|
17
|
+
showRefresh?: boolean;
|
|
18
|
+
showStrength?: boolean;
|
|
19
|
+
simpleMode?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
11
22
|
defineOptions({ name: "TInputPassword" });
|
|
12
23
|
|
|
13
|
-
const props = withDefaults(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}>(),
|
|
24
|
-
{
|
|
25
|
-
keyup: () => () => {},
|
|
26
|
-
encrypt: true,
|
|
27
|
-
canCopy: true,
|
|
28
|
-
simpleMode: false,
|
|
29
|
-
showRefresh: false,
|
|
30
|
-
showStrength: false,
|
|
31
|
-
autocomplete: "current-password",
|
|
32
|
-
},
|
|
33
|
-
);
|
|
24
|
+
const props = withDefaults(defineProps<InputPasswordProps>(), {
|
|
25
|
+
autocomplete: "current-password",
|
|
26
|
+
canCopy: true,
|
|
27
|
+
encryptor: undefined,
|
|
28
|
+
keyup: () => () => {},
|
|
29
|
+
modelValue: undefined,
|
|
30
|
+
showRefresh: false,
|
|
31
|
+
showStrength: false,
|
|
32
|
+
simpleMode: false,
|
|
33
|
+
});
|
|
34
34
|
|
|
35
35
|
const emit = defineEmits<{
|
|
36
36
|
(e: "generate", val: InputPasswordModel): void;
|
|
@@ -44,7 +44,7 @@ const strength = ref<number>(0);
|
|
|
44
44
|
const password = ref<string>("");
|
|
45
45
|
const isLoading = ref<boolean>(false);
|
|
46
46
|
const formStyle = inject("formStyle", { input: "w-full" });
|
|
47
|
-
const updatedAt = ref<Date
|
|
47
|
+
const updatedAt = ref<Date>();
|
|
48
48
|
|
|
49
49
|
const setValue = (localPassword?: InputPasswordModel) => {
|
|
50
50
|
if (typeof localPassword !== "object") {
|
|
@@ -55,22 +55,24 @@ const setValue = (localPassword?: InputPasswordModel) => {
|
|
|
55
55
|
strength.value = localPassword.strength
|
|
56
56
|
? localPassword.strength
|
|
57
57
|
: passwordService.getPasswordStrength(localPassword.value).score;
|
|
58
|
-
updatedAt.value = localPassword.updatedAt
|
|
58
|
+
updatedAt.value = localPassword.updatedAt;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
const passwordToPayload = (
|
|
61
|
+
const passwordToPayload = async (
|
|
62
|
+
password: string,
|
|
63
|
+
): Promise<InputPasswordModel> => {
|
|
62
64
|
strength.value = passwordService.getPasswordStrength(password).score;
|
|
63
65
|
|
|
64
66
|
return {
|
|
65
67
|
value: password,
|
|
66
68
|
strength: strength.value,
|
|
67
|
-
|
|
68
|
-
updatedAt: updatedAt.value
|
|
69
|
-
}
|
|
69
|
+
encrypted: props.encryptor ? await props.encryptor(password) : password,
|
|
70
|
+
updatedAt: updatedAt.value,
|
|
71
|
+
};
|
|
70
72
|
};
|
|
71
73
|
|
|
72
|
-
const onInput = (password: string) => {
|
|
73
|
-
emit("update:modelValue", passwordToPayload(password));
|
|
74
|
+
const onInput = async (password: string) => {
|
|
75
|
+
emit("update:modelValue", await passwordToPayload(password));
|
|
74
76
|
};
|
|
75
77
|
|
|
76
78
|
const focus = () => {
|
|
@@ -87,7 +89,7 @@ const generatePassword = async () => {
|
|
|
87
89
|
|
|
88
90
|
isLoading.value = false;
|
|
89
91
|
|
|
90
|
-
emit("generate", passwordToPayload(password.value));
|
|
92
|
+
emit("generate", await passwordToPayload(password.value));
|
|
91
93
|
onInput(data);
|
|
92
94
|
};
|
|
93
95
|
|
|
@@ -23,7 +23,7 @@ const props = withDefaults(
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
const emit = defineEmits<{
|
|
26
|
-
(e: "update:
|
|
26
|
+
(e: "update:model-value", val: string): void;
|
|
27
27
|
(e: "keyup.enter", val: any): void;
|
|
28
28
|
}>();
|
|
29
29
|
|
|
@@ -37,7 +37,7 @@ const value = computed({
|
|
|
37
37
|
return props.modelValue;
|
|
38
38
|
},
|
|
39
39
|
set: (value: string) => {
|
|
40
|
-
emit("update:
|
|
40
|
+
emit("update:model-value", value);
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
</script>
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { faker } from "@faker-js/faker";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
components: UITable,
|
|
3
|
+
const story = {
|
|
7
4
|
title: "Table",
|
|
8
5
|
};
|
|
9
6
|
|
|
10
|
-
const
|
|
11
|
-
components: { UITable },
|
|
7
|
+
const Template = (args: any) => ({
|
|
12
8
|
setup() {
|
|
13
9
|
return { args };
|
|
14
10
|
},
|
|
15
|
-
template: `<
|
|
11
|
+
template: `<t-table v-bind="args" />`,
|
|
16
12
|
});
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
const Default: any = Template.bind({});
|
|
15
|
+
Default.args = {
|
|
20
16
|
loading: false,
|
|
21
17
|
data: (Array.from({ length: 10 }) as any).map(() => ({
|
|
22
18
|
id: faker.string.uuid(),
|
|
@@ -30,3 +26,5 @@ Table.args = {
|
|
|
30
26
|
{ title: "Job", property: "job" },
|
|
31
27
|
],
|
|
32
28
|
};
|
|
29
|
+
|
|
30
|
+
export { story as default, Default };
|
|
@@ -1,49 +1,22 @@
|
|
|
1
1
|
<script lang="ts" setup generic="T extends object">
|
|
2
|
-
import {
|
|
2
|
+
import { TableProps } from "./types";
|
|
3
3
|
|
|
4
4
|
import { computed, reactive, ref, useSlots } from "vue";
|
|
5
5
|
|
|
6
|
-
export type TableProps<T = object> = {
|
|
7
|
-
data: T[];
|
|
8
|
-
rowKey?: string;
|
|
9
|
-
columns: TableColumn[];
|
|
10
|
-
loading?: boolean;
|
|
11
|
-
selectable?: boolean;
|
|
12
|
-
disableStyle?: boolean;
|
|
13
|
-
stickyHeader?: boolean;
|
|
14
|
-
|
|
15
|
-
rowClass?: string;
|
|
16
|
-
tableDataClass?: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
6
|
defineOptions({ name: "TTable" });
|
|
20
7
|
|
|
21
|
-
const props = withDefaults(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}>(),
|
|
34
|
-
{
|
|
35
|
-
data: () => [],
|
|
36
|
-
rowKey: "id",
|
|
37
|
-
columns: () => [],
|
|
38
|
-
loading: false,
|
|
39
|
-
selectable: false,
|
|
40
|
-
disableStyle: false,
|
|
41
|
-
stickyHeader: true,
|
|
42
|
-
|
|
43
|
-
rowClass: "hover:bg-hover",
|
|
44
|
-
tableDataClass: "px-2 py-2",
|
|
45
|
-
},
|
|
46
|
-
);
|
|
8
|
+
const props = withDefaults(defineProps<TableProps<T>>(), {
|
|
9
|
+
data: () => [],
|
|
10
|
+
rowKey: "id",
|
|
11
|
+
columns: () => [],
|
|
12
|
+
loading: false,
|
|
13
|
+
selectable: false,
|
|
14
|
+
disableStyle: false,
|
|
15
|
+
stickyHeader: true,
|
|
16
|
+
|
|
17
|
+
rowClass: "hover:bg-hover",
|
|
18
|
+
tableDataClass: "px-2 py-2",
|
|
19
|
+
});
|
|
47
20
|
|
|
48
21
|
const emit = defineEmits<{
|
|
49
22
|
(e: "selected", val: any): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TableColumn } from "@/types/ui";
|
|
2
|
+
|
|
3
|
+
export type TableProps<T = object> = {
|
|
4
|
+
data: T[];
|
|
5
|
+
rowKey?: string;
|
|
6
|
+
columns: TableColumn[];
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
selectable?: boolean;
|
|
9
|
+
disableStyle?: boolean;
|
|
10
|
+
stickyHeader?: boolean;
|
|
11
|
+
|
|
12
|
+
rowClass?: string;
|
|
13
|
+
tableDataClass?: string;
|
|
14
|
+
};
|
package/components/Tag/Tag.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ElementSize } from "@/enums/ui";
|
|
3
|
+
import { TagProps, TagEvents } from "./types";
|
|
3
4
|
|
|
4
5
|
defineOptions({ name: "TTag" });
|
|
5
6
|
|
|
@@ -12,9 +13,7 @@ const props = withDefaults(defineProps<TagProps>(), {
|
|
|
12
13
|
hasCloseButton: false,
|
|
13
14
|
});
|
|
14
15
|
|
|
15
|
-
const emit = defineEmits<
|
|
16
|
-
(e: "close"): void;
|
|
17
|
-
}>();
|
|
16
|
+
const emit = defineEmits<TagEvents>();
|
|
18
17
|
</script>
|
|
19
18
|
|
|
20
19
|
<template>
|
|
@@ -60,14 +59,3 @@ const emit = defineEmits<{
|
|
|
60
59
|
</div>
|
|
61
60
|
</div>
|
|
62
61
|
</template>
|
|
63
|
-
|
|
64
|
-
<script lang="ts">
|
|
65
|
-
export interface TagProps {
|
|
66
|
-
text?: string;
|
|
67
|
-
size?: ElementSize;
|
|
68
|
-
role?: string;
|
|
69
|
-
color?: string;
|
|
70
|
-
confirmClose?: boolean;
|
|
71
|
-
hasCloseButton?: boolean;
|
|
72
|
-
}
|
|
73
|
-
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ElementSize } from "@/enums/ui";
|
|
2
|
+
|
|
3
|
+
export type TagProps = {
|
|
4
|
+
text?: string;
|
|
5
|
+
size?: ElementSize;
|
|
6
|
+
role?: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
confirmClose?: boolean;
|
|
9
|
+
hasCloseButton?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type TagEvents = {
|
|
13
|
+
/** Fired when the "x" button from tag is clicked */
|
|
14
|
+
(event: "close"): void;
|
|
15
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const jsonToFormData = (json: any) => {
|
|
2
|
+
const formData = new FormData();
|
|
3
|
+
|
|
4
|
+
if (json) {
|
|
5
|
+
for (const key in json) {
|
|
6
|
+
if (json[key] !== null && json[key] !== undefined) {
|
|
7
|
+
if (Array.isArray(json[key])) {
|
|
8
|
+
json[key].forEach((item: any) => {
|
|
9
|
+
formData.append(`${key}[]`, item);
|
|
10
|
+
});
|
|
11
|
+
} else {
|
|
12
|
+
formData.append(key, json[key]);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return formData;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const formDataToJson = (formData: FormData) => {
|
|
22
|
+
const json: any = {};
|
|
23
|
+
|
|
24
|
+
formData.forEach((value, key) => {
|
|
25
|
+
json[key] = value;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return json;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { jsonToFormData, formDataToJson };
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
formValuePriceTransformer,
|
|
5
5
|
formValueCountryTransformer,
|
|
6
6
|
formValuePasswordTransformer,
|
|
7
|
-
} from "@/
|
|
7
|
+
} from "@/form/form-value-transformers";
|
|
8
8
|
import {
|
|
9
9
|
FormDataForm,
|
|
10
10
|
TransformedForm,
|
|
11
11
|
FormSchemaValueMap,
|
|
12
12
|
AcceptedFormDataValues,
|
|
13
13
|
} from "@/types/form";
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
const sanitizeValue = (value: string | number): AcceptedFormDataValues => {
|
|
16
16
|
if (value === null || value === undefined) {
|
|
17
17
|
value = "";
|
|
@@ -32,7 +32,7 @@ const transformers = {
|
|
|
32
32
|
| FormSchemaValueMap[FormDataTypes.String]
|
|
33
33
|
| FormSchemaValueMap[FormDataTypes.Number],
|
|
34
34
|
form: FormDataForm,
|
|
35
|
-
key: string
|
|
35
|
+
key: string,
|
|
36
36
|
) => {
|
|
37
37
|
value = sanitizeValue(value);
|
|
38
38
|
|
|
@@ -46,7 +46,7 @@ const transformers = {
|
|
|
46
46
|
price: FormSchemaValueMap[FormDataTypes.Price],
|
|
47
47
|
form: FormDataForm,
|
|
48
48
|
key: string,
|
|
49
|
-
suffixes: string[] = ["Currency", "Value"]
|
|
49
|
+
suffixes: string[] = ["Currency", "Value"],
|
|
50
50
|
): FormDataForm => {
|
|
51
51
|
const [iso, value] = formValuePriceTransformer(price);
|
|
52
52
|
|
|
@@ -58,14 +58,14 @@ const transformers = {
|
|
|
58
58
|
address: (
|
|
59
59
|
address: FormSchemaValueMap[FormDataTypes.Address],
|
|
60
60
|
form: FormDataForm,
|
|
61
|
-
key: string
|
|
61
|
+
key: string,
|
|
62
62
|
): FormDataForm => {
|
|
63
63
|
form.append(
|
|
64
64
|
key,
|
|
65
65
|
JSON.stringify({
|
|
66
66
|
...address,
|
|
67
67
|
country: formValueCountryTransformer(address?.country),
|
|
68
|
-
})
|
|
68
|
+
}),
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
return form;
|
|
@@ -73,7 +73,7 @@ const transformers = {
|
|
|
73
73
|
documents: (
|
|
74
74
|
files: FormSchemaValueMap[FormDataTypes.Documents],
|
|
75
75
|
form: FormDataForm,
|
|
76
|
-
key: string
|
|
76
|
+
key: string,
|
|
77
77
|
): FormDataForm => {
|
|
78
78
|
if (!key.endsWith("[]")) {
|
|
79
79
|
key = `${key}[]`;
|
|
@@ -86,7 +86,7 @@ const transformers = {
|
|
|
86
86
|
document: (
|
|
87
87
|
file: FormSchemaValueMap[FormDataTypes.Document],
|
|
88
88
|
form: FormDataForm,
|
|
89
|
-
key: string
|
|
89
|
+
key: string,
|
|
90
90
|
): FormDataForm => {
|
|
91
91
|
form.append(key, file);
|
|
92
92
|
|
|
@@ -95,7 +95,7 @@ const transformers = {
|
|
|
95
95
|
stringArray: (
|
|
96
96
|
value: FormSchemaValueMap[FormDataTypes.StringArray],
|
|
97
97
|
form: FormDataForm,
|
|
98
|
-
key: string
|
|
98
|
+
key: string,
|
|
99
99
|
) => {
|
|
100
100
|
if (!key.endsWith("[]")) {
|
|
101
101
|
key = `${key}[]`;
|
|
@@ -110,15 +110,15 @@ const transformers = {
|
|
|
110
110
|
export const formValueToFormDataValue = async (
|
|
111
111
|
schema: FormDataTypes,
|
|
112
112
|
form: TransformedForm<FormSubmissionFormat.FormData>,
|
|
113
|
-
value:
|
|
114
|
-
key: string
|
|
113
|
+
value: any,
|
|
114
|
+
key: string,
|
|
115
115
|
): Promise<FormDataForm> => {
|
|
116
116
|
switch (schema) {
|
|
117
117
|
case FormDataTypes.Country:
|
|
118
118
|
return transformers.default(
|
|
119
119
|
formValueCountryTransformer(value),
|
|
120
120
|
form,
|
|
121
|
-
key
|
|
121
|
+
key,
|
|
122
122
|
);
|
|
123
123
|
case FormDataTypes.Document:
|
|
124
124
|
return transformers.document(value, form, key);
|
|
@@ -128,7 +128,7 @@ export const formValueToFormDataValue = async (
|
|
|
128
128
|
return transformers.default(
|
|
129
129
|
formValueDateTransformer(value),
|
|
130
130
|
form,
|
|
131
|
-
key
|
|
131
|
+
key,
|
|
132
132
|
);
|
|
133
133
|
case FormDataTypes.Address:
|
|
134
134
|
return transformers.address(value, form, key);
|
|
@@ -138,7 +138,7 @@ export const formValueToFormDataValue = async (
|
|
|
138
138
|
return transformers.default(
|
|
139
139
|
await formValuePasswordTransformer(value),
|
|
140
140
|
form,
|
|
141
|
-
key
|
|
141
|
+
key,
|
|
142
142
|
);
|
|
143
143
|
case FormDataTypes.StringArray:
|
|
144
144
|
return transformers.stringArray(value, form, key);
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
TransformedForm,
|
|
7
7
|
} from "@/types/form";
|
|
8
8
|
|
|
9
|
-
import { formValueToJSONFormValue } from "@/
|
|
10
|
-
import { formValueToFormDataValue } from "@/
|
|
9
|
+
import { formValueToJSONFormValue } from "@/form/json-transformers";
|
|
10
|
+
import { formValueToFormDataValue } from "@/form/form-data-transformers";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Transforms the form values to a format that conforms to the submission format
|
|
@@ -21,10 +21,7 @@ const formValueCountryTransformer = (country?: Country): string => {
|
|
|
21
21
|
const formValuePasswordTransformer = async (
|
|
22
22
|
password?: InputPasswordModel,
|
|
23
23
|
): Promise<string> => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// return password?.encrypt ? await vault.encrypt(pass) : pass;
|
|
27
|
-
return pass;
|
|
24
|
+
return password?.encrypted ?? password?.value ?? "";
|
|
28
25
|
};
|
|
29
26
|
|
|
30
27
|
export {
|
|
@@ -2,7 +2,7 @@ import { FormInstance } from "@/types/form";
|
|
|
2
2
|
import { FormDataTypes, FormSubmissionFormat } from "@/enums/form";
|
|
3
3
|
|
|
4
4
|
import { expect, test } from "vitest";
|
|
5
|
-
import { transformForm } from "@/
|
|
5
|
+
import { transformForm } from "@/form/form-transformer";
|
|
6
6
|
|
|
7
7
|
test("Form is transformed into FormData", async () => {
|
|
8
8
|
const schema = {
|
|
@@ -22,7 +22,6 @@ test("Form is transformed into FormData", async () => {
|
|
|
22
22
|
password: {
|
|
23
23
|
value: "123",
|
|
24
24
|
strength: 100,
|
|
25
|
-
encrypt: false,
|
|
26
25
|
updatedAt: new Date(),
|
|
27
26
|
},
|
|
28
27
|
price: {
|
|
@@ -70,7 +69,6 @@ test("Form is transformed into JSON", async () => {
|
|
|
70
69
|
password: {
|
|
71
70
|
value: "123",
|
|
72
71
|
strength: 100,
|
|
73
|
-
encrypt: false,
|
|
74
72
|
updatedAt: new Date(),
|
|
75
73
|
},
|
|
76
74
|
price: {
|
|
@@ -11,13 +11,13 @@ import {
|
|
|
11
11
|
formValuePriceTransformer,
|
|
12
12
|
formValueCountryTransformer,
|
|
13
13
|
formValuePasswordTransformer,
|
|
14
|
-
} from "@/
|
|
14
|
+
} from "@/form/form-value-transformers";
|
|
15
15
|
|
|
16
16
|
const transformers = {
|
|
17
17
|
default: (
|
|
18
18
|
value: FormSchemaValueMap[FormDataTypes.String],
|
|
19
19
|
form: JSONForm,
|
|
20
|
-
key: string
|
|
20
|
+
key: string,
|
|
21
21
|
) => {
|
|
22
22
|
form[key] = value;
|
|
23
23
|
|
|
@@ -27,7 +27,7 @@ const transformers = {
|
|
|
27
27
|
date: FormSchemaValueMap[FormDataTypes.Price],
|
|
28
28
|
form: JSONForm,
|
|
29
29
|
key: string,
|
|
30
|
-
suffixes: string[] = ["Currency", "Value"]
|
|
30
|
+
suffixes: string[] = ["Currency", "Value"],
|
|
31
31
|
): JSONForm => {
|
|
32
32
|
const [currency, value] = formValuePriceTransformer(date);
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ const transformers = {
|
|
|
39
39
|
password: async (
|
|
40
40
|
value: FormSchemaValueMap[FormDataTypes.Password],
|
|
41
41
|
form: JSONForm,
|
|
42
|
-
key: string
|
|
42
|
+
key: string,
|
|
43
43
|
): Promise<JSONForm> => {
|
|
44
44
|
form[key] = await formValuePasswordTransformer(value);
|
|
45
45
|
|
|
@@ -48,7 +48,7 @@ const transformers = {
|
|
|
48
48
|
stringArray: (
|
|
49
49
|
value: FormSchemaValueMap[FormDataTypes.StringArray],
|
|
50
50
|
form: JSONForm,
|
|
51
|
-
key: string
|
|
51
|
+
key: string,
|
|
52
52
|
) => {
|
|
53
53
|
form[key] = value;
|
|
54
54
|
|
|
@@ -60,14 +60,14 @@ export const formValueToJSONFormValue = async <T extends FormDataTypes>(
|
|
|
60
60
|
schema: FormSchema[T],
|
|
61
61
|
form: TransformedForm<FormSubmissionFormat.JSON>,
|
|
62
62
|
value: any,
|
|
63
|
-
key: string
|
|
63
|
+
key: string,
|
|
64
64
|
): Promise<JSONForm> => {
|
|
65
65
|
switch (schema) {
|
|
66
66
|
case FormDataTypes.Country:
|
|
67
67
|
return transformers.default(
|
|
68
68
|
formValueCountryTransformer(value),
|
|
69
69
|
form,
|
|
70
|
-
key
|
|
70
|
+
key,
|
|
71
71
|
);
|
|
72
72
|
case FormDataTypes.Documents:
|
|
73
73
|
return transformers.default(value, form, key);
|
|
@@ -75,7 +75,7 @@ export const formValueToJSONFormValue = async <T extends FormDataTypes>(
|
|
|
75
75
|
return transformers.default(
|
|
76
76
|
formValueDateTransformer(value),
|
|
77
77
|
form,
|
|
78
|
-
key
|
|
78
|
+
key,
|
|
79
79
|
);
|
|
80
80
|
case FormDataTypes.Address:
|
|
81
81
|
return transformers.default(value, form, key);
|
package/index.css
CHANGED
|
@@ -232,92 +232,6 @@
|
|
|
232
232
|
display: inline-block;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
.fs {
|
|
236
|
-
width: 20px;
|
|
237
|
-
height: 20px;
|
|
238
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/unknown.svg");
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.fs.bmp {
|
|
242
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/bmp.svg");
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
.fs.ics {
|
|
246
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/ics.svg");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
.fs.jpg {
|
|
250
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/jpg.svg");
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
.fs.jpeg {
|
|
254
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/jpeg.svg");
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.fs.doc {
|
|
258
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/doc.svg");
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.fs.docx {
|
|
262
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/docx.svg");
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.fs.gif {
|
|
266
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/gif.svg");
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.fs.mp3 {
|
|
270
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/mp3.svg");
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
.fs.mp4 {
|
|
274
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/mp4.svg");
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.fs.pdf {
|
|
278
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/pdf.svg");
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.fs.png {
|
|
282
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/png.svg");
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
.fs.rar {
|
|
286
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/rar.svg");
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.fs.tar {
|
|
290
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/tar.svg");
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.fs.txt {
|
|
294
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/txt.svg");
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.fs.xls {
|
|
298
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/xls.svg");
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.fs.xlsx {
|
|
302
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/xlsx.svg");
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
.fs.xml {
|
|
306
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/xml.svg");
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.fs.yaml {
|
|
310
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/yaml.svg");
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
.fs.zip {
|
|
314
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/zip.svg");
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
.fs.dir {
|
|
318
|
-
content: url("https://static.%GLOBAL_DOMAIN%/site/assets/images/fs/folder-paleorange.svg");
|
|
319
|
-
}
|
|
320
|
-
|
|
321
235
|
html,
|
|
322
236
|
body {
|
|
323
237
|
font-family: "San Francisco", sans-serif; /* font-family: "Inter", sans-serif; */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caipira/tamandua",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "UI library for the Caipira ecosystem",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://caipira.io",
|
|
@@ -67,4 +67,4 @@
|
|
|
67
67
|
"vue": "^3.4.21",
|
|
68
68
|
"vue-tsc": "^1.8.0"
|
|
69
69
|
}
|
|
70
|
-
}
|
|
70
|
+
}
|
package/types/form.ts
CHANGED
|
@@ -52,23 +52,23 @@ export type SelectOption = {
|
|
|
52
52
|
}
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
-
export interface InputSocialModel {
|
|
56
|
-
profile: string;
|
|
57
|
-
network: number;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
55
|
export interface InputPriceModel {
|
|
61
56
|
iso: string;
|
|
62
57
|
value: number;
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
export interface InputPasswordModel {
|
|
61
|
+
/** Unencrypted password */
|
|
66
62
|
value: string;
|
|
63
|
+
|
|
64
|
+
/** Strength of the password */
|
|
67
65
|
strength?: number;
|
|
66
|
+
|
|
67
|
+
/** Date of creation or last update */
|
|
68
68
|
updatedAt?: Date;
|
|
69
69
|
|
|
70
|
-
/** If
|
|
71
|
-
|
|
70
|
+
/** If an encryptor was passed, this prop will hold the encrypted value */
|
|
71
|
+
encrypted?: string;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export type FormStyle = { [key in "label" | "input"]?: string };
|
package/vite.config.mts
CHANGED
|
@@ -1,38 +1,14 @@
|
|
|
1
1
|
import vue from "@vitejs/plugin-vue";
|
|
2
|
-
import { resolve } from "path";
|
|
3
2
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
-
import { defineConfig
|
|
3
|
+
import { defineConfig } from "vite";
|
|
5
4
|
|
|
6
|
-
export default defineConfig(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return src.replace(/%(.*?)%/g, (match, p1) => env[p1]);
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
plugins: [vue(), tsconfigPaths(), cssPlugin()],
|
|
23
|
-
resolve: {
|
|
24
|
-
alias: {
|
|
25
|
-
"@": resolve(__dirname),
|
|
26
|
-
vue: "vue/dist/vue.esm-bundler.js",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
build: {
|
|
30
|
-
outDir: "./dist",
|
|
31
|
-
},
|
|
32
|
-
envPrefix,
|
|
33
|
-
test: {
|
|
34
|
-
environment: "jsdom",
|
|
35
|
-
setupFiles: ["vitest.setup.ts"],
|
|
36
|
-
},
|
|
37
|
-
};
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [vue(), tsconfigPaths()],
|
|
7
|
+
build: {
|
|
8
|
+
outDir: "./dist",
|
|
9
|
+
},
|
|
10
|
+
test: {
|
|
11
|
+
environment: "jsdom",
|
|
12
|
+
setupFiles: ["vitest.setup.ts"],
|
|
13
|
+
},
|
|
38
14
|
});
|
package/vitest.setup.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import ui from "@/plugins/ui";
|
|
2
1
|
import { vi } from "vitest";
|
|
2
|
+
import Tamandua from "@/index";
|
|
3
3
|
import { config } from "@vue/test-utils";
|
|
4
4
|
|
|
5
5
|
Object.defineProperty(window, "matchMedia", {
|
|
@@ -18,4 +18,4 @@ Object.defineProperty(window, "matchMedia", {
|
|
|
18
18
|
})),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
config.global.plugins = [
|
|
21
|
+
config.global.plugins = [Tamandua];
|
package/services/form/form.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { APISearchFilters } from "@/types/api";
|
|
2
|
-
|
|
3
|
-
const jsonToFormData = (json: any) => {
|
|
4
|
-
const formData = new FormData();
|
|
5
|
-
|
|
6
|
-
if (json) {
|
|
7
|
-
for (const key in json) {
|
|
8
|
-
if (json[key] !== null && json[key] !== undefined) {
|
|
9
|
-
if (Array.isArray(json[key])) {
|
|
10
|
-
json[key].forEach((item: any) => {
|
|
11
|
-
formData.append(`${key}[]`, item);
|
|
12
|
-
});
|
|
13
|
-
} else {
|
|
14
|
-
formData.append(key, json[key]);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return formData;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const formDataToJson = (formData: FormData) => {
|
|
24
|
-
const json: any = {};
|
|
25
|
-
|
|
26
|
-
formData.forEach((value, key) => {
|
|
27
|
-
json[key] = value;
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return json;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const hitSearchCache = (
|
|
34
|
-
filters: APISearchFilters | undefined,
|
|
35
|
-
store: any,
|
|
36
|
-
key: string
|
|
37
|
-
) => {
|
|
38
|
-
if (!store) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (filters?.i) {
|
|
43
|
-
const item = store[
|
|
44
|
-
filters?.r && filters?.r === "option" ? `${key}Options` : key
|
|
45
|
-
]?.find((item: { uuid: string }) => item.uuid === filters.i);
|
|
46
|
-
|
|
47
|
-
if (item) {
|
|
48
|
-
return {
|
|
49
|
-
items: [item],
|
|
50
|
-
pagination: {
|
|
51
|
-
page: 1,
|
|
52
|
-
pages: 1,
|
|
53
|
-
perPage: 12,
|
|
54
|
-
items: 1,
|
|
55
|
-
totalItems: 1,
|
|
56
|
-
skip: 0,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const refreshSearchCache = (
|
|
64
|
-
filters: APISearchFilters | undefined,
|
|
65
|
-
store: any,
|
|
66
|
-
key: string,
|
|
67
|
-
data: any[]
|
|
68
|
-
) => {
|
|
69
|
-
if (!store) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (filters?.r && filters?.r === "option") {
|
|
74
|
-
store[`${key}Options`] = data;
|
|
75
|
-
} else {
|
|
76
|
-
store[key] = data;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export { jsonToFormData, formDataToJson, hitSearchCache, refreshSearchCache };
|
|
File without changes
|