@basmilius/common 3.0.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/README.md +19 -0
- package/dist/composable/index.d.ts +16 -0
- package/dist/composable/useCopy.d.ts +2 -0
- package/dist/composable/useDebounced.d.ts +1 -0
- package/dist/composable/useDtoForm.d.ts +2 -0
- package/dist/composable/useInterval.d.ts +2 -0
- package/dist/composable/useLoaded.d.ts +6 -0
- package/dist/composable/useLoadedAction.d.ts +2 -0
- package/dist/composable/useLocalFile.d.ts +1 -0
- package/dist/composable/useMounted.d.ts +2 -0
- package/dist/composable/useNamedRoute.d.ts +2 -0
- package/dist/composable/useNavigate.d.ts +5 -0
- package/dist/composable/usePagination.d.ts +1 -0
- package/dist/composable/usePasswordStrength.d.ts +2 -0
- package/dist/composable/useRouteMeta.d.ts +5 -0
- package/dist/composable/useRouteNames.d.ts +1 -0
- package/dist/composable/useRouteParam.d.ts +2 -0
- package/dist/composable/useService.d.ts +6 -0
- package/dist/error/ForbiddenException.d.ts +1 -0
- package/dist/error/HandledException.d.ts +1 -0
- package/dist/error/UnauthorizedException.d.ts +1 -0
- package/dist/error/index.d.ts +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +267 -0
- package/dist/store/defineStore.d.ts +8 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/util/emptyNull.d.ts +1 -0
- package/dist/util/generateColorPalette.d.ts +1 -0
- package/dist/util/guarded.d.ts +3 -0
- package/dist/util/index.d.ts +9 -0
- package/dist/util/onError.d.ts +1 -0
- package/dist/util/onErrorSnackbar.d.ts +2 -0
- package/dist/util/persistentRef.d.ts +4 -0
- package/dist/util/persistentStringRef.d.ts +2 -0
- package/dist/util/runBefore.d.ts +1 -0
- package/dist/util/unrefAll.d.ts +3 -0
- package/package.json +66 -0
- package/src/composable/index.ts +16 -0
- package/src/composable/useCopy.ts +8 -0
- package/src/composable/useDebounced.ts +5 -0
- package/src/composable/useDtoForm.ts +17 -0
- package/src/composable/useInterval.ts +22 -0
- package/src/composable/useLoaded.ts +38 -0
- package/src/composable/useLoadedAction.ts +13 -0
- package/src/composable/useLocalFile.ts +40 -0
- package/src/composable/useMounted.ts +9 -0
- package/src/composable/useNamedRoute.ts +17 -0
- package/src/composable/useNavigate.ts +28 -0
- package/src/composable/usePagination.ts +35 -0
- package/src/composable/usePasswordStrength.ts +67 -0
- package/src/composable/useRouteMeta.ts +34 -0
- package/src/composable/useRouteNames.ts +14 -0
- package/src/composable/useRouteParam.ts +13 -0
- package/src/composable/useService.ts +20 -0
- package/src/error/ForbiddenException.ts +2 -0
- package/src/error/HandledException.ts +2 -0
- package/src/error/UnauthorizedException.ts +2 -0
- package/src/error/index.ts +3 -0
- package/src/index.ts +4 -0
- package/src/store/defineStore.ts +31 -0
- package/src/store/index.ts +7 -0
- package/src/util/emptyNull.ts +3 -0
- package/src/util/generateColorPalette.ts +132 -0
- package/src/util/guarded.ts +73 -0
- package/src/util/index.ts +9 -0
- package/src/util/onError.ts +5 -0
- package/src/util/onErrorSnackbar.ts +15 -0
- package/src/util/persistentRef.ts +21 -0
- package/src/util/persistentStringRef.ts +6 -0
- package/src/util/runBefore.ts +8 -0
- package/src/util/unrefAll.ts +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function emptyNull(str: string | undefined | null): string | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function(baseHex: string, prefix?: string);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as emptyNull } from "./emptyNull";
|
|
2
|
+
export { default as generateColorPalette } from "./generateColorPalette";
|
|
3
|
+
export { default as guarded } from "./guarded";
|
|
4
|
+
export { default as onError } from "./onError";
|
|
5
|
+
export { default as onErrorSnackbar } from "./onErrorSnackbar";
|
|
6
|
+
export { default as persistentRef } from "./persistentRef";
|
|
7
|
+
export { default as persistentStringRef } from "./persistentStringRef";
|
|
8
|
+
export { default as runBefore } from "./runBefore";
|
|
9
|
+
export { default as unrefAll } from "./unrefAll";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function<T extends Function>(onError: (err: Error) => void): T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function<T extends Function>(before: () => void): T;
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@basmilius/common",
|
|
3
|
+
"description": "Common code shared in personal projects.",
|
|
4
|
+
"version": "3.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"funding": "https://github.com/sponsors/basmilius",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Bas Milius",
|
|
10
|
+
"email": "bas@mili.us",
|
|
11
|
+
"url": "https://bas.dev"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/basmilius/packages.git",
|
|
16
|
+
"directory": "packages/common"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"common",
|
|
20
|
+
"bun",
|
|
21
|
+
"vue",
|
|
22
|
+
"store",
|
|
23
|
+
"pinia",
|
|
24
|
+
"router"
|
|
25
|
+
],
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"src",
|
|
29
|
+
"CODEOWNERS",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"provenance": false
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsgo --noEmit && bun -b build.ts"
|
|
38
|
+
},
|
|
39
|
+
"main": "./dist/index.js",
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"typings": "./dist/index.d.ts",
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": "./dist/index.d.ts",
|
|
46
|
+
"default": "./dist/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./*": "./*"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@basmilius/http-client": "3.0.0",
|
|
52
|
+
"@basmilius/utils": "3.0.0",
|
|
53
|
+
"@flux-ui/components": "^3.0.0-next.26",
|
|
54
|
+
"@flux-ui/internals": "^3.0.0-next.26",
|
|
55
|
+
"pinia": "^3.0.4",
|
|
56
|
+
"vue": "^3.6.0-beta.6",
|
|
57
|
+
"vue-router": "^5.0.3"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@basmilius/tools": "3.0.0",
|
|
61
|
+
"@types/culori": "^4.0.1",
|
|
62
|
+
"@types/lodash-es": "^4.17.12",
|
|
63
|
+
"culori": "^4.0.2",
|
|
64
|
+
"lodash-es": "^4.17.23"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { default as useCopy } from './useCopy';
|
|
2
|
+
export { default as useDebounced } from './useDebounced';
|
|
3
|
+
export { default as useDtoForm } from './useDtoForm';
|
|
4
|
+
export { default as useInterval } from './useInterval';
|
|
5
|
+
export { default as useLoaded } from './useLoaded';
|
|
6
|
+
export { default as useLoadedAction } from './useLoadedAction';
|
|
7
|
+
export { default as useLocalFile } from './useLocalFile';
|
|
8
|
+
export { default as useMounted } from './useMounted';
|
|
9
|
+
export { default as useNamedRoute } from './useNamedRoute';
|
|
10
|
+
export { default as useNavigate } from './useNavigate';
|
|
11
|
+
export { default as usePagination } from './usePagination';
|
|
12
|
+
export { default as usePasswordStrength } from './usePasswordStrength';
|
|
13
|
+
export { default as useRouteMeta } from './useRouteMeta';
|
|
14
|
+
export { default as useRouteNames } from './useRouteNames';
|
|
15
|
+
export { default as useRouteParam } from './useRouteParam';
|
|
16
|
+
export { default as useService } from './useService';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { cloneDto, markDtoClean } from '@basmilius/http-client';
|
|
2
|
+
import { ref, type Ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
export default function <T>(dtoRef: Ref<T | null>) {
|
|
5
|
+
const form = ref<T>();
|
|
6
|
+
|
|
7
|
+
watch(dtoRef, dto => {
|
|
8
|
+
if (!dto) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
form.value = cloneDto(dto);
|
|
13
|
+
markDtoClean(form.value);
|
|
14
|
+
}, {immediate: true});
|
|
15
|
+
|
|
16
|
+
return form;
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { onMounted, onUnmounted, type Ref, ref, unref } from 'vue';
|
|
2
|
+
|
|
3
|
+
export default function (interval: Ref<number> | number, fn: Function): void {
|
|
4
|
+
const intervalRef = ref<any>();
|
|
5
|
+
|
|
6
|
+
onMounted(() => {
|
|
7
|
+
tick();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
onUnmounted(() => {
|
|
11
|
+
clearTimeout(intervalRef.value);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function schedule(): void {
|
|
15
|
+
intervalRef.value = setTimeout(() => requestAnimationFrame(tick), unref(interval));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function tick(): void {
|
|
19
|
+
schedule();
|
|
20
|
+
fn();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useDebouncedRef } from '@flux-ui/internals';
|
|
2
|
+
import { computed, type ComputedRef, ref, unref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
export default function (debounce: number = 0, initial: boolean = false): UseLoaded {
|
|
5
|
+
const first = ref(initial);
|
|
6
|
+
const tasks = ref(0);
|
|
7
|
+
|
|
8
|
+
const isLoading = computed(() => unref(first) || unref(tasks) > 0);
|
|
9
|
+
|
|
10
|
+
function loaded<T extends Function>(fn: T): T {
|
|
11
|
+
return (async (...args: any[]) => {
|
|
12
|
+
tasks.value++;
|
|
13
|
+
|
|
14
|
+
return await fn(...args)
|
|
15
|
+
.finally(() => tasks.value--);
|
|
16
|
+
}) as unknown as T;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isLoadingDebounced = useDebouncedRef(isLoading, debounce) as unknown as ComputedRef<boolean>;
|
|
20
|
+
|
|
21
|
+
watch(tasks, () => {
|
|
22
|
+
if (!unref(first)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
first.value = false;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
isLoading: isLoadingDebounced,
|
|
31
|
+
loaded
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type UseLoaded = {
|
|
36
|
+
readonly isLoading: ComputedRef<boolean>;
|
|
37
|
+
loaded<T extends Function>(fn: T): T;
|
|
38
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ComputedRef } from 'vue';
|
|
2
|
+
import useLoaded from './useLoaded';
|
|
3
|
+
|
|
4
|
+
export default function <T extends ((...args: any[]) => Promise<any>)>(fn: T): [T, ComputedRef<boolean>] {
|
|
5
|
+
const {isLoading, loaded} = useLoaded();
|
|
6
|
+
|
|
7
|
+
const action = loaded(fn);
|
|
8
|
+
|
|
9
|
+
return [
|
|
10
|
+
action,
|
|
11
|
+
isLoading
|
|
12
|
+
];
|
|
13
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ref, watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
export default function () {
|
|
4
|
+
const file = ref<File | null>(null);
|
|
5
|
+
const url = ref<string | null>(null);
|
|
6
|
+
|
|
7
|
+
const deleteFile = (): void => {
|
|
8
|
+
file.value = null;
|
|
9
|
+
url.value = null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const uploadFile = (uploadedFile: File): void => {
|
|
13
|
+
file.value = uploadedFile;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
watch(file, (file, _, onCleanup) => {
|
|
17
|
+
if (!file) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
url.value = URL.createObjectURL(file);
|
|
22
|
+
|
|
23
|
+
onCleanup(() => {
|
|
24
|
+
if (!url.value) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
URL.revokeObjectURL(url.value);
|
|
29
|
+
url.value = null;
|
|
30
|
+
});
|
|
31
|
+
}, {immediate: true});
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
file,
|
|
35
|
+
url,
|
|
36
|
+
|
|
37
|
+
delete: deleteFile,
|
|
38
|
+
upload: uploadFile
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { computed, provide, type Ref, unref } from 'vue';
|
|
2
|
+
import { useRoute, viewDepthKey } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
export default function (nameRef: Ref<string> | string) {
|
|
5
|
+
const route = useRoute();
|
|
6
|
+
|
|
7
|
+
const depth = computed(() => route.matched.findIndex(m => !!m.components && unref(nameRef) in m.components));
|
|
8
|
+
const matched = computed(() => route.matched[unref(depth)]);
|
|
9
|
+
const viewKey = computed(() => unref(matched)?.path);
|
|
10
|
+
|
|
11
|
+
provide(viewDepthKey, depth);
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
route,
|
|
15
|
+
viewKey
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type NavigationFailure, type RouteLocationRaw, useRouter } from 'vue-router';
|
|
2
|
+
|
|
3
|
+
type To = Omit<RouteLocationRaw, 'replace'>;
|
|
4
|
+
type Navigate = (to: To, replace?: boolean) => Promise<NavigationFailure | void | undefined>;
|
|
5
|
+
type Wrap = (fn: Navigate) => Navigate;
|
|
6
|
+
|
|
7
|
+
export default function (...wrap: Wrap[]) {
|
|
8
|
+
const router = useRouter();
|
|
9
|
+
|
|
10
|
+
let navigate = async (to: To, replace: boolean = false) => {
|
|
11
|
+
if (replace) {
|
|
12
|
+
return await router.replace(to);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return await router.push(to);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
for (let wrapper of wrap) {
|
|
19
|
+
navigate = wrapper(navigate);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
navigate,
|
|
24
|
+
|
|
25
|
+
push: (to: To) => navigate(to),
|
|
26
|
+
replace: (to: To) => navigate(to, true)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_LIMITS = [5, 10, 25, 50, 100];
|
|
4
|
+
const DEFAULT_PAGE = 1;
|
|
5
|
+
const DEFAULT_PER_PAGE = 25;
|
|
6
|
+
|
|
7
|
+
export default function () {
|
|
8
|
+
const limits = ref(DEFAULT_LIMITS);
|
|
9
|
+
const page = ref(DEFAULT_PAGE);
|
|
10
|
+
const perPage = ref(DEFAULT_PER_PAGE);
|
|
11
|
+
const total = ref(0);
|
|
12
|
+
|
|
13
|
+
function setPage(num: number): void {
|
|
14
|
+
page.value = num;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function setPerPage(num: number): void {
|
|
18
|
+
perPage.value = num;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function setTotal(num: number): void {
|
|
22
|
+
total.value = num;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
limits,
|
|
27
|
+
page,
|
|
28
|
+
perPage,
|
|
29
|
+
total,
|
|
30
|
+
|
|
31
|
+
setPage,
|
|
32
|
+
setPerPage,
|
|
33
|
+
setTotal
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { computed, type Ref, unref } from 'vue';
|
|
2
|
+
|
|
3
|
+
type PasswordRuleType =
|
|
4
|
+
| 'lowercase'
|
|
5
|
+
| 'uppercase'
|
|
6
|
+
| 'number'
|
|
7
|
+
| 'symbol';
|
|
8
|
+
|
|
9
|
+
type PasswordStrengthType =
|
|
10
|
+
| 'too_weak'
|
|
11
|
+
| 'weak'
|
|
12
|
+
| 'medium'
|
|
13
|
+
| 'strong';
|
|
14
|
+
|
|
15
|
+
type Result = {
|
|
16
|
+
readonly length: number;
|
|
17
|
+
readonly rules: PasswordRuleType[];
|
|
18
|
+
readonly strength: PasswordStrengthType;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type PasswordRule = {
|
|
22
|
+
readonly regex: RegExp;
|
|
23
|
+
readonly type: PasswordRuleType;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type PasswordStrength = {
|
|
27
|
+
readonly index: number;
|
|
28
|
+
readonly type: PasswordStrengthType;
|
|
29
|
+
readonly minimumDiversity: number;
|
|
30
|
+
readonly minimumLength: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const strengths: PasswordStrength[] = [
|
|
34
|
+
{index: 0, type: 'too_weak', minimumDiversity: 0, minimumLength: 0},
|
|
35
|
+
{index: 1, type: 'weak', minimumDiversity: 2, minimumLength: 6},
|
|
36
|
+
{index: 2, type: 'medium', minimumDiversity: 3, minimumLength: 8},
|
|
37
|
+
{index: 3, type: 'strong', minimumDiversity: 4, minimumLength: 10}
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
40
|
+
const rules: PasswordRule[] = [
|
|
41
|
+
{regex: new RegExp('[a-z]'), type: 'lowercase'},
|
|
42
|
+
{regex: new RegExp('[A-Z]'), type: 'uppercase'},
|
|
43
|
+
{regex: new RegExp('[0-9]'), type: 'number'},
|
|
44
|
+
{regex: new RegExp('[!"#\$%&\'\(\)\*\+,-\./:;<=>\?@\[\\\\\\]\^_`\{|\}~]'), type: 'symbol'}
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export default function (passwordRef: Ref<string>) {
|
|
48
|
+
return computed<Result | null>(() => {
|
|
49
|
+
const password = unref(passwordRef);
|
|
50
|
+
|
|
51
|
+
if (password.length === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const foundRules = rules
|
|
56
|
+
.filter(r => r.regex.test(password))
|
|
57
|
+
.map(r => r.type);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
length: password.length,
|
|
61
|
+
strength: strengths
|
|
62
|
+
.sort((a, b) => b.index - a.index)
|
|
63
|
+
.find(s => foundRules.length >= s.minimumDiversity && password.length >= s.minimumLength)!.type,
|
|
64
|
+
rules: foundRules
|
|
65
|
+
} satisfies Result;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { merge } from 'lodash-es';
|
|
2
|
+
import { computed, type Ref } from 'vue';
|
|
3
|
+
import { useRoute } from 'vue-router';
|
|
4
|
+
|
|
5
|
+
type RouteMeta = {
|
|
6
|
+
readonly name?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function (): Ref<RouteMeta> {
|
|
10
|
+
const route = useRoute();
|
|
11
|
+
|
|
12
|
+
return computed(() => {
|
|
13
|
+
let meta: RouteMeta = {};
|
|
14
|
+
|
|
15
|
+
for (let i = route.matched.length - 1; i >= 0; --i) {
|
|
16
|
+
const record = route.matched[i];
|
|
17
|
+
|
|
18
|
+
if (!record || typeof record.meta !== 'object') {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let matchMeta = {...record.meta};
|
|
23
|
+
|
|
24
|
+
if ('navigation' in meta) {
|
|
25
|
+
const {navigation: _, ...matchMetaWithoutNavigation} = matchMeta;
|
|
26
|
+
matchMeta = matchMetaWithoutNavigation;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
meta = merge(meta, matchMeta);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return meta;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { computed } from 'vue';
|
|
2
|
+
import { useRoute } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
export default function () {
|
|
5
|
+
const route = useRoute();
|
|
6
|
+
|
|
7
|
+
return computed(() => {
|
|
8
|
+
const names: string[] = [];
|
|
9
|
+
|
|
10
|
+
route.matched.forEach(m => m.name && names.push(m.name as string));
|
|
11
|
+
|
|
12
|
+
return names;
|
|
13
|
+
});
|
|
14
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Ref, ref, watch } from 'vue';
|
|
2
|
+
import { useRoute } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
export default function (name: string, defaultValue: string | null = null): Ref<string | null> {
|
|
5
|
+
const route = useRoute();
|
|
6
|
+
const param = ref<string | null>((route.params[name] as string | undefined) ?? defaultValue);
|
|
7
|
+
|
|
8
|
+
watch(() => route.params[name], (value) => {
|
|
9
|
+
param.value = (value || null) as string | null;
|
|
10
|
+
}, {immediate: true});
|
|
11
|
+
|
|
12
|
+
return param;
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BaseService } from '@basmilius/http-client';
|
|
2
|
+
import { guarded } from '../util';
|
|
3
|
+
|
|
4
|
+
type ServiceClass<T extends BaseService> = { new(): T; };
|
|
5
|
+
type Wrap = (fn: Function) => Function;
|
|
6
|
+
|
|
7
|
+
export default function <T extends BaseService>(serviceClass: ServiceClass<T>, ...wrap: Wrap[]): T {
|
|
8
|
+
const service = new serviceClass;
|
|
9
|
+
const methods = Object.getOwnPropertyNames(serviceClass.prototype)
|
|
10
|
+
.filter(m => m !== 'constructor');
|
|
11
|
+
|
|
12
|
+
const functions: Record<string, Function> = {};
|
|
13
|
+
|
|
14
|
+
for (let method of methods) {
|
|
15
|
+
functions[method] = guarded((service as any)[method].bind(service));
|
|
16
|
+
wrap.forEach(w => functions[method] = w(functions[method]!));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return functions as unknown as T;
|
|
20
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineStore, type StoreGeneric, storeToRefs } from 'pinia';
|
|
2
|
+
|
|
3
|
+
export default function <Id extends string, Setup extends (...args: any[]) => any, Context = ReturnType<Setup>>(id: Id, setup: Setup): UseStore<Context> {
|
|
4
|
+
const storeFn = defineStore(id, setup);
|
|
5
|
+
|
|
6
|
+
return () => {
|
|
7
|
+
const store: StoreGeneric = storeFn();
|
|
8
|
+
const keys = Object.getOwnPropertyNames(store);
|
|
9
|
+
const refs = storeToRefs(store as StoreGeneric);
|
|
10
|
+
const result: Record<string, unknown> = {};
|
|
11
|
+
|
|
12
|
+
for (const key of keys) {
|
|
13
|
+
if (key.startsWith('$') || key.startsWith('_')) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (key in refs) {
|
|
18
|
+
result[key] = refs[key];
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
result[key] = store[key];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result as Context;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type UseStore<R> = {
|
|
30
|
+
(): R;
|
|
31
|
+
}
|