@aerogel/core 0.0.0-next.c4825c5cbe0fe3257e478c2a7ec8df27d5a72305 → 0.0.0-next.ce4783d09a83f492e439f8d4c39bc0b4998f4cbf

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.
Files changed (201) hide show
  1. package/dist/aerogel-core.css +1 -0
  2. package/dist/aerogel-core.d.ts +1943 -1948
  3. package/dist/aerogel-core.js +3557 -0
  4. package/dist/aerogel-core.js.map +1 -0
  5. package/package.json +32 -37
  6. package/src/bootstrap/bootstrap.test.ts +4 -7
  7. package/src/bootstrap/index.ts +14 -15
  8. package/src/bootstrap/options.ts +1 -1
  9. package/src/components/AppLayout.vue +14 -0
  10. package/src/components/{AGAppModals.vue → AppModals.vue} +3 -4
  11. package/src/components/AppOverlays.vue +9 -0
  12. package/src/components/AppToasts.vue +16 -0
  13. package/src/components/contracts/AlertModal.ts +19 -0
  14. package/src/components/contracts/Button.ts +16 -0
  15. package/src/components/contracts/ConfirmModal.ts +48 -0
  16. package/src/components/contracts/DropdownMenu.ts +25 -0
  17. package/src/components/contracts/ErrorReportModal.ts +33 -0
  18. package/src/components/contracts/Input.ts +26 -0
  19. package/src/components/contracts/LoadingModal.ts +26 -0
  20. package/src/components/contracts/Modal.ts +21 -0
  21. package/src/components/contracts/PromptModal.ts +34 -0
  22. package/src/components/contracts/Select.ts +45 -0
  23. package/src/components/contracts/Toast.ts +15 -0
  24. package/src/components/contracts/index.ts +11 -0
  25. package/src/components/headless/HeadlessButton.vue +51 -0
  26. package/src/components/headless/HeadlessInput.vue +59 -0
  27. package/src/components/headless/{forms/AGHeadlessInputDescription.vue → HeadlessInputDescription.vue} +7 -8
  28. package/src/components/headless/{forms/AGHeadlessInputError.vue → HeadlessInputError.vue} +4 -8
  29. package/src/components/headless/{forms/AGHeadlessInputInput.vue → HeadlessInputInput.vue} +17 -26
  30. package/src/components/headless/{forms/AGHeadlessInputLabel.vue → HeadlessInputLabel.vue} +3 -7
  31. package/src/components/headless/{forms/AGHeadlessInputTextArea.vue → HeadlessInputTextArea.vue} +10 -13
  32. package/src/components/headless/HeadlessModal.vue +57 -0
  33. package/src/components/headless/HeadlessModalContent.vue +30 -0
  34. package/src/components/headless/HeadlessModalDescription.vue +12 -0
  35. package/src/components/headless/HeadlessModalOverlay.vue +12 -0
  36. package/src/components/headless/HeadlessModalTitle.vue +12 -0
  37. package/src/components/headless/HeadlessSelect.vue +120 -0
  38. package/src/components/headless/{forms/AGHeadlessSelectError.vue → HeadlessSelectError.vue} +5 -6
  39. package/src/components/headless/HeadlessSelectLabel.vue +25 -0
  40. package/src/components/headless/HeadlessSelectOption.vue +34 -0
  41. package/src/components/headless/HeadlessSelectOptions.vue +42 -0
  42. package/src/components/headless/HeadlessSelectTrigger.vue +22 -0
  43. package/src/components/headless/HeadlessSelectValue.vue +18 -0
  44. package/src/components/headless/HeadlessSwitch.vue +96 -0
  45. package/src/components/headless/HeadlessToast.vue +18 -0
  46. package/src/components/headless/HeadlessToastAction.vue +13 -0
  47. package/src/components/headless/index.ts +20 -3
  48. package/src/components/index.ts +6 -11
  49. package/src/components/ui/AdvancedOptions.vue +18 -0
  50. package/src/components/ui/AlertModal.vue +17 -0
  51. package/src/components/ui/Button.vue +115 -0
  52. package/src/components/ui/Checkbox.vue +56 -0
  53. package/src/components/ui/ConfirmModal.vue +50 -0
  54. package/src/components/ui/DropdownMenu.vue +32 -0
  55. package/src/components/ui/DropdownMenuOption.vue +22 -0
  56. package/src/components/ui/DropdownMenuOptions.vue +44 -0
  57. package/src/components/ui/EditableContent.vue +82 -0
  58. package/src/components/ui/ErrorLogs.vue +19 -0
  59. package/src/components/ui/ErrorLogsModal.vue +48 -0
  60. package/src/components/ui/ErrorMessage.vue +15 -0
  61. package/src/components/ui/ErrorReportModal.vue +73 -0
  62. package/src/components/{modals/AGErrorReportModalButtons.vue → ui/ErrorReportModalButtons.vue} +34 -27
  63. package/src/components/ui/ErrorReportModalTitle.vue +24 -0
  64. package/src/components/{forms/AGForm.vue → ui/Form.vue} +4 -5
  65. package/src/components/ui/Input.vue +56 -0
  66. package/src/components/ui/Link.vue +12 -0
  67. package/src/components/ui/LoadingModal.vue +34 -0
  68. package/src/components/ui/Markdown.vue +97 -0
  69. package/src/components/ui/Modal.vue +123 -0
  70. package/src/components/{modals/AGModalContext.vue → ui/ModalContext.vue} +8 -9
  71. package/src/components/ui/ProgressBar.vue +51 -0
  72. package/src/components/ui/PromptModal.vue +38 -0
  73. package/src/components/ui/Select.vue +27 -0
  74. package/src/components/ui/SelectLabel.vue +21 -0
  75. package/src/components/ui/SelectOption.vue +29 -0
  76. package/src/components/ui/SelectOptions.vue +35 -0
  77. package/src/components/ui/SelectTrigger.vue +29 -0
  78. package/src/components/ui/SettingsModal.vue +15 -0
  79. package/src/components/{lib/AGStartupCrash.vue → ui/StartupCrash.vue} +8 -8
  80. package/src/components/ui/Switch.vue +11 -0
  81. package/src/components/ui/Toast.vue +46 -0
  82. package/src/components/ui/index.ts +33 -0
  83. package/src/directives/index.ts +9 -5
  84. package/src/directives/measure.ts +12 -6
  85. package/src/errors/Errors.state.ts +1 -1
  86. package/src/errors/Errors.ts +29 -27
  87. package/src/errors/index.ts +15 -8
  88. package/src/errors/settings/Debug.vue +39 -0
  89. package/src/errors/settings/index.ts +10 -0
  90. package/src/errors/utils.ts +1 -1
  91. package/src/forms/{Form.test.ts → FormController.test.ts} +32 -8
  92. package/src/forms/{Form.ts → FormController.ts} +42 -38
  93. package/src/forms/index.ts +2 -3
  94. package/src/forms/utils.ts +35 -35
  95. package/src/index.css +73 -0
  96. package/src/jobs/Job.ts +2 -2
  97. package/src/jobs/listeners.ts +1 -1
  98. package/src/lang/DefaultLangProvider.ts +7 -4
  99. package/src/lang/Lang.state.ts +1 -1
  100. package/src/lang/Lang.ts +1 -1
  101. package/src/lang/index.ts +12 -6
  102. package/src/lang/settings/Language.vue +48 -0
  103. package/src/lang/settings/index.ts +10 -0
  104. package/src/plugins/Plugin.ts +1 -1
  105. package/src/plugins/index.ts +10 -7
  106. package/src/services/App.state.ts +15 -4
  107. package/src/services/App.ts +12 -4
  108. package/src/services/Cache.ts +1 -1
  109. package/src/services/Events.test.ts +8 -8
  110. package/src/services/Events.ts +4 -10
  111. package/src/services/Service.ts +21 -21
  112. package/src/services/Storage.ts +3 -3
  113. package/src/services/index.ts +10 -6
  114. package/src/services/utils.ts +2 -2
  115. package/src/testing/index.ts +4 -3
  116. package/src/testing/setup.ts +3 -19
  117. package/src/ui/UI.state.ts +8 -13
  118. package/src/ui/UI.ts +124 -111
  119. package/src/ui/index.ts +27 -28
  120. package/src/utils/classes.ts +41 -0
  121. package/src/utils/composition/events.ts +4 -6
  122. package/src/utils/composition/forms.ts +20 -4
  123. package/src/utils/composition/state.ts +11 -2
  124. package/src/utils/index.ts +4 -1
  125. package/src/utils/markdown.ts +37 -5
  126. package/src/utils/types.ts +3 -0
  127. package/src/utils/vue.ts +31 -137
  128. package/dist/aerogel-core.cjs.js +0 -2
  129. package/dist/aerogel-core.cjs.js.map +0 -1
  130. package/dist/aerogel-core.esm.js +0 -2
  131. package/dist/aerogel-core.esm.js.map +0 -1
  132. package/histoire.config.ts +0 -7
  133. package/noeldemartin.config.js +0 -5
  134. package/postcss.config.js +0 -6
  135. package/src/assets/histoire.css +0 -3
  136. package/src/components/AGAppLayout.vue +0 -16
  137. package/src/components/AGAppOverlays.vue +0 -41
  138. package/src/components/AGAppSnackbars.vue +0 -13
  139. package/src/components/composition.ts +0 -23
  140. package/src/components/constants.ts +0 -8
  141. package/src/components/forms/AGButton.vue +0 -44
  142. package/src/components/forms/AGCheckbox.vue +0 -41
  143. package/src/components/forms/AGInput.vue +0 -40
  144. package/src/components/forms/AGSelect.story.vue +0 -46
  145. package/src/components/forms/AGSelect.vue +0 -60
  146. package/src/components/forms/index.ts +0 -5
  147. package/src/components/headless/forms/AGHeadlessButton.ts +0 -3
  148. package/src/components/headless/forms/AGHeadlessButton.vue +0 -62
  149. package/src/components/headless/forms/AGHeadlessInput.ts +0 -34
  150. package/src/components/headless/forms/AGHeadlessInput.vue +0 -70
  151. package/src/components/headless/forms/AGHeadlessSelect.ts +0 -42
  152. package/src/components/headless/forms/AGHeadlessSelect.vue +0 -77
  153. package/src/components/headless/forms/AGHeadlessSelectButton.vue +0 -24
  154. package/src/components/headless/forms/AGHeadlessSelectLabel.vue +0 -24
  155. package/src/components/headless/forms/AGHeadlessSelectOption.ts +0 -4
  156. package/src/components/headless/forms/AGHeadlessSelectOption.vue +0 -39
  157. package/src/components/headless/forms/AGHeadlessSelectOptions.ts +0 -3
  158. package/src/components/headless/forms/composition.ts +0 -10
  159. package/src/components/headless/forms/index.ts +0 -18
  160. package/src/components/headless/modals/AGHeadlessModal.ts +0 -36
  161. package/src/components/headless/modals/AGHeadlessModal.vue +0 -92
  162. package/src/components/headless/modals/AGHeadlessModalPanel.vue +0 -32
  163. package/src/components/headless/modals/AGHeadlessModalTitle.vue +0 -23
  164. package/src/components/headless/modals/index.ts +0 -4
  165. package/src/components/headless/snackbars/AGHeadlessSnackbar.vue +0 -10
  166. package/src/components/headless/snackbars/index.ts +0 -40
  167. package/src/components/interfaces.ts +0 -24
  168. package/src/components/lib/AGErrorMessage.vue +0 -16
  169. package/src/components/lib/AGLink.vue +0 -9
  170. package/src/components/lib/AGMarkdown.vue +0 -54
  171. package/src/components/lib/AGMeasured.vue +0 -16
  172. package/src/components/lib/AGProgressBar.vue +0 -30
  173. package/src/components/lib/index.ts +0 -6
  174. package/src/components/modals/AGAlertModal.ts +0 -18
  175. package/src/components/modals/AGAlertModal.vue +0 -14
  176. package/src/components/modals/AGConfirmModal.ts +0 -42
  177. package/src/components/modals/AGConfirmModal.vue +0 -26
  178. package/src/components/modals/AGErrorReportModal.ts +0 -49
  179. package/src/components/modals/AGErrorReportModal.vue +0 -54
  180. package/src/components/modals/AGErrorReportModalTitle.vue +0 -25
  181. package/src/components/modals/AGLoadingModal.ts +0 -29
  182. package/src/components/modals/AGLoadingModal.vue +0 -15
  183. package/src/components/modals/AGModal.ts +0 -11
  184. package/src/components/modals/AGModal.vue +0 -39
  185. package/src/components/modals/AGModalContext.ts +0 -8
  186. package/src/components/modals/AGModalTitle.vue +0 -9
  187. package/src/components/modals/AGPromptModal.ts +0 -41
  188. package/src/components/modals/AGPromptModal.vue +0 -34
  189. package/src/components/modals/index.ts +0 -17
  190. package/src/components/snackbars/AGSnackbar.vue +0 -36
  191. package/src/components/snackbars/index.ts +0 -3
  192. package/src/components/utils.ts +0 -10
  193. package/src/directives/initial-focus.ts +0 -11
  194. package/src/forms/composition.ts +0 -6
  195. package/src/main.histoire.ts +0 -1
  196. package/src/utils/tailwindcss.test.ts +0 -26
  197. package/src/utils/tailwindcss.ts +0 -7
  198. package/tailwind.config.js +0 -4
  199. package/tsconfig.json +0 -11
  200. package/vite.config.ts +0 -17
  201. /package/src/{main.ts → index.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { GetClosureArgs } from '@noeldemartin/utils';
2
2
 
3
- import App from '@/services/App';
3
+ import App from '@aerogel/core/services/App';
4
4
 
5
5
  import type { Plugin } from './Plugin';
6
6
 
@@ -13,13 +13,16 @@ export function definePlugin<T extends Plugin>(plugin: T): T {
13
13
  export async function installPlugins(plugins: Plugin[], ...args: GetClosureArgs<Plugin['install']>): Promise<void> {
14
14
  App.setState(
15
15
  'plugins',
16
- plugins.reduce((pluginsMap, plugin) => {
17
- if (plugin.name) {
18
- pluginsMap[plugin.name] = plugin;
19
- }
16
+ plugins.reduce(
17
+ (pluginsMap, plugin) => {
18
+ if (plugin.name) {
19
+ pluginsMap[plugin.name] = plugin;
20
+ }
20
21
 
21
- return pluginsMap;
22
- }, {} as Record<string, Plugin>),
22
+ return pluginsMap;
23
+ },
24
+ {} as Record<string, Plugin>,
25
+ ),
23
26
  );
24
27
 
25
28
  await Promise.all(plugins.map((plugin) => plugin.install(...args)) ?? []);
@@ -1,18 +1,29 @@
1
1
  import Aerogel from 'virtual:aerogel';
2
2
 
3
- import type { App } from 'vue';
3
+ import { getEnv } from '@noeldemartin/utils';
4
+ import type { App, Component } from 'vue';
4
5
 
5
- import { defineServiceState } from '@/services/Service';
6
- import type { Plugin } from '@/plugins/Plugin';
6
+ import { defineServiceState } from '@aerogel/core/services/Service';
7
+ import type { Plugin } from '@aerogel/core/plugins/Plugin';
8
+
9
+ export interface AppSetting {
10
+ component: Component;
11
+ priority: number;
12
+ }
13
+
14
+ export function defineSettings<T extends AppSetting[]>(settings: T): T {
15
+ return settings;
16
+ }
7
17
 
8
18
  export default defineServiceState({
9
19
  name: 'app',
10
20
  initialState: {
11
21
  plugins: {} as Record<string, Plugin>,
12
22
  instance: null as App | null,
13
- environment: Aerogel.environment,
23
+ environment: getEnv() ?? 'development',
14
24
  version: Aerogel.version,
15
25
  sourceUrl: Aerogel.sourceUrl,
26
+ settings: [] as AppSetting[],
16
27
  },
17
28
  computed: {
18
29
  development: (state) => state.environment === 'development',
@@ -1,13 +1,17 @@
1
1
  import Aerogel from 'virtual:aerogel';
2
2
 
3
3
  import { PromisedValue, facade, forever, updateLocationQueryParameters } from '@noeldemartin/utils';
4
+ import { markRaw } from 'vue';
4
5
 
5
- import Events from '@/services/Events';
6
- import type { Plugin } from '@/plugins';
7
- import type { Services } from '@/services';
6
+ import Events from '@aerogel/core/services/Events';
7
+ import type { Plugin } from '@aerogel/core/plugins';
8
+ import type { AppSetting, Services } from '@aerogel/core/services';
8
9
 
9
10
  import Service from './App.state';
10
11
 
12
+ export { defineSettings } from './App.state';
13
+ export type { AppSetting } from './App.state';
14
+
11
15
  export class AppService extends Service {
12
16
 
13
17
  public readonly name = Aerogel.name;
@@ -22,6 +26,10 @@ export class AppService extends Service {
22
26
  return this.mounted.isResolved();
23
27
  }
24
28
 
29
+ public addSetting(setting: AppSetting): void {
30
+ this.settings.push(markRaw(setting));
31
+ }
32
+
25
33
  public async whenReady<T>(callback: () => T): Promise<T> {
26
34
  const result = await this.ready.then(callback);
27
35
 
@@ -45,7 +53,7 @@ export class AppService extends Service {
45
53
  return this.instance?.config.globalProperties[name] ?? null;
46
54
  }
47
55
 
48
- protected async boot(): Promise<void> {
56
+ protected override async boot(): Promise<void> {
49
57
  Events.once('application-ready', () => this.ready.resolve());
50
58
  Events.once('application-mounted', () => this.mounted.resolve());
51
59
  }
@@ -1,6 +1,6 @@
1
1
  import { PromisedValue, facade, tap } from '@noeldemartin/utils';
2
2
 
3
- import Service from '@/services/Service';
3
+ import Service from '@aerogel/core/services/Service';
4
4
 
5
5
  export class CacheService extends Service {
6
6
 
@@ -10,12 +10,12 @@ describe('Events', () => {
10
10
  // Arrange
11
11
  let counter = 0;
12
12
 
13
- Events.on('trigger', () => counter++);
13
+ Events.on('application-mounted', () => counter++);
14
14
 
15
15
  // Act
16
- await Events.emit('trigger');
17
- await Events.emit('trigger');
18
- await Events.emit('trigger');
16
+ await Events.emit('application-mounted');
17
+ await Events.emit('application-mounted');
18
+ await Events.emit('application-mounted');
19
19
 
20
20
  // Assert
21
21
  expect(counter).toEqual(3);
@@ -25,12 +25,12 @@ describe('Events', () => {
25
25
  // Arrange
26
26
  const storage: string[] = [];
27
27
 
28
- Events.on('trigger', () => storage.push('second'));
29
- Events.on('trigger', { priority: EventListenerPriorities.Low }, () => storage.push('third'));
30
- Events.on('trigger', { priority: EventListenerPriorities.High }, () => storage.push('first'));
28
+ Events.on('application-mounted', () => storage.push('second'));
29
+ Events.on('application-mounted', { priority: EventListenerPriorities.Low }, () => storage.push('third'));
30
+ Events.on('application-mounted', { priority: EventListenerPriorities.High }, () => storage.push('first'));
31
31
 
32
32
  // Act
33
- await Events.emit('trigger');
33
+ await Events.emit('application-mounted');
34
34
 
35
35
  // Assert
36
36
  expect(storage).toEqual(['first', 'second', 'third']);
@@ -1,6 +1,6 @@
1
1
  import { arrayRemove, facade, fail, tap } from '@noeldemartin/utils';
2
2
 
3
- import Service from '@/services/Service';
3
+ import Service from '@aerogel/core/services/Service';
4
4
 
5
5
  export interface EventsPayload {}
6
6
  export interface EventListenerOptions {
@@ -10,7 +10,6 @@ export type AerogelGlobalEvents = Partial<{ [Event in EventWithoutPayload]: () =
10
10
  Partial<{ [Event in EventWithPayload]: EventListener<EventsPayload[Event]> }>;
11
11
 
12
12
  export type EventListener<T = unknown> = (payload: T) => unknown;
13
- export type UnknownEvent<T> = T extends keyof EventsPayload ? never : T;
14
13
 
15
14
  export type EventWithoutPayload = {
16
15
  [K in keyof EventsPayload]: EventsPayload[K] extends void ? K : never;
@@ -32,14 +31,14 @@ export class EventsService extends Service {
32
31
 
33
32
  private listeners: Record<string, { priorities: number[]; handlers: Record<number, EventListener[]> }> = {};
34
33
 
35
- protected async boot(): Promise<void> {
34
+ protected override async boot(): Promise<void> {
36
35
  Object.entries(globalThis.__aerogelEvents__ ?? {}).forEach(([event, listener]) =>
37
- this.on(event as string, listener as EventListener));
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ this.on(event as any, listener as EventListener));
38
38
  }
39
39
 
40
40
  public emit<Event extends EventWithoutPayload>(event: Event): Promise<void>;
41
41
  public emit<Event extends EventWithPayload>(event: Event, payload: EventsPayload[Event]): Promise<void>;
42
- public emit<Event extends string>(event: UnknownEvent<Event>, payload?: unknown): Promise<void>;
43
42
  public async emit(event: string, payload?: unknown): Promise<void> {
44
43
  const listeners = this.listeners[event] ?? { priorities: [], handlers: {} };
45
44
 
@@ -55,9 +54,6 @@ export class EventsService extends Service {
55
54
  public on<Event extends EventWithPayload>(event: Event, listener: EventListener<EventsPayload[Event]>): () => void | void; // prettier-ignore
56
55
  public on<Event extends EventWithPayload>(event: Event, priority: EventListenerPriority, listener: EventListener<EventsPayload[Event]>): () => void | void; // prettier-ignore
57
56
  public on<Event extends EventWithPayload>(event: Event, options: Partial<EventListenerOptions>, listener: EventListener<EventsPayload[Event]>): () => void | void; // prettier-ignore
58
- public on<Event extends string>(event: UnknownEvent<Event>, listener: EventListener): () => void;
59
- public on<Event extends string>(event: UnknownEvent<Event>, priority: EventListenerPriority, listener: EventListener): () => void; // prettier-ignore
60
- public on<Event extends string>(event: UnknownEvent<Event>, options: Partial<EventListenerOptions>, listener: EventListener): () => void; // prettier-ignore
61
57
  /* eslint-enable max-len */
62
58
 
63
59
  public on(
@@ -83,8 +79,6 @@ export class EventsService extends Service {
83
79
  public once<Event extends EventWithoutPayload>(event: Event, options: Partial<EventListenerOptions>, listener: () => unknown): () => void; // prettier-ignore
84
80
  public once<Event extends EventWithPayload>(event: Event, listener: EventListener<EventsPayload[Event]>): () => void | void; // prettier-ignore
85
81
  public once<Event extends EventWithPayload>(event: Event, options: Partial<EventListenerOptions>, listener: EventListener<EventsPayload[Event]>): () => void | void; // prettier-ignore
86
- public once<Event extends string>(event: UnknownEvent<Event>, listener: EventListener): () => void;
87
- public once<Event extends string>(event: UnknownEvent<Event>, options: Partial<EventListenerOptions>, listener: EventListener): () => void; // prettier-ignore
88
82
  /* eslint-enable max-len */
89
83
 
90
84
  public once(
@@ -11,9 +11,9 @@ import {
11
11
  import type { Constructor, Nullable } from '@noeldemartin/utils';
12
12
  import type { Store } from 'pinia';
13
13
 
14
- import ServiceBootError from '@/errors/ServiceBootError';
15
- import { defineServiceStore } from '@/services/store';
16
- import type { Unref } from '@/utils/vue';
14
+ import ServiceBootError from '@aerogel/core/errors/ServiceBootError';
15
+ import { defineServiceStore } from '@aerogel/core/services/store';
16
+ import type { Unref } from '@aerogel/core/utils/vue';
17
17
 
18
18
  export type ServiceState = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any
19
19
  export type DefaultServiceState = any; // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -32,7 +32,7 @@ export type StateWatchers<TService extends Service, TState extends ServiceState>
32
32
  export type ServiceWithState<
33
33
  State extends ServiceState = ServiceState,
34
34
  ComputedState extends ServiceState = {},
35
- ServiceStorage = Partial<State>
35
+ ServiceStorage = Partial<State>,
36
36
  > = Constructor<Unref<State>> &
37
37
  Constructor<ComputedState> &
38
38
  Constructor<Service<Unref<State>, ComputedState, Unref<ServiceStorage>>>;
@@ -40,7 +40,7 @@ export type ServiceWithState<
40
40
  export function defineServiceState<
41
41
  State extends ServiceState = ServiceState,
42
42
  ComputedState extends ServiceState = {},
43
- ServiceStorage = Partial<State>
43
+ ServiceStorage = Partial<State>,
44
44
  >(options: {
45
45
  name: string;
46
46
  initialState: State | (() => State);
@@ -52,17 +52,17 @@ export function defineServiceState<
52
52
  }): ServiceWithState<State, ComputedState, ServiceStorage> {
53
53
  return class extends Service<Unref<State>, ComputedState, ServiceStorage> {
54
54
 
55
- public static persist = (options.persist as string[]) ?? [];
55
+ public static override persist = (options.persist as string[]) ?? [];
56
56
 
57
- protected usesStore(): boolean {
57
+ protected override usesStore(): boolean {
58
58
  return true;
59
59
  }
60
60
 
61
- protected getName(): string | null {
61
+ protected override getName(): string | null {
62
62
  return options.name ?? null;
63
63
  }
64
64
 
65
- protected getInitialState(): Unref<State> {
65
+ protected override getInitialState(): Unref<State> {
66
66
  if (typeof options.initialState === 'function') {
67
67
  return options.initialState();
68
68
  }
@@ -86,19 +86,19 @@ export function defineServiceState<
86
86
  }, {} as Unref<State>);
87
87
  }
88
88
 
89
- protected getComputedStateDefinition(): ComputedStateDefinition<Unref<State>, ComputedState> {
89
+ protected override getComputedStateDefinition(): ComputedStateDefinition<Unref<State>, ComputedState> {
90
90
  return (options.computed ?? {}) as ComputedStateDefinition<Unref<State>, ComputedState>;
91
91
  }
92
92
 
93
- protected getStateWatchers(): StateWatchers<Service, Unref<State>> {
93
+ protected override getStateWatchers(): StateWatchers<Service, Unref<State>> {
94
94
  return (options.watch ?? {}) as StateWatchers<Service, Unref<State>>;
95
95
  }
96
96
 
97
- protected serializePersistedState(state: Partial<State>): ServiceStorage {
97
+ protected override serializePersistedState(state: Partial<State>): ServiceStorage {
98
98
  return options.serialize?.(state) ?? (state as ServiceStorage);
99
99
  }
100
100
 
101
- protected deserializePersistedState(state: ServiceStorage): Partial<State> {
101
+ protected override deserializePersistedState(state: ServiceStorage): Partial<State> {
102
102
  return options.restore?.(state) ?? (state as Partial<State>);
103
103
  }
104
104
 
@@ -108,7 +108,7 @@ export function defineServiceState<
108
108
  export default class Service<
109
109
  State extends ServiceState = DefaultServiceState,
110
110
  ComputedState extends ServiceState = {},
111
- ServiceStorage = Partial<State>
111
+ ServiceStorage = Partial<State>,
112
112
  > extends MagicObject {
113
113
 
114
114
  public static persist: string[] = [];
@@ -142,9 +142,9 @@ export default class Service<
142
142
  return this._booted;
143
143
  }
144
144
 
145
- public static<T extends typeof Service>(): T;
146
- public static<T extends typeof Service, K extends keyof T>(property: K): T[K];
147
- public static<T extends typeof Service, K extends keyof T>(property?: K): T | T[K] {
145
+ public override static<T extends typeof Service>(): T;
146
+ public override static<T extends typeof Service, K extends keyof T>(property: K): T[K];
147
+ public override static<T extends typeof Service, K extends keyof T>(property?: K): T | T[K] {
148
148
  return super.static<T, K>(property as K);
149
149
  }
150
150
 
@@ -182,10 +182,10 @@ export default class Service<
182
182
  const store = this._store as any;
183
183
 
184
184
  if (property) {
185
- return store ? store[property] : undefined;
185
+ return store ? store[property] : (undefined as State[P]);
186
186
  }
187
187
 
188
- return store ? store : {};
188
+ return store ? store : ({} as State);
189
189
  }
190
190
 
191
191
  public setState<P extends keyof State>(property: P, value: State[P]): void;
@@ -219,7 +219,7 @@ export default class Service<
219
219
  this.onPersistentStateUpdated(state);
220
220
  }
221
221
 
222
- protected __get(property: string): unknown {
222
+ protected override __get(property: string): unknown {
223
223
  if (this.hasState(property)) {
224
224
  return this.getState(property);
225
225
  }
@@ -227,7 +227,7 @@ export default class Service<
227
227
  return super.__get(property);
228
228
  }
229
229
 
230
- protected __set(property: string, value: unknown): void {
230
+ protected override __set(property: string, value: unknown): void {
231
231
  this.setState({ [property]: value } as Partial<State>);
232
232
  }
233
233
 
@@ -1,7 +1,7 @@
1
1
  import { facade } from '@noeldemartin/utils';
2
2
 
3
- import Events from '@/services/Events';
4
- import Service from '@/services/Service';
3
+ import Events from '@aerogel/core/services/Events';
4
+ import Service from '@aerogel/core/services/Service';
5
5
 
6
6
  export class StorageService extends Service {
7
7
 
@@ -13,7 +13,7 @@ export class StorageService extends Service {
13
13
 
14
14
  export default facade(StorageService);
15
15
 
16
- declare module '@/services/Events' {
16
+ declare module '@aerogel/core/services/Events' {
17
17
  export interface EventsPayload {
18
18
  'purge-storage': void;
19
19
  }
@@ -1,6 +1,7 @@
1
- import type { App as VueApp } from 'vue';
1
+ import type { App as AppInstance } from 'vue';
2
2
 
3
- import { definePlugin } from '@/plugins';
3
+ import { definePlugin } from '@aerogel/core/plugins';
4
+ import { isDevelopment, isTesting } from '@noeldemartin/utils';
4
5
 
5
6
  import App from './App';
6
7
  import Cache from './Cache';
@@ -8,6 +9,7 @@ import Events from './Events';
8
9
  import Service from './Service';
9
10
  import Storage from './Storage';
10
11
  import { getPiniaStore } from './store';
12
+ import type { AppSetting } from './App.state';
11
13
 
12
14
  export * from './App';
13
15
  export * from './Cache';
@@ -28,7 +30,7 @@ export type DefaultServices = typeof defaultServices;
28
30
 
29
31
  export interface Services extends DefaultServices {}
30
32
 
31
- export async function bootServices(app: VueApp, services: Record<string, Service>): Promise<void> {
33
+ export async function bootServices(app: AppInstance, services: Record<string, Service>): Promise<void> {
32
34
  await Promise.all(
33
35
  Object.entries(services).map(async ([name, service]) => {
34
36
  await service
@@ -39,7 +41,7 @@ export async function bootServices(app: VueApp, services: Record<string, Service
39
41
 
40
42
  Object.assign(app.config.globalProperties, services);
41
43
 
42
- if (App.development || App.testing) {
44
+ if (isDevelopment() || isTesting()) {
43
45
  Object.assign(globalThis, services);
44
46
  }
45
47
  }
@@ -52,17 +54,19 @@ export default definePlugin({
52
54
  };
53
55
 
54
56
  app.use(getPiniaStore());
57
+ options.settings?.forEach((setting) => App.addSetting(setting));
55
58
 
56
59
  await bootServices(app, services);
57
60
  },
58
61
  });
59
62
 
60
- declare module '@/bootstrap/options' {
63
+ declare module '@aerogel/core/bootstrap/options' {
61
64
  export interface AerogelOptions {
62
65
  services?: Record<string, Service>;
66
+ settings?: AppSetting[];
63
67
  }
64
68
  }
65
69
 
66
- declare module '@vue/runtime-core' {
70
+ declare module 'vue' {
67
71
  interface ComponentCustomProperties extends Services {}
68
72
  }
@@ -2,14 +2,14 @@ import { objectOnly } from '@noeldemartin/utils';
2
2
 
3
3
  export type Replace<
4
4
  TOriginal extends Record<string, unknown>,
5
- TReplacements extends Partial<Record<keyof TOriginal, unknown>>
5
+ TReplacements extends Partial<Record<keyof TOriginal, unknown>>,
6
6
  > = {
7
7
  [K in keyof TOriginal]: TReplacements extends Record<K, infer Replacement> ? Replacement : TOriginal[K];
8
8
  };
9
9
 
10
10
  export function replaceExisting<
11
11
  TOriginal extends Record<string, unknown>,
12
- TReplacements extends Partial<Record<keyof TOriginal, unknown>>
12
+ TReplacements extends Partial<Record<keyof TOriginal, unknown>>,
13
13
  >(original: TOriginal, replacements: TReplacements): Replace<TOriginal, TReplacements> {
14
14
  return {
15
15
  ...original,
@@ -1,7 +1,8 @@
1
+ import { isTesting } from '@noeldemartin/utils';
1
2
  import type { GetClosureArgs } from '@noeldemartin/utils';
2
3
 
3
- import Events from '@/services/Events';
4
- import { definePlugin } from '@/plugins';
4
+ import Events from '@aerogel/core/services/Events';
5
+ import { definePlugin } from '@aerogel/core/plugins';
5
6
 
6
7
  export interface AerogelTestingRuntime {
7
8
  on: (typeof Events)['on'];
@@ -9,7 +10,7 @@ export interface AerogelTestingRuntime {
9
10
 
10
11
  export default definePlugin({
11
12
  async install() {
12
- if (import.meta.env.MODE !== 'testing') {
13
+ if (!isTesting()) {
13
14
  return;
14
15
  }
15
16
 
@@ -1,27 +1,11 @@
1
- import { mock, tap, toString } from '@noeldemartin/utils';
1
+ import { FakeLocalStorage } from '@noeldemartin/testing';
2
2
  import { beforeEach, vi } from 'vitest';
3
3
 
4
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- tap(globalThis, (global: any) => {
6
- const localStorage: Record<string, string> = {};
7
-
8
- global.jest = vi;
9
- global.navigator = { languages: ['en'] };
10
- global.localStorage = mock<Storage>({
11
- getItem: (key) => localStorage[key] ?? null,
12
- setItem(key, value) {
13
- localStorage[key] = toString(value);
14
- },
15
- });
16
- });
17
-
18
4
  vi.mock('dompurify', async () => {
19
5
  return { default: { sanitize: (html: string) => html } };
20
6
  });
21
7
 
22
8
  beforeEach(() => {
23
- vi.stubGlobal('document', {
24
- querySelector: () => null,
25
- getElementById: () => null,
26
- });
9
+ FakeLocalStorage.reset();
10
+ FakeLocalStorage.patchGlobal();
27
11
  });
@@ -1,25 +1,19 @@
1
1
  import type { Component } from 'vue';
2
2
 
3
- import { defineServiceState } from '@/services/Service';
3
+ import { defineServiceState } from '@aerogel/core/services/Service';
4
4
 
5
5
  import { Layouts, getCurrentLayout } from './utils';
6
6
 
7
- export interface Modal<T = unknown> {
7
+ export interface UIModal<T = unknown> {
8
8
  id: string;
9
9
  properties: Record<string, unknown>;
10
10
  component: Component;
11
+ closing: boolean;
11
12
  beforeClose: Promise<T | undefined>;
12
13
  afterClose: Promise<T | undefined>;
13
14
  }
14
15
 
15
- export interface ModalComponent<
16
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
- Properties extends Record<string, unknown> = Record<string, unknown>,
18
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
- Result = unknown
20
- > {}
21
-
22
- export interface Snackbar {
16
+ export interface UIToast {
23
17
  id: string;
24
18
  component: Component;
25
19
  properties: Record<string, unknown>;
@@ -28,12 +22,13 @@ export interface Snackbar {
28
22
  export default defineServiceState({
29
23
  name: 'ui',
30
24
  initialState: {
31
- modals: [] as Modal[],
32
- snackbars: [] as Snackbar[],
25
+ modals: [] as UIModal[],
26
+ toasts: [] as UIToast[],
33
27
  layout: getCurrentLayout(),
34
28
  },
35
29
  computed: {
36
- mobile: ({ layout }) => layout === Layouts.Mobile,
37
30
  desktop: ({ layout }) => layout === Layouts.Desktop,
31
+ mobile: ({ layout }) => layout === Layouts.Mobile,
32
+ openModals: ({ modals }) => modals.filter(({ closing }) => !closing),
38
33
  },
39
34
  });