@aerogel/core 0.1.0 → 0.1.1-next.095137d5f89c4b989d4961087f7a670de815e07f

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 (67) hide show
  1. package/dist/aerogel-core.d.ts +534 -312
  2. package/dist/aerogel-core.js +1979 -1595
  3. package/dist/aerogel-core.js.map +1 -1
  4. package/package.json +4 -2
  5. package/src/bootstrap/index.ts +2 -1
  6. package/src/components/AppLayout.vue +1 -1
  7. package/src/components/AppOverlays.vue +3 -2
  8. package/src/components/contracts/AlertModal.ts +1 -1
  9. package/src/components/contracts/Button.ts +1 -1
  10. package/src/components/contracts/Combobox.ts +5 -0
  11. package/src/components/contracts/ConfirmModal.ts +5 -2
  12. package/src/components/contracts/Modal.ts +8 -3
  13. package/src/components/contracts/PromptModal.ts +6 -2
  14. package/src/components/contracts/Select.ts +98 -4
  15. package/src/components/contracts/Toast.ts +1 -1
  16. package/src/components/contracts/index.ts +1 -0
  17. package/src/components/headless/HeadlessInputInput.vue +13 -5
  18. package/src/components/headless/HeadlessModal.vue +6 -34
  19. package/src/components/headless/HeadlessModalContent.vue +5 -12
  20. package/src/components/headless/HeadlessSelect.vue +10 -91
  21. package/src/components/headless/HeadlessSelectOption.vue +1 -5
  22. package/src/components/index.ts +1 -1
  23. package/src/components/ui/AdvancedOptions.vue +4 -13
  24. package/src/components/ui/Button.vue +1 -0
  25. package/src/components/ui/Combobox.vue +94 -0
  26. package/src/components/ui/ComboboxLabel.vue +29 -0
  27. package/src/components/ui/ComboboxOption.vue +46 -0
  28. package/src/components/ui/ComboboxOptions.vue +71 -0
  29. package/src/components/ui/ComboboxTrigger.vue +67 -0
  30. package/src/components/ui/ConfirmModal.vue +7 -2
  31. package/src/components/ui/Details.vue +33 -0
  32. package/src/components/ui/Form.vue +1 -1
  33. package/src/components/ui/Input.vue +12 -4
  34. package/src/components/ui/LoadingModal.vue +1 -2
  35. package/src/components/ui/Modal.vue +53 -33
  36. package/src/components/ui/ProgressBar.vue +16 -2
  37. package/src/components/ui/PromptModal.vue +7 -2
  38. package/src/components/ui/Select.vue +2 -0
  39. package/src/components/ui/SelectTrigger.vue +13 -2
  40. package/src/components/ui/SettingsModal.vue +1 -1
  41. package/src/components/ui/Toast.vue +1 -0
  42. package/src/components/ui/index.ts +6 -1
  43. package/src/components/vue/Provide.vue +11 -0
  44. package/src/components/vue/index.ts +1 -0
  45. package/src/directives/index.ts +10 -8
  46. package/src/directives/safe-html.ts +10 -0
  47. package/src/errors/Errors.ts +4 -0
  48. package/src/forms/FormController.test.ts +4 -4
  49. package/src/forms/FormController.ts +7 -3
  50. package/src/forms/index.ts +11 -0
  51. package/src/forms/utils.ts +36 -17
  52. package/src/forms/validation.ts +5 -1
  53. package/src/index.css +10 -0
  54. package/src/jobs/Job.ts +1 -1
  55. package/src/services/App.state.ts +1 -0
  56. package/src/services/App.ts +4 -0
  57. package/src/services/index.ts +7 -0
  58. package/src/ui/UI.state.ts +0 -11
  59. package/src/ui/UI.ts +42 -125
  60. package/src/ui/index.ts +1 -0
  61. package/src/ui/modals.ts +36 -0
  62. package/src/utils/composition/reactiveSet.test.ts +32 -0
  63. package/src/utils/composition/reactiveSet.ts +53 -0
  64. package/src/utils/index.ts +2 -0
  65. package/src/utils/time.ts +2 -0
  66. package/src/components/AppModals.vue +0 -14
  67. package/src/components/ui/ModalContext.vue +0 -31
@@ -2,11 +2,15 @@
2
2
  <HeadlessSelectTrigger :class="renderedClasses">
3
3
  <HeadlessSelectValue class="col-start-1 row-start-1 truncate pr-6" />
4
4
  <IconCheveronDown class="col-start-1 row-start-1 size-5 self-center justify-self-end text-gray-500 sm:size-4" />
5
+ <div v-if="select?.errors" class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
6
+ <IconExclamationSolid class="size-5 text-red-500" />
7
+ </div>
5
8
  </HeadlessSelectTrigger>
6
9
  </template>
7
10
 
8
11
  <script setup lang="ts">
9
12
  import IconCheveronDown from '~icons/zondicons/cheveron-down';
13
+ import IconExclamationSolid from '~icons/zondicons/exclamation-solid';
10
14
 
11
15
  import { computed } from 'vue';
12
16
  import type { HTMLAttributes } from 'vue';
@@ -22,8 +26,15 @@ const select = injectReactiveOrFail<SelectExpose>('select', '<SelectTrigger> mus
22
26
  const renderedClasses = computed(() =>
23
27
  classes(
24
28
  // eslint-disable-next-line vue/max-len
25
- 'focus:outline-primary-600 data-[state=open]:outline-primary-600 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-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 sm:text-sm/6',
26
- { 'mt-1': select.label },
29
+ 'relative 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-1 -outline-offset-1',
30
+ 'focus:outline-2 focus:-outline-offset-2 sm:text-sm/6',
31
+ {
32
+ 'mt-1': select.label,
33
+ 'outline-gray-300 focus:outline-primary-600 data-[state=open]:outline-primary-600': !select.errors,
34
+ 'text-gray-900 shadow-2xs ring-gray-900/10 placeholder:text-gray-400': !select.errors,
35
+ 'outline-red-900/10 pr-10 text-red-900 placeholder:text-red-300': select.errors,
36
+ 'focus:outline-red-500 data-[state=open]:outline-red-500': select.errors,
37
+ },
27
38
  rootClasses,
28
39
  ));
29
40
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <Modal :title="$td('settings.title', 'Settings')">
2
+ <Modal :title="$td('settings.title', 'Settings')" :fullscreen-on-mobile="$app.settingsFullscreenOnMobile">
3
3
  <component :is="setting.component" v-for="(setting, key) in settings" :key />
4
4
  </Modal>
5
5
  </template>
@@ -34,6 +34,7 @@ const renderedClasses = computed(() =>
34
34
  variant: {
35
35
  secondary: 'bg-gray-900 text-white ring-black',
36
36
  danger: 'bg-red-50 text-red-900 ring-red-100',
37
+ warning: 'bg-yellow-50 text-yellow-900 ring-yellow-100',
37
38
  },
38
39
  },
39
40
  defaultVariants: {
@@ -2,7 +2,13 @@ export { default as AdvancedOptions } from './AdvancedOptions.vue';
2
2
  export { default as AlertModal } from './AlertModal.vue';
3
3
  export { default as Button } from './Button.vue';
4
4
  export { default as Checkbox } from './Checkbox.vue';
5
+ export { default as Combobox } from './Combobox.vue';
6
+ export { default as ComboboxLabel } from './ComboboxLabel.vue';
7
+ export { default as ComboboxOption } from './ComboboxOption.vue';
8
+ export { default as ComboboxOptions } from './ComboboxOptions.vue';
9
+ export { default as ComboboxTrigger } from './ComboboxTrigger.vue';
5
10
  export { default as ConfirmModal } from './ConfirmModal.vue';
11
+ export { default as Details } from './Details.vue';
6
12
  export { default as DropdownMenu } from './DropdownMenu.vue';
7
13
  export { default as DropdownMenuOption } from './DropdownMenuOption.vue';
8
14
  export { default as DropdownMenuOptions } from './DropdownMenuOptions.vue';
@@ -19,7 +25,6 @@ export { default as Link } from './Link.vue';
19
25
  export { default as LoadingModal } from './LoadingModal.vue';
20
26
  export { default as Markdown } from './Markdown.vue';
21
27
  export { default as Modal } from './Modal.vue';
22
- export { default as ModalContext } from './ModalContext.vue';
23
28
  export { default as ProgressBar } from './ProgressBar.vue';
24
29
  export { default as PromptModal } from './PromptModal.vue';
25
30
  export { default as Select } from './Select.vue';
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <slot />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { provide } from 'vue';
7
+
8
+ const { name, value } = defineProps<{ name: string; value: unknown }>();
9
+
10
+ provide(name, value);
11
+ </script>
@@ -0,0 +1 @@
1
+ export { default as Provide } from './Provide.vue';
@@ -3,22 +3,26 @@ import type { Directive } from 'vue';
3
3
  import { definePlugin } from '@aerogel/core/plugins';
4
4
 
5
5
  import measure from './measure';
6
+ import safeHtml from './safe-html';
6
7
 
7
- const builtInDirectives: Record<string, Directive> = {
8
- measure: measure,
9
- };
8
+ export const aerogelDirectives = {
9
+ 'measure': measure,
10
+ 'safe-html': safeHtml,
11
+ } as const satisfies Record<string, Directive>;
12
+
13
+ export type AerogelDirectives = typeof aerogelDirectives;
10
14
 
11
15
  export * from './measure';
12
16
 
13
17
  export default definePlugin({
14
18
  install(app, options) {
15
19
  const directives = {
16
- ...builtInDirectives,
20
+ ...aerogelDirectives,
17
21
  ...options.directives,
18
22
  };
19
23
 
20
24
  for (const [name, directive] of Object.entries(directives)) {
21
- app.directive(name, directive);
25
+ app.directive(name, directive as Directive);
22
26
  }
23
27
  },
24
28
  });
@@ -30,7 +34,5 @@ declare module '@aerogel/core/bootstrap/options' {
30
34
  }
31
35
 
32
36
  declare module 'vue' {
33
- interface ComponentCustomDirectives {
34
- measure: Directive<string, string>;
35
- }
37
+ interface ComponentCustomDirectives extends AerogelDirectives {}
36
38
  }
@@ -0,0 +1,10 @@
1
+ import { safeHtml } from '@aerogel/core/utils';
2
+ import { defineDirective } from '@aerogel/core/utils/vue';
3
+
4
+ export type SafeHTMLDirectiveValue = string;
5
+
6
+ export default defineDirective<SafeHTMLDirectiveValue>({
7
+ mounted(element: HTMLElement, { value }) {
8
+ element.innerHTML = safeHtml(value);
9
+ },
10
+ });
@@ -1,6 +1,7 @@
1
1
  import { JSError, facade, isDevelopment, isObject, isTesting, objectWithoutEmpty, toString } from '@noeldemartin/utils';
2
2
  import { watchEffect } from 'vue';
3
3
  import type Eruda from 'eruda';
4
+ import type ErudaIndexedDB from 'eruda-indexeddb';
4
5
 
5
6
  import App from '@aerogel/core/services/App';
6
7
  import ServiceBootError from '@aerogel/core/errors/ServiceBootError';
@@ -16,6 +17,7 @@ export class ErrorsService extends Service {
16
17
  public forceReporting: boolean = false;
17
18
  private enabled: boolean = true;
18
19
  private eruda: typeof Eruda | null = null;
20
+ private erudaPlugins: [typeof ErudaIndexedDB] | null = null;
19
21
 
20
22
  public enable(): void {
21
23
  this.enabled = true;
@@ -131,8 +133,10 @@ export class ErrorsService extends Service {
131
133
  }
132
134
 
133
135
  this.eruda ??= (await import('eruda')).default;
136
+ this.erudaPlugins ??= [(await import('eruda-indexeddb')).default];
134
137
 
135
138
  this.eruda.init();
139
+ this.erudaPlugins.forEach((plugin) => this.eruda?.add(plugin));
136
140
  });
137
141
  }
138
142
 
@@ -30,7 +30,7 @@ describe('FormController', () => {
30
30
  const form = useForm({
31
31
  name: {
32
32
  type: 'string',
33
- rules: 'required',
33
+ rules: ['required'],
34
34
  },
35
35
  });
36
36
 
@@ -48,7 +48,7 @@ describe('FormController', () => {
48
48
  const form = useForm({
49
49
  name: {
50
50
  type: 'string',
51
- rules: 'required',
51
+ rules: ['required'],
52
52
  },
53
53
  });
54
54
 
@@ -69,11 +69,11 @@ describe('FormController', () => {
69
69
  const form = useForm({
70
70
  trimmed: {
71
71
  type: 'string',
72
- rules: 'required',
72
+ rules: ['required'],
73
73
  },
74
74
  untrimmed: {
75
75
  type: 'string',
76
- rules: 'required',
76
+ rules: ['required'],
77
77
  trim: false,
78
78
  },
79
79
  });
@@ -14,7 +14,7 @@ export interface FormFieldDefinition<
14
14
  type: TType;
15
15
  trim?: boolean;
16
16
  default?: GetFormFieldValue<TType>;
17
- rules?: TRules;
17
+ rules?: TRules[];
18
18
  values?: readonly TValueType[];
19
19
  [__valueType]?: TValueType;
20
20
  }
@@ -109,7 +109,11 @@ export default class FormController<Fields extends FormFieldDefinitions = FormFi
109
109
  }
110
110
 
111
111
  public getFieldRules<T extends keyof Fields>(field: T): string[] {
112
- return this._fields[field]?.rules?.split('|') ?? [];
112
+ return this._fields[field]?.rules ?? [];
113
+ }
114
+
115
+ public setFieldErrors<T extends keyof Fields>(field: T, errors: string[] | null): void {
116
+ this._errors[field] = errors;
113
117
  }
114
118
 
115
119
  public getFieldType<T extends keyof Fields>(field: T): FormFieldType | null {
@@ -197,7 +201,7 @@ export default class FormController<Fields extends FormFieldDefinitions = FormFi
197
201
  private getFieldErrors(name: keyof Fields, definition: FormFieldDefinition): string[] | null {
198
202
  const errors = [];
199
203
  const value = this._data[name];
200
- const rules = definition.rules?.split('|') ?? [];
204
+ const rules = definition.rules ?? [];
201
205
 
202
206
  errors.push(...validateType(value, definition));
203
207
 
@@ -1,4 +1,15 @@
1
+ import { registerFormValidationRule } from '@aerogel/core/forms/validation';
2
+ import { definePlugin } from '@aerogel/core/plugins';
3
+
1
4
  export * from './FormController';
2
5
  export * from './utils';
3
6
  export * from './validation';
4
7
  export { default as FormController } from './FormController';
8
+
9
+ export default definePlugin({
10
+ async install(_, { formValidationRules }) {
11
+ for (const [rule, validator] of Object.entries(formValidationRules ?? {})) {
12
+ registerFormValidationRule(rule, validator);
13
+ }
14
+ },
15
+ });
@@ -1,6 +1,9 @@
1
1
  import type { FormFieldDefinition } from './FormController';
2
2
 
3
- export function booleanInput(defaultValue?: boolean, options: { rules?: string } = {}): FormFieldDefinition<'boolean'> {
3
+ export function booleanInput(
4
+ defaultValue?: boolean,
5
+ options: { rules?: string[] } = {},
6
+ ): FormFieldDefinition<'boolean'> {
4
7
  return {
5
8
  default: defaultValue,
6
9
  type: 'boolean',
@@ -8,7 +11,7 @@ export function booleanInput(defaultValue?: boolean, options: { rules?: string }
8
11
  };
9
12
  }
10
13
 
11
- export function dateInput(defaultValue?: Date, options: { rules?: string } = {}): FormFieldDefinition<'date'> {
14
+ export function dateInput(defaultValue?: Date, options: { rules?: string[] } = {}): FormFieldDefinition<'date'> {
12
15
  return {
13
16
  default: defaultValue,
14
17
  type: 'date',
@@ -19,7 +22,7 @@ export function dateInput(defaultValue?: Date, options: { rules?: string } = {})
19
22
  export function enumInput<const T extends string>(
20
23
  values: readonly T[],
21
24
  defaultValue?: T,
22
- options: { rules?: string } = {},
25
+ options: { rules?: string[] } = {},
23
26
  ): FormFieldDefinition<'enum', string, T> {
24
27
  return {
25
28
  default: defaultValue,
@@ -29,59 +32,75 @@ export function enumInput<const T extends string>(
29
32
  };
30
33
  }
31
34
 
32
- export function requiredBooleanInput(defaultValue?: boolean): FormFieldDefinition<'boolean', 'required'> {
35
+ export function requiredBooleanInput(
36
+ defaultValue?: boolean,
37
+ options: { rules?: string[] } = {},
38
+ ): FormFieldDefinition<'boolean', 'required'> {
33
39
  return {
34
40
  default: defaultValue,
35
41
  type: 'boolean',
36
- rules: 'required',
42
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
37
43
  };
38
44
  }
39
45
 
40
- export function requiredDateInput(defaultValue?: Date): FormFieldDefinition<'date', 'required'> {
46
+ export function requiredDateInput(
47
+ defaultValue?: Date,
48
+ options: { rules?: string[] } = {},
49
+ ): FormFieldDefinition<'date', 'required'> {
41
50
  return {
42
51
  default: defaultValue,
43
52
  type: 'date',
44
- rules: 'required',
53
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
45
54
  };
46
55
  }
47
56
 
48
57
  export function requiredEnumInput<const T extends string>(
49
58
  values: readonly T[],
50
59
  defaultValue?: T,
60
+ options: { rules?: string[] } = {},
51
61
  ): FormFieldDefinition<'enum', 'required', T> {
52
62
  return {
53
63
  default: defaultValue,
54
64
  type: 'enum',
55
- rules: 'required',
65
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
56
66
  values,
57
67
  };
58
68
  }
59
69
 
60
- export function requiredNumberInput(defaultValue?: number): FormFieldDefinition<'number', 'required'> {
70
+ export function requiredNumberInput(
71
+ defaultValue?: number,
72
+ options: { rules?: string[] } = {},
73
+ ): FormFieldDefinition<'number', 'required'> {
61
74
  return {
62
75
  default: defaultValue,
63
76
  type: 'number',
64
- rules: 'required',
77
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
65
78
  };
66
79
  }
67
80
 
68
- export function requiredObjectInput<T extends object>(defaultValue?: T): FormFieldDefinition<'object', 'required', T> {
81
+ export function requiredObjectInput<T extends object>(
82
+ defaultValue?: T,
83
+ options: { rules?: string[] } = {},
84
+ ): FormFieldDefinition<'object', 'required', T> {
69
85
  return {
70
86
  default: defaultValue,
71
87
  type: 'object',
72
- rules: 'required',
88
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
73
89
  };
74
90
  }
75
91
 
76
- export function requiredStringInput(defaultValue?: string): FormFieldDefinition<'string', 'required'> {
92
+ export function requiredStringInput(
93
+ defaultValue?: string,
94
+ options: { rules?: string[] } = {},
95
+ ): FormFieldDefinition<'string', 'required'> {
77
96
  return {
78
97
  default: defaultValue,
79
98
  type: 'string',
80
- rules: 'required',
99
+ rules: ['required', ...((options.rules as 'required'[]) ?? [])],
81
100
  };
82
101
  }
83
102
 
84
- export function numberInput(defaultValue?: number, options: { rules?: string } = {}): FormFieldDefinition<'number'> {
103
+ export function numberInput(defaultValue?: number, options: { rules?: string[] } = {}): FormFieldDefinition<'number'> {
85
104
  return {
86
105
  default: defaultValue,
87
106
  type: 'number',
@@ -91,7 +110,7 @@ export function numberInput(defaultValue?: number, options: { rules?: string } =
91
110
 
92
111
  export function objectInput<T extends object>(
93
112
  defaultValue?: T,
94
- options: { rules?: string } = {},
113
+ options: { rules?: string[] } = {},
95
114
  ): FormFieldDefinition<'object', string, T> {
96
115
  return {
97
116
  default: defaultValue,
@@ -100,7 +119,7 @@ export function objectInput<T extends object>(
100
119
  };
101
120
  }
102
121
 
103
- export function stringInput(defaultValue?: string, options: { rules?: string } = {}): FormFieldDefinition<'string'> {
122
+ export function stringInput(defaultValue?: string, options: { rules?: string[] } = {}): FormFieldDefinition<'string'> {
104
123
  return {
105
124
  default: defaultValue,
106
125
  type: 'string',
@@ -31,10 +31,14 @@ export type FormFieldValidator<T = unknown> = (value: T) => string | string[] |
31
31
 
32
32
  export const validators: Record<string, FormFieldValidator> = { ...builtInRules };
33
33
 
34
- export function defineFormValidationRule<T>(rule: string, validator: FormFieldValidator<T>): void {
34
+ export function registerFormValidationRule<T>(rule: string, validator: FormFieldValidator<T>): void {
35
35
  validators[rule] = validator as FormFieldValidator;
36
36
  }
37
37
 
38
+ export function defineFormValidationRules<T extends Record<string, FormFieldValidator>>(rules: T): T {
39
+ return rules;
40
+ }
41
+
38
42
  export function validateType(value: unknown, definition: FormFieldDefinition): string[] {
39
43
  if (isValidType(value, definition)) {
40
44
  return [];
package/src/index.css CHANGED
@@ -20,6 +20,7 @@
20
20
  --color-primary-950: color-mix(in oklab, var(--color-primary-600) 50%, black);
21
21
 
22
22
  --color-background: oklch(1 0 0);
23
+ --color-primary-text: var(--color-gray-900);
23
24
  --color-links: var(--color-primary);
24
25
 
25
26
  --breakpoint-content: var(--breakpoint-md);
@@ -66,6 +67,15 @@ button[data-markdown-action] {
66
67
  }
67
68
  }
68
69
 
70
+ @keyframes slide-in {
71
+ 0% {
72
+ transform: translateY(100%);
73
+ }
74
+ 100% {
75
+ transform: translateY(0);
76
+ }
77
+ }
78
+
69
79
  @keyframes grow {
70
80
  0% {
71
81
  scale: 0;
package/src/jobs/Job.ts CHANGED
@@ -115,7 +115,7 @@ export default abstract class Job<
115
115
  return 1;
116
116
  }
117
117
 
118
- if (!status.children) {
118
+ if (!status.children || status.children.length === 0) {
119
119
  return 0;
120
120
  }
121
121
 
@@ -24,6 +24,7 @@ export default defineServiceState({
24
24
  version: Aerogel.version,
25
25
  sourceUrl: Aerogel.sourceUrl,
26
26
  settings: [] as AppSetting[],
27
+ settingsFullscreenOnMobile: false,
27
28
  },
28
29
  computed: {
29
30
  development: (state) => state.environment === 'development',
@@ -30,6 +30,10 @@ export class AppService extends Service {
30
30
  this.settings.push(markRaw(setting));
31
31
  }
32
32
 
33
+ public setSettingsFullscreenOnMobile(fullscreenOnMobile: boolean): void {
34
+ this.settingsFullscreenOnMobile = fullscreenOnMobile;
35
+ }
36
+
33
37
  public async whenReady<T>(callback: () => T): Promise<T> {
34
38
  const result = await this.ready.then(callback);
35
39
 
@@ -10,6 +10,7 @@ import Service from './Service';
10
10
  import Storage from './Storage';
11
11
  import { getPiniaStore } from './store';
12
12
  import type { AppSetting } from './App.state';
13
+ import type { FormFieldValidator } from '@aerogel/core/forms';
13
14
 
14
15
  export * from './App';
15
16
  export * from './Cache';
@@ -56,6 +57,10 @@ export default definePlugin({
56
57
  app.use(getPiniaStore());
57
58
  options.settings?.forEach((setting) => App.addSetting(setting));
58
59
 
60
+ if (options.settingsFullscreenOnMobile !== undefined) {
61
+ App.setSettingsFullscreenOnMobile(options.settingsFullscreenOnMobile);
62
+ }
63
+
59
64
  await bootServices(app, services);
60
65
  },
61
66
  });
@@ -64,6 +69,8 @@ declare module '@aerogel/core/bootstrap/options' {
64
69
  export interface AerogelOptions {
65
70
  services?: Record<string, Service>;
66
71
  settings?: AppSetting[];
72
+ formValidationRules?: Record<string, FormFieldValidator>;
73
+ settingsFullscreenOnMobile?: boolean;
67
74
  }
68
75
  }
69
76
 
@@ -4,15 +4,6 @@ import { defineServiceState } from '@aerogel/core/services/Service';
4
4
 
5
5
  import { Layouts, getCurrentLayout } from './utils';
6
6
 
7
- export interface UIModal<T = unknown> {
8
- id: string;
9
- properties: Record<string, unknown>;
10
- component: Component;
11
- closing: boolean;
12
- beforeClose: Promise<T | undefined>;
13
- afterClose: Promise<T | undefined>;
14
- }
15
-
16
7
  export interface UIToast {
17
8
  id: string;
18
9
  component: Component;
@@ -22,13 +13,11 @@ export interface UIToast {
22
13
  export default defineServiceState({
23
14
  name: 'ui',
24
15
  initialState: {
25
- modals: [] as UIModal[],
26
16
  toasts: [] as UIToast[],
27
17
  layout: getCurrentLayout(),
28
18
  },
29
19
  computed: {
30
20
  desktop: ({ layout }) => layout === Layouts.Desktop,
31
21
  mobile: ({ layout }) => layout === Layouts.Mobile,
32
- openModals: ({ modals }) => modals.filter(({ closing }) => !closing),
33
22
  },
34
23
  });