@aerogel/core 0.1.1-next.97f5cf5c97f16ab8a0ef63b82aaab049a0f9e15b → 0.1.1-next.99b3fb08de2a9c2e13062ba0459f432627992d23

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 (50) hide show
  1. package/dist/aerogel-core.d.ts +411 -122
  2. package/dist/aerogel-core.js +1850 -1427
  3. package/dist/aerogel-core.js.map +1 -1
  4. package/package.json +2 -1
  5. package/src/bootstrap/index.ts +2 -1
  6. package/src/components/AppLayout.vue +1 -1
  7. package/src/components/contracts/Button.ts +1 -1
  8. package/src/components/contracts/Combobox.ts +5 -0
  9. package/src/components/contracts/Modal.ts +2 -0
  10. package/src/components/contracts/Select.ts +98 -4
  11. package/src/components/contracts/Toast.ts +1 -1
  12. package/src/components/contracts/index.ts +1 -0
  13. package/src/components/headless/HeadlessInputInput.vue +27 -5
  14. package/src/components/headless/HeadlessSelect.vue +10 -91
  15. package/src/components/headless/HeadlessSelectOption.vue +1 -5
  16. package/src/components/index.ts +1 -0
  17. package/src/components/ui/AdvancedOptions.vue +4 -13
  18. package/src/components/ui/Button.vue +1 -0
  19. package/src/components/ui/Combobox.vue +94 -0
  20. package/src/components/ui/ComboboxLabel.vue +29 -0
  21. package/src/components/ui/ComboboxOption.vue +46 -0
  22. package/src/components/ui/ComboboxOptions.vue +71 -0
  23. package/src/components/ui/ComboboxTrigger.vue +67 -0
  24. package/src/components/ui/Details.vue +33 -0
  25. package/src/components/ui/Input.vue +12 -4
  26. package/src/components/ui/LoadingModal.vue +1 -2
  27. package/src/components/ui/Modal.vue +30 -11
  28. package/src/components/ui/ProgressBar.vue +16 -2
  29. package/src/components/ui/Select.vue +2 -0
  30. package/src/components/ui/SelectTrigger.vue +13 -2
  31. package/src/components/ui/SettingsModal.vue +1 -1
  32. package/src/components/ui/Toast.vue +1 -0
  33. package/src/components/ui/index.ts +6 -0
  34. package/src/components/vue/Provide.vue +11 -0
  35. package/src/components/vue/index.ts +1 -0
  36. package/src/errors/Errors.ts +4 -0
  37. package/src/errors/index.ts +5 -0
  38. package/src/forms/FormController.test.ts +4 -4
  39. package/src/forms/FormController.ts +23 -13
  40. package/src/forms/index.ts +11 -0
  41. package/src/forms/utils.ts +36 -17
  42. package/src/forms/validation.ts +5 -1
  43. package/src/index.css +10 -0
  44. package/src/jobs/Job.ts +1 -1
  45. package/src/services/App.state.ts +1 -0
  46. package/src/services/App.ts +4 -0
  47. package/src/services/index.ts +7 -0
  48. package/src/utils/composition/reactiveSet.ts +10 -2
  49. package/src/utils/index.ts +1 -0
  50. package/src/utils/time.ts +7 -0
@@ -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
 
@@ -2,10 +2,14 @@ import { fail } from '@noeldemartin/utils';
2
2
  import { customRef } from 'vue';
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
5
- export function reactiveSet<T>(initial?: T[] | Set<T>) {
5
+ export function reactiveSet<T>(initial?: T[] | Set<T>, options: { equals?: (a: T, b: T) => boolean } = {}) {
6
6
  let set: Set<T> = new Set(initial);
7
7
  let trigger: () => void;
8
8
  let track: () => void;
9
+ const equals = options?.equals;
10
+ const hasEqual = equals
11
+ ? (item: T) => ref.value.values().some((existingItem) => equals(item, existingItem))
12
+ : () => false;
9
13
  const ref = customRef((_track, _trigger) => {
10
14
  track = _track;
11
15
  trigger = _trigger;
@@ -25,11 +29,15 @@ export function reactiveSet<T>(initial?: T[] | Set<T>) {
25
29
  has(item: T) {
26
30
  track();
27
31
 
28
- return ref.value.has(item);
32
+ return ref.value.has(item) || hasEqual(item);
29
33
  },
30
34
  add(item: T) {
31
35
  trigger();
32
36
 
37
+ if (hasEqual(item)) {
38
+ return;
39
+ }
40
+
33
41
  ref.value.add(item);
34
42
  },
35
43
  delete(item: T) {
@@ -7,5 +7,6 @@ export * from './composition/persistent';
7
7
  export * from './composition/reactiveSet';
8
8
  export * from './composition/state';
9
9
  export * from './markdown';
10
+ export * from './time';
10
11
  export * from './types';
11
12
  export * from './vue';
@@ -0,0 +1,7 @@
1
+ import type { Nullable } from '@noeldemartin/utils';
2
+
3
+ export const MINUTE_MILLISECONDS = 60000;
4
+
5
+ export function getLocalTimezoneOffset(date?: Nullable<Date>): number {
6
+ return -(date ?? new Date()).getTimezoneOffset() * -MINUTE_MILLISECONDS;
7
+ }