@aerogel/core 0.0.0-next.eed7a057cf5b844cd9f7fc6bda2d8df49fcd6736 → 0.0.0-next.f0368a3107664018eb88652e719d2cb7d24b82e7

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 (157) hide show
  1. package/dist/aerogel-core.d.ts +1699 -2701
  2. package/dist/aerogel-core.js +2544 -2037
  3. package/dist/aerogel-core.js.map +1 -1
  4. package/package.json +14 -6
  5. package/src/components/{AGAppLayout.vue → AppLayout.vue} +3 -3
  6. package/src/components/{AGAppModals.vue → AppModals.vue} +2 -3
  7. package/src/components/AppOverlays.vue +9 -0
  8. package/src/components/AppToasts.vue +16 -0
  9. package/src/components/contracts/AlertModal.ts +4 -0
  10. package/src/components/contracts/Button.ts +16 -0
  11. package/src/components/contracts/ConfirmModal.ts +42 -0
  12. package/src/components/contracts/DropdownMenu.ts +20 -0
  13. package/src/components/{modals/AGErrorReportModal.ts → contracts/ErrorReportModal.ts} +3 -23
  14. package/src/components/contracts/Input.ts +26 -0
  15. package/src/components/contracts/LoadingModal.ts +22 -0
  16. package/src/components/contracts/Modal.ts +21 -0
  17. package/src/components/contracts/PromptModal.ts +31 -0
  18. package/src/components/contracts/Select.ts +45 -0
  19. package/src/components/contracts/Toast.ts +13 -0
  20. package/src/components/contracts/index.ts +11 -0
  21. package/src/components/headless/HeadlessButton.vue +51 -0
  22. package/src/components/headless/HeadlessInput.vue +59 -0
  23. package/src/components/headless/{forms/AGHeadlessInputDescription.vue → HeadlessInputDescription.vue} +6 -7
  24. package/src/components/headless/{forms/AGHeadlessInputError.vue → HeadlessInputError.vue} +2 -6
  25. package/src/components/headless/{forms/AGHeadlessInputInput.vue → HeadlessInputInput.vue} +16 -25
  26. package/src/components/headless/{forms/AGHeadlessInputLabel.vue → HeadlessInputLabel.vue} +2 -6
  27. package/src/components/headless/{forms/AGHeadlessInputTextArea.vue → HeadlessInputTextArea.vue} +9 -12
  28. package/src/components/headless/HeadlessModal.vue +57 -0
  29. package/src/components/headless/HeadlessModalContent.vue +30 -0
  30. package/src/components/headless/HeadlessModalDescription.vue +12 -0
  31. package/src/components/headless/HeadlessModalOverlay.vue +12 -0
  32. package/src/components/headless/HeadlessModalTitle.vue +12 -0
  33. package/src/components/headless/HeadlessSelect.vue +120 -0
  34. package/src/components/headless/{forms/AGHeadlessSelectError.vue → HeadlessSelectError.vue} +3 -4
  35. package/src/components/headless/HeadlessSelectLabel.vue +25 -0
  36. package/src/components/headless/HeadlessSelectOption.vue +34 -0
  37. package/src/components/headless/HeadlessSelectOptions.vue +42 -0
  38. package/src/components/headless/HeadlessSelectTrigger.vue +22 -0
  39. package/src/components/headless/HeadlessSelectValue.vue +18 -0
  40. package/src/components/headless/HeadlessToast.vue +18 -0
  41. package/src/components/headless/HeadlessToastAction.vue +13 -0
  42. package/src/components/headless/index.ts +19 -3
  43. package/src/components/index.ts +6 -11
  44. package/src/components/ui/AdvancedOptions.vue +18 -0
  45. package/src/components/ui/AlertModal.vue +13 -0
  46. package/src/components/ui/Button.vue +98 -0
  47. package/src/components/ui/Checkbox.vue +56 -0
  48. package/src/components/ui/ConfirmModal.vue +42 -0
  49. package/src/components/ui/DropdownMenu.vue +32 -0
  50. package/src/components/ui/DropdownMenuOption.vue +14 -0
  51. package/src/components/ui/DropdownMenuOptions.vue +27 -0
  52. package/src/components/ui/EditableContent.vue +82 -0
  53. package/src/components/ui/ErrorMessage.vue +15 -0
  54. package/src/components/ui/ErrorReportModal.vue +62 -0
  55. package/src/components/{modals/AGErrorReportModalButtons.vue → ui/ErrorReportModalButtons.vue} +29 -22
  56. package/src/components/ui/ErrorReportModalTitle.vue +24 -0
  57. package/src/components/{forms/AGForm.vue → ui/Form.vue} +4 -5
  58. package/src/components/ui/Input.vue +56 -0
  59. package/src/components/ui/Link.vue +12 -0
  60. package/src/components/ui/LoadingModal.vue +32 -0
  61. package/src/components/ui/Markdown.vue +69 -0
  62. package/src/components/ui/Modal.vue +121 -0
  63. package/src/components/{modals/AGModalContext.vue → ui/ModalContext.vue} +7 -9
  64. package/src/components/ui/ProgressBar.vue +51 -0
  65. package/src/components/ui/PromptModal.vue +35 -0
  66. package/src/components/ui/Select.vue +27 -0
  67. package/src/components/ui/SelectLabel.vue +17 -0
  68. package/src/components/ui/SelectOption.vue +29 -0
  69. package/src/components/ui/SelectOptions.vue +35 -0
  70. package/src/components/ui/SelectTrigger.vue +29 -0
  71. package/src/components/ui/SettingsModal.vue +15 -0
  72. package/src/components/{lib/AGStartupCrash.vue → ui/StartupCrash.vue} +8 -8
  73. package/src/components/ui/Toast.vue +42 -0
  74. package/src/components/ui/index.ts +30 -0
  75. package/src/directives/index.ts +6 -0
  76. package/src/errors/Errors.ts +9 -10
  77. package/src/forms/{Form.test.ts → FormController.test.ts} +29 -4
  78. package/src/forms/{Form.ts → FormController.ts} +20 -11
  79. package/src/forms/index.ts +2 -3
  80. package/src/forms/utils.ts +23 -2
  81. package/src/index.css +72 -0
  82. package/src/lang/index.ts +5 -1
  83. package/src/lang/settings/Language.vue +48 -0
  84. package/src/lang/settings/index.ts +10 -0
  85. package/src/services/App.state.ts +11 -1
  86. package/src/services/App.ts +9 -1
  87. package/src/services/Events.test.ts +8 -8
  88. package/src/services/Events.ts +2 -8
  89. package/src/services/index.ts +4 -1
  90. package/src/ui/UI.state.ts +13 -6
  91. package/src/ui/UI.ts +70 -75
  92. package/src/ui/index.ts +14 -14
  93. package/src/utils/classes.ts +49 -0
  94. package/src/utils/composition/events.ts +2 -4
  95. package/src/utils/composition/forms.ts +20 -4
  96. package/src/utils/composition/state.ts +11 -2
  97. package/src/utils/index.ts +3 -1
  98. package/src/utils/types.ts +3 -0
  99. package/src/utils/vue.ts +22 -133
  100. package/src/components/AGAppOverlays.vue +0 -41
  101. package/src/components/AGAppSnackbars.vue +0 -13
  102. package/src/components/composition.ts +0 -23
  103. package/src/components/constants.ts +0 -8
  104. package/src/components/forms/AGButton.vue +0 -44
  105. package/src/components/forms/AGCheckbox.vue +0 -42
  106. package/src/components/forms/AGInput.vue +0 -42
  107. package/src/components/forms/AGSelect.story.vue +0 -46
  108. package/src/components/forms/AGSelect.vue +0 -60
  109. package/src/components/forms/index.ts +0 -5
  110. package/src/components/headless/forms/AGHeadlessButton.ts +0 -3
  111. package/src/components/headless/forms/AGHeadlessButton.vue +0 -62
  112. package/src/components/headless/forms/AGHeadlessInput.ts +0 -41
  113. package/src/components/headless/forms/AGHeadlessInput.vue +0 -70
  114. package/src/components/headless/forms/AGHeadlessSelect.ts +0 -42
  115. package/src/components/headless/forms/AGHeadlessSelect.vue +0 -77
  116. package/src/components/headless/forms/AGHeadlessSelectButton.vue +0 -24
  117. package/src/components/headless/forms/AGHeadlessSelectLabel.vue +0 -24
  118. package/src/components/headless/forms/AGHeadlessSelectOption.ts +0 -4
  119. package/src/components/headless/forms/AGHeadlessSelectOption.vue +0 -39
  120. package/src/components/headless/forms/AGHeadlessSelectOptions.ts +0 -3
  121. package/src/components/headless/forms/composition.ts +0 -10
  122. package/src/components/headless/forms/index.ts +0 -18
  123. package/src/components/headless/modals/AGHeadlessModal.ts +0 -36
  124. package/src/components/headless/modals/AGHeadlessModal.vue +0 -92
  125. package/src/components/headless/modals/AGHeadlessModalPanel.vue +0 -32
  126. package/src/components/headless/modals/AGHeadlessModalTitle.vue +0 -23
  127. package/src/components/headless/modals/index.ts +0 -4
  128. package/src/components/headless/snackbars/AGHeadlessSnackbar.vue +0 -10
  129. package/src/components/headless/snackbars/index.ts +0 -40
  130. package/src/components/interfaces.ts +0 -24
  131. package/src/components/lib/AGErrorMessage.vue +0 -16
  132. package/src/components/lib/AGLink.vue +0 -9
  133. package/src/components/lib/AGMarkdown.vue +0 -54
  134. package/src/components/lib/AGMeasured.vue +0 -16
  135. package/src/components/lib/AGProgressBar.vue +0 -55
  136. package/src/components/lib/index.ts +0 -6
  137. package/src/components/modals/AGAlertModal.ts +0 -18
  138. package/src/components/modals/AGAlertModal.vue +0 -14
  139. package/src/components/modals/AGConfirmModal.ts +0 -42
  140. package/src/components/modals/AGConfirmModal.vue +0 -26
  141. package/src/components/modals/AGErrorReportModal.vue +0 -54
  142. package/src/components/modals/AGErrorReportModalTitle.vue +0 -25
  143. package/src/components/modals/AGLoadingModal.ts +0 -29
  144. package/src/components/modals/AGLoadingModal.vue +0 -15
  145. package/src/components/modals/AGModal.ts +0 -11
  146. package/src/components/modals/AGModal.vue +0 -42
  147. package/src/components/modals/AGModalContext.ts +0 -8
  148. package/src/components/modals/AGModalTitle.vue +0 -9
  149. package/src/components/modals/AGPromptModal.ts +0 -41
  150. package/src/components/modals/AGPromptModal.vue +0 -34
  151. package/src/components/modals/index.ts +0 -17
  152. package/src/components/snackbars/AGSnackbar.vue +0 -36
  153. package/src/components/snackbars/index.ts +0 -3
  154. package/src/components/utils.ts +0 -13
  155. package/src/forms/composition.ts +0 -6
  156. package/src/utils/tailwindcss.test.ts +0 -26
  157. package/src/utils/tailwindcss.ts +0 -7
package/src/utils/vue.ts CHANGED
@@ -1,64 +1,21 @@
1
1
  import { fail, toString } from '@noeldemartin/utils';
2
- import { computed, inject, reactive, ref, watch } from 'vue';
3
- import type { Directive, InjectionKey, MaybeRef, PropType, Ref, UnwrapNestedRefs } from 'vue';
4
-
5
- type BaseProp<T> = {
6
- type?: PropType<T>;
7
- validator?(value: unknown): boolean;
8
- };
9
-
10
- type RequiredProp<T> = BaseProp<T> & { required: true };
11
- type OptionalProp<T> = BaseProp<T> & { default: T | (() => T) | null };
2
+ import { Comment, Static, Text, inject, reactive } from 'vue';
3
+ import type { Directive, InjectionKey, MaybeRef, Ref, UnwrapNestedRefs, VNode } from 'vue';
12
4
 
13
5
  export type AcceptRefs<T> = { [K in keyof T]: T[K] | RefUnion<T[K]> };
14
- export type ComponentProps = Record<string, unknown>;
15
6
  export type RefUnion<T> = T extends infer R ? Ref<R> : never;
16
7
  export type Unref<T> = { [K in keyof T]: T[K] extends MaybeRef<infer Value> ? Value : T[K] };
17
8
 
18
- export function arrayProp<T>(defaultValue?: () => T[]): OptionalProp<T[]> {
19
- return {
20
- type: Array as PropType<T[]>,
21
- default: defaultValue ?? (() => []),
22
- };
23
- }
24
-
25
- export function booleanProp(defaultValue: boolean = false): OptionalProp<boolean> {
26
- return {
27
- type: Boolean,
28
- default: defaultValue,
29
- };
30
- }
31
-
32
- export function componentRef<T>(): Ref<UnwrapNestedRefs<T> | undefined> {
33
- return ref<UnwrapNestedRefs<T>>();
34
- }
35
-
36
- export function computedAsync<T>(getter: () => Promise<T>): Ref<T | undefined> {
37
- const result = ref<T>();
38
- const asyncValue = computed(getter);
39
-
40
- watch(asyncValue, async () => (result.value = await asyncValue.value), { immediate: true });
41
-
42
- return result;
9
+ function renderVNodeAttrs(node: VNode): string {
10
+ return Object.entries(node.props ?? {}).reduce((attrs, [name, value]) => {
11
+ return attrs + `${name}="${toString(value)}"`;
12
+ }, '');
43
13
  }
44
14
 
45
15
  export function defineDirective(directive: Directive): Directive {
46
16
  return directive;
47
17
  }
48
18
 
49
- export function enumProp<Enum extends Record<string, unknown>>(
50
- enumeration: Enum,
51
- defaultValue?: Enum[keyof Enum],
52
- ): OptionalProp<Enum[keyof Enum]> {
53
- const values = Object.values(enumeration) as Enum[keyof Enum][];
54
-
55
- return {
56
- type: String as unknown as PropType<Enum[keyof Enum]>,
57
- default: defaultValue ?? values[0] ?? null,
58
- validator: (value) => values.includes(value as Enum[keyof Enum]),
59
- };
60
- }
61
-
62
19
  export function injectReactive<T extends object>(key: InjectionKey<T> | string): UnwrapNestedRefs<T> | undefined {
63
20
  const value = inject(key);
64
21
 
@@ -76,92 +33,24 @@ export function injectOrFail<T>(key: InjectionKey<T> | string, errorMessage?: st
76
33
  return inject(key) ?? fail(errorMessage ?? `Could not resolve '${toString(key)}' injection key`);
77
34
  }
78
35
 
79
- export function listenerProp<T extends Function = Function>(): OptionalProp<T | null> {
80
- return {
81
- type: Function as PropType<T>,
82
- default: null,
83
- };
84
- }
85
-
86
- export function mixedProp<T>(type?: PropType<T>): OptionalProp<T | null>;
87
- export function mixedProp<T>(type: PropType<T>, defaultValue: T): OptionalProp<T>;
88
- export function mixedProp<T>(type?: PropType<T>, defaultValue?: T): OptionalProp<T | null> {
89
- return {
90
- type,
91
- default: defaultValue ?? null,
92
- };
93
- }
94
-
95
- export function numberProp(): OptionalProp<number | null>;
96
- export function numberProp(defaultValue: number): OptionalProp<number>;
97
- export function numberProp(defaultValue: number | null = null): OptionalProp<number | null> {
98
- return {
99
- type: Number,
100
- default: defaultValue,
101
- };
102
- }
103
-
104
- export function objectProp<T = Object>(): OptionalProp<T | null>;
105
- export function objectProp<T>(defaultValue: () => T): OptionalProp<T>;
106
- export function objectProp<T = Object>(defaultValue: (() => T) | null = null): OptionalProp<T | null> {
107
- return {
108
- type: Object,
109
- default: defaultValue,
110
- };
111
- }
112
-
113
- export function requiredArrayProp<T>(): RequiredProp<T[]> {
114
- return {
115
- type: Array as PropType<T[]>,
116
- required: true,
117
- };
118
- }
36
+ export function renderVNode(node: VNode | string): string {
37
+ if (typeof node === 'string') {
38
+ return node;
39
+ }
119
40
 
120
- export function requiredEnumProp<Enum extends Record<string, unknown>>(
121
- enumeration: Enum,
122
- ): RequiredProp<Enum[keyof Enum]> {
123
- const values = Object.values(enumeration);
41
+ if (node.type === Comment) {
42
+ return '';
43
+ }
124
44
 
125
- return {
126
- type: String as unknown as PropType<Enum[keyof Enum]>,
127
- required: true,
128
- validator: (value) => values.includes(value),
129
- };
130
- }
45
+ if (node.type === Text || node.type === Static) {
46
+ return node.children as string;
47
+ }
131
48
 
132
- export function requiredMixedProp<T>(type?: PropType<T>): RequiredProp<T> {
133
- return {
134
- type,
135
- required: true,
136
- };
137
- }
138
-
139
- export function requiredNumberProp(): RequiredProp<number> {
140
- return {
141
- type: Number,
142
- required: true,
143
- };
144
- }
145
-
146
- export function requiredObjectProp<T = Object>(): RequiredProp<T> {
147
- return {
148
- type: Object,
149
- required: true,
150
- };
151
- }
152
-
153
- export function requiredStringProp(): RequiredProp<string> {
154
- return {
155
- type: String,
156
- required: true,
157
- };
158
- }
49
+ if (node.type === 'br') {
50
+ return '\n\n';
51
+ }
159
52
 
160
- export function stringProp(): OptionalProp<string | null>;
161
- export function stringProp(defaultValue: string): OptionalProp<string>;
162
- export function stringProp(defaultValue: string | null = null): OptionalProp<string | null> {
163
- return {
164
- type: String,
165
- default: defaultValue,
166
- };
53
+ return `<${node.type} ${renderVNodeAttrs(node)}>${Array.from(node.children as Array<VNode | string>)
54
+ .map(renderVNode)
55
+ .join('')}</${node.type}>`;
167
56
  }
@@ -1,41 +0,0 @@
1
- <template>
2
- <div
3
- id="aerogel-overlays-backdrop"
4
- ref="$backdrop"
5
- class="pointer-events-none fixed inset-0 z-50 bg-black/30 opacity-0"
6
- />
7
- <AGAppModals />
8
- <AGAppSnackbars />
9
- </template>
10
-
11
- <script setup lang="ts">
12
- import { ref } from 'vue';
13
-
14
- import { useEvent } from '@aerogel/core/utils/composition/events';
15
-
16
- import AGAppModals from './AGAppModals.vue';
17
- import AGAppSnackbars from './AGAppSnackbars.vue';
18
-
19
- const $backdrop = ref<HTMLElement | null>(null);
20
- const backdropHidden = ref(true);
21
-
22
- useEvent('show-overlays-backdrop', async () => {
23
- if (!$backdrop.value || !backdropHidden.value) {
24
- return;
25
- }
26
-
27
- backdropHidden.value = false;
28
-
29
- $backdrop.value.classList.remove('opacity-0');
30
- });
31
-
32
- useEvent('hide-overlays-backdrop', async () => {
33
- if (!$backdrop.value || backdropHidden.value) {
34
- return;
35
- }
36
-
37
- backdropHidden.value = true;
38
-
39
- $backdrop.value.classList.add('opacity-0');
40
- });
41
- </script>
@@ -1,13 +0,0 @@
1
- <template>
2
- <div aria-live="assertive" class="pointer-events-none fixed inset-0 z-50 flex items-end px-4 py-6 sm:p-6">
3
- <div class="flex w-full flex-col items-end space-y-4">
4
- <component
5
- :is="snackbar.component"
6
- v-for="snackbar of $ui.snackbars"
7
- :id="snackbar.id"
8
- :key="snackbar.id"
9
- v-bind="snackbar.properties"
10
- />
11
- </div>
12
- </div>
13
- </template>
@@ -1,23 +0,0 @@
1
- import { customRef } from 'vue';
2
- import type { Ref } from 'vue';
3
-
4
- import { getElement } from '@aerogel/core/components/interfaces';
5
-
6
- export function elementRef(): Ref<HTMLElement | undefined> {
7
- return customRef((track, trigger) => {
8
- let value: HTMLElement | undefined = undefined;
9
-
10
- return {
11
- get() {
12
- track();
13
-
14
- return value;
15
- },
16
- set(newValue) {
17
- value = getElement(newValue);
18
-
19
- trigger();
20
- },
21
- };
22
- });
23
- }
@@ -1,8 +0,0 @@
1
- export const Colors = {
2
- Primary: 'primary',
3
- Secondary: 'secondary',
4
- Danger: 'danger',
5
- Clear: 'clear',
6
- } as const;
7
-
8
- export type Color = (typeof Colors)[keyof typeof Colors];
@@ -1,44 +0,0 @@
1
- <template>
2
- <AGHeadlessButton class="px-2.5 py-1.5 focus-visible:outline focus-visible:outline-2" :class="colorClasses">
3
- <slot />
4
- </AGHeadlessButton>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { computed } from 'vue';
9
-
10
- import { enumProp } from '@aerogel/core/utils/vue';
11
- import { Colors } from '@aerogel/core/components/constants';
12
-
13
- import AGHeadlessButton from '../headless/forms/AGHeadlessButton.vue';
14
-
15
- const props = defineProps({
16
- color: enumProp(Colors, Colors.Primary),
17
- });
18
-
19
- const colorClasses = computed(() => {
20
- switch (props.color) {
21
- case Colors.Secondary:
22
- return [
23
- 'text-white bg-gray-600',
24
- 'hover:bg-gray-500',
25
- 'focus-visible:outline-offset-2 focus-visible:outline-gray-600',
26
- ].join(' ');
27
- case Colors.Clear:
28
- return 'hover:bg-gray-500/20 focus-visible:outline-gray-500/60';
29
- case Colors.Danger:
30
- return [
31
- 'text-white bg-red-600',
32
- 'hover:bg-red-500',
33
- 'focus-visible:outline-offset-2 focus-visible:outline-red-600',
34
- ].join(' ');
35
- case Colors.Primary:
36
- default:
37
- return [
38
- 'text-white bg-indigo-600',
39
- 'hover:bg-indigo-500',
40
- 'focus-visible:outline-offset-2 focus-visible:outline-indigo-600',
41
- ].join(' ');
42
- }
43
- });
44
- </script>
@@ -1,42 +0,0 @@
1
- <template>
2
- <AGHeadlessInput
3
- ref="$input"
4
- :name="name"
5
- class="flex"
6
- @update:model-value="$emit('update:modelValue', $event)"
7
- >
8
- <AGHeadlessInputInput
9
- v-bind="$attrs"
10
- type="checkbox"
11
- :class="{
12
- 'text-indigo-600 focus:ring-indigo-600': !$input?.errors,
13
- 'border-red-200 text-red-600 focus:ring-red-600': $input?.errors,
14
- }"
15
- />
16
-
17
- <div class="ml-2">
18
- <AGHeadlessInputLabel v-if="$slots.default">
19
- <slot />
20
- </AGHeadlessInputLabel>
21
- <AGHeadlessInputError class="text-sm text-red-600" />
22
- </div>
23
- </AGHeadlessInput>
24
- </template>
25
-
26
- <script setup lang="ts">
27
- import { componentRef, stringProp } from '@aerogel/core/utils/vue';
28
-
29
- import { useInputEmits } from '@aerogel/core/components/headless/forms/AGHeadlessInput';
30
- import type { IAGHeadlessInput } from '@aerogel/core/components/headless/forms/AGHeadlessInput';
31
-
32
- import AGHeadlessInput from '../headless/forms/AGHeadlessInput.vue';
33
- import AGHeadlessInputError from '../headless/forms/AGHeadlessInputError.vue';
34
- import AGHeadlessInputInput from '../headless/forms/AGHeadlessInputInput.vue';
35
- import AGHeadlessInputLabel from '../headless/forms/AGHeadlessInputLabel.vue';
36
-
37
- defineProps({ name: stringProp() });
38
- defineOptions({ inheritAttrs: false });
39
- defineEmits(useInputEmits());
40
-
41
- const $input = componentRef<IAGHeadlessInput>();
42
- </script>
@@ -1,42 +0,0 @@
1
- <template>
2
- <AGHeadlessInput
3
- ref="$input"
4
- class="relative flex flex-col items-center"
5
- :class="className"
6
- v-bind="props"
7
- @update:model-value="$emit('update:modelValue', $event)"
8
- >
9
- <AGHeadlessInputLabel class="sr-only" />
10
- <AGHeadlessInputInput
11
- v-bind="attrs"
12
- class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"
13
- :class="{
14
- 'ring-1 ring-red-500': $input?.errors,
15
- }"
16
- />
17
- <AGHeadlessInputDescription />
18
- <div class="absolute bottom-0 left-0 translate-y-full">
19
- <AGHeadlessInputError class="mt-1 text-sm text-red-500" />
20
- </div>
21
- </AGHeadlessInput>
22
- </template>
23
-
24
- <script setup lang="ts">
25
- import { componentRef } from '@aerogel/core/utils/vue';
26
- import { useInputAttrs } from '@aerogel/core/utils/composition/forms';
27
- import { useInputEmits, useInputProps } from '@aerogel/core/components/headless/forms/AGHeadlessInput';
28
- import type { IAGHeadlessInput } from '@aerogel/core/components/headless/forms/AGHeadlessInput';
29
-
30
- import AGHeadlessInput from '../headless/forms/AGHeadlessInput.vue';
31
- import AGHeadlessInputDescription from '../headless/forms/AGHeadlessInputDescription.vue';
32
- import AGHeadlessInputError from '../headless/forms/AGHeadlessInputError.vue';
33
- import AGHeadlessInputInput from '../headless/forms/AGHeadlessInputInput.vue';
34
- import AGHeadlessInputLabel from '../headless/forms/AGHeadlessInputLabel.vue';
35
-
36
- defineOptions({ inheritAttrs: false });
37
- defineEmits(useInputEmits());
38
-
39
- const props = defineProps(useInputProps());
40
- const $input = componentRef<IAGHeadlessInput>();
41
- const [attrs, className] = useInputAttrs();
42
- </script>
@@ -1,46 +0,0 @@
1
- <template>
2
- <Story>
3
- <div class="h-96">
4
- <AGSelect v-model="bestMugiwara" :label="bestMugiwaraLabel" :options="bestMugiwaraOptions" />
5
- <AGSelect
6
- v-model="bestFood"
7
- :label="bestFoodLabel"
8
- :options="bestFoodOptions"
9
- options-text="name"
10
- />
11
- </div>
12
- </Story>
13
- </template>
14
-
15
- <script setup lang="ts">
16
- import { ref } from 'vue';
17
-
18
- import AGSelect from './AGSelect.vue';
19
-
20
- const bestMugiwara = ref(null);
21
- const bestFood = ref(null);
22
- const bestMugiwaraLabel = 'Who\'s the best Mugiwara?';
23
- const bestFoodLabel = 'What\'s the best food?';
24
- const bestMugiwaraOptions = [
25
- 'Monkey D. Luffy',
26
- 'Roronoa Zoro',
27
- 'Nami',
28
- 'Usopp',
29
- 'Sanji',
30
- 'Tony Tony Chopper',
31
- 'Nico Robin',
32
- 'Franky',
33
- 'Brook',
34
- 'Jinbe',
35
- ];
36
- const bestFoodOptions = [
37
- {
38
- id: 'ramen',
39
- name: 'Ramen',
40
- },
41
- {
42
- id: 'pizza',
43
- name: 'Pizza',
44
- },
45
- ];
46
- </script>
@@ -1,60 +0,0 @@
1
- <template>
2
- <AGHeadlessSelect
3
- v-bind="props"
4
- ref="$select"
5
- as="div"
6
- @update:model-value="$emit('update:modelValue', $event)"
7
- >
8
- <AGHeadlessSelectLabel class="block text-sm font-medium leading-6 text-gray-900" />
9
- <div class="relative" :class="{ 'mt-2': $select?.label }">
10
- <AGHeadlessSelectButton
11
- class="relative w-full cursor-default bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-600"
12
- text-class="block truncate"
13
- :class="{
14
- 'ring-1 ring-red-500': $select?.errors,
15
- }"
16
- >
17
- <template #icon>
18
- <span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
19
- <IconCheveronDown class="h-5 w-5 text-gray-400" />
20
- </span>
21
- </template>
22
- </AGHeadlessSelectButton>
23
- <AGHeadlessSelectOptions
24
- class="absolute z-10 mt-1 max-h-60 w-full overflow-auto border bg-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none"
25
- >
26
- <AGHeadlessSelectOption
27
- v-for="(option, index) in $select?.options ?? []"
28
- :key="index"
29
- :value="option"
30
- class="relative block cursor-default select-none truncate py-2 pl-3 pr-9"
31
- selected-class="font-semibold"
32
- unselected-class="font-normal"
33
- active-class="bg-indigo-600 text-white"
34
- inactive-class="text-gray-900"
35
- />
36
- </AGHeadlessSelectOptions>
37
- </div>
38
- <AGHeadlessSelectError class="mt-2 text-sm text-red-600" />
39
- </AGHeadlessSelect>
40
- </template>
41
-
42
- <script setup lang="ts">
43
- import IconCheveronDown from '~icons/zondicons/cheveron-down';
44
-
45
- import { componentRef } from '@aerogel/core/utils/vue';
46
- import { useSelectEmits, useSelectProps } from '@aerogel/core/components/headless/forms/AGHeadlessSelect';
47
- import type { IAGHeadlessSelect } from '@aerogel/core/components/headless/forms/AGHeadlessSelect';
48
-
49
- import AGHeadlessSelect from '../headless/forms/AGHeadlessSelect.vue';
50
- import AGHeadlessSelectButton from '../headless/forms/AGHeadlessSelectButton.vue';
51
- import AGHeadlessSelectError from '../headless/forms/AGHeadlessSelectError.vue';
52
- import AGHeadlessSelectLabel from '../headless/forms/AGHeadlessSelectLabel.vue';
53
- import AGHeadlessSelectOption from '../headless/forms/AGHeadlessSelectOption.vue';
54
- import AGHeadlessSelectOptions from '../headless/forms/AGHeadlessSelectOptions';
55
-
56
- defineEmits(useSelectEmits());
57
-
58
- const props = defineProps(useSelectProps());
59
- const $select = componentRef<IAGHeadlessSelect>();
60
- </script>
@@ -1,5 +0,0 @@
1
- export { default as AGButton } from './AGButton.vue';
2
- export { default as AGCheckbox } from './AGCheckbox.vue';
3
- export { default as AGForm } from './AGForm.vue';
4
- export { default as AGInput } from './AGInput.vue';
5
- export { default as AGSelect } from './AGSelect.vue';
@@ -1,3 +0,0 @@
1
- import type { HasElement } from '@aerogel/core/components/interfaces';
2
-
3
- export interface IAGHeadlessButton extends HasElement {}
@@ -1,62 +0,0 @@
1
- <template>
2
- <component :is="component.as" ref="$root" v-bind="component.props">
3
- <slot />
4
- </component>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { computed } from 'vue';
9
- import { objectWithoutEmpty } from '@noeldemartin/utils';
10
-
11
- import { booleanProp, objectProp, stringProp } from '@aerogel/core/utils/vue';
12
- import { elementRef } from '@aerogel/core/components/composition';
13
-
14
- import type { IAGHeadlessButton } from './AGHeadlessButton';
15
-
16
- const props = defineProps({
17
- as: objectProp(),
18
- href: stringProp(),
19
- url: stringProp(),
20
- route: stringProp(),
21
- routeParams: objectProp(() => ({})),
22
- routeQuery: objectProp(() => ({})),
23
- submit: booleanProp(),
24
- });
25
-
26
- const $root = elementRef();
27
- const component = computed(() => {
28
- if (props.as) {
29
- return { as: props.as, props: {} };
30
- }
31
-
32
- if (props.route) {
33
- return {
34
- as: 'router-link',
35
- props: {
36
- to: objectWithoutEmpty({
37
- name: props.route,
38
- params: props.routeParams,
39
- query: props.routeQuery,
40
- }),
41
- },
42
- };
43
- }
44
-
45
- if (props.href || props.url) {
46
- return {
47
- as: 'a',
48
- props: {
49
- target: '_blank',
50
- href: props.href || props.url,
51
- },
52
- };
53
- }
54
-
55
- return {
56
- as: 'button',
57
- props: { type: props.submit ? 'submit' : 'button' },
58
- };
59
- });
60
-
61
- defineExpose<IAGHeadlessButton>({ $el: $root });
62
- </script>
@@ -1,41 +0,0 @@
1
- import type { ComputedRef, DeepReadonly, ExtractPropTypes, Ref } from 'vue';
2
- import type { Writable } from '@noeldemartin/utils';
3
-
4
- import { mixedProp, stringProp } from '@aerogel/core/utils';
5
- import { extractComponentProps } from '@aerogel/core/components/utils';
6
- import type { FormFieldValue } from '@aerogel/core/forms/Form';
7
- import type { HasElement } from '@aerogel/core/components/interfaces';
8
-
9
- export interface IAGHeadlessInput extends HasElement {
10
- id: string;
11
- name: ComputedRef<string | null>;
12
- label: ComputedRef<string | null>;
13
- description: ComputedRef<string | boolean | null>;
14
- value: ComputedRef<FormFieldValue | null>;
15
- required: ComputedRef<boolean | null>;
16
- errors: DeepReadonly<Ref<string[] | null>>;
17
- update(value: FormFieldValue | null): void;
18
- }
19
-
20
- export const inputProps = {
21
- name: stringProp(),
22
- label: stringProp(),
23
- description: stringProp(),
24
- modelValue: mixedProp<FormFieldValue>([String, Number, Boolean]),
25
- };
26
-
27
- export const inputEmits = ['update:modelValue'] as const;
28
-
29
- export function useInputEmits(): Writable<typeof inputEmits> {
30
- return [...inputEmits];
31
- }
32
-
33
- export function useInputProps(): typeof inputProps {
34
- return inputProps;
35
- }
36
-
37
- export function extractInputProps<T extends ExtractPropTypes<typeof inputProps>>(
38
- props: T,
39
- ): Pick<T, keyof typeof inputProps> {
40
- return extractComponentProps(props, inputProps);
41
- }