@weni/unnnic-system 3.25.3 → 3.25.4

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": "@weni/unnnic-system",
3
- "version": "3.25.3",
3
+ "version": "3.25.4",
4
4
  "type": "commonjs",
5
5
  "files": [
6
6
  "dist",
@@ -3,6 +3,8 @@
3
3
  class="unnnic-drawer"
4
4
  data-testid="drawer"
5
5
  :open="modelValue"
6
+ :lazyMount="lazyMount"
7
+ :unmountDelay="unmountDelay"
6
8
  @update:open="$event ? () => {} : back()"
7
9
  >
8
10
  <DrawerContent
@@ -158,6 +160,14 @@ const props = defineProps({
158
160
  type: Boolean,
159
161
  required: true,
160
162
  },
163
+ lazyMount: {
164
+ type: Boolean,
165
+ default: false,
166
+ },
167
+ unmountDelay: {
168
+ type: Number,
169
+ default: 300,
170
+ },
161
171
  withoutOverlay: {
162
172
  type: Boolean,
163
173
  default: false,
@@ -1,7 +1,7 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Drawer.vue > Component Rendering > Component Rendering > matches the snapshot 1`] = `
4
- "<div data-v-196de012="" class="unnnic-drawer" data-testid="drawer" open="true">
4
+ "<div data-v-196de012="" class="unnnic-drawer" data-testid="drawer" open="true" lazymount="false" unmountdelay="300">
5
5
  <div data-v-196de012="" showoverlay="true" data-testid="drawer-container" size="medium" class="unnnic-drawer__container unnnic-drawer__container--md">
6
6
  <header data-v-39d0dfb8="" data-v-196de012="" class="unnnic-drawer__header unnnic-drawer__header">
7
7
  <section data-v-196de012="" class="unnnic-drawer__title-container">
@@ -1,19 +1,51 @@
1
1
  <script setup lang="ts">
2
2
  import type { DialogRootEmits, DialogRootProps } from 'reka-ui';
3
+ import { computed, toRef } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
3
5
  import { DialogRoot, useForwardPropsEmits } from 'reka-ui';
6
+ import useDelayedUnmount from '@/composables/useDelayedUnmount';
4
7
 
5
8
  defineOptions({
6
9
  name: 'UnnnicDialog',
7
10
  });
8
11
 
9
- const props = defineProps<DialogRootProps>();
12
+ const props = withDefaults(
13
+ defineProps<
14
+ DialogRootProps & {
15
+ /**
16
+ * When true, the dialog is only mounted while open and stays mounted for
17
+ * `unmountDelay` ms after closing so the exit animation can play. Use it
18
+ * to avoid mounting many dialogs eagerly inside lists.
19
+ */
20
+ lazyMount?: boolean;
21
+ /**
22
+ * Delay (ms) before the dialog is unmounted after closing. Should match
23
+ * the leave animation duration. Only applies when `lazyMount` is true.
24
+ */
25
+ unmountDelay?: number;
26
+ }
27
+ >(),
28
+ {
29
+ lazyMount: false,
30
+ unmountDelay: 300,
31
+ },
32
+ );
10
33
  const emits = defineEmits<DialogRootEmits>();
11
34
 
12
- const forwarded = useForwardPropsEmits(props, emits);
35
+ const delegatedProps = reactiveOmit(props, 'lazyMount', 'unmountDelay');
36
+ const forwarded = useForwardPropsEmits(delegatedProps, emits);
37
+
38
+ const open = toRef(props, 'open');
39
+ const lazyShouldRender = useDelayedUnmount(open, props.unmountDelay);
40
+
41
+ const shouldRender = computed(() => !props.lazyMount || lazyShouldRender.value);
13
42
  </script>
14
43
 
15
44
  <template>
16
- <DialogRoot v-bind="forwarded">
45
+ <DialogRoot
46
+ v-if="shouldRender"
47
+ v-bind="forwarded"
48
+ >
17
49
  <slot />
18
50
  </DialogRoot>
19
51
  </template>
@@ -15,6 +15,7 @@ import { useTeleportTarget } from '@/lib/teleport-target';
15
15
 
16
16
  defineOptions({
17
17
  name: 'UnnnicDialogContent',
18
+ inheritAttrs: false,
18
19
  });
19
20
 
20
21
  const props = withDefaults(
@@ -69,7 +70,7 @@ const ConditionalWrapper: Component = (_, { slots }) => {
69
70
 
70
71
  <ConditionalWrapper>
71
72
  <DialogContent
72
- v-bind="forwarded"
73
+ v-bind="{ ...forwarded, ...$attrs }"
73
74
  :class="contentClasses"
74
75
  :style="{ zIndex: modalZIndex }"
75
76
  >
@@ -1,23 +1,76 @@
1
1
  <script lang="ts" setup>
2
- import type { DrawerRootEmits, DrawerRootProps } from 'vaul-vue';
2
+ import type { DrawerRootEmits } from 'vaul-vue';
3
+ import { computed, toRef } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
3
5
  import { useForwardPropsEmits } from 'reka-ui';
4
6
  import { DrawerRoot } from 'vaul-vue';
7
+ import useDelayedUnmount from '@/composables/useDelayedUnmount';
5
8
 
6
9
  defineOptions({
7
10
  name: 'UnnnicDrawerNext',
8
11
  });
9
12
 
10
- const props = withDefaults(defineProps<DrawerRootProps>(), {
13
+ /**
14
+ * Self-contained props type that mirrors `vaul-vue`'s `DrawerRootProps`.
15
+ *
16
+ * We intentionally avoid extending or intersecting `DrawerRootProps` because
17
+ * its definition includes the internal, non-exported `WithoutFadeFromProps`
18
+ * type, which breaks `vite-plugin-dts` declaration rollup with TS4023 when
19
+ * combined with our extra `lazyMount` / `unmountDelay` props.
20
+ */
21
+ interface DrawerRootProps {
22
+ activeSnapPoint?: number | string | null;
23
+ closeThreshold?: number;
24
+ shouldScaleBackground?: boolean;
25
+ setBackgroundColorOnScale?: boolean;
26
+ scrollLockTimeout?: number;
27
+ fixed?: boolean;
28
+ dismissible?: boolean;
29
+ modal?: boolean;
30
+ open?: boolean;
31
+ defaultOpen?: boolean;
32
+ nested?: boolean;
33
+ direction?: 'top' | 'bottom' | 'left' | 'right';
34
+ noBodyStyles?: boolean;
35
+ handleOnly?: boolean;
36
+ preventScrollRestoration?: boolean;
37
+ snapPoints?: (number | string)[];
38
+ }
39
+
40
+ export interface UnnnicDrawerNextProps extends DrawerRootProps {
41
+ /**
42
+ * When true, the drawer is only mounted while open and stays mounted for
43
+ * `unmountDelay` ms after closing so the exit animation can play. Use it
44
+ * to avoid mounting many drawers eagerly inside lists.
45
+ */
46
+ lazyMount?: boolean;
47
+ /**
48
+ * Delay (ms) before the drawer is unmounted after closing. Should match
49
+ * the leave animation duration. Only applies when `lazyMount` is true.
50
+ */
51
+ unmountDelay?: number;
52
+ }
53
+
54
+ const props = withDefaults(defineProps<UnnnicDrawerNextProps>(), {
11
55
  shouldScaleBackground: true,
56
+ lazyMount: false,
57
+ unmountDelay: 300,
12
58
  });
13
59
 
14
60
  const emits = defineEmits<DrawerRootEmits>();
15
61
 
16
- const forwarded = useForwardPropsEmits(props, emits);
62
+ const delegatedProps = reactiveOmit(props, 'lazyMount', 'unmountDelay');
63
+ const forwarded = useForwardPropsEmits(delegatedProps, emits);
64
+
65
+ const open = toRef(props, 'open');
66
+ const lazyShouldRender = useDelayedUnmount(open, props.unmountDelay);
67
+
68
+ const shouldRender = computed(() => !props.lazyMount || lazyShouldRender.value);
17
69
  </script>
18
70
 
19
71
  <template>
20
72
  <DrawerRoot
73
+ v-if="shouldRender"
21
74
  v-bind="forwarded"
22
75
  direction="right"
23
76
  handleOnly
@@ -11,6 +11,7 @@ import DrawerOverlay from './DrawerOverlay.vue';
11
11
 
12
12
  defineOptions({
13
13
  name: 'UnnnicDrawerContent',
14
+ inheritAttrs: false,
14
15
  });
15
16
 
16
17
  const props = withDefaults(
@@ -43,7 +44,7 @@ const portalTarget = useTeleportTarget();
43
44
  :style="{ zIndex: layerZIndex - 2 }"
44
45
  />
45
46
  <DrawerContent
46
- v-bind="forwardedProps"
47
+ v-bind="{ ...forwardedProps, ...$attrs }"
47
48
  :class="
48
49
  cn(
49
50
  'unnnic-drawer__content',
@@ -0,0 +1,48 @@
1
+ import { type Ref, onBeforeUnmount, ref, watch } from 'vue';
2
+
3
+ /**
4
+ * Keeps an overlay mounted for `delay` ms after it closes so the leave
5
+ * animation can play, while still allowing lazy mounting on first open.
6
+ *
7
+ * Used internally by drawer/dialog components when `lazyMount` is enabled to
8
+ * preserve their exit animation without keeping every overlay's portal
9
+ * eagerly mounted in the DOM.
10
+ */
11
+ export default function useDelayedUnmount(
12
+ isOpen: Ref<boolean | undefined>,
13
+ delay = 300,
14
+ ): Ref<boolean> {
15
+ const shouldRender = ref(!!isOpen.value);
16
+ let timer: ReturnType<typeof setTimeout> | null = null;
17
+
18
+ const clearTimer = () => {
19
+ if (timer !== null) {
20
+ clearTimeout(timer);
21
+ timer = null;
22
+ }
23
+ };
24
+
25
+ watch(
26
+ isOpen,
27
+ (open) => {
28
+ clearTimer();
29
+
30
+ if (open) {
31
+ shouldRender.value = true;
32
+ return;
33
+ }
34
+
35
+ if (shouldRender.value) {
36
+ timer = setTimeout(() => {
37
+ shouldRender.value = false;
38
+ timer = null;
39
+ }, delay);
40
+ }
41
+ },
42
+ { immediate: true },
43
+ );
44
+
45
+ onBeforeUnmount(clearTimer);
46
+
47
+ return shouldRender;
48
+ }
@@ -46,10 +46,28 @@ export default {
46
46
  },
47
47
  description: 'The type of the dialog (affects header icon)',
48
48
  },
49
+ lazyMount: {
50
+ control: { type: 'boolean' },
51
+ defaultValue: {
52
+ summary: false,
53
+ },
54
+ description:
55
+ 'When true, the dialog is only mounted while open and stays mounted for `unmountDelay` ms after closing so the exit animation can play. Use it to avoid mounting many dialogs eagerly inside lists.',
56
+ },
57
+ unmountDelay: {
58
+ control: { type: 'number' },
59
+ defaultValue: {
60
+ summary: 300,
61
+ },
62
+ description:
63
+ 'Delay (ms) before the dialog is unmounted after closing. Should match the leave animation duration. Only applies when `lazyMount` is true.',
64
+ },
49
65
  },
50
66
  args: {
51
67
  size: 'medium',
52
68
  type: 'default',
69
+ lazyMount: false,
70
+ unmountDelay: 300,
53
71
  },
54
72
  };
55
73
 
@@ -66,10 +66,28 @@ export default {
66
66
  },
67
67
  description: 'Whether to show the overlay background',
68
68
  },
69
+ lazyMount: {
70
+ control: { type: 'boolean' },
71
+ defaultValue: {
72
+ summary: false,
73
+ },
74
+ description:
75
+ 'When true, the drawer is only mounted while open and stays mounted for `unmountDelay` ms after closing so the exit animation can play. Use it to avoid mounting many drawers eagerly inside lists.',
76
+ },
77
+ unmountDelay: {
78
+ control: { type: 'number' },
79
+ defaultValue: {
80
+ summary: 300,
81
+ },
82
+ description:
83
+ 'Delay (ms) before the drawer is unmounted after closing. Should match the leave animation duration. Only applies when `lazyMount` is true.',
84
+ },
69
85
  },
70
86
  args: {
71
87
  size: 'medium',
72
88
  showOverlay: true,
89
+ lazyMount: false,
90
+ unmountDelay: 300,
73
91
  },
74
92
  };
75
93