@aerogel/core 0.0.0-next.9a1c5ba39a454b316eba36ec7bdf579fed3d95d2 → 0.0.0-next.9aa7c279868edbedbcee075aef52212597d803fb

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 (154) hide show
  1. package/dist/aerogel-core.d.ts +1283 -1588
  2. package/dist/aerogel-core.js +2496 -1994
  3. package/dist/aerogel-core.js.map +1 -1
  4. package/package.json +10 -2
  5. package/src/components/AppLayout.vue +14 -0
  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 +8 -0
  10. package/src/components/contracts/Button.ts +16 -0
  11. package/src/components/contracts/ConfirmModal.ts +46 -0
  12. package/src/components/contracts/DropdownMenu.ts +20 -0
  13. package/src/components/{modals/AGErrorReportModal.ts → contracts/ErrorReportModal.ts} +5 -22
  14. package/src/components/contracts/Input.ts +26 -0
  15. package/src/components/contracts/LoadingModal.ts +26 -0
  16. package/src/components/contracts/Modal.ts +15 -10
  17. package/src/components/contracts/PromptModal.ts +34 -0
  18. package/src/components/contracts/Select.ts +45 -0
  19. package/src/components/contracts/Toast.ts +15 -0
  20. package/src/components/contracts/index.ts +10 -1
  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 +5 -10
  44. package/src/components/ui/AdvancedOptions.vue +18 -0
  45. package/src/components/ui/AlertModal.vue +14 -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 +45 -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 +67 -0
  55. package/src/components/{modals/AGErrorReportModalButtons.vue → ui/ErrorReportModalButtons.vue} +28 -21
  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 +34 -0
  61. package/src/components/ui/Markdown.vue +69 -0
  62. package/src/components/ui/Modal.vue +122 -0
  63. package/src/components/{modals/AGModalContext.vue → ui/ModalContext.vue} +8 -9
  64. package/src/components/ui/ProgressBar.vue +51 -0
  65. package/src/components/ui/PromptModal.vue +38 -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} +7 -7
  73. package/src/components/ui/Toast.vue +44 -0
  74. package/src/components/ui/index.ts +30 -0
  75. package/src/errors/Errors.ts +7 -16
  76. package/src/forms/{Form.test.ts → FormController.test.ts} +32 -9
  77. package/src/forms/{Form.ts → FormController.ts} +28 -27
  78. package/src/forms/index.ts +2 -3
  79. package/src/forms/utils.ts +35 -35
  80. package/src/index.css +72 -0
  81. package/src/lang/index.ts +4 -0
  82. package/src/lang/settings/Language.vue +48 -0
  83. package/src/lang/settings/index.ts +10 -0
  84. package/src/services/App.state.ts +11 -1
  85. package/src/services/App.ts +9 -1
  86. package/src/services/Events.test.ts +8 -8
  87. package/src/services/Events.ts +2 -8
  88. package/src/services/index.ts +3 -0
  89. package/src/ui/UI.state.ts +7 -12
  90. package/src/ui/UI.ts +102 -103
  91. package/src/ui/index.ts +23 -24
  92. package/src/utils/classes.ts +49 -0
  93. package/src/utils/composition/events.ts +2 -4
  94. package/src/utils/composition/forms.ts +20 -4
  95. package/src/utils/composition/state.ts +11 -2
  96. package/src/utils/index.ts +3 -1
  97. package/src/utils/types.ts +3 -0
  98. package/src/utils/vue.ts +22 -128
  99. package/src/components/AGAppLayout.vue +0 -16
  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/contracts/shared.ts +0 -9
  105. package/src/components/forms/AGButton.vue +0 -44
  106. package/src/components/forms/AGCheckbox.vue +0 -42
  107. package/src/components/forms/AGInput.vue +0 -42
  108. package/src/components/forms/AGSelect.story.vue +0 -46
  109. package/src/components/forms/AGSelect.vue +0 -54
  110. package/src/components/forms/index.ts +0 -5
  111. package/src/components/headless/forms/AGHeadlessButton.ts +0 -3
  112. package/src/components/headless/forms/AGHeadlessButton.vue +0 -62
  113. package/src/components/headless/forms/AGHeadlessInput.ts +0 -41
  114. package/src/components/headless/forms/AGHeadlessInput.vue +0 -70
  115. package/src/components/headless/forms/AGHeadlessSelect.ts +0 -42
  116. package/src/components/headless/forms/AGHeadlessSelect.vue +0 -77
  117. package/src/components/headless/forms/AGHeadlessSelectOption.ts +0 -4
  118. package/src/components/headless/forms/AGHeadlessSelectOption.vue +0 -31
  119. package/src/components/headless/forms/AGHeadlessSelectOptions.vue +0 -19
  120. package/src/components/headless/forms/AGHeadlessSelectTrigger.vue +0 -25
  121. package/src/components/headless/forms/composition.ts +0 -10
  122. package/src/components/headless/forms/index.ts +0 -17
  123. package/src/components/headless/modals/AGHeadlessModal.ts +0 -33
  124. package/src/components/headless/modals/AGHeadlessModal.vue +0 -88
  125. package/src/components/headless/modals/AGHeadlessModalContent.vue +0 -25
  126. package/src/components/headless/modals/index.ts +0 -5
  127. package/src/components/headless/snackbars/AGHeadlessSnackbar.vue +0 -10
  128. package/src/components/headless/snackbars/index.ts +0 -40
  129. package/src/components/lib/AGErrorMessage.vue +0 -16
  130. package/src/components/lib/AGLink.vue +0 -9
  131. package/src/components/lib/AGMarkdown.vue +0 -54
  132. package/src/components/lib/AGMeasured.vue +0 -16
  133. package/src/components/lib/AGProgressBar.vue +0 -55
  134. package/src/components/lib/index.ts +0 -6
  135. package/src/components/modals/AGAlertModal.ts +0 -18
  136. package/src/components/modals/AGAlertModal.vue +0 -14
  137. package/src/components/modals/AGConfirmModal.ts +0 -42
  138. package/src/components/modals/AGConfirmModal.vue +0 -27
  139. package/src/components/modals/AGErrorReportModal.vue +0 -54
  140. package/src/components/modals/AGErrorReportModalTitle.vue +0 -25
  141. package/src/components/modals/AGLoadingModal.ts +0 -29
  142. package/src/components/modals/AGLoadingModal.vue +0 -15
  143. package/src/components/modals/AGModal.vue +0 -40
  144. package/src/components/modals/AGModalContext.ts +0 -8
  145. package/src/components/modals/AGModalTitle.vue +0 -9
  146. package/src/components/modals/AGPromptModal.ts +0 -41
  147. package/src/components/modals/AGPromptModal.vue +0 -35
  148. package/src/components/modals/index.ts +0 -16
  149. package/src/components/snackbars/AGSnackbar.vue +0 -36
  150. package/src/components/snackbars/index.ts +0 -3
  151. package/src/components/utils.ts +0 -63
  152. package/src/forms/composition.ts +0 -6
  153. package/src/utils/tailwindcss.test.ts +0 -26
  154. package/src/utils/tailwindcss.ts +0 -7
package/src/utils/vue.ts CHANGED
@@ -1,59 +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';
2
+ import { Comment, Static, Text, inject, reactive } from 'vue';
3
+ import type { Directive, InjectionKey, MaybeRef, Ref, UnwrapNestedRefs, VNode } from 'vue';
4
4
 
5
5
  export type AcceptRefs<T> = { [K in keyof T]: T[K] | RefUnion<T[K]> };
6
- export type BaseProp<T> = { type?: PropType<T>; validator?(value: unknown): boolean };
7
- export type ComponentProps<T = {}> = T & Record<string, unknown>;
8
- export type OptionalProp<T> = BaseProp<T> & { default: T | (() => T) | null };
9
6
  export type RefUnion<T> = T extends infer R ? Ref<R> : never;
10
- export type RequiredProp<T> = BaseProp<T> & { required: true };
11
7
  export type Unref<T> = { [K in keyof T]: T[K] extends MaybeRef<infer Value> ? Value : T[K] };
12
8
 
13
- export function arrayProp<T>(defaultValue?: () => T[]): OptionalProp<T[]> {
14
- return {
15
- type: Array as PropType<T[]>,
16
- default: defaultValue ?? (() => []),
17
- };
18
- }
19
-
20
- export function booleanProp(defaultValue: boolean = false): OptionalProp<boolean> {
21
- return {
22
- type: Boolean,
23
- default: defaultValue,
24
- };
25
- }
26
-
27
- export function componentRef<T>(): Ref<UnwrapNestedRefs<T> | undefined> {
28
- return ref<UnwrapNestedRefs<T>>();
29
- }
30
-
31
- export function computedAsync<T>(getter: () => Promise<T>): Ref<T | undefined> {
32
- const result = ref<T>();
33
- const asyncValue = computed(getter);
34
-
35
- watch(asyncValue, async () => (result.value = await asyncValue.value), { immediate: true });
36
-
37
- 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
+ }, '');
38
13
  }
39
14
 
40
15
  export function defineDirective(directive: Directive): Directive {
41
16
  return directive;
42
17
  }
43
18
 
44
- export function enumProp<Enum extends Record<string, unknown>>(
45
- enumeration: Enum,
46
- defaultValue?: Enum[keyof Enum],
47
- ): OptionalProp<Enum[keyof Enum]> {
48
- const values = Object.values(enumeration) as Enum[keyof Enum][];
49
-
50
- return {
51
- type: String as unknown as PropType<Enum[keyof Enum]>,
52
- default: defaultValue ?? values[0] ?? null,
53
- validator: (value) => values.includes(value as Enum[keyof Enum]),
54
- };
55
- }
56
-
57
19
  export function injectReactive<T extends object>(key: InjectionKey<T> | string): UnwrapNestedRefs<T> | undefined {
58
20
  const value = inject(key);
59
21
 
@@ -71,92 +33,24 @@ export function injectOrFail<T>(key: InjectionKey<T> | string, errorMessage?: st
71
33
  return inject(key) ?? fail(errorMessage ?? `Could not resolve '${toString(key)}' injection key`);
72
34
  }
73
35
 
74
- export function listenerProp<T extends Function = Function>(): OptionalProp<T | null> {
75
- return {
76
- type: Function as PropType<T>,
77
- default: null,
78
- };
79
- }
80
-
81
- export function mixedProp<T>(type?: PropType<T>): OptionalProp<T | null>;
82
- export function mixedProp<T>(type: PropType<T>, defaultValue: T): OptionalProp<T>;
83
- export function mixedProp<T>(type?: PropType<T>, defaultValue?: T): OptionalProp<T | null> {
84
- return {
85
- type,
86
- default: defaultValue ?? null,
87
- };
88
- }
89
-
90
- export function numberProp(): OptionalProp<number | null>;
91
- export function numberProp(defaultValue: number): OptionalProp<number>;
92
- export function numberProp(defaultValue: number | null = null): OptionalProp<number | null> {
93
- return {
94
- type: Number,
95
- default: defaultValue,
96
- };
97
- }
98
-
99
- export function objectProp<T = Object>(): OptionalProp<T | null>;
100
- export function objectProp<T>(defaultValue: () => T): OptionalProp<T>;
101
- export function objectProp<T = Object>(defaultValue: (() => T) | null = null): OptionalProp<T | null> {
102
- return {
103
- type: Object,
104
- default: defaultValue,
105
- };
106
- }
107
-
108
- export function requiredArrayProp<T>(): RequiredProp<T[]> {
109
- return {
110
- type: Array as PropType<T[]>,
111
- required: true,
112
- };
113
- }
114
-
115
- export function requiredEnumProp<Enum extends Record<string, unknown>>(
116
- enumeration: Enum,
117
- ): RequiredProp<Enum[keyof Enum]> {
118
- const values = Object.values(enumeration);
36
+ export function renderVNode(node: VNode | string): string {
37
+ if (typeof node === 'string') {
38
+ return node;
39
+ }
119
40
 
120
- return {
121
- type: String as unknown as PropType<Enum[keyof Enum]>,
122
- required: true,
123
- validator: (value) => values.includes(value),
124
- };
125
- }
126
-
127
- export function requiredMixedProp<T>(type?: PropType<T>): RequiredProp<T> {
128
- return {
129
- type,
130
- required: true,
131
- };
132
- }
41
+ if (node.type === Comment) {
42
+ return '';
43
+ }
133
44
 
134
- export function requiredNumberProp(): RequiredProp<number> {
135
- return {
136
- type: Number,
137
- required: true,
138
- };
139
- }
45
+ if (node.type === Text || node.type === Static) {
46
+ return node.children as string;
47
+ }
140
48
 
141
- export function requiredObjectProp<T = Object>(): RequiredProp<T> {
142
- return {
143
- type: Object,
144
- required: true,
145
- };
146
- }
147
-
148
- export function requiredStringProp(): RequiredProp<string> {
149
- return {
150
- type: String,
151
- required: true,
152
- };
153
- }
49
+ if (node.type === 'br') {
50
+ return '\n\n';
51
+ }
154
52
 
155
- export function stringProp(): OptionalProp<string | null>;
156
- export function stringProp(defaultValue: string): OptionalProp<string>;
157
- export function stringProp(defaultValue: string | null = null): OptionalProp<string | null> {
158
- return {
159
- type: String,
160
- default: defaultValue,
161
- };
53
+ return `<${node.type} ${renderVNodeAttrs(node)}>${Array.from(node.children as Array<VNode | string>)
54
+ .map(renderVNode)
55
+ .join('')}</${node.type}>`;
162
56
  }
@@ -1,16 +0,0 @@
1
- <template>
2
- <div class="flex min-h-full flex-col text-base font-normal leading-tight text-gray-900 antialiased">
3
- <slot v-if="$errors.hasStartupErrors" name="startup-crash">
4
- <component :is="$ui.requireComponent(UIComponents.StartupCrash)" />
5
- </slot>
6
- <slot v-else />
7
-
8
- <AGAppOverlays />
9
- </div>
10
- </template>
11
-
12
- <script setup lang="ts">
13
- import { UIComponents } from '@aerogel/core/ui/UI';
14
-
15
- import AGAppOverlays from './AGAppOverlays.vue';
16
- </script>
@@ -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/utils';
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,9 +0,0 @@
1
- import type { Ref } from 'vue';
2
-
3
- export interface HasElement {
4
- $el: Readonly<Ref<HTMLElement | undefined>>;
5
- }
6
-
7
- export interface __SetsElement {
8
- __setElement(element?: HTMLElement): void;
9
- }
@@ -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,54 +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
- <div class="relative" :class="{ 'mt-2': $select?.label }">
9
- <AGHeadlessSelectTrigger
10
- class="relative w-full cursor-default bg-white py-1.5 pr-10 pl-3 text-left text-gray-900 ring-1 ring-gray-300 ring-inset focus:ring-2 focus:ring-indigo-600 focus:outline-hidden"
11
- text-class="block truncate"
12
- :class="{
13
- 'ring-1 ring-red-500': $select?.errors,
14
- }"
15
- >
16
- <template #icon>
17
- <span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
18
- <IconCheveronDown class="size-5 text-gray-400" />
19
- </span>
20
- </template>
21
- </AGHeadlessSelectTrigger>
22
- <AGHeadlessSelectOptions
23
- class="absolute z-10 mt-1 max-h-60 w-full overflow-auto border border-gray-300 bg-white py-1 text-base ring-1 ring-black/5 focus:outline-hidden"
24
- >
25
- <AGHeadlessSelectOption
26
- v-for="(option, index) in $select?.options ?? []"
27
- :key="index"
28
- :value="option"
29
- class="relative block cursor-default truncate py-2 pr-9 pl-3 text-gray-900 select-none data-[highlighted]:bg-indigo-600 data-[highlighted]:text-white data-[state=checked]:font-semibold data-[state=unchecked]:font-normal"
30
- />
31
- </AGHeadlessSelectOptions>
32
- </div>
33
- <AGHeadlessSelectError class="mt-2 text-sm text-red-600" />
34
- </AGHeadlessSelect>
35
- </template>
36
-
37
- <script setup lang="ts">
38
- import IconCheveronDown from '~icons/zondicons/cheveron-down';
39
-
40
- import { componentRef } from '@aerogel/core/utils/vue';
41
- import { useSelectEmits, useSelectProps } from '@aerogel/core/components/headless/forms/AGHeadlessSelect';
42
- import type { IAGHeadlessSelect } from '@aerogel/core/components/headless/forms/AGHeadlessSelect';
43
-
44
- import AGHeadlessSelect from '../headless/forms/AGHeadlessSelect.vue';
45
- import AGHeadlessSelectTrigger from '../headless/forms/AGHeadlessSelectTrigger.vue';
46
- import AGHeadlessSelectError from '../headless/forms/AGHeadlessSelectError.vue';
47
- import AGHeadlessSelectOption from '../headless/forms/AGHeadlessSelectOption.vue';
48
- import AGHeadlessSelectOptions from '../headless/forms/AGHeadlessSelectOptions.vue';
49
-
50
- defineEmits(useSelectEmits());
51
-
52
- const props = defineProps(useSelectProps());
53
- const $select = componentRef<IAGHeadlessSelect>();
54
- </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/contracts/shared';
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/contracts/shared';
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
- }