@aerogel/core 0.0.0-next.c2e6acc000e97a1020c2e232678563c53884dd0e → 0.0.0-next.c33ad773d3eb977461630ff22012d99eeedf46cb
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.d.ts +1025 -429
- package/dist/aerogel-core.js +1601 -1440
- package/dist/aerogel-core.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AppModals.vue +1 -1
- package/src/components/AppOverlays.vue +2 -7
- package/src/components/AppToasts.vue +16 -0
- package/src/components/contracts/Button.ts +1 -0
- package/src/components/contracts/DropdownMenu.ts +11 -0
- package/src/components/contracts/Input.ts +4 -4
- package/src/components/contracts/Modal.ts +4 -0
- package/src/components/contracts/Select.ts +33 -0
- package/src/components/contracts/Toast.ts +13 -0
- package/src/components/contracts/index.ts +2 -0
- package/src/components/headless/HeadlessButton.vue +7 -2
- package/src/components/headless/HeadlessInputDescription.vue +1 -1
- package/src/components/headless/HeadlessInputInput.vue +3 -3
- package/src/components/headless/HeadlessInputTextArea.vue +2 -2
- package/src/components/headless/HeadlessModal.vue +4 -2
- package/src/components/headless/HeadlessModalOverlay.vue +2 -2
- package/src/components/headless/HeadlessModalTitle.vue +2 -2
- package/src/components/headless/HeadlessSelect.vue +92 -0
- package/src/components/headless/{forms/AGHeadlessSelectError.vue → HeadlessSelectError.vue} +3 -4
- package/src/components/headless/HeadlessSelectLabel.vue +25 -0
- package/src/components/headless/HeadlessSelectOption.vue +34 -0
- package/src/components/headless/HeadlessSelectOptions.vue +30 -0
- package/src/components/headless/HeadlessSelectTrigger.vue +22 -0
- package/src/components/headless/HeadlessSelectValue.vue +15 -0
- package/src/components/headless/HeadlessToast.vue +18 -0
- package/src/components/headless/HeadlessToastAction.vue +13 -0
- package/src/components/headless/index.ts +7 -3
- package/src/components/index.ts +2 -8
- package/src/components/ui/AdvancedOptions.vue +18 -0
- package/src/components/ui/AlertModal.vue +1 -1
- package/src/components/ui/Button.vue +54 -14
- package/src/components/ui/Checkbox.vue +17 -10
- package/src/components/ui/ConfirmModal.vue +3 -3
- package/src/components/ui/DropdownMenu.vue +33 -0
- package/src/components/ui/EditableContent.vue +82 -0
- package/src/components/{lib/AGErrorMessage.vue → ui/ErrorMessage.vue} +2 -3
- package/src/components/ui/ErrorReportModal.vue +1 -1
- package/src/components/ui/ErrorReportModalButtons.vue +6 -8
- package/src/components/ui/ErrorReportModalTitle.vue +1 -1
- package/src/components/ui/Input.vue +8 -4
- package/src/components/ui/Link.vue +2 -2
- package/src/components/ui/LoadingModal.vue +3 -3
- package/src/components/ui/Markdown.vue +10 -3
- package/src/components/ui/Modal.vue +23 -8
- package/src/components/ui/PromptModal.vue +4 -4
- package/src/components/ui/Select.vue +53 -0
- package/src/components/ui/Toast.vue +42 -0
- package/src/components/ui/index.ts +7 -0
- package/src/components/utils.ts +4 -4
- package/src/errors/Errors.ts +4 -5
- package/src/index.css +33 -0
- package/src/ui/UI.state.ts +2 -2
- package/src/ui/UI.ts +12 -20
- package/src/ui/index.ts +4 -4
- package/src/utils/vue.ts +0 -4
- package/src/components/AppSnackbars.vue +0 -13
- package/src/components/constants.ts +0 -8
- package/src/components/forms/AGSelect.story.vue +0 -46
- package/src/components/forms/AGSelect.vue +0 -54
- package/src/components/forms/index.ts +0 -1
- package/src/components/headless/forms/AGHeadlessSelect.ts +0 -42
- package/src/components/headless/forms/AGHeadlessSelect.vue +0 -77
- package/src/components/headless/forms/AGHeadlessSelectOption.ts +0 -4
- package/src/components/headless/forms/AGHeadlessSelectOption.vue +0 -31
- package/src/components/headless/forms/AGHeadlessSelectOptions.vue +0 -19
- package/src/components/headless/forms/AGHeadlessSelectTrigger.vue +0 -25
- package/src/components/headless/forms/composition.ts +0 -10
- package/src/components/headless/forms/index.ts +0 -8
- package/src/components/headless/snackbars/AGHeadlessSnackbar.vue +0 -10
- package/src/components/headless/snackbars/index.ts +0 -40
- package/src/components/lib/AGMeasured.vue +0 -16
- package/src/components/lib/index.ts +0 -3
- package/src/components/snackbars/AGSnackbar.vue +0 -38
- package/src/components/snackbars/index.ts +0 -3
- /package/src/components/{lib/AGStartupCrash.vue → ui/StartupCrash.vue} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<HeadlessButton :class="renderedClasses" v-bind="props">
|
|
2
|
+
<HeadlessButton :class="renderedClasses" :disabled v-bind="props">
|
|
3
3
|
<slot />
|
|
4
4
|
</HeadlessButton>
|
|
5
5
|
</template>
|
|
@@ -10,29 +10,33 @@ import { computedVariantClasses } from '@aerogel/core/components/utils';
|
|
|
10
10
|
import type { ButtonProps } from '@aerogel/core/components/contracts/Button';
|
|
11
11
|
import type { Variants } from '@aerogel/core/components/utils';
|
|
12
12
|
|
|
13
|
-
const { class: baseClasses, size, variant, ...props } = defineProps<ButtonProps>();
|
|
13
|
+
const { class: baseClasses, size, variant, disabled, ...props } = defineProps<ButtonProps>();
|
|
14
14
|
|
|
15
15
|
/* eslint-disable vue/max-len */
|
|
16
16
|
// prettier-ignore
|
|
17
|
-
const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size' | 'variant'>>>(
|
|
18
|
-
{ baseClasses, variant, size },
|
|
17
|
+
const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size' | 'variant' | 'disabled'>>>(
|
|
18
|
+
{ baseClasses, variant, size, disabled },
|
|
19
19
|
{
|
|
20
|
-
baseClasses: 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
|
|
20
|
+
baseClasses: 'flex items-center justify-center gap-1 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
|
|
21
21
|
variants: {
|
|
22
22
|
variant: {
|
|
23
|
-
default: 'bg-primary text-white
|
|
24
|
-
secondary: 'bg-background text-gray-900 ring-gray-300
|
|
25
|
-
danger: 'bg-danger text-white
|
|
26
|
-
ghost: 'bg-
|
|
27
|
-
outline: 'bg-
|
|
28
|
-
link: 'text-primary
|
|
23
|
+
default: 'bg-primary text-white focus-visible:outline-primary',
|
|
24
|
+
secondary: 'bg-background text-gray-900 ring-gray-300',
|
|
25
|
+
danger: 'bg-danger text-white focus-visible:outline-danger',
|
|
26
|
+
ghost: 'bg-transparent',
|
|
27
|
+
outline: 'bg-transparent text-primary ring-primary',
|
|
28
|
+
link: 'text-primary',
|
|
29
29
|
},
|
|
30
30
|
size: {
|
|
31
|
-
small: '
|
|
32
|
-
default: '
|
|
33
|
-
large: '
|
|
31
|
+
small: 'text-xs',
|
|
32
|
+
default: 'text-sm',
|
|
33
|
+
large: 'text-base',
|
|
34
34
|
icon: 'rounded-full p-2.5',
|
|
35
35
|
},
|
|
36
|
+
disabled: {
|
|
37
|
+
false: null,
|
|
38
|
+
true: 'opacity-50 cursor-not-allowed',
|
|
39
|
+
},
|
|
36
40
|
},
|
|
37
41
|
compoundVariants: [
|
|
38
42
|
{
|
|
@@ -47,10 +51,46 @@ const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size'
|
|
|
47
51
|
variant: ['secondary', 'outline'],
|
|
48
52
|
class: 'ring-1 ring-inset',
|
|
49
53
|
},
|
|
54
|
+
{
|
|
55
|
+
variant: ['default', 'secondary', 'danger', 'ghost', 'outline'],
|
|
56
|
+
size: 'small',
|
|
57
|
+
class: 'rounded px-2 py-1',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
variant: ['default', 'secondary', 'danger', 'ghost', 'outline'],
|
|
61
|
+
size: 'default',
|
|
62
|
+
class: 'rounded-md px-2.5 py-1.5',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
variant: ['default', 'secondary', 'danger', 'ghost', 'outline'],
|
|
66
|
+
size: 'large',
|
|
67
|
+
class: 'rounded-md px-3 py-2',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
variant: 'default',
|
|
71
|
+
disabled: false,
|
|
72
|
+
class: 'hover:bg-primary/90',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
variant: ['secondary', 'ghost', 'outline'],
|
|
76
|
+
disabled: false,
|
|
77
|
+
class: 'hover:bg-accent',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
variant: 'danger',
|
|
81
|
+
disabled: false,
|
|
82
|
+
class: 'hover:bg-danger/80',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
variant: 'link',
|
|
86
|
+
disabled: false,
|
|
87
|
+
class: 'hover:underline',
|
|
88
|
+
},
|
|
50
89
|
],
|
|
51
90
|
defaultVariants: {
|
|
52
91
|
variant: 'default',
|
|
53
92
|
size: 'default',
|
|
93
|
+
disabled: false,
|
|
54
94
|
},
|
|
55
95
|
},
|
|
56
96
|
);
|
|
@@ -8,33 +8,39 @@
|
|
|
8
8
|
<div class="flex h-6 items-center">
|
|
9
9
|
<HeadlessInputInput v-bind="inputAttrs" type="checkbox" :class="renderedInputClasses" />
|
|
10
10
|
</div>
|
|
11
|
-
<div v-if="$slots.default" class="
|
|
11
|
+
<div v-if="$slots.default" :class="renderedLabelClasses">
|
|
12
12
|
<HeadlessInputLabel class="text-gray-900">
|
|
13
13
|
<slot />
|
|
14
14
|
</HeadlessInputLabel>
|
|
15
|
-
<HeadlessInputError class="text-
|
|
15
|
+
<HeadlessInputError class="text-red-600" />
|
|
16
16
|
</div>
|
|
17
|
-
<div v-else-if="label" class="
|
|
18
|
-
<HeadlessInputLabel />
|
|
19
|
-
<HeadlessInputError class="text-
|
|
17
|
+
<div v-else-if="label" :class="renderedLabelClasses">
|
|
18
|
+
<HeadlessInputLabel class="text-gray-900" />
|
|
19
|
+
<HeadlessInputError class="text-red-600" />
|
|
20
20
|
</div>
|
|
21
21
|
</HeadlessInput>
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
|
-
import { computed } from 'vue';
|
|
25
|
+
import { computed, useTemplateRef } from 'vue';
|
|
26
26
|
import type { HTMLAttributes } from 'vue';
|
|
27
27
|
|
|
28
|
+
import HeadlessInput from '@aerogel/core/components/headless/HeadlessInput.vue';
|
|
29
|
+
import HeadlessInputError from '@aerogel/core/components/headless/HeadlessInputError.vue';
|
|
30
|
+
import HeadlessInputInput from '@aerogel/core/components/headless/HeadlessInputInput.vue';
|
|
31
|
+
import HeadlessInputLabel from '@aerogel/core/components/headless/HeadlessInputLabel.vue';
|
|
28
32
|
import { classes } from '@aerogel/core/components/utils';
|
|
29
33
|
import { useInputAttrs } from '@aerogel/core/utils/composition/forms';
|
|
30
|
-
import {
|
|
31
|
-
import type { InputEmits, InputExpose, InputProps } from '@aerogel/core/components/contracts/Input';
|
|
34
|
+
import type { InputEmits, InputProps } from '@aerogel/core/components/contracts/Input';
|
|
32
35
|
|
|
33
36
|
defineOptions({ inheritAttrs: false });
|
|
34
37
|
defineEmits<InputEmits>();
|
|
35
|
-
const { inputClass, ...props } = defineProps<InputProps & { inputClass?: HTMLAttributes['class'] }>();
|
|
36
38
|
|
|
37
|
-
const
|
|
39
|
+
const { inputClass, labelClass, ...props } = defineProps<
|
|
40
|
+
InputProps & { inputClass?: HTMLAttributes['class']; labelClass?: HTMLAttributes['class'] }
|
|
41
|
+
>();
|
|
42
|
+
|
|
43
|
+
const $input = useTemplateRef('$input');
|
|
38
44
|
const [inputAttrs, rootClasses] = useInputAttrs();
|
|
39
45
|
const renderedClasses = computed(() => classes('relative flex items-start', rootClasses.value));
|
|
40
46
|
const renderedInputClasses = computed(() =>
|
|
@@ -46,4 +52,5 @@ const renderedInputClasses = computed(() =>
|
|
|
46
52
|
},
|
|
47
53
|
inputClass,
|
|
48
54
|
));
|
|
55
|
+
const renderedLabelClasses = computed(() => classes('ml-2 text-sm leading-6', labelClass));
|
|
49
56
|
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Modal v-slot="{ close }" :title
|
|
3
|
-
<Form :form
|
|
4
|
-
<Markdown :text="message" :actions
|
|
2
|
+
<Modal v-slot="{ close }" :title persistent>
|
|
3
|
+
<Form :form @submit="close([true, form.data()])">
|
|
4
|
+
<Markdown :text="message" :actions />
|
|
5
5
|
|
|
6
6
|
<ul v-if="checkboxes" class="mt-4 flex flex-col text-sm text-gray-600">
|
|
7
7
|
<li v-for="(checkbox, name) of checkboxes" :key="name">
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<DropdownMenuRoot>
|
|
3
|
+
<DropdownMenuTrigger>
|
|
4
|
+
<slot />
|
|
5
|
+
</DropdownMenuTrigger>
|
|
6
|
+
<DropdownMenuPortal>
|
|
7
|
+
<DropdownMenuContent class="gap-y-0.5 rounded-lg bg-white p-1.5 shadow-lg ring-1 ring-black/5" :align>
|
|
8
|
+
<DropdownMenuItem
|
|
9
|
+
v-for="(option, key) in options"
|
|
10
|
+
:key
|
|
11
|
+
class="flex w-full items-center rounded-lg px-2 py-2 text-sm text-gray-900 data-[highlighted]:bg-gray-100"
|
|
12
|
+
@select="option.click"
|
|
13
|
+
>
|
|
14
|
+
{{ option.label }}
|
|
15
|
+
</DropdownMenuItem>
|
|
16
|
+
</DropdownMenuContent>
|
|
17
|
+
</DropdownMenuPortal>
|
|
18
|
+
</DropdownMenuRoot>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import {
|
|
23
|
+
DropdownMenuContent,
|
|
24
|
+
DropdownMenuItem,
|
|
25
|
+
DropdownMenuPortal,
|
|
26
|
+
DropdownMenuRoot,
|
|
27
|
+
DropdownMenuTrigger,
|
|
28
|
+
} from 'reka-ui';
|
|
29
|
+
|
|
30
|
+
import type { DropdownMenuProps } from '@aerogel/core/components/contracts/DropdownMenu';
|
|
31
|
+
|
|
32
|
+
defineProps<DropdownMenuProps>();
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="relative" :class="{ 'pointer-events-none!': disabled && !editing }">
|
|
3
|
+
<div v-if="!editing" :class="renderedContentClass">
|
|
4
|
+
<slot />
|
|
5
|
+
</div>
|
|
6
|
+
<span v-else :class="renderedFillerClass">
|
|
7
|
+
{{ draft }}
|
|
8
|
+
</span>
|
|
9
|
+
<span v-if="type === 'number'" class="inline-block transition-[width]" :class="editing ? 'w-5' : 'w-0'" />
|
|
10
|
+
<form class="w-full" :aria-hidden="formAriaHidden" @submit.prevent="$input?.blur()">
|
|
11
|
+
<input
|
|
12
|
+
ref="$input"
|
|
13
|
+
v-model="draft"
|
|
14
|
+
:tabindex="tabindex ?? undefined"
|
|
15
|
+
:aria-label="ariaLabel ?? undefined"
|
|
16
|
+
:type
|
|
17
|
+
:class="[
|
|
18
|
+
renderedInputClass,
|
|
19
|
+
{ 'opacity-0': !editing, 'appearance-textfield': !editing && type === 'number' },
|
|
20
|
+
]"
|
|
21
|
+
@keyup="$emit('update', draft)"
|
|
22
|
+
@focus="startEditing()"
|
|
23
|
+
@blur="stopEditing()"
|
|
24
|
+
>
|
|
25
|
+
</form>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { computed, ref, watchEffect } from 'vue';
|
|
31
|
+
import type { HTMLAttributes } from 'vue';
|
|
32
|
+
|
|
33
|
+
import { classes } from '@aerogel/core/components/utils';
|
|
34
|
+
|
|
35
|
+
const emit = defineEmits<{ update: [value: string | number]; save: [] }>();
|
|
36
|
+
const {
|
|
37
|
+
type = 'text',
|
|
38
|
+
text,
|
|
39
|
+
contentClass,
|
|
40
|
+
ariaLabel,
|
|
41
|
+
formAriaHidden,
|
|
42
|
+
tabindex,
|
|
43
|
+
disabled,
|
|
44
|
+
} = defineProps<{
|
|
45
|
+
type?: string;
|
|
46
|
+
contentClass?: HTMLAttributes['class'];
|
|
47
|
+
ariaLabel?: string;
|
|
48
|
+
formAriaHidden?: boolean;
|
|
49
|
+
tabindex?: string;
|
|
50
|
+
text: string;
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
}>();
|
|
53
|
+
const $input = ref<HTMLElement>();
|
|
54
|
+
const editing = ref<string | null>(null);
|
|
55
|
+
const draft = ref(text);
|
|
56
|
+
const renderedContentClass = computed(() => classes('inline whitespace-pre', contentClass));
|
|
57
|
+
const renderedFillerClass = computed(() => classes('invisible whitespace-pre', contentClass));
|
|
58
|
+
const renderedInputClass = computed(() =>
|
|
59
|
+
classes('absolute inset-0 h-full w-full resize-none border-0 bg-transparent p-0 focus:ring-0', contentClass));
|
|
60
|
+
|
|
61
|
+
function startEditing() {
|
|
62
|
+
editing.value = text;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function stopEditing() {
|
|
66
|
+
if (!editing.value) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (type !== 'number' && draft.value.trim().length === 0) {
|
|
71
|
+
draft.value = editing.value;
|
|
72
|
+
|
|
73
|
+
emit('update', draft.value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
editing.value = null;
|
|
77
|
+
|
|
78
|
+
emit('save');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
watchEffect(() => (draft.value = text));
|
|
82
|
+
</script>
|
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
6
|
import { computed } from 'vue';
|
|
7
7
|
|
|
8
|
-
import { requiredObjectProp } from '@aerogel/core/utils/vue';
|
|
9
8
|
import { getErrorMessage } from '@aerogel/core/errors/utils';
|
|
10
9
|
import type { ErrorSource } from '@aerogel/core/errors/Errors.state';
|
|
11
10
|
|
|
12
11
|
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
13
12
|
|
|
14
|
-
const
|
|
15
|
-
const message = computed(() => getErrorMessage(
|
|
13
|
+
const { error } = defineProps<{ error: ErrorSource }>();
|
|
14
|
+
const message = computed(() => getErrorMessage(error));
|
|
16
15
|
</script>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</Button>
|
|
34
34
|
</span>
|
|
35
35
|
</div>
|
|
36
|
-
<ErrorReportModalButtons :report
|
|
36
|
+
<ErrorReportModalButtons :report class="gap-0.5" />
|
|
37
37
|
</h2>
|
|
38
38
|
<Markdown v-if="report.description" :text="report.description" class="text-gray-600" />
|
|
39
39
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
class="group whitespace-nowrap"
|
|
8
8
|
:href="button.url"
|
|
9
9
|
:title="$td(`errors.report_${button.id}`, button.description)"
|
|
10
|
-
@click="button.
|
|
10
|
+
@click="button.click"
|
|
11
11
|
>
|
|
12
12
|
<span class="sr-only">{{ $td(`errors.report_${button.id}`, button.description) }}</span>
|
|
13
13
|
<component :is="button.iconComponent" class="size-4" aria-hidden="true" />
|
|
@@ -36,7 +36,7 @@ interface ErrorReportModalButtonsDefaultSlotProps {
|
|
|
36
36
|
description: string;
|
|
37
37
|
iconComponent: Component;
|
|
38
38
|
url?: string;
|
|
39
|
-
|
|
39
|
+
click?(): void;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
defineSlots<{
|
|
@@ -75,19 +75,17 @@ const buttons = computed(() =>
|
|
|
75
75
|
id: 'clipboard',
|
|
76
76
|
description: 'Copy to clipboard',
|
|
77
77
|
iconComponent: IconCopy,
|
|
78
|
-
async
|
|
78
|
+
async click() {
|
|
79
79
|
await navigator.clipboard.writeText(`${summary.value}\n\n${props.report.details}`);
|
|
80
80
|
|
|
81
|
-
UI.
|
|
82
|
-
translateWithDefault('errors.copiedToClipboard', 'Debug information copied to clipboard'),
|
|
83
|
-
);
|
|
81
|
+
UI.toast(translateWithDefault('errors.copiedToClipboard', 'Debug information copied to clipboard'));
|
|
84
82
|
},
|
|
85
83
|
},
|
|
86
84
|
{
|
|
87
85
|
id: 'console',
|
|
88
86
|
description: 'Log to console',
|
|
89
87
|
iconComponent: IconConsole,
|
|
90
|
-
|
|
88
|
+
click() {
|
|
91
89
|
const error = props.report.error ?? props.report;
|
|
92
90
|
|
|
93
91
|
(window as { error?: unknown }).error = error;
|
|
@@ -95,7 +93,7 @@ const buttons = computed(() =>
|
|
|
95
93
|
// eslint-disable-next-line no-console
|
|
96
94
|
console.error(error);
|
|
97
95
|
|
|
98
|
-
UI.
|
|
96
|
+
UI.toast(
|
|
99
97
|
translateWithDefault(
|
|
100
98
|
'errors.addedToConsole',
|
|
101
99
|
'You can now use the **error** variable in the console',
|
|
@@ -21,20 +21,24 @@
|
|
|
21
21
|
<script setup lang="ts">
|
|
22
22
|
import IconExclamationSolid from '~icons/zondicons/exclamation-solid';
|
|
23
23
|
|
|
24
|
-
import { computed } from 'vue';
|
|
24
|
+
import { computed, useTemplateRef } from 'vue';
|
|
25
25
|
import type { HTMLAttributes } from 'vue';
|
|
26
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';
|
|
27
32
|
import { classes } from '@aerogel/core/components/utils';
|
|
28
33
|
import { useInputAttrs } from '@aerogel/core/utils/composition/forms';
|
|
29
|
-
import {
|
|
30
|
-
import type { InputEmits, InputExpose, InputProps } from '@aerogel/core/components/contracts/Input';
|
|
34
|
+
import type { InputEmits, InputProps } from '@aerogel/core/components/contracts/Input';
|
|
31
35
|
|
|
32
36
|
defineOptions({ inheritAttrs: false });
|
|
33
37
|
defineEmits<InputEmits>();
|
|
34
38
|
const { label, inputClass, wrapperClass, ...props } = defineProps<
|
|
35
39
|
InputProps & { inputClass?: HTMLAttributes['class']; wrapperClass?: HTMLAttributes['class'] }
|
|
36
40
|
>();
|
|
37
|
-
const $input =
|
|
41
|
+
const $input = useTemplateRef('$input');
|
|
38
42
|
const [inputAttrs, rootClasses] = useInputAttrs();
|
|
39
43
|
const renderedWrapperClasses = computed(() =>
|
|
40
44
|
classes('relative rounded-md shadow-2xs', { 'mt-1': label }, wrapperClass));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Button variant="link" v-bind="props">
|
|
2
|
+
<Button variant="link" v-bind="$props">
|
|
3
3
|
<slot />
|
|
4
4
|
</Button>
|
|
5
5
|
</template>
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
9
9
|
import type { ButtonProps } from '@aerogel/core/components/contracts/Button';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
defineProps<Omit<ButtonProps, 'variant'>>();
|
|
12
12
|
</script>
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
persistent
|
|
4
4
|
class="flex"
|
|
5
5
|
wrapper-class="w-auto"
|
|
6
|
-
:title
|
|
6
|
+
:title
|
|
7
7
|
:class="{ 'flex-col-reverse': showProgress, 'items-center justify-center gap-2': !showProgress }"
|
|
8
8
|
>
|
|
9
9
|
<ProgressBar
|
|
10
10
|
v-if="showProgress"
|
|
11
|
-
:progress
|
|
12
|
-
:job
|
|
11
|
+
:progress
|
|
12
|
+
:job
|
|
13
13
|
class="min-w-[min(400px,80vw)]"
|
|
14
14
|
/>
|
|
15
15
|
<IconSpinner v-else class="text-primary mr-1 size-6" />
|
|
@@ -8,14 +8,15 @@ import { isInstanceOf } from '@noeldemartin/utils';
|
|
|
8
8
|
import type { VNode } from 'vue';
|
|
9
9
|
|
|
10
10
|
import { renderMarkdown } from '@aerogel/core/utils/markdown';
|
|
11
|
-
import { translate } from '@aerogel/core/lang';
|
|
11
|
+
import { translate, translateWithDefault } from '@aerogel/core/lang';
|
|
12
12
|
import { renderNode } from '@aerogel/core/utils/vdom';
|
|
13
13
|
|
|
14
|
-
const { as, inline, langKey, langParams, text, actions } = defineProps<{
|
|
14
|
+
const { as, inline, langKey, langParams, langDefault, text, actions } = defineProps<{
|
|
15
15
|
as?: string;
|
|
16
16
|
inline?: boolean;
|
|
17
17
|
langKey?: string;
|
|
18
18
|
langParams?: number | Record<string, unknown>;
|
|
19
|
+
langDefault?: string;
|
|
19
20
|
text?: string;
|
|
20
21
|
actions?: Record<string, () => unknown>;
|
|
21
22
|
}>();
|
|
@@ -27,7 +28,13 @@ const markdown = computed(() => {
|
|
|
27
28
|
return slots.default().map(renderNode).join('');
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
return
|
|
31
|
+
return (
|
|
32
|
+
text ??
|
|
33
|
+
(langKey &&
|
|
34
|
+
(langDefault
|
|
35
|
+
? translateWithDefault(langKey, langDefault, langParams ?? {})
|
|
36
|
+
: translate(langKey, langParams ?? {})))
|
|
37
|
+
);
|
|
31
38
|
});
|
|
32
39
|
const html = computed(() => {
|
|
33
40
|
if (!markdown.value) {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<HeadlessModal
|
|
2
|
+
<HeadlessModal
|
|
3
|
+
v-slot="{ close }"
|
|
4
|
+
v-bind="props"
|
|
5
|
+
ref="$modal"
|
|
6
|
+
:persistent
|
|
7
|
+
>
|
|
3
8
|
<HeadlessModalOverlay class="fixed inset-0 bg-gray-500/75" />
|
|
4
9
|
|
|
5
10
|
<HeadlessModalContent :class="renderedWrapperClass">
|
|
6
|
-
<div v-if="!persistent" class="absolute top-0 right-0 hidden pt-1.5 pr-1.5 sm:block">
|
|
11
|
+
<div v-if="!persistent && dismissable" class="absolute top-0 right-0 hidden pt-1.5 pr-1.5 sm:block">
|
|
7
12
|
<Button variant="ghost" size="icon" @click="close()">
|
|
8
13
|
<span class="sr-only">{{ $td('ui.close', 'Close') }}</span>
|
|
9
14
|
<IconClose class="size-3 text-gray-400" />
|
|
@@ -15,7 +20,7 @@
|
|
|
15
20
|
</HeadlessModalTitle>
|
|
16
21
|
|
|
17
22
|
<div :class="renderedContentClass">
|
|
18
|
-
<slot :close
|
|
23
|
+
<slot :close />
|
|
19
24
|
</div>
|
|
20
25
|
</HeadlessModalContent>
|
|
21
26
|
</HeadlessModal>
|
|
@@ -24,27 +29,34 @@
|
|
|
24
29
|
<script setup lang="ts">
|
|
25
30
|
import IconClose from '~icons/zondicons/close';
|
|
26
31
|
|
|
27
|
-
import { computed } from 'vue';
|
|
32
|
+
import { computed, useTemplateRef } from 'vue';
|
|
28
33
|
import type { HTMLAttributes } from 'vue';
|
|
29
34
|
|
|
30
35
|
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
36
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
31
37
|
import HeadlessModal from '@aerogel/core/components/headless/HeadlessModal.vue';
|
|
32
38
|
import HeadlessModalContent from '@aerogel/core/components/headless/HeadlessModalContent.vue';
|
|
33
39
|
import HeadlessModalOverlay from '@aerogel/core/components/headless/HeadlessModalOverlay.vue';
|
|
34
40
|
import HeadlessModalTitle from '@aerogel/core/components/headless/HeadlessModalTitle.vue';
|
|
35
41
|
import { classes } from '@aerogel/core/components/utils';
|
|
36
|
-
import type { ModalProps, ModalSlots } from '@aerogel/core/components/contracts/Modal';
|
|
42
|
+
import type { ModalExpose, ModalProps, ModalSlots } from '@aerogel/core/components/contracts/Modal';
|
|
37
43
|
|
|
38
44
|
const {
|
|
39
45
|
class: contentClass = '',
|
|
46
|
+
dismissable = true,
|
|
40
47
|
wrapperClass = '',
|
|
41
48
|
title,
|
|
42
49
|
persistent,
|
|
43
50
|
...props
|
|
44
|
-
} = defineProps<
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
} = defineProps<
|
|
52
|
+
ModalProps & {
|
|
53
|
+
dismissable?: boolean;
|
|
54
|
+
wrapperClass?: HTMLAttributes['class'];
|
|
55
|
+
class?: HTMLAttributes['class'];
|
|
56
|
+
}
|
|
57
|
+
>();
|
|
47
58
|
|
|
59
|
+
const $modal = useTemplateRef('$modal');
|
|
48
60
|
const renderedContentClass = computed(() => classes({ 'mt-2': title }, contentClass));
|
|
49
61
|
const renderedWrapperClass = computed(() =>
|
|
50
62
|
classes(
|
|
@@ -52,4 +64,7 @@ const renderedWrapperClass = computed(() =>
|
|
|
52
64
|
'fixed top-1/2 left-1/2 z-50 w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg bg-white px-4 pt-5 pb-4 text-left shadow-xl sm:max-w-lg',
|
|
53
65
|
wrapperClass,
|
|
54
66
|
));
|
|
67
|
+
|
|
68
|
+
defineSlots<ModalSlots>();
|
|
69
|
+
defineExpose<ModalExpose>({ close: async () => $modal.value?.close() });
|
|
55
70
|
</script>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Modal v-slot="{ close }" :title
|
|
3
|
-
<Form :form
|
|
2
|
+
<Modal v-slot="{ close }" :title persistent>
|
|
3
|
+
<Form :form @submit="close(form.draft)">
|
|
4
4
|
<Markdown :text="message" />
|
|
5
5
|
<Input
|
|
6
6
|
name="draft"
|
|
7
7
|
class="mt-2"
|
|
8
|
-
:placeholder
|
|
9
|
-
:label
|
|
8
|
+
:placeholder
|
|
9
|
+
:label
|
|
10
10
|
/>
|
|
11
11
|
|
|
12
12
|
<div class="mt-4 flex flex-row-reverse gap-2">
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<HeadlessSelect ref="$select" v-bind="$props" @update:model-value="$emit('update:modelValue', $event)">
|
|
3
|
+
<HeadlessSelectLabel class="block text-sm leading-6 font-medium text-gray-900" />
|
|
4
|
+
<slot>
|
|
5
|
+
<HeadlessSelectTrigger
|
|
6
|
+
class="focus:outline-primary grid w-full cursor-default grid-cols-1 rounded-md bg-white py-1.5 pr-2 pl-3 text-left text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 focus:outline focus:outline-2 focus:-outline-offset-2 sm:text-sm/6"
|
|
7
|
+
:class="{ 'mt-1': label }"
|
|
8
|
+
>
|
|
9
|
+
<HeadlessSelectValue class="col-start-1 row-start-1 truncate pr-6" />
|
|
10
|
+
<IconCheveronDown
|
|
11
|
+
class="col-start-1 row-start-1 size-5 self-center justify-self-end text-gray-500 sm:size-4"
|
|
12
|
+
/>
|
|
13
|
+
</HeadlessSelectTrigger>
|
|
14
|
+
<HeadlessSelectOptions
|
|
15
|
+
class="z-50 overflow-auto rounded-lg bg-white text-base shadow-lg ring-1 ring-black/5 focus:outline-hidden"
|
|
16
|
+
>
|
|
17
|
+
<HeadlessSelectOption
|
|
18
|
+
v-for="option of $select?.options ?? []"
|
|
19
|
+
:key="option.key"
|
|
20
|
+
:value="option.value"
|
|
21
|
+
class="group p-1 outline-none"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
class="relative flex max-w-[calc(100vw-2rem)] cursor-pointer items-center truncate rounded-md px-2 py-1 select-none *:truncate group-data-[highlighted]:bg-gray-100 group-data-[state=checked]:font-semibold group-data-[state=unchecked]:opacity-50"
|
|
25
|
+
>
|
|
26
|
+
<span class="text-sm">
|
|
27
|
+
{{ option.label }}
|
|
28
|
+
</span>
|
|
29
|
+
</div>
|
|
30
|
+
</HeadlessSelectOption>
|
|
31
|
+
</HeadlessSelectOptions>
|
|
32
|
+
</slot>
|
|
33
|
+
</HeadlessSelect>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
import IconCheveronDown from '~icons/zondicons/cheveron-down';
|
|
38
|
+
|
|
39
|
+
import { useTemplateRef } from 'vue';
|
|
40
|
+
|
|
41
|
+
import HeadlessSelect from '@aerogel/core/components/headless/HeadlessSelect.vue';
|
|
42
|
+
import HeadlessSelectLabel from '@aerogel/core/components/headless/HeadlessSelectLabel.vue';
|
|
43
|
+
import HeadlessSelectTrigger from '@aerogel/core/components/headless/HeadlessSelectTrigger.vue';
|
|
44
|
+
import HeadlessSelectOptions from '@aerogel/core/components/headless/HeadlessSelectOptions.vue';
|
|
45
|
+
import HeadlessSelectOption from '@aerogel/core/components/headless/HeadlessSelectOption.vue';
|
|
46
|
+
import HeadlessSelectValue from '@aerogel/core/components/headless/HeadlessSelectValue.vue';
|
|
47
|
+
import type { SelectEmits, SelectProps } from '@aerogel/core/components/contracts/Select';
|
|
48
|
+
|
|
49
|
+
defineProps<SelectProps>();
|
|
50
|
+
defineEmits<SelectEmits>();
|
|
51
|
+
|
|
52
|
+
const $select = useTemplateRef('$select');
|
|
53
|
+
</script>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<HeadlessToast :class="renderedClasses">
|
|
3
|
+
<Markdown v-if="message" :text="message" inline />
|
|
4
|
+
|
|
5
|
+
<Button
|
|
6
|
+
v-for="(action, key) of actions"
|
|
7
|
+
:key
|
|
8
|
+
:action
|
|
9
|
+
:variant
|
|
10
|
+
:as="HeadlessToastAction"
|
|
11
|
+
/>
|
|
12
|
+
</HeadlessToast>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import type { HTMLAttributes } from 'vue';
|
|
17
|
+
|
|
18
|
+
import Button from '@aerogel/core/components/ui/Button.vue';
|
|
19
|
+
import Markdown from '@aerogel/core/components/ui/Markdown.vue';
|
|
20
|
+
import HeadlessToast from '@aerogel/core/components/headless/HeadlessToast.vue';
|
|
21
|
+
import HeadlessToastAction from '@aerogel/core/components/headless/HeadlessToastAction.vue';
|
|
22
|
+
import { computedVariantClasses } from '@aerogel/core/components/utils';
|
|
23
|
+
import type { ToastProps } from '@aerogel/core/components/contracts/Toast';
|
|
24
|
+
import type { Variants } from '@aerogel/core/components/utils';
|
|
25
|
+
|
|
26
|
+
const { class: baseClasses, variant = 'secondary' } = defineProps<ToastProps & { class?: HTMLAttributes['class'] }>();
|
|
27
|
+
const renderedClasses = computedVariantClasses<Variants<Pick<ToastProps, 'variant'>>>(
|
|
28
|
+
{ baseClasses, variant },
|
|
29
|
+
{
|
|
30
|
+
baseClasses: 'flex items-center gap-2 rounded-md p-2 ring-1 shadow-lg border-gray-200',
|
|
31
|
+
variants: {
|
|
32
|
+
variant: {
|
|
33
|
+
secondary: 'bg-gray-900 text-white ring-black',
|
|
34
|
+
danger: 'bg-red-50 text-red-900 ring-red-100',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: 'secondary',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
</script>
|