@aerogel/core 0.0.0-next.fd1bd21aea7a9ab8c4eab69a5f5776db5de8bf35 → 0.1.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/dist/aerogel-core.css +1 -0
- package/dist/aerogel-core.d.ts +2263 -1698
- package/dist/aerogel-core.js +3809 -0
- package/dist/aerogel-core.js.map +1 -0
- package/package.json +32 -37
- package/src/bootstrap/bootstrap.test.ts +4 -8
- package/src/bootstrap/index.ts +25 -16
- package/src/bootstrap/options.ts +1 -1
- package/src/components/AppLayout.vue +14 -0
- package/src/components/{AGAppModals.vue → AppModals.vue} +3 -4
- package/src/components/AppOverlays.vue +9 -0
- package/src/components/AppToasts.vue +16 -0
- package/src/components/contracts/AlertModal.ts +19 -0
- package/src/components/contracts/Button.ts +16 -0
- package/src/components/contracts/ConfirmModal.ts +48 -0
- package/src/components/contracts/DropdownMenu.ts +25 -0
- package/src/components/contracts/ErrorReportModal.ts +33 -0
- package/src/components/contracts/Input.ts +26 -0
- package/src/components/contracts/LoadingModal.ts +26 -0
- package/src/components/contracts/Modal.ts +21 -0
- package/src/components/contracts/PromptModal.ts +34 -0
- package/src/components/contracts/Select.ts +45 -0
- package/src/components/contracts/Toast.ts +15 -0
- package/src/components/contracts/index.ts +11 -0
- package/src/components/headless/HeadlessButton.vue +51 -0
- package/src/components/headless/HeadlessInput.vue +59 -0
- package/src/components/headless/{forms/AGHeadlessInputDescription.vue → HeadlessInputDescription.vue} +7 -8
- package/src/components/headless/{forms/AGHeadlessInputError.vue → HeadlessInputError.vue} +4 -8
- package/src/components/headless/HeadlessInputInput.vue +86 -0
- package/src/components/headless/{forms/AGHeadlessInputLabel.vue → HeadlessInputLabel.vue} +3 -7
- package/src/components/headless/{forms/AGHeadlessInputTextArea.vue → HeadlessInputTextArea.vue} +11 -11
- package/src/components/headless/HeadlessModal.vue +57 -0
- package/src/components/headless/HeadlessModalContent.vue +30 -0
- package/src/components/headless/HeadlessModalDescription.vue +12 -0
- package/src/components/headless/HeadlessModalOverlay.vue +12 -0
- package/src/components/headless/HeadlessModalTitle.vue +12 -0
- package/src/components/headless/HeadlessSelect.vue +120 -0
- package/src/components/headless/{forms/AGHeadlessSelectError.vue → HeadlessSelectError.vue} +5 -6
- package/src/components/headless/HeadlessSelectLabel.vue +25 -0
- package/src/components/headless/HeadlessSelectOption.vue +34 -0
- package/src/components/headless/HeadlessSelectOptions.vue +42 -0
- package/src/components/headless/HeadlessSelectTrigger.vue +22 -0
- package/src/components/headless/HeadlessSelectValue.vue +18 -0
- package/src/components/headless/HeadlessSwitch.vue +96 -0
- package/src/components/headless/HeadlessToast.vue +18 -0
- package/src/components/headless/HeadlessToastAction.vue +13 -0
- package/src/components/headless/index.ts +20 -3
- package/src/components/index.ts +6 -9
- package/src/components/ui/AdvancedOptions.vue +18 -0
- package/src/components/ui/AlertModal.vue +17 -0
- package/src/components/ui/Button.vue +115 -0
- package/src/components/ui/Checkbox.vue +56 -0
- package/src/components/ui/ConfirmModal.vue +50 -0
- package/src/components/ui/DropdownMenu.vue +32 -0
- package/src/components/ui/DropdownMenuOption.vue +22 -0
- package/src/components/ui/DropdownMenuOptions.vue +44 -0
- package/src/components/ui/EditableContent.vue +82 -0
- package/src/components/ui/ErrorLogs.vue +19 -0
- package/src/components/ui/ErrorLogsModal.vue +48 -0
- package/src/components/ui/ErrorMessage.vue +15 -0
- package/src/components/ui/ErrorReportModal.vue +73 -0
- package/src/components/{modals/AGErrorReportModalButtons.vue → ui/ErrorReportModalButtons.vue} +34 -27
- package/src/components/ui/ErrorReportModalTitle.vue +24 -0
- package/src/components/{forms/AGForm.vue → ui/Form.vue} +4 -5
- package/src/components/ui/Input.vue +56 -0
- package/src/components/ui/Link.vue +12 -0
- package/src/components/ui/LoadingModal.vue +34 -0
- package/src/components/ui/Markdown.vue +97 -0
- package/src/components/ui/Modal.vue +131 -0
- package/src/components/ui/ModalContext.vue +31 -0
- package/src/components/ui/ProgressBar.vue +51 -0
- package/src/components/ui/PromptModal.vue +38 -0
- package/src/components/ui/Select.vue +27 -0
- package/src/components/ui/SelectLabel.vue +21 -0
- package/src/components/ui/SelectOption.vue +29 -0
- package/src/components/ui/SelectOptions.vue +35 -0
- package/src/components/ui/SelectTrigger.vue +29 -0
- package/src/components/ui/Setting.vue +31 -0
- package/src/components/ui/SettingsModal.vue +15 -0
- package/src/components/ui/StartupCrash.vue +76 -0
- package/src/components/ui/Switch.vue +11 -0
- package/src/components/ui/TextArea.vue +56 -0
- package/src/components/ui/Toast.vue +46 -0
- package/src/components/ui/index.ts +35 -0
- package/src/directives/index.ts +9 -5
- package/src/directives/measure.ts +33 -8
- package/src/errors/Errors.state.ts +2 -1
- package/src/errors/Errors.ts +56 -33
- package/src/errors/JobCancelledError.ts +3 -0
- package/src/errors/index.ts +15 -8
- package/src/errors/settings/Debug.vue +14 -0
- package/src/errors/settings/index.ts +10 -0
- package/src/errors/utils.ts +17 -1
- package/src/forms/FormController.test.ts +113 -0
- package/src/forms/{Form.ts → FormController.ts} +73 -42
- package/src/forms/index.ts +3 -3
- package/src/forms/utils.ts +65 -24
- package/src/forms/validation.ts +50 -0
- package/src/index.css +76 -0
- package/src/jobs/Job.ts +144 -2
- package/src/jobs/index.ts +4 -1
- package/src/jobs/listeners.ts +3 -0
- package/src/jobs/status.ts +4 -0
- package/src/lang/DefaultLangProvider.ts +46 -0
- package/src/lang/Lang.state.ts +11 -0
- package/src/lang/Lang.ts +48 -21
- package/src/lang/index.ts +12 -6
- package/src/lang/settings/Language.vue +48 -0
- package/src/lang/settings/index.ts +10 -0
- package/src/plugins/Plugin.ts +1 -1
- package/src/plugins/index.ts +10 -7
- package/src/services/App.state.ts +36 -3
- package/src/services/App.ts +19 -3
- package/src/services/Cache.ts +1 -1
- package/src/services/Events.test.ts +8 -8
- package/src/services/Events.ts +16 -12
- package/src/services/Service.ts +135 -59
- package/src/services/Storage.ts +20 -0
- package/src/services/index.ts +16 -7
- package/src/services/utils.ts +18 -0
- package/src/testing/index.ts +8 -3
- package/src/testing/setup.ts +11 -0
- package/src/ui/UI.state.ts +14 -12
- package/src/ui/UI.ts +250 -123
- package/src/ui/index.ts +28 -28
- package/src/ui/utils.ts +16 -0
- package/src/utils/app.ts +7 -0
- package/src/utils/classes.ts +41 -0
- package/src/utils/composition/events.ts +4 -6
- package/src/utils/composition/forms.ts +20 -4
- package/src/utils/composition/persistent.test.ts +33 -0
- package/src/utils/composition/persistent.ts +11 -0
- package/src/utils/composition/state.test.ts +47 -0
- package/src/utils/composition/state.ts +33 -0
- package/src/utils/index.ts +6 -1
- package/src/utils/markdown.test.ts +50 -0
- package/src/utils/markdown.ts +53 -6
- package/src/utils/types.ts +3 -0
- package/src/utils/vue.ts +38 -132
- package/dist/aerogel-core.cjs.js +0 -2
- package/dist/aerogel-core.cjs.js.map +0 -1
- package/dist/aerogel-core.esm.js +0 -2
- package/dist/aerogel-core.esm.js.map +0 -1
- package/histoire.config.ts +0 -7
- package/noeldemartin.config.js +0 -5
- package/postcss.config.js +0 -6
- package/src/assets/histoire.css +0 -3
- package/src/components/AGAppLayout.vue +0 -16
- package/src/components/AGAppOverlays.vue +0 -41
- package/src/components/AGAppSnackbars.vue +0 -13
- package/src/components/constants.ts +0 -8
- package/src/components/forms/AGButton.vue +0 -44
- package/src/components/forms/AGCheckbox.vue +0 -41
- package/src/components/forms/AGInput.vue +0 -40
- package/src/components/forms/AGSelect.story.vue +0 -46
- package/src/components/forms/AGSelect.vue +0 -60
- package/src/components/forms/index.ts +0 -5
- package/src/components/headless/forms/AGHeadlessButton.vue +0 -56
- package/src/components/headless/forms/AGHeadlessInput.ts +0 -32
- package/src/components/headless/forms/AGHeadlessInput.vue +0 -57
- package/src/components/headless/forms/AGHeadlessInputInput.vue +0 -81
- package/src/components/headless/forms/AGHeadlessSelect.ts +0 -42
- package/src/components/headless/forms/AGHeadlessSelect.vue +0 -77
- package/src/components/headless/forms/AGHeadlessSelectButton.vue +0 -24
- package/src/components/headless/forms/AGHeadlessSelectLabel.vue +0 -24
- package/src/components/headless/forms/AGHeadlessSelectOption.ts +0 -4
- package/src/components/headless/forms/AGHeadlessSelectOption.vue +0 -39
- package/src/components/headless/forms/AGHeadlessSelectOptions.ts +0 -3
- package/src/components/headless/forms/composition.ts +0 -10
- package/src/components/headless/forms/index.ts +0 -17
- package/src/components/headless/modals/AGHeadlessModal.ts +0 -34
- package/src/components/headless/modals/AGHeadlessModal.vue +0 -86
- package/src/components/headless/modals/AGHeadlessModalPanel.vue +0 -28
- package/src/components/headless/modals/AGHeadlessModalTitle.vue +0 -13
- package/src/components/headless/modals/index.ts +0 -4
- package/src/components/headless/snackbars/AGHeadlessSnackbar.vue +0 -10
- package/src/components/headless/snackbars/index.ts +0 -40
- package/src/components/lib/AGErrorMessage.vue +0 -16
- package/src/components/lib/AGLink.vue +0 -9
- package/src/components/lib/AGMarkdown.vue +0 -41
- package/src/components/lib/AGMeasured.vue +0 -15
- package/src/components/lib/AGStartupCrash.vue +0 -31
- package/src/components/lib/index.ts +0 -5
- package/src/components/modals/AGAlertModal.ts +0 -15
- package/src/components/modals/AGAlertModal.vue +0 -14
- package/src/components/modals/AGConfirmModal.ts +0 -27
- package/src/components/modals/AGConfirmModal.vue +0 -26
- package/src/components/modals/AGErrorReportModal.ts +0 -46
- package/src/components/modals/AGErrorReportModal.vue +0 -54
- package/src/components/modals/AGErrorReportModalTitle.vue +0 -25
- package/src/components/modals/AGLoadingModal.ts +0 -23
- package/src/components/modals/AGLoadingModal.vue +0 -15
- package/src/components/modals/AGModal.ts +0 -10
- package/src/components/modals/AGModal.vue +0 -39
- package/src/components/modals/AGModalContext.ts +0 -8
- package/src/components/modals/AGModalContext.vue +0 -22
- package/src/components/modals/AGModalTitle.vue +0 -9
- package/src/components/modals/AGPromptModal.ts +0 -30
- package/src/components/modals/AGPromptModal.vue +0 -34
- package/src/components/modals/index.ts +0 -17
- package/src/components/snackbars/AGSnackbar.vue +0 -36
- package/src/components/snackbars/index.ts +0 -3
- package/src/components/utils.ts +0 -10
- package/src/directives/initial-focus.ts +0 -11
- package/src/forms/Form.test.ts +0 -58
- package/src/forms/composition.ts +0 -6
- package/src/main.histoire.ts +0 -1
- package/src/utils/tailwindcss.test.ts +0 -26
- package/src/utils/tailwindcss.ts +0 -7
- package/tailwind.config.js +0 -4
- package/tsconfig.json +0 -11
- package/vite.config.ts +0 -14
- /package/src/{main.ts → index.ts} +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal :title="$td('errors.report', 'Errors ({count})', { count: $errors.logs.length })">
|
|
3
|
+
<ol>
|
|
4
|
+
<li
|
|
5
|
+
v-for="(log, index) of $errors.logs"
|
|
6
|
+
:key="index"
|
|
7
|
+
class="mb-2 flex max-w-prose min-w-56 justify-between py-2 last:mb-0"
|
|
8
|
+
>
|
|
9
|
+
<div>
|
|
10
|
+
<h3 class="font-medium">
|
|
11
|
+
{{ log.report.title }}
|
|
12
|
+
</h3>
|
|
13
|
+
<time :datetime="log.date.toISOString()" class="text-xs text-gray-700">
|
|
14
|
+
{{ log.date.toLocaleTimeString() }}
|
|
15
|
+
</time>
|
|
16
|
+
<Markdown
|
|
17
|
+
class="text-sm text-gray-500"
|
|
18
|
+
:text="log.report.description ?? getErrorMessage(log.report)"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
<Button
|
|
22
|
+
size="icon"
|
|
23
|
+
variant="ghost"
|
|
24
|
+
:aria-label="$td('errors.viewDetails', 'View details')"
|
|
25
|
+
:title="$td('errors.viewDetails', 'View details')"
|
|
26
|
+
class="self-center"
|
|
27
|
+
@click="
|
|
28
|
+
$errors.inspect(
|
|
29
|
+
log.report,
|
|
30
|
+
$errors.logs.map(({ report }) => report)
|
|
31
|
+
)
|
|
32
|
+
"
|
|
33
|
+
>
|
|
34
|
+
<IconViewShow class="size-4" aria-hidden="true" />
|
|
35
|
+
</Button>
|
|
36
|
+
</li>
|
|
37
|
+
</ol>
|
|
38
|
+
</Modal>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup lang="ts">
|
|
42
|
+
import IconViewShow from '~icons/zondicons/view-show';
|
|
43
|
+
|
|
44
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
45
|
+
import Modal from '@aerogel/core/components/ui/Modal.vue';
|
|
46
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
47
|
+
import { getErrorMessage } from '@aerogel/core/errors';
|
|
48
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Markdown :text="message" inline />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed } from 'vue';
|
|
7
|
+
|
|
8
|
+
import { getErrorMessage } from '@aerogel/core/errors/utils';
|
|
9
|
+
import type { ErrorSource } from '@aerogel/core/errors/Errors.state';
|
|
10
|
+
|
|
11
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
12
|
+
|
|
13
|
+
const { error } = defineProps<{ error: ErrorSource }>();
|
|
14
|
+
const message = computed(() => getErrorMessage(error));
|
|
15
|
+
</script>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal
|
|
3
|
+
:title="$td('errors.report', 'Error report')"
|
|
4
|
+
title-hidden
|
|
5
|
+
close-hidden
|
|
6
|
+
class="p-0"
|
|
7
|
+
wrapper-class="sm:w-auto sm:min-w-lg sm:max-w-[80vw]"
|
|
8
|
+
>
|
|
9
|
+
<div class="px-4 pt-5 pb-4">
|
|
10
|
+
<h2 class="flex justify-between gap-4">
|
|
11
|
+
<div class="flex items-center gap-2">
|
|
12
|
+
<IconExclamationSolid class="size-5 text-red-600" />
|
|
13
|
+
<ErrorReportModalTitle
|
|
14
|
+
class="text-lg leading-6 font-semibold text-gray-900"
|
|
15
|
+
:report="activeReport"
|
|
16
|
+
:current-report="activeReportIndex + 1"
|
|
17
|
+
:total-reports="reports.length"
|
|
18
|
+
/>
|
|
19
|
+
<span v-if="reports.length > 1" class="flex gap-0.5">
|
|
20
|
+
<Button
|
|
21
|
+
size="icon"
|
|
22
|
+
variant="ghost"
|
|
23
|
+
:disabled="activeReportIndex === 0"
|
|
24
|
+
:aria-label="previousReportText"
|
|
25
|
+
:title="previousReportText"
|
|
26
|
+
@click="activeReportIndex--"
|
|
27
|
+
>
|
|
28
|
+
<IconCheveronLeft class="size-4" />
|
|
29
|
+
</Button>
|
|
30
|
+
<Button
|
|
31
|
+
size="icon"
|
|
32
|
+
variant="ghost"
|
|
33
|
+
:disabled="activeReportIndex === reports.length - 1"
|
|
34
|
+
:aria-label="nextReportText"
|
|
35
|
+
:title="nextReportText"
|
|
36
|
+
@click="activeReportIndex++"
|
|
37
|
+
>
|
|
38
|
+
<IconCheveronRight class="size-4" />
|
|
39
|
+
</Button>
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
<ErrorReportModalButtons :report="activeReport" class="gap-0.5" />
|
|
43
|
+
</h2>
|
|
44
|
+
<Markdown v-if="activeReport.description" :text="activeReport.description" class="text-gray-600" />
|
|
45
|
+
</div>
|
|
46
|
+
<div class="-mt-2 max-h-[75vh] overflow-auto bg-red-800/10">
|
|
47
|
+
<pre class="p-4 text-xs text-red-800" v-text="details" />
|
|
48
|
+
</div>
|
|
49
|
+
</Modal>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
import IconCheveronLeft from '~icons/zondicons/cheveron-left';
|
|
54
|
+
import IconCheveronRight from '~icons/zondicons/cheveron-right';
|
|
55
|
+
import IconExclamationSolid from '~icons/zondicons/exclamation-solid';
|
|
56
|
+
|
|
57
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
58
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
59
|
+
import ErrorReportModalButtons from '@aerogel/core/components/ui/ErrorReportModalButtons.vue';
|
|
60
|
+
import ErrorReportModalTitle from '@aerogel/core/components/ui/ErrorReportModalTitle.vue';
|
|
61
|
+
import Modal from '@aerogel/core/components/ui/Modal.vue';
|
|
62
|
+
import { useErrorReportModal } from '@aerogel/core/components/contracts/ErrorReportModal';
|
|
63
|
+
import type {
|
|
64
|
+
ErrorReportModalExpose,
|
|
65
|
+
ErrorReportModalProps,
|
|
66
|
+
} from '@aerogel/core/components/contracts/ErrorReportModal';
|
|
67
|
+
|
|
68
|
+
const props = defineProps<ErrorReportModalProps>();
|
|
69
|
+
|
|
70
|
+
const { activeReportIndex, details, nextReportText, previousReportText, activeReport } = useErrorReportModal(props);
|
|
71
|
+
|
|
72
|
+
defineExpose<ErrorReportModalExpose>();
|
|
73
|
+
</script>
|
package/src/components/{modals/AGErrorReportModalButtons.vue → ui/ErrorReportModalButtons.vue}
RENAMED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="flex">
|
|
3
|
-
<slot v-for="
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
<slot v-for="button of buttons" v-bind="button">
|
|
4
|
+
<Button
|
|
5
|
+
size="icon"
|
|
6
|
+
variant="ghost"
|
|
7
|
+
class="group whitespace-nowrap"
|
|
8
|
+
:href="button.url"
|
|
7
9
|
:title="$td(`errors.report_${button.id}`, button.description)"
|
|
8
|
-
|
|
9
|
-
@click="button.handler"
|
|
10
|
+
@click="button.click"
|
|
10
11
|
>
|
|
11
|
-
<
|
|
12
|
-
|
|
12
|
+
<span class="sr-only">{{ $td(`errors.report_${button.id}`, button.description) }}</span>
|
|
13
|
+
<component :is="button.iconComponent" class="size-4" aria-hidden="true" />
|
|
14
|
+
</Button>
|
|
13
15
|
</slot>
|
|
14
16
|
</div>
|
|
15
17
|
</template>
|
|
@@ -21,20 +23,27 @@ import IconGitHub from '~icons/mdi/github';
|
|
|
21
23
|
|
|
22
24
|
import { computed } from 'vue';
|
|
23
25
|
import { stringExcerpt, tap } from '@noeldemartin/utils';
|
|
26
|
+
import type { Component } from 'vue';
|
|
24
27
|
|
|
25
|
-
import App from '
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import { translateWithDefault } from '
|
|
29
|
-
import type {
|
|
30
|
-
import type { ErrorReport } from '@/errors';
|
|
28
|
+
import App from '@aerogel/core/services/App';
|
|
29
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
30
|
+
import UI from '@aerogel/core/ui/UI';
|
|
31
|
+
import { translateWithDefault } from '@aerogel/core/lang/utils';
|
|
32
|
+
import type { ErrorReport } from '@aerogel/core/errors';
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
interface ErrorReportModalButtonsDefaultSlotProps {
|
|
35
|
+
id: string;
|
|
36
|
+
description: string;
|
|
37
|
+
iconComponent: Component;
|
|
38
|
+
url?: string;
|
|
39
|
+
click?(): void;
|
|
40
|
+
}
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
42
|
+
defineSlots<{
|
|
43
|
+
default(props: ErrorReportModalButtonsDefaultSlotProps): unknown;
|
|
44
|
+
}>();
|
|
45
|
+
|
|
46
|
+
const props = defineProps<{ report: ErrorReport }>();
|
|
38
47
|
const summary = computed(() =>
|
|
39
48
|
props.report.description ? `${props.report.title}: ${props.report.description}` : props.report.title);
|
|
40
49
|
const githubReportUrl = computed(() => {
|
|
@@ -66,19 +75,17 @@ const buttons = computed(() =>
|
|
|
66
75
|
id: 'clipboard',
|
|
67
76
|
description: 'Copy to clipboard',
|
|
68
77
|
iconComponent: IconCopy,
|
|
69
|
-
async
|
|
78
|
+
async click() {
|
|
70
79
|
await navigator.clipboard.writeText(`${summary.value}\n\n${props.report.details}`);
|
|
71
80
|
|
|
72
|
-
UI.
|
|
73
|
-
translateWithDefault('errors.copiedToClipboard', 'Debug information copied to clipboard'),
|
|
74
|
-
);
|
|
81
|
+
UI.toast(translateWithDefault('errors.copiedToClipboard', 'Debug information copied to clipboard'));
|
|
75
82
|
},
|
|
76
83
|
},
|
|
77
84
|
{
|
|
78
85
|
id: 'console',
|
|
79
86
|
description: 'Log to console',
|
|
80
87
|
iconComponent: IconConsole,
|
|
81
|
-
|
|
88
|
+
click() {
|
|
82
89
|
const error = props.report.error ?? props.report;
|
|
83
90
|
|
|
84
91
|
(window as { error?: unknown }).error = error;
|
|
@@ -86,7 +93,7 @@ const buttons = computed(() =>
|
|
|
86
93
|
// eslint-disable-next-line no-console
|
|
87
94
|
console.error(error);
|
|
88
95
|
|
|
89
|
-
UI.
|
|
96
|
+
UI.toast(
|
|
90
97
|
translateWithDefault(
|
|
91
98
|
'errors.addedToConsole',
|
|
92
99
|
'You can now use the **error** variable in the console',
|
|
@@ -94,8 +101,8 @@ const buttons = computed(() =>
|
|
|
94
101
|
);
|
|
95
102
|
},
|
|
96
103
|
},
|
|
97
|
-
],
|
|
98
|
-
(reportButtons
|
|
104
|
+
] as ErrorReportModalButtonsDefaultSlotProps[],
|
|
105
|
+
(reportButtons) => {
|
|
99
106
|
if (!githubReportUrl.value) {
|
|
100
107
|
return;
|
|
101
108
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Markdown :text inline />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed } from 'vue';
|
|
7
|
+
|
|
8
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
9
|
+
import type { ErrorReport } from '@aerogel/core/errors';
|
|
10
|
+
|
|
11
|
+
const { totalReports, currentReport, report } = defineProps<{
|
|
12
|
+
report: ErrorReport;
|
|
13
|
+
currentReport?: number;
|
|
14
|
+
totalReports?: number;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
const text = computed(() => {
|
|
18
|
+
if (!totalReports || totalReports <= 1) {
|
|
19
|
+
return report.title;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return `${report.title} (${currentReport}/${totalReports})`;
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
@@ -7,19 +7,18 @@
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import { provide, watchEffect } from 'vue';
|
|
9
9
|
|
|
10
|
-
import
|
|
11
|
-
import type Form from '@/forms/Form';
|
|
10
|
+
import type FormController from '@aerogel/core/forms/FormController';
|
|
12
11
|
|
|
13
12
|
let offSubmit: (() => void) | undefined;
|
|
14
|
-
const
|
|
13
|
+
const { form } = defineProps<{ form?: FormController }>();
|
|
15
14
|
const emit = defineEmits<{ submit: [] }>();
|
|
16
15
|
|
|
17
16
|
watchEffect((onCleanup) => {
|
|
18
17
|
offSubmit?.();
|
|
19
|
-
offSubmit =
|
|
18
|
+
offSubmit = form?.on('submit', () => emit('submit'));
|
|
20
19
|
|
|
21
20
|
onCleanup(() => offSubmit?.());
|
|
22
21
|
});
|
|
23
22
|
|
|
24
|
-
provide('form',
|
|
23
|
+
provide('form', form);
|
|
25
24
|
</script>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<HeadlessInput
|
|
3
|
+
ref="$inputRef"
|
|
4
|
+
:label="label"
|
|
5
|
+
:class="rootClasses"
|
|
6
|
+
v-bind="props"
|
|
7
|
+
@update:model-value="$emit('update:modelValue', $event)"
|
|
8
|
+
>
|
|
9
|
+
<HeadlessInputLabel class="block text-sm leading-6 font-medium text-gray-900" />
|
|
10
|
+
<div :class="renderedWrapperClasses">
|
|
11
|
+
<HeadlessInputInput v-bind="inputAttrs" :class="renderedInputClasses" />
|
|
12
|
+
<div v-if="$input?.errors" class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
|
13
|
+
<IconExclamationSolid class="size-5 text-red-500" />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
<HeadlessInputDescription class="mt-2 text-sm text-gray-600" />
|
|
17
|
+
<HeadlessInputError class="mt-2 text-sm text-red-600" />
|
|
18
|
+
</HeadlessInput>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import IconExclamationSolid from '~icons/zondicons/exclamation-solid';
|
|
23
|
+
|
|
24
|
+
import { computed, useTemplateRef } from 'vue';
|
|
25
|
+
import type { HTMLAttributes } from 'vue';
|
|
26
|
+
|
|
27
|
+
import HeadlessInput from '@aerogel/core/components/headless/HeadlessInput.vue';
|
|
28
|
+
import HeadlessInputLabel from '@aerogel/core/components/headless/HeadlessInputLabel.vue';
|
|
29
|
+
import HeadlessInputInput from '@aerogel/core/components/headless/HeadlessInputInput.vue';
|
|
30
|
+
import HeadlessInputDescription from '@aerogel/core/components/headless/HeadlessInputDescription.vue';
|
|
31
|
+
import HeadlessInputError from '@aerogel/core/components/headless/HeadlessInputError.vue';
|
|
32
|
+
import { classes } from '@aerogel/core/utils/classes';
|
|
33
|
+
import { useInputAttrs } from '@aerogel/core/utils/composition/forms';
|
|
34
|
+
import type { InputEmits, InputProps } from '@aerogel/core/components/contracts/Input';
|
|
35
|
+
|
|
36
|
+
defineOptions({ inheritAttrs: false });
|
|
37
|
+
defineEmits<InputEmits>();
|
|
38
|
+
const { label, inputClass, wrapperClass, ...props } = defineProps<
|
|
39
|
+
InputProps & { inputClass?: HTMLAttributes['class']; wrapperClass?: HTMLAttributes['class'] }
|
|
40
|
+
>();
|
|
41
|
+
const $input = useTemplateRef('$inputRef');
|
|
42
|
+
const [inputAttrs, rootClasses] = useInputAttrs();
|
|
43
|
+
const renderedWrapperClasses = computed(() =>
|
|
44
|
+
classes('relative rounded-md shadow-2xs', { 'mt-1': label }, wrapperClass));
|
|
45
|
+
const renderedInputClasses = computed(() =>
|
|
46
|
+
classes(
|
|
47
|
+
// eslint-disable-next-line vue/max-len
|
|
48
|
+
'block w-full rounded-md border-0 py-1.5 ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6',
|
|
49
|
+
{
|
|
50
|
+
'focus:ring-primary-600': !$input.value?.errors,
|
|
51
|
+
'text-gray-900 shadow-2xs ring-gray-900/10 placeholder:text-gray-400': !$input.value?.errors,
|
|
52
|
+
'pr-10 text-red-900 ring-red-900/10 placeholder:text-red-300 focus:ring-red-500': $input.value?.errors,
|
|
53
|
+
},
|
|
54
|
+
inputClass,
|
|
55
|
+
));
|
|
56
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Button variant="link" v-bind="$props">
|
|
3
|
+
<slot />
|
|
4
|
+
</Button>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
9
|
+
import type { ButtonProps } from '@aerogel/core/components/contracts/Button';
|
|
10
|
+
|
|
11
|
+
defineProps<Omit<ButtonProps, 'variant'>>();
|
|
12
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal
|
|
3
|
+
persistent
|
|
4
|
+
class="flex"
|
|
5
|
+
wrapper-class="w-auto"
|
|
6
|
+
:title="renderedTitle"
|
|
7
|
+
:title-hidden
|
|
8
|
+
:class="{ 'flex-col-reverse': showProgress, 'items-center justify-center gap-2': !showProgress }"
|
|
9
|
+
>
|
|
10
|
+
<ProgressBar
|
|
11
|
+
v-if="showProgress"
|
|
12
|
+
:progress
|
|
13
|
+
:job
|
|
14
|
+
class="min-w-[min(400px,80vw)]"
|
|
15
|
+
/>
|
|
16
|
+
<IconSpinner v-else class="text-primary-600 mr-1 size-6" />
|
|
17
|
+
<Markdown :text="renderedMessage" />
|
|
18
|
+
</Modal>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import IconSpinner from '~icons/svg-spinners/90-ring-with-bg';
|
|
23
|
+
|
|
24
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
25
|
+
import Modal from '@aerogel/core/components/ui/Modal.vue';
|
|
26
|
+
import ProgressBar from '@aerogel/core/components/ui/ProgressBar.vue';
|
|
27
|
+
import { useLoadingModal } from '@aerogel/core/components/contracts/LoadingModal';
|
|
28
|
+
import type { LoadingModalExpose, LoadingModalProps } from '@aerogel/core/components/contracts/LoadingModal';
|
|
29
|
+
|
|
30
|
+
const props = defineProps<LoadingModalProps>();
|
|
31
|
+
const { renderedTitle, renderedMessage, titleHidden, showProgress } = useLoadingModal(props);
|
|
32
|
+
|
|
33
|
+
defineExpose<LoadingModalExpose>();
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<root />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed, h, useAttrs } from 'vue';
|
|
7
|
+
import { isInstanceOf } from '@noeldemartin/utils';
|
|
8
|
+
import type { VNode } from 'vue';
|
|
9
|
+
|
|
10
|
+
import { getMarkdownRouter, renderMarkdown } from '@aerogel/core/utils/markdown';
|
|
11
|
+
import { translate, translateWithDefault } from '@aerogel/core/lang';
|
|
12
|
+
import { renderVNode } from '@aerogel/core/utils/vue';
|
|
13
|
+
|
|
14
|
+
const { as, inline, langKey, langParams, langDefault, text, actions } = defineProps<{
|
|
15
|
+
as?: string;
|
|
16
|
+
inline?: boolean;
|
|
17
|
+
langKey?: string;
|
|
18
|
+
langParams?: number | Record<string, unknown>;
|
|
19
|
+
langDefault?: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
actions?: Record<string, () => unknown>;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const attrs = useAttrs();
|
|
25
|
+
const slots = defineSlots<{ default?(): VNode[] }>();
|
|
26
|
+
const markdown = computed(() => {
|
|
27
|
+
if (slots.default) {
|
|
28
|
+
return slots.default().map(renderVNode).join('');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
text ??
|
|
33
|
+
(langKey &&
|
|
34
|
+
(langDefault
|
|
35
|
+
? translateWithDefault(langKey, langDefault, langParams ?? {})
|
|
36
|
+
: translate(langKey, langParams ?? {})))
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
const html = computed(() => {
|
|
40
|
+
if (!markdown.value) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let renderedHtml = renderMarkdown(markdown.value);
|
|
45
|
+
|
|
46
|
+
if (inline) {
|
|
47
|
+
renderedHtml = renderedHtml.replace('<p>', '<span>').replace('</p>', '</span>');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return renderedHtml;
|
|
51
|
+
});
|
|
52
|
+
const root = () =>
|
|
53
|
+
h(as ?? (inline ? 'span' : 'div'), {
|
|
54
|
+
innerHTML: html.value,
|
|
55
|
+
onClick,
|
|
56
|
+
...attrs,
|
|
57
|
+
class: `${attrs.class ?? ''} ${inline ? '' : 'prose'}`,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
async function onClick(event: Event) {
|
|
61
|
+
const { target } = event;
|
|
62
|
+
|
|
63
|
+
if (isInstanceOf(target, HTMLElement) && target.dataset.markdownAction) {
|
|
64
|
+
actions?.[target.dataset.markdownAction]?.();
|
|
65
|
+
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isInstanceOf(target, HTMLAnchorElement) && target.dataset.markdownRoute) {
|
|
70
|
+
const router = getMarkdownRouter();
|
|
71
|
+
|
|
72
|
+
if (router) {
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
|
|
75
|
+
router.visit(target.dataset.markdownRoute);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style scoped>
|
|
84
|
+
/* @apply .text-links .font-normal .no-underline .hover:underline; */
|
|
85
|
+
* :deep(a) {
|
|
86
|
+
--tw-font-weight: var(--font-weight-normal);
|
|
87
|
+
text-decoration-line: none;
|
|
88
|
+
color: var(--color-links);
|
|
89
|
+
font-weight: var(--font-weight-normal);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@media (hover: hover) {
|
|
93
|
+
* :deep(a:hover) {
|
|
94
|
+
text-decoration-line: underline;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- @vue-generic {T} -->
|
|
3
|
+
<HeadlessModal
|
|
4
|
+
v-slot="{ close }"
|
|
5
|
+
v-bind="props"
|
|
6
|
+
:ref="($modal) => forwardRef($modal as HeadlessModalInstance)"
|
|
7
|
+
:persistent
|
|
8
|
+
>
|
|
9
|
+
<HeadlessModalOverlay
|
|
10
|
+
class="fixed inset-0 animate-[fade-in_var(--tw-duration)_ease-in-out] transition-opacity duration-300 will-change-[opacity]"
|
|
11
|
+
:class="{
|
|
12
|
+
'bg-black/30': context.childIndex === 1,
|
|
13
|
+
'opacity-0': context.childIndex === 1 && context.modal.closing,
|
|
14
|
+
}"
|
|
15
|
+
/>
|
|
16
|
+
<HeadlessModalContent v-bind="contentProps" :class="renderedWrapperClass">
|
|
17
|
+
<div v-if="!persistent && !closeHidden" class="absolute top-0 right-0 hidden pt-3.5 pr-2.5 sm:block">
|
|
18
|
+
<button
|
|
19
|
+
type="button"
|
|
20
|
+
class="clickable z-10 rounded-full p-2.5 text-gray-400 hover:text-gray-500"
|
|
21
|
+
@click="close()"
|
|
22
|
+
>
|
|
23
|
+
<span class="sr-only">{{ $td('ui.close', 'Close') }}</span>
|
|
24
|
+
<IconClose class="size-4" />
|
|
25
|
+
</button>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<HeadlessModalTitle
|
|
29
|
+
v-if="title"
|
|
30
|
+
class="px-4 pt-5 text-base font-semibold text-gray-900"
|
|
31
|
+
:class="{
|
|
32
|
+
'sr-only': titleHidden,
|
|
33
|
+
'pb-0': description && !descriptionHidden,
|
|
34
|
+
'pb-2': !description || descriptionHidden,
|
|
35
|
+
}"
|
|
36
|
+
>
|
|
37
|
+
<Markdown :text="title" inline />
|
|
38
|
+
</HeadlessModalTitle>
|
|
39
|
+
|
|
40
|
+
<HeadlessModalDescription
|
|
41
|
+
v-if="description"
|
|
42
|
+
class="px-4 pt-1 pb-2"
|
|
43
|
+
:class="{ 'sr-only': descriptionHidden }"
|
|
44
|
+
>
|
|
45
|
+
<Markdown :text="description" class="text-sm leading-6 text-gray-500" />
|
|
46
|
+
</HeadlessModalDescription>
|
|
47
|
+
|
|
48
|
+
<div :class="renderedContentClass">
|
|
49
|
+
<slot :close />
|
|
50
|
+
</div>
|
|
51
|
+
</HeadlessModalContent>
|
|
52
|
+
</HeadlessModal>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts" generic="T = void">
|
|
56
|
+
import IconClose from '~icons/zondicons/close';
|
|
57
|
+
|
|
58
|
+
import { after } from '@noeldemartin/utils';
|
|
59
|
+
import { computed } from 'vue';
|
|
60
|
+
import { useForwardExpose } from 'reka-ui';
|
|
61
|
+
import type { ComponentPublicInstance, HTMLAttributes, Ref } from 'vue';
|
|
62
|
+
import type { Nullable } from '@noeldemartin/utils';
|
|
63
|
+
|
|
64
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
65
|
+
import HeadlessModal from '@aerogel/core/components/headless/HeadlessModal.vue';
|
|
66
|
+
import HeadlessModalContent from '@aerogel/core/components/headless/HeadlessModalContent.vue';
|
|
67
|
+
import HeadlessModalDescription from '@aerogel/core/components/headless/HeadlessModalDescription.vue';
|
|
68
|
+
import HeadlessModalOverlay from '@aerogel/core/components/headless/HeadlessModalOverlay.vue';
|
|
69
|
+
import HeadlessModalTitle from '@aerogel/core/components/headless/HeadlessModalTitle.vue';
|
|
70
|
+
import UI from '@aerogel/core/ui/UI';
|
|
71
|
+
import { classes } from '@aerogel/core/utils/classes';
|
|
72
|
+
import { injectReactiveOrFail } from '@aerogel/core/utils/vue';
|
|
73
|
+
import { useEvent } from '@aerogel/core/utils/composition/events';
|
|
74
|
+
import type { AcceptRefs } from '@aerogel/core/utils/vue';
|
|
75
|
+
import type { ModalExpose, ModalProps, ModalSlots } from '@aerogel/core/components/contracts/Modal';
|
|
76
|
+
import type { UIModalContext } from '@aerogel/core/ui/UI';
|
|
77
|
+
|
|
78
|
+
type HeadlessModalInstance = ComponentPublicInstance & ModalExpose<T>;
|
|
79
|
+
|
|
80
|
+
const {
|
|
81
|
+
class: contentClass = '',
|
|
82
|
+
wrapperClass = '',
|
|
83
|
+
title,
|
|
84
|
+
titleHidden,
|
|
85
|
+
description,
|
|
86
|
+
persistent,
|
|
87
|
+
closeHidden,
|
|
88
|
+
...props
|
|
89
|
+
} = defineProps<
|
|
90
|
+
ModalProps & {
|
|
91
|
+
wrapperClass?: HTMLAttributes['class'];
|
|
92
|
+
class?: HTMLAttributes['class'];
|
|
93
|
+
closeHidden?: boolean;
|
|
94
|
+
}
|
|
95
|
+
>();
|
|
96
|
+
|
|
97
|
+
defineSlots<ModalSlots<T>>();
|
|
98
|
+
defineExpose<AcceptRefs<ModalExpose<T>>>({
|
|
99
|
+
close: async (result) => $modal.value?.close(result),
|
|
100
|
+
$content: computed(() => $modal.value?.$content),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const { forwardRef, currentRef } = useForwardExpose<HeadlessModalInstance>();
|
|
104
|
+
const $modal = currentRef as Ref<Nullable<HeadlessModalInstance>>;
|
|
105
|
+
const context = injectReactiveOrFail<UIModalContext>('modal');
|
|
106
|
+
const inForeground = computed(() => !context.modal.closing && context.childIndex === UI.openModals.length);
|
|
107
|
+
const contentProps = computed(() => (description ? {} : { 'aria-describedby': undefined }));
|
|
108
|
+
const renderedContentClass = computed(() =>
|
|
109
|
+
classes('max-h-[90vh] overflow-auto px-4 pb-4', { 'pt-4': !title || titleHidden }, contentClass));
|
|
110
|
+
const renderedWrapperClass = computed(() =>
|
|
111
|
+
classes(
|
|
112
|
+
'isolate fixed top-1/2 left-1/2 z-50 w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2',
|
|
113
|
+
'overflow-hidden rounded-lg bg-white text-left shadow-xl sm:max-w-lg',
|
|
114
|
+
'animate-[fade-in_var(--tw-duration)_ease-in-out,grow_var(--tw-duration)_ease-in-out]',
|
|
115
|
+
'transition-[scale,opacity] will-change-[scale,opacity] duration-300',
|
|
116
|
+
{
|
|
117
|
+
'scale-50 opacity-0': !inForeground.value,
|
|
118
|
+
'scale-100 opacity-100': inForeground.value,
|
|
119
|
+
},
|
|
120
|
+
wrapperClass,
|
|
121
|
+
));
|
|
122
|
+
|
|
123
|
+
useEvent('modal-will-close', async ({ modal: { id } }) => {
|
|
124
|
+
if (id !== context.modal.id) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Wait for transitions to finish
|
|
129
|
+
await after({ ms: 300 });
|
|
130
|
+
});
|
|
131
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="modal.component" v-bind="modalProperties" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed, provide, toRef, unref } from 'vue';
|
|
7
|
+
|
|
8
|
+
import type { UIModal } from '@aerogel/core/ui/UI.state';
|
|
9
|
+
import type { UIModalContext } from '@aerogel/core/ui/UI';
|
|
10
|
+
import type { AcceptRefs } from '@aerogel/core/utils/vue';
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
modal: UIModal;
|
|
14
|
+
childIndex?: number;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
const modalProperties = computed(() => {
|
|
18
|
+
const properties = {} as typeof props.modal.properties;
|
|
19
|
+
|
|
20
|
+
for (const property in props.modal.properties) {
|
|
21
|
+
properties[property] = unref(props.modal.properties[property]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return properties;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
provide<AcceptRefs<UIModalContext>>('modal', {
|
|
28
|
+
modal: toRef(props, 'modal'),
|
|
29
|
+
childIndex: toRef(props, 'childIndex'),
|
|
30
|
+
});
|
|
31
|
+
</script>
|