@aerogel/core 0.0.0-next.f16bd1d894543c5303039c49f6f33488a1ffe931 → 0.0.0-next.f86b4b09f066c4aef21796a37dbc8417b7dce3cd

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 (118) hide show
  1. package/dist/aerogel-core.cjs.js +1 -1
  2. package/dist/aerogel-core.cjs.js.map +1 -1
  3. package/dist/aerogel-core.d.ts +1396 -235
  4. package/dist/aerogel-core.esm.js +1 -1
  5. package/dist/aerogel-core.esm.js.map +1 -1
  6. package/histoire.config.ts +7 -0
  7. package/package.json +14 -5
  8. package/postcss.config.js +6 -0
  9. package/src/assets/histoire.css +3 -0
  10. package/src/bootstrap/bootstrap.test.ts +3 -3
  11. package/src/bootstrap/index.ts +35 -5
  12. package/src/bootstrap/options.ts +3 -0
  13. package/src/components/AGAppLayout.vue +7 -2
  14. package/src/components/AGAppOverlays.vue +5 -1
  15. package/src/components/AGAppSnackbars.vue +2 -2
  16. package/src/components/composition.ts +23 -0
  17. package/src/components/forms/AGCheckbox.vue +7 -1
  18. package/src/components/forms/AGForm.vue +9 -10
  19. package/src/components/forms/AGInput.vue +10 -6
  20. package/src/components/forms/AGSelect.story.vue +46 -0
  21. package/src/components/forms/AGSelect.vue +60 -0
  22. package/src/components/forms/index.ts +5 -6
  23. package/src/components/headless/forms/AGHeadlessButton.ts +3 -0
  24. package/src/components/headless/forms/AGHeadlessButton.vue +24 -12
  25. package/src/components/headless/forms/AGHeadlessInput.ts +30 -4
  26. package/src/components/headless/forms/AGHeadlessInput.vue +23 -7
  27. package/src/components/headless/forms/AGHeadlessInputDescription.vue +28 -0
  28. package/src/components/headless/forms/AGHeadlessInputInput.vue +44 -5
  29. package/src/components/headless/forms/AGHeadlessInputLabel.vue +8 -2
  30. package/src/components/headless/forms/AGHeadlessInputTextArea.vue +43 -0
  31. package/src/components/headless/forms/AGHeadlessSelect.ts +42 -0
  32. package/src/components/headless/forms/AGHeadlessSelect.vue +77 -0
  33. package/src/components/headless/forms/AGHeadlessSelectButton.vue +24 -0
  34. package/src/components/headless/forms/AGHeadlessSelectError.vue +26 -0
  35. package/src/components/headless/forms/AGHeadlessSelectLabel.vue +24 -0
  36. package/src/components/headless/forms/AGHeadlessSelectOption.ts +4 -0
  37. package/src/components/headless/forms/AGHeadlessSelectOption.vue +39 -0
  38. package/src/components/headless/forms/AGHeadlessSelectOptions.ts +3 -0
  39. package/src/components/headless/forms/composition.ts +10 -0
  40. package/src/components/headless/forms/index.ts +13 -1
  41. package/src/components/headless/modals/AGHeadlessModal.ts +27 -0
  42. package/src/components/headless/modals/AGHeadlessModal.vue +3 -5
  43. package/src/components/headless/modals/index.ts +4 -6
  44. package/src/components/headless/snackbars/index.ts +23 -8
  45. package/src/components/index.ts +3 -1
  46. package/src/components/interfaces.ts +24 -0
  47. package/src/components/lib/AGErrorMessage.vue +16 -0
  48. package/src/components/lib/AGLink.vue +9 -0
  49. package/src/components/{basic → lib}/AGMarkdown.vue +12 -11
  50. package/src/components/lib/AGMeasured.vue +16 -0
  51. package/src/components/lib/AGStartupCrash.vue +31 -0
  52. package/src/components/lib/index.ts +5 -0
  53. package/src/components/modals/AGAlertModal.ts +15 -0
  54. package/src/components/modals/AGAlertModal.vue +4 -16
  55. package/src/components/modals/AGConfirmModal.ts +35 -0
  56. package/src/components/modals/AGConfirmModal.vue +9 -13
  57. package/src/components/modals/AGErrorReportModal.ts +27 -1
  58. package/src/components/modals/AGErrorReportModal.vue +8 -16
  59. package/src/components/modals/AGErrorReportModalButtons.vue +6 -1
  60. package/src/components/modals/AGErrorReportModalTitle.vue +2 -2
  61. package/src/components/modals/AGLoadingModal.ts +23 -0
  62. package/src/components/modals/AGLoadingModal.vue +4 -8
  63. package/src/components/modals/AGModal.ts +1 -1
  64. package/src/components/modals/AGModal.vue +15 -12
  65. package/src/components/modals/AGModalTitle.vue +9 -0
  66. package/src/components/modals/AGPromptModal.ts +36 -0
  67. package/src/components/modals/AGPromptModal.vue +34 -0
  68. package/src/components/modals/index.ts +13 -17
  69. package/src/components/snackbars/AGSnackbar.vue +4 -10
  70. package/src/components/utils.ts +10 -0
  71. package/src/directives/index.ts +5 -1
  72. package/src/directives/measure.ts +40 -0
  73. package/src/errors/Errors.ts +36 -12
  74. package/src/errors/index.ts +10 -23
  75. package/src/errors/utils.ts +35 -0
  76. package/src/forms/Form.test.ts +28 -0
  77. package/src/forms/Form.ts +80 -14
  78. package/src/forms/index.ts +3 -1
  79. package/src/forms/utils.ts +34 -3
  80. package/src/forms/validation.ts +19 -0
  81. package/src/jobs/Job.ts +5 -0
  82. package/src/jobs/index.ts +7 -0
  83. package/src/lang/DefaultLangProvider.ts +43 -0
  84. package/src/lang/Lang.state.ts +11 -0
  85. package/src/lang/Lang.ts +44 -29
  86. package/src/main.histoire.ts +1 -0
  87. package/src/main.ts +3 -0
  88. package/src/plugins/Plugin.ts +1 -0
  89. package/src/plugins/index.ts +19 -0
  90. package/src/services/App.state.ts +24 -6
  91. package/src/services/App.ts +43 -5
  92. package/src/services/Cache.ts +43 -0
  93. package/src/services/Events.test.ts +39 -0
  94. package/src/services/Events.ts +100 -30
  95. package/src/services/Service.ts +64 -17
  96. package/src/services/index.ts +11 -5
  97. package/src/services/store.ts +8 -5
  98. package/src/testing/index.ts +25 -0
  99. package/src/testing/setup.ts +19 -0
  100. package/src/ui/UI.state.ts +7 -0
  101. package/src/ui/UI.ts +194 -27
  102. package/src/ui/index.ts +9 -3
  103. package/src/ui/utils.ts +16 -0
  104. package/src/utils/composition/events.ts +1 -0
  105. package/src/utils/composition/state.test.ts +47 -0
  106. package/src/utils/composition/state.ts +24 -0
  107. package/src/utils/index.ts +1 -0
  108. package/src/utils/markdown.ts +11 -2
  109. package/src/utils/tailwindcss.test.ts +26 -0
  110. package/src/utils/tailwindcss.ts +7 -0
  111. package/src/utils/vue.ts +23 -5
  112. package/tailwind.config.js +4 -0
  113. package/tsconfig.json +1 -1
  114. package/vite.config.ts +4 -1
  115. package/.eslintrc.js +0 -3
  116. package/dist/virtual.d.ts +0 -11
  117. package/src/components/basic/index.ts +0 -3
  118. package/src/types/virtual.d.ts +0 -11
@@ -0,0 +1,47 @@
1
+ import { after } from '@noeldemartin/utils';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { ref } from 'vue';
4
+
5
+ import { computedDebounce } from './state';
6
+
7
+ describe('Vue state helpers', () => {
8
+
9
+ it('computes debounced state', async () => {
10
+ // Initial
11
+ const state = ref(0);
12
+ const value = computedDebounce({ delay: 90 }, () => state.value);
13
+
14
+ expect(value.value).toBe(null);
15
+
16
+ await after({ ms: 100 });
17
+
18
+ expect(value.value).toBe(0);
19
+
20
+ // Update
21
+ state.value = 42;
22
+
23
+ expect(value.value).toBe(0);
24
+
25
+ await after({ ms: 100 });
26
+
27
+ expect(value.value).toBe(42);
28
+
29
+ // Debounced Update
30
+ state.value = 23;
31
+
32
+ expect(value.value).toBe(42);
33
+
34
+ await after({ ms: 50 });
35
+
36
+ state.value = 32;
37
+
38
+ await after({ ms: 50 });
39
+
40
+ expect(value.value).toBe(42);
41
+
42
+ await after({ ms: 100 });
43
+
44
+ expect(value.value).toBe(32);
45
+ });
46
+
47
+ });
@@ -0,0 +1,24 @@
1
+ import { debounce } from '@noeldemartin/utils';
2
+ import { ref, watchEffect } from 'vue';
3
+ import type { ComputedGetter, ComputedRef } from '@vue/runtime-core';
4
+
5
+ export interface ComputedDebounceOptions<T> {
6
+ initial?: T;
7
+ delay?: number;
8
+ }
9
+
10
+ export function computedDebounce<T>(options: ComputedDebounceOptions<T>, getter: ComputedGetter<T>): ComputedRef<T>;
11
+ export function computedDebounce<T>(getter: ComputedGetter<T>): ComputedRef<T | null>;
12
+ export function computedDebounce<T>(
13
+ optionsOrGetter: ComputedGetter<T> | ComputedDebounceOptions<T>,
14
+ inputGetter?: ComputedGetter<T>,
15
+ ): ComputedRef<T> {
16
+ const inputOptions = inputGetter ? (optionsOrGetter as ComputedDebounceOptions<T>) : {};
17
+ const getter = inputGetter ?? (optionsOrGetter as ComputedGetter<T>);
18
+ const state = ref(inputOptions.initial ?? null);
19
+ const update = debounce((value) => (state.value = value), inputOptions.delay ?? 300);
20
+
21
+ watchEffect(() => update(getter()));
22
+
23
+ return state as unknown as ComputedRef<T>;
24
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './composition/events';
2
2
  export * from './composition/forms';
3
3
  export * from './composition/hooks';
4
+ export * from './tailwindcss';
4
5
  export * from './vue';
@@ -1,8 +1,17 @@
1
+ import { tap } from '@noeldemartin/utils';
1
2
  import DOMPurify from 'dompurify';
2
- import { marked } from 'marked';
3
+ import { Renderer, marked } from 'marked';
4
+
5
+ function makeRenderer(): Renderer {
6
+ return tap(new Renderer(), (renderer) => {
7
+ renderer.link = function(href, title, text) {
8
+ return Renderer.prototype.link.apply(this, [href, title, text]).replace('<a', '<a target="_blank"');
9
+ };
10
+ });
11
+ }
3
12
 
4
13
  export function renderMarkdown(markdown: string): string {
5
- return safeHtml(marked(markdown, { mangle: false, headerIds: false }));
14
+ return safeHtml(marked(markdown, { mangle: false, headerIds: false, renderer: makeRenderer() }));
6
15
  }
7
16
 
8
17
  export function safeHtml(html: string): string {
@@ -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
+ });
@@ -0,0 +1,7 @@
1
+ export function removeInteractiveClasses(classes: string): string {
2
+ return classes
3
+ .split(/\s+/)
4
+ .filter((className) => !/^(hover|focus|focus-visible):/.test(className))
5
+ .join(' ')
6
+ .trim();
7
+ }
package/src/utils/vue.ts CHANGED
@@ -1,9 +1,9 @@
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> = {
6
- type: PropType<T>;
6
+ type?: PropType<T>;
7
7
  validator?(value: unknown): boolean;
8
8
  };
9
9
 
@@ -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
  }
@@ -64,13 +73,22 @@ export function injectOrFail<T>(key: InjectionKey<T> | string, errorMessage?: st
64
73
  return inject(key) ?? fail(errorMessage ?? `Could not resolve '${key}' injection key`);
65
74
  }
66
75
 
67
- export function mixedProp<T>(type: PropType<T>): OptionalProp<T | null> {
76
+ export function listenerProp<T extends Function = Function>(): OptionalProp<T | null> {
68
77
  return {
69
- type,
78
+ type: Function as PropType<T>,
70
79
  default: null,
71
80
  };
72
81
  }
73
82
 
83
+ export function mixedProp<T>(type?: PropType<T>): OptionalProp<T | null>;
84
+ export function mixedProp<T>(type: PropType<T>, defaultValue: T): OptionalProp<T>;
85
+ export function mixedProp<T>(type?: PropType<T>, defaultValue?: T): OptionalProp<T | null> {
86
+ return {
87
+ type,
88
+ default: defaultValue ?? null,
89
+ };
90
+ }
91
+
74
92
  export function numberProp(): OptionalProp<number | null>;
75
93
  export function numberProp(defaultValue: number): OptionalProp<number>;
76
94
  export function numberProp(defaultValue: number | null = null): OptionalProp<number | null> {
@@ -108,7 +126,7 @@ export function requiredEnumProp<Enum extends Record<string, unknown>>(
108
126
  };
109
127
  }
110
128
 
111
- export function requiredMixedProp<T>(type: PropType<T>): RequiredProp<T> {
129
+ export function requiredMixedProp<T>(type?: PropType<T>): RequiredProp<T> {
112
130
  return {
113
131
  type,
114
132
  required: true,
@@ -0,0 +1,4 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: ['./src/**/*.{vue,ts}'],
4
+ };
package/tsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
- "types": ["unplugin-icons/types/vue3"],
4
+ "types": ["unplugin-icons/types/vue3", "@aerogel/vite/dist/virtual"],
5
5
  "baseUrl": ".",
6
6
  "paths": {
7
7
  "@/*": ["./src/*"]
package/vite.config.ts CHANGED
@@ -4,7 +4,10 @@ import { defineConfig } from 'vitest/config';
4
4
  import { resolve } from 'path';
5
5
 
6
6
  export default defineConfig({
7
- test: { clearMocks: true },
7
+ test: {
8
+ clearMocks: true,
9
+ setupFiles: ['./src/testing/setup.ts'],
10
+ },
8
11
  plugins: [Aerogel(), Icons()],
9
12
  resolve: {
10
13
  alias: {
package/.eslintrc.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- extends: ['@noeldemartin/eslint-config-vue'],
3
- };
package/dist/virtual.d.ts DELETED
@@ -1,11 +0,0 @@
1
- declare module 'virtual:aerogel' {
2
- interface AerogelBuild {
3
- environment: 'production' | 'development' | 'testing';
4
- basePath?: string;
5
- sourceUrl?: string;
6
- }
7
-
8
- const build: AerogelBuild;
9
-
10
- export default build;
11
- }
@@ -1,3 +0,0 @@
1
- import AGMarkdown from './AGMarkdown.vue';
2
-
3
- export { AGMarkdown };
@@ -1,11 +0,0 @@
1
- declare module 'virtual:aerogel' {
2
- interface AerogelBuild {
3
- environment: 'production' | 'development' | 'testing';
4
- basePath?: string;
5
- sourceUrl?: string;
6
- }
7
-
8
- const build: AerogelBuild;
9
-
10
- export default build;
11
- }