@effect-app/vue-components 4.0.0-beta.32 → 4.0.0-beta.321
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 +13 -9
- package/dist/reset.css +39 -38
- package/dist/types/components/CommandButton.vue.d.ts +24 -5
- package/dist/types/components/Dialog.vue.d.ts +4 -2
- package/dist/types/components/FixedNuxtErrorBoundary.vue.d.ts +39 -0
- package/dist/types/components/OmegaForm/InputProps.d.ts +2 -1
- package/dist/types/components/OmegaForm/OmegaArray.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +2 -2
- package/dist/types/components/OmegaForm/OmegaErrorsInternal.vue.d.ts +2 -3
- package/dist/types/components/OmegaForm/OmegaFormInput.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaInput.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaInputVuetify.vue.d.ts +12 -0
- package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +7 -9
- package/dist/types/components/OmegaForm/OmegaTaggedUnion.vue.d.ts +2 -2
- package/dist/types/components/OmegaForm/OmegaTaggedUnionInternal.vue.d.ts +3 -3
- package/dist/types/components/OmegaForm/OmegaWrapper.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/createUseFormWithCustomInput.d.ts +4 -2
- package/dist/types/components/OmegaForm/decimalSeparatorInput.d.ts +13 -0
- package/dist/types/components/OmegaForm/errors.d.ts +33 -0
- package/dist/types/components/OmegaForm/getOmegaStore.d.ts +1 -1
- package/dist/types/components/OmegaForm/hocs.d.ts +3 -0
- package/dist/types/components/OmegaForm/index.d.ts +14 -3
- package/dist/types/components/OmegaForm/inputs.d.ts +4 -0
- package/dist/types/components/OmegaForm/meta/checks.d.ts +4 -0
- package/dist/types/components/OmegaForm/meta/createMeta.d.ts +33 -0
- package/dist/types/components/OmegaForm/meta/defaults.d.ts +21 -0
- package/dist/types/components/OmegaForm/meta/redacted.d.ts +2 -0
- package/dist/types/components/OmegaForm/meta/types.d.ts +56 -0
- package/dist/types/components/OmegaForm/meta/walker.d.ts +18 -0
- package/dist/types/components/OmegaForm/persistency.d.ts +58 -0
- package/dist/types/components/OmegaForm/submit.d.ts +60 -0
- package/dist/types/components/OmegaForm/types.d.ts +312 -0
- package/dist/types/components/OmegaForm/useOmegaForm.d.ts +9 -213
- package/dist/types/components/OmegaForm/validation/localized.d.ts +10 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/utils/index.d.ts +8 -8
- package/dist/vue-components.es.js +30 -44
- package/dist/vue-components10.es.js +5 -0
- package/dist/vue-components11.es.js +56 -0
- package/dist/vue-components12.es.js +5 -0
- package/dist/vue-components13.es.js +20 -0
- package/dist/vue-components14.es.js +50 -0
- package/dist/vue-components15.es.js +128 -0
- package/dist/vue-components16.es.js +65 -0
- package/dist/vue-components17.es.js +114 -0
- package/dist/vue-components18.es.js +26 -0
- package/dist/vue-components19.es.js +5 -0
- package/dist/vue-components2.es.js +11 -0
- package/dist/vue-components20.es.js +80 -0
- package/dist/vue-components21.es.js +115 -0
- package/dist/vue-components22.es.js +74 -0
- package/dist/vue-components23.es.js +12 -0
- package/dist/vue-components24.es.js +54 -0
- package/dist/vue-components25.es.js +5 -0
- package/dist/vue-components26.es.js +44 -0
- package/dist/vue-components27.es.js +5 -0
- package/dist/vue-components28.es.js +84 -0
- package/dist/vue-components3.es.js +98 -0
- package/dist/vue-components30.es.js +8 -0
- package/dist/vue-components31.es.js +9 -0
- package/dist/vue-components32.es.js +15 -0
- package/dist/vue-components33.es.js +24 -0
- package/dist/vue-components34.es.js +344 -0
- package/dist/vue-components36.es.js +8 -0
- package/dist/vue-components37.es.js +74 -0
- package/dist/vue-components38.es.js +5 -0
- package/dist/vue-components39.es.js +64 -0
- package/dist/vue-components4.es.js +5 -0
- package/dist/vue-components40.es.js +5 -0
- package/dist/vue-components41.es.js +24 -0
- package/dist/vue-components42.es.js +5 -0
- package/dist/vue-components43.es.js +59 -0
- package/dist/vue-components44.es.js +5 -0
- package/dist/vue-components45.es.js +12 -0
- package/dist/vue-components46.es.js +22 -0
- package/dist/vue-components48.es.js +9 -0
- package/dist/vue-components49.es.js +4 -0
- package/dist/vue-components5.es.js +24 -0
- package/dist/vue-components50.es.js +38 -0
- package/dist/vue-components51.es.js +27 -0
- package/dist/vue-components52.es.js +28 -0
- package/dist/vue-components53.es.js +7 -0
- package/dist/vue-components54.es.js +18 -0
- package/dist/vue-components55.es.js +36 -0
- package/dist/vue-components56.es.js +18 -0
- package/dist/vue-components57.es.js +21 -0
- package/dist/vue-components58.es.js +30 -0
- package/dist/vue-components59.es.js +7 -0
- package/dist/vue-components6.es.js +13 -0
- package/dist/vue-components60.es.js +9 -0
- package/dist/vue-components61.es.js +38 -0
- package/dist/vue-components62.es.js +25 -0
- package/dist/vue-components63.es.js +128 -0
- package/dist/vue-components64.es.js +24 -0
- package/dist/vue-components65.es.js +21 -0
- package/dist/vue-components66.es.js +9 -0
- package/dist/vue-components67.es.js +19 -0
- package/dist/vue-components68.es.js +5 -0
- package/dist/vue-components69.es.js +29 -0
- package/dist/vue-components7.es.js +13 -0
- package/dist/vue-components70.es.js +5 -0
- package/dist/vue-components71.es.js +43 -0
- package/dist/vue-components72.es.js +101 -0
- package/dist/vue-components73.es.js +36 -0
- package/dist/vue-components74.es.js +19 -0
- package/dist/vue-components75.es.js +50 -0
- package/dist/vue-components8.es.js +35 -0
- package/dist/vue-components9.es.js +47 -0
- package/package.json +39 -33
- package/src/components/CommandButton.vue +96 -16
- package/src/components/Dialog.vue +0 -1
- package/src/components/FixedNuxtErrorBoundary.vue +112 -0
- package/src/components/OmegaForm/InputProps.ts +2 -1
- package/src/components/OmegaForm/OmegaArray.vue +9 -23
- package/src/components/OmegaForm/OmegaAutoGen.vue +3 -2
- package/src/components/OmegaForm/OmegaErrorsInternal.vue +20 -17
- package/src/components/OmegaForm/OmegaFormInput.vue +1 -1
- package/src/components/OmegaForm/OmegaInput.vue +29 -43
- package/src/components/OmegaForm/OmegaInputVuetify.vue +122 -16
- package/src/components/OmegaForm/OmegaInternalInput.vue +33 -13
- package/src/components/OmegaForm/OmegaTaggedUnion.vue +10 -3
- package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +6 -6
- package/src/components/OmegaForm/OmegaWrapper.vue +1 -1
- package/src/components/OmegaForm/blockDialog.ts +18 -6
- package/src/components/OmegaForm/createUseFormWithCustomInput.ts +16 -14
- package/src/components/OmegaForm/decimalSeparatorInput.ts +38 -0
- package/src/components/OmegaForm/errors.ts +139 -0
- package/src/components/OmegaForm/getOmegaStore.ts +1 -1
- package/src/components/OmegaForm/hocs.ts +19 -0
- package/src/components/OmegaForm/index.ts +17 -4
- package/src/components/OmegaForm/inputs.ts +22 -0
- package/src/components/OmegaForm/meta/checks.ts +107 -0
- package/src/components/OmegaForm/meta/createMeta.ts +140 -0
- package/src/components/OmegaForm/meta/defaults.ts +263 -0
- package/src/components/OmegaForm/meta/redacted.ts +71 -0
- package/src/components/OmegaForm/meta/types.ts +78 -0
- package/src/components/OmegaForm/meta/walker.ts +248 -0
- package/src/components/OmegaForm/persistency.ts +247 -0
- package/src/components/OmegaForm/submit.ts +131 -0
- package/src/components/OmegaForm/types.ts +801 -0
- package/src/components/OmegaForm/useOmegaForm.ts +103 -896
- package/src/components/OmegaForm/useRegisterField.ts +1 -1
- package/src/components/OmegaForm/validation/localized.ts +242 -0
- package/src/components/index.ts +1 -0
- package/src/index.ts +0 -1
- package/src/reset.css +39 -38
- package/src/utils/index.ts +11 -8
- package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +0 -159
- package/dist/types/constants/index.d.ts +0 -1
- package/dist/vue-components.es10.js +0 -239
- package/dist/vue-components.es11.js +0 -32
- package/dist/vue-components.es12.js +0 -503
- package/dist/vue-components.es13.js +0 -49
- package/dist/vue-components.es14.js +0 -4
- package/dist/vue-components.es15.js +0 -4
- package/dist/vue-components.es16.js +0 -6
- package/dist/vue-components.es17.js +0 -13
- package/dist/vue-components.es18.js +0 -57
- package/dist/vue-components.es19.js +0 -56
- package/dist/vue-components.es2.js +0 -30
- package/dist/vue-components.es20.js +0 -8
- package/dist/vue-components.es21.js +0 -8
- package/dist/vue-components.es22.js +0 -5
- package/dist/vue-components.es23.js +0 -5
- package/dist/vue-components.es24.js +0 -4
- package/dist/vue-components.es25.js +0 -4
- package/dist/vue-components.es26.js +0 -4
- package/dist/vue-components.es27.js +0 -4
- package/dist/vue-components.es28.js +0 -19
- package/dist/vue-components.es29.js +0 -13
- package/dist/vue-components.es3.js +0 -17
- package/dist/vue-components.es30.js +0 -31
- package/dist/vue-components.es31.js +0 -6
- package/dist/vue-components.es32.js +0 -4
- package/dist/vue-components.es33.js +0 -4
- package/dist/vue-components.es34.js +0 -113
- package/dist/vue-components.es36.js +0 -9
- package/dist/vue-components.es37.js +0 -34
- package/dist/vue-components.es39.js +0 -194
- package/dist/vue-components.es4.js +0 -52
- package/dist/vue-components.es41.js +0 -6
- package/dist/vue-components.es42.js +0 -25
- package/dist/vue-components.es43.js +0 -7
- package/dist/vue-components.es44.js +0 -23
- package/dist/vue-components.es45.js +0 -32
- package/dist/vue-components.es46.js +0 -24
- package/dist/vue-components.es47.js +0 -14
- package/dist/vue-components.es48.js +0 -7
- package/dist/vue-components.es49.js +0 -21
- package/dist/vue-components.es5.js +0 -52
- package/dist/vue-components.es50.js +0 -11
- package/dist/vue-components.es51.js +0 -33
- package/dist/vue-components.es52.js +0 -50
- package/dist/vue-components.es53.js +0 -28
- package/dist/vue-components.es54.js +0 -13
- package/dist/vue-components.es55.js +0 -67
- package/dist/vue-components.es56.js +0 -58
- package/dist/vue-components.es57.js +0 -19
- package/dist/vue-components.es58.js +0 -35
- package/dist/vue-components.es59.js +0 -31
- package/dist/vue-components.es6.js +0 -69
- package/dist/vue-components.es60.js +0 -44
- package/dist/vue-components.es61.js +0 -4
- package/dist/vue-components.es62.js +0 -46
- package/dist/vue-components.es63.js +0 -4
- package/dist/vue-components.es7.js +0 -83
- package/dist/vue-components.es8.js +0 -63
- package/dist/vue-components.es9.js +0 -21
- package/src/components/OmegaForm/OmegaFormStuff.ts +0 -1276
- package/src/constants/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,45 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/vue-components",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.321",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/effect-app/libs.git",
|
|
7
|
+
"directory": "packages/vue-components"
|
|
8
|
+
},
|
|
4
9
|
"peerDependencies": {
|
|
5
10
|
"@mdi/js": "^7.4.47",
|
|
6
|
-
"effect": "^4.0.0-
|
|
7
|
-
"intl-messageformat": "^11.
|
|
11
|
+
"effect": "^4.0.0-rc.114",
|
|
12
|
+
"intl-messageformat": "^11.2.7",
|
|
8
13
|
"mdi-js": "^1.0.1",
|
|
9
14
|
"primeflex": "^4.0.0",
|
|
10
15
|
"primeicons": "^7.0.0",
|
|
11
|
-
"primevue": "^4.5.
|
|
12
|
-
"vue": "^3.5.
|
|
13
|
-
"
|
|
16
|
+
"primevue": "^4.5.5",
|
|
17
|
+
"vue": "^3.5.35",
|
|
18
|
+
"vue-router": "^5.1.0",
|
|
19
|
+
"vuetify": "^4.0.8"
|
|
14
20
|
},
|
|
15
21
|
"devDependencies": {
|
|
16
|
-
"@storybook/vue3": "^10.
|
|
17
|
-
"@storybook/vue3-vite": "^10.
|
|
18
|
-
"@types/node": "^25.
|
|
19
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
20
|
-
"@vue/test-utils": "^2.4.
|
|
21
|
-
"@vueuse/core": "^14.
|
|
22
|
-
"
|
|
23
|
-
"jsdom": "^28.1.0",
|
|
22
|
+
"@storybook/vue3": "^10.4.1",
|
|
23
|
+
"@storybook/vue3-vite": "^10.4.1",
|
|
24
|
+
"@types/node": "^25.9.1",
|
|
25
|
+
"@vitejs/plugin-vue": "^6.0.7",
|
|
26
|
+
"@vue/test-utils": "^2.4.10",
|
|
27
|
+
"@vueuse/core": "^14.3.0",
|
|
28
|
+
"jsdom": "^29.1.1",
|
|
24
29
|
"rimraf": "^6.1.3",
|
|
25
|
-
"sass": "^1.
|
|
26
|
-
"storybook": "^10.
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"vite
|
|
30
|
+
"sass": "^1.100.0",
|
|
31
|
+
"storybook": "^10.4.1",
|
|
32
|
+
"storybook-vue3-router": "^7.0.0",
|
|
33
|
+
"typescript": "~6.0.3",
|
|
34
|
+
"vite": "^8.0.15",
|
|
35
|
+
"vite-plugin-css-injected-by-js": "^5.0.1",
|
|
30
36
|
"vitepress": "^1.6.4",
|
|
31
|
-
"vitest": "^4.
|
|
32
|
-
"vue-router": "^5.0
|
|
37
|
+
"vitest": "^4.1.7",
|
|
38
|
+
"vue-router": "^5.1.0",
|
|
33
39
|
"vue-toastification": "^2.0.0-rc.5",
|
|
34
|
-
"vue-tsc": "^3.
|
|
35
|
-
"vuetify": "^4.0.
|
|
36
|
-
"@effect-app/eslint-shared-config": "0.
|
|
40
|
+
"vue-tsc": "^3.3.3",
|
|
41
|
+
"vuetify": "^4.0.8",
|
|
42
|
+
"@effect-app/eslint-shared-config": "0.6.0-beta.36"
|
|
37
43
|
},
|
|
38
44
|
"files": [
|
|
39
45
|
"src",
|
|
40
46
|
"dist"
|
|
41
47
|
],
|
|
42
|
-
"module": "./dist/vue-components.es.js",
|
|
43
48
|
"exports": {
|
|
44
49
|
".": {
|
|
45
50
|
"types": "./dist/types/index.d.ts",
|
|
@@ -52,29 +57,30 @@
|
|
|
52
57
|
}
|
|
53
58
|
},
|
|
54
59
|
"dependencies": {
|
|
55
|
-
"@opentelemetry/api": "^1.9.
|
|
56
|
-
"@tanstack/vue-form": "^1.
|
|
60
|
+
"@opentelemetry/api": "^1.9.1",
|
|
61
|
+
"@tanstack/vue-form": "^1.32.0",
|
|
57
62
|
"highlight.js": "^11.11.1",
|
|
58
63
|
"mitt": "^3.0.1",
|
|
59
64
|
"vue3-highlightjs": "^1.0.5",
|
|
60
|
-
"effect-app": "4.0.0-beta.
|
|
61
|
-
"
|
|
65
|
+
"@effect-app/vue": "4.0.0-beta.321",
|
|
66
|
+
"effect-app": "4.0.0-beta.321"
|
|
62
67
|
},
|
|
63
68
|
"scripts": {
|
|
64
69
|
"check": "vue-tsc",
|
|
65
70
|
"build": "pnpm build:run",
|
|
66
|
-
"build:run": "rimraf dist && vue-tsc && vite build && cp src/reset.css dist/reset.css",
|
|
71
|
+
"build:run": "rimraf dist && vue-tsc -p tsconfig.build.json && vite build && cp src/reset.css dist/reset.css",
|
|
67
72
|
"docs:dev": "vitepress dev docs",
|
|
68
73
|
"docs:build": "vitepress build docs",
|
|
69
74
|
"docs:serve": "vitepress serve docs",
|
|
70
|
-
"lint": "NODE_OPTIONS=--max-old-space-size=8192 eslint src stories .storybook",
|
|
75
|
+
"lint": "oxlint --quiet --type-aware src stories && NODE_OPTIONS=--max-old-space-size=8192 ESLINT_TS=1 eslint --quiet src stories .storybook && pnpm exec dprint check --config ../../dprint.jsonc .",
|
|
71
76
|
"ncu": "ncu",
|
|
72
77
|
"clean": "rm -rf dist",
|
|
73
|
-
"lint-fix": "pnpm
|
|
78
|
+
"lint-fix": "oxlint --quiet --type-aware --fix src stories && NODE_OPTIONS=--max-old-space-size=8192 ESLINT_TS=1 eslint --quiet --fix src stories .storybook && pnpm exec dprint fmt --config ../../dprint.jsonc .",
|
|
74
79
|
"storybook": "storybook dev -p 6006",
|
|
75
80
|
"build-storybook": "storybook build",
|
|
76
81
|
"test": "vitest",
|
|
77
82
|
"test:run": "vitest run",
|
|
78
83
|
"test:watch": "vitest watch"
|
|
79
|
-
}
|
|
84
|
+
},
|
|
85
|
+
"module": "./dist/vue-components.es.js"
|
|
80
86
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script
|
|
2
2
|
setup
|
|
3
3
|
lang="ts"
|
|
4
|
-
generic="I = never"
|
|
4
|
+
generic="I = never, RA = unknown, RE = unknown"
|
|
5
5
|
>
|
|
6
|
-
import type { CommandBase } from "@effect-app/vue"
|
|
6
|
+
import type { CommandBase, Progress } from "@effect-app/vue/makeClient"
|
|
7
|
+
import * as Option from "effect-app/Option"
|
|
8
|
+
import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
7
9
|
import { computed } from "vue"
|
|
8
10
|
import type { VBtn } from "vuetify/components"
|
|
9
11
|
|
|
@@ -14,38 +16,89 @@ const props = defineProps<
|
|
|
14
16
|
& (
|
|
15
17
|
| {
|
|
16
18
|
input: NoInfer<I>
|
|
17
|
-
|
|
19
|
+
optionalInput?: undefined
|
|
20
|
+
command: CommandBase<I, any, RA, RE>
|
|
18
21
|
empty?: boolean
|
|
19
22
|
}
|
|
20
23
|
| {
|
|
21
|
-
|
|
24
|
+
optionalInput: Option.Option<NoInfer<I>>
|
|
22
25
|
input?: undefined
|
|
26
|
+
command: CommandBase<I, any, RA, RE>
|
|
27
|
+
empty?: boolean
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
command: CommandBase<any, any, RA, RE>
|
|
31
|
+
input?: undefined
|
|
32
|
+
optionalInput?: undefined
|
|
23
33
|
empty?: boolean
|
|
24
34
|
}
|
|
25
35
|
)
|
|
26
36
|
& {
|
|
27
37
|
disabled?: ButtonProps["disabled"]
|
|
28
38
|
title?: string // why isn't it part of VBtnProps??
|
|
39
|
+
mapProgress?: (result: AsyncResult.AsyncResult<RA, RE>) => Progress | undefined
|
|
29
40
|
}
|
|
30
41
|
& ButtonProps
|
|
31
42
|
>()
|
|
32
43
|
|
|
33
|
-
const
|
|
44
|
+
const resolvedInput = computed<{ _tag: "ready"; value: I } | { _tag: "missing" } | { _tag: "void" }>(() => {
|
|
45
|
+
if ("optionalInput" in props && props.optionalInput !== undefined) {
|
|
46
|
+
return Option.isSome(props.optionalInput)
|
|
47
|
+
? { _tag: "ready", value: props.optionalInput.value }
|
|
48
|
+
: { _tag: "missing" }
|
|
49
|
+
}
|
|
50
|
+
if ("input" in props && props.input !== undefined) {
|
|
51
|
+
return { _tag: "ready", value: props.input as I }
|
|
52
|
+
}
|
|
53
|
+
return { _tag: "void" }
|
|
54
|
+
})
|
|
34
55
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
const isDisabled = computed(() =>
|
|
57
|
+
props.command.blocked
|
|
58
|
+
|| props.disabled
|
|
59
|
+
|| resolvedInput.value._tag === "missing"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const resolvedProgress = computed(() => {
|
|
63
|
+
if (props.mapProgress) {
|
|
64
|
+
const result = props.command.result
|
|
65
|
+
return result !== undefined ? props.mapProgress(result) : undefined
|
|
39
66
|
}
|
|
67
|
+
return props.command.progress
|
|
68
|
+
})
|
|
40
69
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
70
|
+
const progressText = computed(() => {
|
|
71
|
+
const p = resolvedProgress.value
|
|
72
|
+
if (p === undefined) return undefined
|
|
73
|
+
return typeof p === "string" ? p : p.text
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const progressPercentage = computed(() => {
|
|
77
|
+
const p = resolvedProgress.value
|
|
78
|
+
return typeof p === "object" && p !== null ? p.percentage : undefined
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const handleClick = () => {
|
|
82
|
+
if (isDisabled.value) return
|
|
83
|
+
const ri = resolvedInput.value
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
const handle = props.command.handle as any
|
|
86
|
+
if (ri._tag === "ready") handle(ri.value)
|
|
87
|
+
else if (ri._tag === "void") handle(undefined)
|
|
88
|
+
// _tag === "missing" can't reach here — guarded by isDisabled
|
|
45
89
|
}
|
|
46
90
|
</script>
|
|
47
91
|
<script lang="ts">
|
|
48
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* CommandButton connects a command to a button and tracks disabled / loading state.
|
|
94
|
+
*
|
|
95
|
+
* Input variants:
|
|
96
|
+
* - `input`: pass a validated value; button enabled when command + disabled allow it.
|
|
97
|
+
* - `optionalInput`: pass an `Option<I>`. `Some` → enabled, click fires with the value.
|
|
98
|
+
* `None` → disabled. Use this when the input is gated by a `computed` instead of
|
|
99
|
+
* a `v-if` on the button itself.
|
|
100
|
+
* - neither: command takes no input.
|
|
101
|
+
*/
|
|
49
102
|
export default {
|
|
50
103
|
name: "CommandButton"
|
|
51
104
|
}
|
|
@@ -55,27 +108,54 @@ export default {
|
|
|
55
108
|
v-if="command.allowed && !empty"
|
|
56
109
|
v-bind="$attrs"
|
|
57
110
|
:loading="command.waiting"
|
|
111
|
+
:disabled="isDisabled"
|
|
58
112
|
:aria-disabled="isDisabled"
|
|
59
113
|
:title="title ?? command.action"
|
|
60
114
|
:class="{ 'v-btn--disabled': isDisabled }"
|
|
61
115
|
@click="handleClick"
|
|
62
116
|
>
|
|
117
|
+
<template
|
|
118
|
+
v-if="progressText !== undefined"
|
|
119
|
+
#loader
|
|
120
|
+
>
|
|
121
|
+
<v-progress-circular
|
|
122
|
+
:indeterminate="progressPercentage === undefined"
|
|
123
|
+
:model-value="progressPercentage"
|
|
124
|
+
size="20"
|
|
125
|
+
width="2"
|
|
126
|
+
/>
|
|
127
|
+
<span class="ml-2">{{ progressText }}</span>
|
|
128
|
+
</template>
|
|
63
129
|
<slot
|
|
64
130
|
:loading="command.waiting"
|
|
65
131
|
:disabled="isDisabled"
|
|
66
132
|
:label="command.label"
|
|
67
133
|
:title="title ?? command.action"
|
|
68
134
|
>
|
|
69
|
-
|
|
135
|
+
{{ command.label }}
|
|
70
136
|
</slot>
|
|
71
137
|
</v-btn>
|
|
72
138
|
<v-btn
|
|
73
139
|
v-else-if="command.allowed"
|
|
74
140
|
v-bind="$attrs"
|
|
75
141
|
:loading="command.waiting"
|
|
142
|
+
:disabled="isDisabled"
|
|
76
143
|
:aria-disabled="isDisabled"
|
|
77
144
|
:title="title ?? command.action"
|
|
78
145
|
:class="{ 'v-btn--disabled': isDisabled }"
|
|
79
146
|
@click="handleClick"
|
|
80
|
-
|
|
147
|
+
>
|
|
148
|
+
<template
|
|
149
|
+
v-if="progressText !== undefined"
|
|
150
|
+
#loader
|
|
151
|
+
>
|
|
152
|
+
<v-progress-circular
|
|
153
|
+
:indeterminate="progressPercentage === undefined"
|
|
154
|
+
:model-value="progressPercentage"
|
|
155
|
+
size="20"
|
|
156
|
+
width="2"
|
|
157
|
+
/>
|
|
158
|
+
<span class="ml-2">{{ progressText }}</span>
|
|
159
|
+
</template>
|
|
160
|
+
</v-btn>
|
|
81
161
|
</template>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { CauseException } from "effect-app/client"
|
|
3
|
+
import * as Cause from "effect/Cause"
|
|
4
|
+
import { onErrorCaptured, shallowRef } from "vue"
|
|
5
|
+
import { useRouter } from "vue-router"
|
|
6
|
+
|
|
7
|
+
// withDefaults, NOT `props.enabled ?? true`: Vue's boolean casting resolves an
|
|
8
|
+
// ABSENT boolean prop to `false`, so the `??` fallback would never fire and an
|
|
9
|
+
// omitted `enabled` (the frontend case) would silently disable the boundary.
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<{
|
|
12
|
+
captureException: (err: Error, hint?: { extra?: Record<string, unknown> }) => void
|
|
13
|
+
toastError: (message: string) => void
|
|
14
|
+
debug: boolean
|
|
15
|
+
/** register the boundary only when true (backend passes import.meta.client; frontend omits → true) */
|
|
16
|
+
enabled?: boolean
|
|
17
|
+
/** defer handling until app ready (backend: onNuxtReady while hydrating; frontend: omit → run now) */
|
|
18
|
+
scheduleAfterReady?: (fn: () => void) => void
|
|
19
|
+
/** extra side-effect after emit, before error.value is set (backend: nuxtApp vue:error hook) */
|
|
20
|
+
onHandled?: (err: Error, instance: unknown, info: string) => void
|
|
21
|
+
}>(),
|
|
22
|
+
{ enabled: true }
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
defineOptions({ name: "NuxtErrorBoundary", inheritAttrs: false })
|
|
26
|
+
|
|
27
|
+
const emit = defineEmits<{ error: [error: Error] }>()
|
|
28
|
+
|
|
29
|
+
defineSlots<{
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
error(props: { error: Error; clearError: () => void }): any
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
default(): any
|
|
34
|
+
}>()
|
|
35
|
+
|
|
36
|
+
const error = shallowRef<Error | null>(null)
|
|
37
|
+
function clearError() {
|
|
38
|
+
error.value = null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// lol in production these are different...
|
|
42
|
+
const supportedErrors = ["https://vuejs.org/error-reference/#runtime-0", 0, "0", "setup function"]
|
|
43
|
+
|
|
44
|
+
function handleError(...args: Parameters<Parameters<typeof onErrorCaptured<Error>>[0]>) {
|
|
45
|
+
const [err, instance, info] = args
|
|
46
|
+
const fiberFailure = err instanceof CauseException ? err : null
|
|
47
|
+
// PRO: log that we hit the error boundary
|
|
48
|
+
console.warn(
|
|
49
|
+
"NuxtErrorBoundary caught error in " + info + ": " + (fiberFailure ? "CauseException" : "classic error"),
|
|
50
|
+
fiberFailure ? Cause.pretty(fiberFailure.originalCause) : err,
|
|
51
|
+
instance
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
// PRO: we don't handle native event handlers the same way we handle setup errors,
|
|
55
|
+
// because these errors should only get reported, not take over the page.
|
|
56
|
+
if (!supportedErrors.includes(info)) {
|
|
57
|
+
props.captureException(err, { extra: { info, instance } })
|
|
58
|
+
if (props.debug) {
|
|
59
|
+
props.toastError("An unexpected error has occurred: " + err.toString())
|
|
60
|
+
}
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// PRO: don't render interruptions..
|
|
65
|
+
// e.g when we run useSuspenseQuery, and we navigate away before a query is finished, we get a CancelledError
|
|
66
|
+
// if we however render it here instead of the default slot, we will show the cancellation error of the previous page, instead of rendering the new page
|
|
67
|
+
//
|
|
68
|
+
// NOTE the engine-side contract that makes this blanket silence safe: `useSuspenseQuery(New)`
|
|
69
|
+
// converts an interrupt that settles while the component is STILL MOUNTED (a query-side interrupt,
|
|
70
|
+
// e.g. a server RPC interrupt Exit — the thing that used to blank the page) into a typed
|
|
71
|
+
// `SuspenseInterruptedError` (@effect-app/vue makeClient), whose cause is NOT interrupt-only and
|
|
72
|
+
// therefore falls through to the error slot below. What remains interrupt-only here is genuinely
|
|
73
|
+
// "navigated away / unmounted" — silencing it is correct and avoids rendering the previous page's
|
|
74
|
+
// cancellation over the new page.
|
|
75
|
+
if (fiberFailure && Cause.hasInterruptsOnly(fiberFailure.originalCause)) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
emit("error", err)
|
|
80
|
+
props.onHandled?.(err, instance, info)
|
|
81
|
+
error.value = err
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (props.enabled) {
|
|
85
|
+
onErrorCaptured((err, instance, info) => {
|
|
86
|
+
if (props.scheduleAfterReady) props.scheduleAfterReady(() => handleError(err, instance, info))
|
|
87
|
+
else handleError(err, instance, info)
|
|
88
|
+
return false
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// PRO: fix error not clearing after route change: https://github.com/nuxt/nuxt/issues/15781#issuecomment-2320928163
|
|
93
|
+
const router = useRouter()
|
|
94
|
+
router.afterEach(() => {
|
|
95
|
+
clearError()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
defineExpose({ error, clearError })
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<slot
|
|
103
|
+
v-if="error"
|
|
104
|
+
v-bind="{ error, clearError }"
|
|
105
|
+
name="error"
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
<slot
|
|
109
|
+
v-else
|
|
110
|
+
name="default"
|
|
111
|
+
/>
|
|
112
|
+
</template>
|
|
@@ -36,6 +36,7 @@ export type InputProps<From extends Record<PropertyKey, any>, TName extends Deep
|
|
|
36
36
|
maxLength?: number | false
|
|
37
37
|
max?: number | false
|
|
38
38
|
min?: number | false
|
|
39
|
+
refinement?: "int"
|
|
39
40
|
errorMessages: string[]
|
|
40
41
|
error: boolean
|
|
41
42
|
label: string
|
|
@@ -43,7 +44,7 @@ export type InputProps<From extends Record<PropertyKey, any>, TName extends Deep
|
|
|
43
44
|
inputClass: string | undefined | null
|
|
44
45
|
}
|
|
45
46
|
field: OmegaFieldInternalApi<From, TName>
|
|
46
|
-
/**
|
|
47
|
+
/** reactive field state, sourced from `field.state` (the Field slot's own `state` prop is a stale snapshot since @tanstack/vue-form 1.32) */
|
|
47
48
|
state: OmegaFieldInternalApi<From, TName>["state"]
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -3,24 +3,23 @@
|
|
|
3
3
|
:is="form.Field"
|
|
4
4
|
:name="name"
|
|
5
5
|
>
|
|
6
|
-
|
|
6
|
+
<!-- `field.state` is reactive; the Field slot's `state` prop is a stale snapshot since @tanstack/vue-form 1.32 -->
|
|
7
|
+
<template #default="{ field }">
|
|
7
8
|
<slot
|
|
8
9
|
name="pre-array"
|
|
9
|
-
v-bind="{ field, state }"
|
|
10
|
+
v-bind="{ field, state: field.state }"
|
|
10
11
|
/>
|
|
11
12
|
<component
|
|
12
13
|
:is="form.Field"
|
|
13
14
|
v-for="(_, i) of items"
|
|
14
15
|
:key="`${name}[${Number(i)}]`"
|
|
15
|
-
:name="
|
|
16
|
-
`${name}[${Number(i)}]` as DeepKeys<From>
|
|
17
|
-
"
|
|
16
|
+
:name="`${name}[${Number(i)}]` as DeepKeys<From>"
|
|
18
17
|
>
|
|
19
|
-
<template #default="{ field: subField
|
|
18
|
+
<template #default="{ field: subField }">
|
|
20
19
|
<slot
|
|
21
20
|
v-bind="{
|
|
22
21
|
subField,
|
|
23
|
-
subState,
|
|
22
|
+
subState: subField.state,
|
|
24
23
|
index: Number(i),
|
|
25
24
|
field
|
|
26
25
|
}"
|
|
@@ -29,7 +28,7 @@
|
|
|
29
28
|
</component>
|
|
30
29
|
<slot
|
|
31
30
|
name="post-array"
|
|
32
|
-
v-bind="{ field, state }"
|
|
31
|
+
v-bind="{ field, state: field.state }"
|
|
33
32
|
/>
|
|
34
33
|
<!-- TODO: legacy slot, remove this slot -->
|
|
35
34
|
<slot
|
|
@@ -45,8 +44,8 @@
|
|
|
45
44
|
generic="From extends Record<PropertyKey, any>, To extends Record<PropertyKey, any>, Name extends DeepKeys<From>"
|
|
46
45
|
>
|
|
47
46
|
import { type DeepKeys } from "@tanstack/vue-form"
|
|
48
|
-
import { computed, onMounted
|
|
49
|
-
import { type OmegaArrayProps } from "./
|
|
47
|
+
import { computed, onMounted } from "vue"
|
|
48
|
+
import { type OmegaArrayProps } from "./types"
|
|
50
49
|
|
|
51
50
|
const props = defineProps<OmegaArrayProps<From, To, Name>>()
|
|
52
51
|
|
|
@@ -74,17 +73,4 @@ onMounted(async () => {
|
|
|
74
73
|
props.form.setFieldValue(props.name, props.defaultItems)
|
|
75
74
|
}
|
|
76
75
|
})
|
|
77
|
-
|
|
78
|
-
const getMetaFromArray = computed(() => {
|
|
79
|
-
const getMeta = (path: string) => {
|
|
80
|
-
// Transform path like 'a[0].b[11].c' into 'a.b.c'
|
|
81
|
-
const simplifiedPath = path.replace(/\[\d+\]/g, "")
|
|
82
|
-
|
|
83
|
-
return props.form.meta[simplifiedPath as keyof typeof props.form.meta]
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return getMeta
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
provide("getMetaFromArray", getMetaFromArray)
|
|
90
76
|
</script>
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
Name extends DeepKeys<From>"
|
|
21
21
|
>
|
|
22
22
|
import { type DeepKeys } from "@tanstack/vue-form"
|
|
23
|
-
import
|
|
23
|
+
import * as Order from "effect/Order"
|
|
24
24
|
import { computed } from "vue"
|
|
25
|
-
import { type FieldMeta
|
|
25
|
+
import { type FieldMeta } from "./meta/types"
|
|
26
|
+
import { type FieldPath, type OmegaAutoGenMeta, type OmegaInputProps } from "./types"
|
|
26
27
|
|
|
27
28
|
type NewMeta = OmegaAutoGenMeta<From, To, Name>
|
|
28
29
|
|
|
@@ -99,17 +99,16 @@
|
|
|
99
99
|
</template>
|
|
100
100
|
|
|
101
101
|
<script setup lang="ts">
|
|
102
|
-
import type { StandardSchemaV1Issue } from "@tanstack/vue-form"
|
|
103
102
|
import { computed, getCurrentInstance } from "vue"
|
|
104
103
|
import { useIntl } from "../../utils"
|
|
105
|
-
import { type OmegaError } from "./
|
|
104
|
+
import { type OmegaError } from "./types"
|
|
106
105
|
|
|
107
106
|
const instance = getCurrentInstance()
|
|
108
107
|
const vuetified = instance?.appContext.components["VAlert"]
|
|
109
108
|
|
|
110
109
|
const props = defineProps<
|
|
111
110
|
{
|
|
112
|
-
generalErrors:
|
|
111
|
+
generalErrors: unknown[]
|
|
113
112
|
errors: OmegaError[]
|
|
114
113
|
hideErrorDetails?: boolean
|
|
115
114
|
}
|
|
@@ -120,21 +119,25 @@ const { trans } = useIntl()
|
|
|
120
119
|
const showedGeneralErrors = computed(() => {
|
|
121
120
|
if (!props.generalErrors) return []
|
|
122
121
|
|
|
123
|
-
return props
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
return props.generalErrors.flatMap((record) => {
|
|
123
|
+
if (typeof record === "string") return record ? [record] : []
|
|
124
|
+
if (typeof record !== "object" || record === null) return []
|
|
125
|
+
|
|
126
|
+
return Object
|
|
127
|
+
.values(record)
|
|
128
|
+
.filter((issues): issues is unknown[] => Array.isArray(issues))
|
|
129
|
+
.flatMap((issues) =>
|
|
130
|
+
issues.flatMap((issue) =>
|
|
131
|
+
typeof issue === "object"
|
|
132
|
+
&& issue !== null
|
|
133
|
+
&& "message" in issue
|
|
134
|
+
&& typeof issue.message === "string"
|
|
135
|
+
&& issue.message
|
|
136
|
+
? [issue.message]
|
|
137
|
+
: []
|
|
136
138
|
)
|
|
137
|
-
|
|
139
|
+
)
|
|
140
|
+
})
|
|
138
141
|
})
|
|
139
142
|
</script>
|
|
140
143
|
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
import { type DeepKeys } from "@tanstack/vue-form"
|
|
18
18
|
import { inject } from "vue"
|
|
19
19
|
import type { MergedInputProps } from "./InputProps"
|
|
20
|
-
import type { BaseProps, DefaultTypeProps, OmegaInputProps } from "./OmegaFormStuff"
|
|
21
20
|
import OmegaInput from "./OmegaInput.vue"
|
|
21
|
+
import type { BaseProps, DefaultTypeProps, OmegaInputProps } from "./types"
|
|
22
22
|
import { OmegaFormKey } from "./useOmegaForm"
|
|
23
23
|
|
|
24
24
|
const form = inject(OmegaFormKey) as unknown as OmegaInputProps<
|