@aerogel/core 0.0.0-next.980a397d575dcb5ff8c5a0bff769d09f938ea03c → 0.0.0-next.9a02fcd3bcf698211dd7a71d4c48257c96dd7832
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.cjs.js +1 -1
- package/dist/aerogel-core.cjs.js.map +1 -1
- package/dist/aerogel-core.d.ts +553 -113
- package/dist/aerogel-core.esm.js +1 -1
- package/dist/aerogel-core.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/bootstrap/bootstrap.test.ts +3 -3
- package/src/bootstrap/index.ts +16 -5
- package/src/bootstrap/options.ts +3 -0
- package/src/components/AGAppLayout.vue +3 -2
- package/src/components/AGAppOverlays.vue +5 -1
- package/src/components/forms/AGCheckbox.vue +7 -1
- package/src/components/forms/AGInput.vue +8 -6
- package/src/components/forms/AGSelect.story.vue +21 -3
- package/src/components/forms/AGSelect.vue +10 -3
- package/src/components/headless/forms/AGHeadlessButton.vue +8 -8
- package/src/components/headless/forms/AGHeadlessInput.ts +5 -10
- package/src/components/headless/forms/AGHeadlessInputInput.vue +2 -0
- package/src/components/headless/forms/AGHeadlessSelect.ts +20 -22
- package/src/components/headless/forms/AGHeadlessSelect.vue +23 -22
- package/src/components/headless/forms/AGHeadlessSelectOption.vue +6 -6
- package/src/components/headless/modals/AGHeadlessModal.ts +19 -1
- package/src/components/headless/modals/AGHeadlessModal.vue +3 -5
- package/src/components/headless/snackbars/index.ts +23 -8
- package/src/components/lib/AGErrorMessage.vue +2 -2
- package/src/components/lib/AGMeasured.vue +15 -0
- package/src/components/lib/index.ts +1 -0
- package/src/components/modals/AGAlertModal.ts +15 -0
- package/src/components/modals/AGAlertModal.vue +3 -14
- package/src/components/modals/AGConfirmModal.ts +17 -0
- package/src/components/modals/AGConfirmModal.vue +6 -10
- package/src/components/modals/AGErrorReportModal.ts +27 -1
- package/src/components/modals/AGErrorReportModal.vue +7 -15
- package/src/components/modals/AGErrorReportModalButtons.vue +4 -2
- package/src/components/modals/AGLoadingModal.ts +14 -0
- package/src/components/modals/AGLoadingModal.vue +3 -7
- package/src/components/modals/AGModal.vue +14 -12
- package/src/components/modals/AGPromptModal.ts +30 -0
- package/src/components/modals/AGPromptModal.vue +34 -0
- package/src/components/modals/index.ts +11 -19
- package/src/components/snackbars/AGSnackbar.vue +2 -8
- package/src/components/utils.ts +10 -0
- package/src/directives/index.ts +3 -1
- package/src/directives/measure.ts +12 -0
- package/src/errors/Errors.ts +26 -24
- package/src/errors/index.ts +2 -11
- package/src/errors/utils.ts +19 -0
- package/src/forms/Form.ts +1 -0
- package/src/jobs/Job.ts +5 -0
- package/src/jobs/index.ts +7 -0
- package/src/lang/Lang.ts +11 -23
- package/src/main.ts +2 -0
- package/src/services/App.state.ts +1 -2
- package/src/services/App.ts +21 -3
- package/src/services/Events.test.ts +39 -0
- package/src/services/Events.ts +100 -30
- package/src/services/Service.ts +42 -12
- package/src/services/index.ts +2 -1
- package/src/services/store.ts +8 -5
- package/src/testing/index.ts +25 -0
- package/src/ui/UI.ts +98 -15
- package/src/ui/index.ts +8 -3
- package/src/utils/composition/events.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tailwindcss.test.ts +26 -0
- package/src/utils/tailwindcss.ts +7 -0
- package/src/utils/vue.ts +10 -1
package/src/ui/UI.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { ObjectValues } from '@noeldemartin/utils';
|
|
|
5
5
|
|
|
6
6
|
import Events from '@/services/Events';
|
|
7
7
|
import type { SnackbarAction, SnackbarColor } from '@/components/headless/snackbars';
|
|
8
|
+
import type { AGAlertModalProps, AGConfirmModalProps, AGLoadingModalProps, AGPromptModalProps } from '@/components';
|
|
8
9
|
|
|
9
10
|
import Service from './UI.state';
|
|
10
11
|
import type { Modal, ModalComponent, Snackbar } from './UI.state';
|
|
@@ -24,11 +25,26 @@ export const UIComponents = {
|
|
|
24
25
|
ConfirmModal: 'confirm-modal',
|
|
25
26
|
ErrorReportModal: 'error-report-modal',
|
|
26
27
|
LoadingModal: 'loading-modal',
|
|
28
|
+
PromptModal: 'prompt-modal',
|
|
27
29
|
Snackbar: 'snackbar',
|
|
30
|
+
StartupCrash: 'startup-crash',
|
|
28
31
|
} as const;
|
|
29
32
|
|
|
30
33
|
export type UIComponent = ObjectValues<typeof UIComponents>;
|
|
31
34
|
|
|
35
|
+
export interface ConfirmOptions {
|
|
36
|
+
acceptText?: string;
|
|
37
|
+
cancelText?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PromptOptions {
|
|
41
|
+
label?: string;
|
|
42
|
+
defaultValue?: string;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
acceptText?: string;
|
|
45
|
+
cancelText?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
export interface ShowSnackbarOptions {
|
|
33
49
|
component?: Component;
|
|
34
50
|
color?: SnackbarColor;
|
|
@@ -47,33 +63,98 @@ export class UIService extends Service {
|
|
|
47
63
|
public alert(message: string): void;
|
|
48
64
|
public alert(title: string, message: string): void;
|
|
49
65
|
public alert(messageOrTitle: string, message?: string): void {
|
|
50
|
-
const
|
|
66
|
+
const getProperties = (): AGAlertModalProps => {
|
|
67
|
+
if (typeof message !== 'string') {
|
|
68
|
+
return { message: messageOrTitle };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
title: messageOrTitle,
|
|
73
|
+
message,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
51
76
|
|
|
52
|
-
this.openModal(this.requireComponent(UIComponents.AlertModal),
|
|
77
|
+
this.openModal(this.requireComponent(UIComponents.AlertModal), getProperties());
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
public async confirm(message: string): Promise<boolean>;
|
|
56
|
-
public async confirm(title: string, message: string): Promise<boolean>;
|
|
57
|
-
public async confirm(
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
public async confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
|
|
81
|
+
public async confirm(title: string, message: string, options?: ConfirmOptions): Promise<boolean>;
|
|
82
|
+
public async confirm(
|
|
83
|
+
messageOrTitle: string,
|
|
84
|
+
messageOrOptions?: string | ConfirmOptions,
|
|
85
|
+
options?: ConfirmOptions,
|
|
86
|
+
): Promise<boolean> {
|
|
87
|
+
const getProperties = (): AGConfirmModalProps => {
|
|
88
|
+
if (typeof messageOrOptions !== 'string') {
|
|
89
|
+
return {
|
|
90
|
+
message: messageOrTitle,
|
|
91
|
+
...(messageOrOptions ?? {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
title: messageOrTitle,
|
|
97
|
+
message: messageOrOptions,
|
|
98
|
+
...(options ?? {}),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const modal = await this.openModal<ModalComponent<AGConfirmModalProps, boolean>>(
|
|
60
103
|
this.requireComponent(UIComponents.ConfirmModal),
|
|
61
|
-
|
|
104
|
+
getProperties(),
|
|
62
105
|
);
|
|
63
106
|
const result = await modal.beforeClose;
|
|
64
107
|
|
|
65
108
|
return result ?? false;
|
|
66
109
|
}
|
|
67
110
|
|
|
111
|
+
public async prompt(message: string, options?: PromptOptions): Promise<string | null>;
|
|
112
|
+
public async prompt(title: string, message: string, options?: PromptOptions): Promise<string | null>;
|
|
113
|
+
public async prompt(
|
|
114
|
+
messageOrTitle: string,
|
|
115
|
+
messageOrOptions?: string | PromptOptions,
|
|
116
|
+
options?: PromptOptions,
|
|
117
|
+
): Promise<string | null> {
|
|
118
|
+
const getProperties = (): AGPromptModalProps => {
|
|
119
|
+
if (typeof messageOrOptions !== 'string') {
|
|
120
|
+
return {
|
|
121
|
+
message: messageOrTitle,
|
|
122
|
+
...(messageOrOptions ?? {}),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
title: messageOrTitle,
|
|
128
|
+
message: messageOrOptions,
|
|
129
|
+
...(options ?? {}),
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const modal = await this.openModal<ModalComponent<AGPromptModalProps, string | null>>(
|
|
134
|
+
this.requireComponent(UIComponents.PromptModal),
|
|
135
|
+
getProperties(),
|
|
136
|
+
);
|
|
137
|
+
const result = await modal.beforeClose;
|
|
138
|
+
|
|
139
|
+
return result ?? null;
|
|
140
|
+
}
|
|
141
|
+
|
|
68
142
|
public async loading<T>(operation: Promise<T>): Promise<T>;
|
|
69
143
|
public async loading<T>(message: string, operation: Promise<T>): Promise<T>;
|
|
70
144
|
public async loading<T>(messageOrOperation: string | Promise<T>, operation?: Promise<T>): Promise<T> {
|
|
71
|
-
|
|
145
|
+
const getProperties = (): AGLoadingModalProps => {
|
|
146
|
+
if (typeof messageOrOperation !== 'string') {
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
72
149
|
|
|
73
|
-
|
|
74
|
-
|
|
150
|
+
return { message: messageOrOperation };
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const modal = await this.openModal(this.requireComponent(UIComponents.LoadingModal), getProperties());
|
|
75
154
|
|
|
76
155
|
try {
|
|
156
|
+
operation = typeof messageOrOperation === 'string' ? (operation as Promise<T>) : messageOrOperation;
|
|
157
|
+
|
|
77
158
|
const [result] = await Promise.all([operation, after({ seconds: 1 })]);
|
|
78
159
|
|
|
79
160
|
return result;
|
|
@@ -86,7 +167,7 @@ export class UIService extends Service {
|
|
|
86
167
|
const snackbar: Snackbar = {
|
|
87
168
|
id: uuid(),
|
|
88
169
|
properties: { message, ...options },
|
|
89
|
-
component: options.component ??
|
|
170
|
+
component: markRaw(options.component ?? this.requireComponent(UIComponents.Snackbar)),
|
|
90
171
|
};
|
|
91
172
|
|
|
92
173
|
this.setState('snackbars', this.snackbars.concat(snackbar));
|
|
@@ -189,14 +270,16 @@ export class UIService extends Service {
|
|
|
189
270
|
|
|
190
271
|
}
|
|
191
272
|
|
|
192
|
-
export default facade(
|
|
273
|
+
export default facade(UIService);
|
|
193
274
|
|
|
194
275
|
declare module '@/services/Events' {
|
|
195
276
|
export interface EventsPayload {
|
|
196
|
-
'modal-will-close': { modal: Modal; result?: unknown };
|
|
197
|
-
'modal-closed': { modal: Modal; result?: unknown };
|
|
198
277
|
'close-modal': { id: string; result?: unknown };
|
|
199
278
|
'hide-modal': { id: string };
|
|
279
|
+
'hide-overlays-backdrop': void;
|
|
280
|
+
'modal-closed': { modal: Modal; result?: unknown };
|
|
281
|
+
'modal-will-close': { modal: Modal; result?: unknown };
|
|
200
282
|
'show-modal': { id: string };
|
|
283
|
+
'show-overlays-backdrop': void;
|
|
201
284
|
}
|
|
202
285
|
}
|
package/src/ui/index.ts
CHANGED
|
@@ -8,13 +8,16 @@ import AGAlertModal from '../components/modals/AGAlertModal.vue';
|
|
|
8
8
|
import AGConfirmModal from '../components/modals/AGConfirmModal.vue';
|
|
9
9
|
import AGErrorReportModal from '../components/modals/AGErrorReportModal.vue';
|
|
10
10
|
import AGLoadingModal from '../components/modals/AGLoadingModal.vue';
|
|
11
|
+
import AGPromptModal from '../components/modals/AGPromptModal.vue';
|
|
11
12
|
import AGSnackbar from '../components/snackbars/AGSnackbar.vue';
|
|
13
|
+
import AGStartupCrash from '../components/lib/AGStartupCrash.vue';
|
|
12
14
|
import type { UIComponent } from './UI';
|
|
13
15
|
|
|
14
|
-
export { UI, UIComponents, UIComponent };
|
|
15
|
-
|
|
16
16
|
const services = { $ui: UI };
|
|
17
17
|
|
|
18
|
+
export * from './UI';
|
|
19
|
+
export { default as UI } from './UI';
|
|
20
|
+
|
|
18
21
|
export type UIServices = typeof services;
|
|
19
22
|
|
|
20
23
|
export default definePlugin({
|
|
@@ -24,7 +27,9 @@ export default definePlugin({
|
|
|
24
27
|
[UIComponents.ConfirmModal]: AGConfirmModal,
|
|
25
28
|
[UIComponents.ErrorReportModal]: AGErrorReportModal,
|
|
26
29
|
[UIComponents.LoadingModal]: AGLoadingModal,
|
|
30
|
+
[UIComponents.PromptModal]: AGPromptModal,
|
|
27
31
|
[UIComponents.Snackbar]: AGSnackbar,
|
|
32
|
+
[UIComponents.StartupCrash]: AGStartupCrash,
|
|
28
33
|
};
|
|
29
34
|
|
|
30
35
|
Object.entries({
|
|
@@ -37,7 +42,7 @@ export default definePlugin({
|
|
|
37
42
|
});
|
|
38
43
|
|
|
39
44
|
declare module '@/bootstrap/options' {
|
|
40
|
-
interface AerogelOptions {
|
|
45
|
+
export interface AerogelOptions {
|
|
41
46
|
components?: Partial<Record<UIComponent, Component>>;
|
|
42
47
|
}
|
|
43
48
|
}
|
|
@@ -14,6 +14,7 @@ export function useEvent<Event extends EventWithPayload>(
|
|
|
14
14
|
event: Event,
|
|
15
15
|
listener: EventListener<EventsPayload[Event]>
|
|
16
16
|
): void;
|
|
17
|
+
export function useEvent<Payload>(event: string, listener: (payload: Payload) => unknown): void;
|
|
17
18
|
export function useEvent<Event extends string>(event: UnknownEvent<Event>, listener: EventListener): void;
|
|
18
19
|
|
|
19
20
|
export function useEvent(event: string, listener: EventListener): void {
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { removeInteractiveClasses } from './tailwindcss';
|
|
4
|
+
|
|
5
|
+
describe('TailwindCSS utils', () => {
|
|
6
|
+
|
|
7
|
+
it('Removes interactive classes', () => {
|
|
8
|
+
const cases: [string, string][] = [
|
|
9
|
+
['text-red hover:text-green', 'text-red'],
|
|
10
|
+
['text-red hover:text-green text-lg', 'text-red text-lg'],
|
|
11
|
+
[
|
|
12
|
+
`
|
|
13
|
+
text-red text-lg
|
|
14
|
+
focus:text-yellow
|
|
15
|
+
hover:focus:text-black
|
|
16
|
+
`,
|
|
17
|
+
'text-red text-lg',
|
|
18
|
+
],
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
cases.forEach(([original, expected]) => {
|
|
22
|
+
expect(removeInteractiveClasses(original)).toEqual(expected);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
});
|
package/src/utils/vue.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fail } from '@noeldemartin/utils';
|
|
2
|
-
import { inject, reactive, ref } from 'vue';
|
|
2
|
+
import { computed, inject, reactive, ref, watch } from 'vue';
|
|
3
3
|
import type { Directive, InjectionKey, PropType, Ref, UnwrapNestedRefs } from 'vue';
|
|
4
4
|
|
|
5
5
|
type BaseProp<T> = {
|
|
@@ -30,6 +30,15 @@ export function componentRef<T>(): Ref<UnwrapNestedRefs<T> | undefined> {
|
|
|
30
30
|
return ref<UnwrapNestedRefs<T>>();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export function computedAsync<T>(getter: () => Promise<T>): Ref<T | undefined> {
|
|
34
|
+
const result = ref<T>();
|
|
35
|
+
const asyncValue = computed(getter);
|
|
36
|
+
|
|
37
|
+
watch(asyncValue, async () => (result.value = await asyncValue.value), { immediate: true });
|
|
38
|
+
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
export function defineDirective(directive: Directive): Directive {
|
|
34
43
|
return directive;
|
|
35
44
|
}
|