@aerogel/core 0.0.0-next.d197d66a9d339318d752a1d8a96b2919faba3003 → 0.0.0-next.d4f3ae130b52cace673d7c95681c19256ee1acb4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerogel/core",
3
- "version": "0.0.0-next.d197d66a9d339318d752a1d8a96b2919faba3003",
3
+ "version": "0.0.0-next.d4f3ae130b52cace673d7c95681c19256ee1acb4",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "peerDependencies": {
26
26
  "@tailwindcss/forms": "^0.5.10",
27
27
  "@tailwindcss/typography": "^0.5.16",
28
- "tailwindcss": "^4.1.1",
28
+ "tailwindcss": "^4.1.4",
29
29
  "vue": "^3.5.0"
30
30
  },
31
31
  "dependencies": {
@@ -1,3 +1,6 @@
1
+ import { computed } from 'vue';
2
+
3
+ import { translateWithDefault } from '@aerogel/core/lang';
1
4
  import type { ModalExpose } from '@aerogel/core/components/contracts/Modal';
2
5
 
3
6
  export interface AlertModalProps {
@@ -6,3 +9,11 @@ export interface AlertModalProps {
6
9
  }
7
10
 
8
11
  export interface AlertModalExpose extends ModalExpose<void> {}
12
+
13
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
14
+ export function useAlertModal(props: AlertModalProps) {
15
+ const renderedTitle = computed(() => props.title ?? translateWithDefault('ui.alert', 'Alert'));
16
+ const titleHidden = computed(() => !props.title);
17
+
18
+ return { renderedTitle, titleHidden };
19
+ }
@@ -39,8 +39,10 @@ export function useConfirmModal(props: ConfirmModalProps) {
39
39
  ),
40
40
  );
41
41
 
42
+ const renderedTitle = computed(() => props.title ?? translateWithDefault('ui.confirm', 'Confirm'));
43
+ const titleHidden = computed(() => !props.title);
42
44
  const renderedAcceptText = computed(() => props.acceptText ?? translateWithDefault('ui.accept', 'Ok'));
43
45
  const renderedCancelText = computed(() => props.cancelText ?? translateWithDefault('ui.cancel', 'Cancel'));
44
46
 
45
- return { form, renderedAcceptText, renderedCancelText };
47
+ return { form, renderedTitle, titleHidden, renderedAcceptText, renderedCancelText };
46
48
  }
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <details class="group">
3
3
  <summary
4
- class="-ml-2 flex w-[max-content] cursor-pointer items-center rounded-lg py-2 pr-3 pl-1 hover:bg-gray-100 focus-visible:outline focus-visible:outline-gray-700"
4
+ class="-ml-2 flex w-[max-content] items-center rounded-lg py-2 pr-3 pl-1 hover:bg-gray-100 focus-visible:outline focus-visible:outline-gray-700"
5
5
  >
6
6
  <IconCheveronRight class="size-6 transition-transform group-open:rotate-90" />
7
7
  <span>{{ $td('ui.advancedOptions', 'Advanced options') }}</span>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <Modal :title>
2
+ <Modal :title="renderedTitle" :title-hidden="titleHidden">
3
3
  <Markdown :text="message" />
4
4
  </Modal>
5
5
  </template>
@@ -7,8 +7,11 @@
7
7
  <script setup lang="ts">
8
8
  import Modal from '@aerogel/core/components/ui/Modal.vue';
9
9
  import Markdown from '@aerogel/core/components/ui/Markdown.vue';
10
+ import { useAlertModal } from '@aerogel/core/components/contracts/AlertModal';
10
11
  import type { AlertModalExpose, AlertModalProps } from '@aerogel/core/components/contracts/AlertModal';
11
12
 
12
- defineProps<AlertModalProps>();
13
+ const props = defineProps<AlertModalProps>();
14
+ const { renderedTitle, titleHidden } = useAlertModal(props);
15
+
13
16
  defineExpose<AlertModalExpose>();
14
17
  </script>
@@ -5,8 +5,10 @@
5
5
  </template>
6
6
 
7
7
  <script setup lang="ts">
8
+ import { computed } from 'vue';
9
+
8
10
  import HeadlessButton from '@aerogel/core/components/headless/HeadlessButton.vue';
9
- import { computedVariantClasses } from '@aerogel/core/utils/classes';
11
+ import { variantClasses } from '@aerogel/core/utils/classes';
10
12
  import type { ButtonProps } from '@aerogel/core/components/contracts/Button';
11
13
  import type { Variants } from '@aerogel/core/utils/classes';
12
14
 
@@ -14,10 +16,10 @@ const { class: baseClasses, size, variant, disabled, ...props } = defineProps<Bu
14
16
 
15
17
  /* eslint-disable vue/max-len */
16
18
  // prettier-ignore
17
- const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size' | 'variant' | 'disabled'>>>(
19
+ const renderedClasses = computed(() => variantClasses<Variants<Pick<ButtonProps, 'size' | 'variant' | 'disabled'>>>(
18
20
  { baseClasses, variant, size, disabled },
19
21
  {
20
- baseClasses: 'flex items-center justify-center gap-1 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
22
+ baseClasses: 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
21
23
  variants: {
22
24
  variant: {
23
25
  default: 'bg-primary-600 text-white focus-visible:outline-primary-600',
@@ -25,12 +27,12 @@ const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size'
25
27
  danger: 'bg-red-600 text-white focus-visible:outline-red-600',
26
28
  ghost: 'bg-transparent',
27
29
  outline: 'bg-transparent text-primary-600 ring-primary-600',
28
- link: 'text-primary-600',
30
+ link: 'text-links',
29
31
  },
30
32
  size: {
31
- small: 'text-xs',
32
- default: 'text-sm',
33
- large: 'text-base',
33
+ small: 'text-xs min-h-6',
34
+ default: 'text-sm min-h-8',
35
+ large: 'text-base min-h-10',
34
36
  icon: 'rounded-full p-2.5',
35
37
  },
36
38
  disabled: {
@@ -41,7 +43,7 @@ const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size'
41
43
  compoundVariants: [
42
44
  {
43
45
  variant: ['default', 'secondary', 'danger', 'ghost', 'outline'],
44
- class: 'font-medium',
46
+ class: 'flex items-center justify-center gap-1 font-medium',
45
47
  },
46
48
  {
47
49
  variant: ['default', 'danger'],
@@ -93,6 +95,6 @@ const renderedClasses = computedVariantClasses<Variants<Pick<ButtonProps, 'size'
93
95
  disabled: false,
94
96
  },
95
97
  },
96
- );
98
+ ));
97
99
  /* eslint-enable vue/max-len */
98
100
  </script>
@@ -1,6 +1,11 @@
1
1
  <template>
2
2
  <!-- @vue-generic {import('@aerogel/core/ui/UI').ModalExposeResult<ConfirmModalExpose>} -->
3
- <Modal v-slot="{ close }" :title persistent>
3
+ <Modal
4
+ v-slot="{ close }"
5
+ :title="renderedTitle"
6
+ :title-hidden="titleHidden"
7
+ persistent
8
+ >
4
9
  <Form :form @submit="close([true, form.data()])">
5
10
  <Markdown :text="message" :actions />
6
11
 
@@ -39,7 +44,7 @@ import { useConfirmModal } from '@aerogel/core/components/contracts/ConfirmModal
39
44
  import type { ConfirmModalExpose, ConfirmModalProps } from '@aerogel/core/components/contracts/ConfirmModal';
40
45
 
41
46
  const { cancelVariant = 'secondary', ...props } = defineProps<ConfirmModalProps>();
42
- const { form, renderedAcceptText, renderedCancelText } = useConfirmModal(props);
47
+ const { form, renderedTitle, titleHidden, renderedAcceptText, renderedCancelText } = useConfirmModal(props);
43
48
 
44
49
  defineExpose<ConfirmModalExpose>();
45
50
  </script>
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <Modal wrapper-class="p-0 sm:w-auto sm:min-w-lg sm:max-w-[80vw]">
2
+ <Modal
3
+ :title="$td('errors.report', 'Errors report')"
4
+ title-hidden
5
+ wrapper-class="p-0 sm:w-auto sm:min-w-lg sm:max-w-[80vw]"
6
+ close-class="hidden"
7
+ >
3
8
  <div class="px-4 pt-5 pb-4">
4
9
  <h2 class="flex justify-between gap-4">
5
10
  <div class="flex items-center gap-2">
@@ -67,3 +67,19 @@ async function onClick(event: Event) {
67
67
  }
68
68
  }
69
69
  </script>
70
+
71
+ <style scoped>
72
+ /* @apply .text-links .font-normal .no-underline .hover:underline; */
73
+ * :deep(a) {
74
+ --tw-font-weight: var(--font-weight-normal);
75
+ text-decoration-line: none;
76
+ color: var(--color-links);
77
+ font-weight: var(--font-weight-normal);
78
+ }
79
+
80
+ @media (hover: hover) {
81
+ * :deep(a:hover) {
82
+ text-decoration-line: underline;
83
+ }
84
+ }
85
+ </style>
@@ -14,7 +14,7 @@
14
14
  }"
15
15
  />
16
16
  <HeadlessModalContent v-bind="contentProps" :class="renderedWrapperClass">
17
- <div v-if="!persistent && dismissable" class="absolute top-0 right-0 hidden pt-3.5 pr-2.5 sm:block">
17
+ <div v-if="!persistent" :class="renderedCloseClass">
18
18
  <button
19
19
  type="button"
20
20
  class="clickable z-10 rounded-full p-2.5 text-gray-400 hover:text-gray-500"
@@ -71,7 +71,7 @@ type HeadlessModalInstance = ComponentPublicInstance & ModalExpose<T>;
71
71
 
72
72
  const {
73
73
  class: contentClass = '',
74
- dismissable = true,
74
+ closeClass = '',
75
75
  wrapperClass = '',
76
76
  title,
77
77
  titleHidden,
@@ -80,7 +80,7 @@ const {
80
80
  ...props
81
81
  } = defineProps<
82
82
  ModalProps & {
83
- dismissable?: boolean;
83
+ closeClass?: HTMLAttributes['class'];
84
84
  wrapperClass?: HTMLAttributes['class'];
85
85
  class?: HTMLAttributes['class'];
86
86
  }
@@ -98,6 +98,7 @@ const context = injectReactiveOrFail<UIModalContext>('modal');
98
98
  const inForeground = computed(() => !context.modal.closing && context.childIndex === UI.openModals.length);
99
99
  const contentProps = computed(() => (description ? {} : { 'aria-describedby': undefined }));
100
100
  const renderedContentClass = computed(() => classes({ 'mt-2': title && !titleHidden }, contentClass));
101
+ const renderedCloseClass = computed(() => classes('absolute top-0 right-0 hidden pt-3.5 pr-2.5 sm:block', closeClass));
101
102
  const renderedWrapperClass = computed(() =>
102
103
  classes(
103
104
  'isolate fixed top-1/2 left-1/2 z-50 w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2',
@@ -1,11 +1,11 @@
1
1
  <template>
2
2
  <HeadlessSelectOptions :class="renderedClasses">
3
- <slot v-if="select?.options?.length">
3
+ <slot v-if="select.options?.length">
4
4
  <SelectOption v-for="option of select?.options ?? []" :key="option.key" :value="option.value">
5
5
  {{ option.label }}
6
6
  </SelectOption>
7
7
  </slot>
8
- <slot v-else name="empty">
8
+ <slot v-else>
9
9
  <SelectOption disabled :value="null">
10
10
  {{ $td('ui.selectEmpty', 'No options available') }}
11
11
  </SelectOption>
@@ -13,32 +13,34 @@
13
13
  </template>
14
14
 
15
15
  <script setup lang="ts">
16
+ import { computed } from 'vue';
16
17
  import type { HTMLAttributes } from 'vue';
17
18
 
18
19
  import Button from '@aerogel/core/components/ui/Button.vue';
19
20
  import Markdown from '@aerogel/core/components/ui/Markdown.vue';
20
21
  import HeadlessToast from '@aerogel/core/components/headless/HeadlessToast.vue';
21
22
  import HeadlessToastAction from '@aerogel/core/components/headless/HeadlessToastAction.vue';
22
- import { computedVariantClasses } from '@aerogel/core/utils/classes';
23
+ import { variantClasses } from '@aerogel/core/utils/classes';
23
24
  import type { ToastExpose, ToastProps } from '@aerogel/core/components/contracts/Toast';
24
25
  import type { Variants } from '@aerogel/core/utils/classes';
25
26
 
26
27
  const { class: baseClasses, variant = 'secondary' } = defineProps<ToastProps & { class?: HTMLAttributes['class'] }>();
27
- const renderedClasses = computedVariantClasses<Variants<Pick<ToastProps, 'variant'>>>(
28
- { baseClasses, variant },
29
- {
30
- baseClasses: 'flex items-center gap-2 rounded-md p-2 ring-1 shadow-lg border-gray-200',
31
- variants: {
32
- variant: {
33
- secondary: 'bg-gray-900 text-white ring-black',
34
- danger: 'bg-red-50 text-red-900 ring-red-100',
28
+ const renderedClasses = computed(() =>
29
+ variantClasses<Variants<Pick<ToastProps, 'variant'>>>(
30
+ { baseClasses, variant },
31
+ {
32
+ baseClasses: 'flex items-center gap-2 rounded-md p-2 ring-1 shadow-lg border-gray-200',
33
+ variants: {
34
+ variant: {
35
+ secondary: 'bg-gray-900 text-white ring-black',
36
+ danger: 'bg-red-50 text-red-900 ring-red-100',
37
+ },
38
+ },
39
+ defaultVariants: {
40
+ variant: 'secondary',
35
41
  },
36
42
  },
37
- defaultVariants: {
38
- variant: 'secondary',
39
- },
40
- },
41
- );
43
+ ));
42
44
 
43
45
  defineExpose<ToastExpose>();
44
46
  </script>
@@ -3,6 +3,15 @@ import { tap } from '@noeldemartin/utils';
3
3
 
4
4
  const resizeObservers: WeakMap<HTMLElement, ResizeObserver> = new WeakMap();
5
5
 
6
+ export type MeasureDirectiveValue =
7
+ | MeasureDirectiveListener
8
+ | {
9
+ css?: boolean;
10
+ watch?: boolean;
11
+ };
12
+
13
+ export type MeasureDirectiveModifiers = 'css' | 'watch';
14
+
6
15
  export interface ElementSize {
7
16
  width: number;
8
17
  height: number;
@@ -10,11 +19,8 @@ export interface ElementSize {
10
19
 
11
20
  export type MeasureDirectiveListener = (size: ElementSize) => unknown;
12
21
 
13
- export default defineDirective({
14
- mounted(element: HTMLElement, { value }) {
15
- // TODO replace with argument when typed properly
16
- const modifiers = { css: true, watch: true };
17
-
22
+ export default defineDirective<MeasureDirectiveValue, MeasureDirectiveModifiers>({
23
+ mounted(element: HTMLElement, { value, modifiers }) {
18
24
  const listener = typeof value === 'function' ? (value as MeasureDirectiveListener) : null;
19
25
  const update = () => {
20
26
  const sizes = element.getBoundingClientRect();
package/src/index.css CHANGED
@@ -6,8 +6,6 @@
6
6
  @source './';
7
7
 
8
8
  @theme {
9
- --color-background: oklch(1 0 0);
10
-
11
9
  --color-primary: oklch(0.205 0 0);
12
10
  --color-primary-50: color-mix(in oklab, var(--color-primary-600) 5%, transparent);
13
11
  --color-primary-100: color-mix(in oklab, var(--color-primary-600) 15%, transparent);
@@ -20,6 +18,9 @@
20
18
  --color-primary-800: color-mix(in oklab, var(--color-primary-600) 80%, black);
21
19
  --color-primary-900: color-mix(in oklab, var(--color-primary-600) 70%, black);
22
20
  --color-primary-950: color-mix(in oklab, var(--color-primary-600) 50%, black);
21
+
22
+ --color-background: oklch(1 0 0);
23
+ --color-links: var(--color-primary);
23
24
  }
24
25
 
25
26
  .clickable {
@@ -1,14 +1,13 @@
1
1
  import clsx from 'clsx';
2
- import { computed, unref } from 'vue';
2
+ import { unref } from 'vue';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import type { ClassValue } from 'clsx';
6
- import type { ComputedRef, PropType, Ref } from 'vue';
6
+ import type { PropType } from 'vue';
7
7
  import type { GetClosureArgs, GetClosureResult } from '@noeldemartin/utils';
8
8
 
9
9
  export type CVAConfig<T> = NonNullable<GetClosureArgs<typeof cva<T>>[1]>;
10
10
  export type CVAProps<T> = NonNullable<GetClosureArgs<GetClosureResult<typeof cva<T>>>[0]>;
11
- export type RefsObject<T> = { [K in keyof T]: Ref<T[K]> | T[K] };
12
11
  export type Variants<T extends Record<string, string | boolean>> = Required<{
13
12
  [K in keyof T]: Exclude<T[K], undefined> extends string
14
13
  ? { [key in Exclude<T[K], undefined>]: string | null }
@@ -26,22 +25,15 @@ export type PickComponentProps<TValues, TDefinitions> = {
26
25
  [K in keyof TValues]: K extends keyof TDefinitions ? TValues[K] : never;
27
26
  };
28
27
 
29
- export function computedVariantClasses<T>(
30
- value: RefsObject<{ baseClasses?: string } & CVAProps<T>>,
28
+ export function variantClasses<T>(
29
+ value: { baseClasses?: string } & CVAProps<T>,
31
30
  config: { baseClasses?: string } & CVAConfig<T>,
32
- ): ComputedRef<string> {
33
- return computed(() => {
34
- const { baseClasses: valueBaseClasses, ...valueRefs } = value;
35
- const { baseClasses: configBaseClasses, ...configs } = config;
36
- const variants = cva(configBaseClasses, configs as CVAConfig<T>);
37
- const values = Object.entries(valueRefs).reduce((extractedValues, [name, valueRef]) => {
38
- extractedValues[name as keyof CVAProps<T>] = unref(valueRef);
31
+ ): string {
32
+ const { baseClasses: valueBaseClasses, ...values } = value;
33
+ const { baseClasses: configBaseClasses, ...configs } = config;
34
+ const variants = cva(configBaseClasses, configs as CVAConfig<T>);
39
35
 
40
- return extractedValues;
41
- }, {} as CVAProps<T>);
42
-
43
- return classes(variants(values), unref(valueBaseClasses));
44
- });
36
+ return classes(variants(values as CVAProps<T>), unref(valueBaseClasses));
45
37
  }
46
38
 
47
39
  export function classes(...inputs: ClassValue[]): string {
package/src/utils/vue.ts CHANGED
@@ -12,7 +12,12 @@ function renderVNodeAttrs(node: VNode): string {
12
12
  }, '');
13
13
  }
14
14
 
15
- export function defineDirective(directive: Directive): Directive {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ export function defineDirective<TValue = any, TModifiers extends string = string>(
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ directive: Directive<any, TValue, TModifiers>,
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ ): Directive<any, TValue, TModifiers> {
16
21
  return directive;
17
22
  }
18
23