@shwfed/nuxt 0.11.19 → 0.11.20

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/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
3
  "configKey": "shwfed",
4
- "version": "0.11.19",
4
+ "version": "0.11.20",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -76,15 +76,6 @@ const open = computed({
76
76
  function close() {
77
77
  open.value = false;
78
78
  }
79
- function isClosedContentTarget(target) {
80
- return target instanceof HTMLElement && target.dataset.state === "closed";
81
- }
82
- function handleContentAnimationEnd(event) {
83
- if (open.value || event.target !== event.currentTarget || !isClosedContentTarget(event.currentTarget)) {
84
- return;
85
- }
86
- emit("after-close");
87
- }
88
79
  </script>
89
80
 
90
81
  <template>
@@ -108,7 +99,7 @@ function handleContentAnimationEnd(event) {
108
99
  :is="modalComponents.Content"
109
100
  v-bind="attrs"
110
101
  :show-close-button="props.showCloseButton"
111
- @animationend="handleContentAnimationEnd"
102
+ @after-close="emit('after-close')"
112
103
  >
113
104
  <component
114
105
  :is="modalComponents.Header"
@@ -4,9 +4,9 @@ type __VLS_Props = DialogContentProps & {
4
4
  class?: HTMLAttributes['class'];
5
5
  showCloseButton?: boolean;
6
6
  };
7
- declare var __VLS_19: {};
7
+ declare var __VLS_22: {};
8
8
  type __VLS_Slots = {} & {
9
- default?: (props: typeof __VLS_19) => any;
9
+ default?: (props: typeof __VLS_22) => any;
10
10
  };
11
11
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
12
  escapeKeyDown: (event: KeyboardEvent) => any;
@@ -15,6 +15,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
15
15
  interactOutside: (event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => any;
16
16
  openAutoFocus: (event: Event) => any;
17
17
  closeAutoFocus: (event: Event) => any;
18
+ "after-close": () => any;
18
19
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
19
20
  onEscapeKeyDown?: ((event: KeyboardEvent) => any) | undefined;
20
21
  onPointerDownOutside?: ((event: import("reka-ui").PointerDownOutsideEvent) => any) | undefined;
@@ -22,6 +23,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
22
23
  onInteractOutside?: ((event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => any) | undefined;
23
24
  onOpenAutoFocus?: ((event: Event) => any) | undefined;
24
25
  onCloseAutoFocus?: ((event: Event) => any) | undefined;
26
+ "onAfter-close"?: (() => any) | undefined;
25
27
  }>, {
26
28
  showCloseButton: boolean;
27
29
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -9,6 +9,7 @@ import {
9
9
  import { cn } from "../../../utils/cn";
10
10
  import DialogOverlay from "./DialogOverlay.vue";
11
11
  import { Icon } from "@iconify/vue";
12
+ import { onBeforeUnmount, shallowRef, watchEffect } from "vue";
12
13
  defineOptions({
13
14
  inheritAttrs: false
14
15
  });
@@ -20,15 +21,123 @@ const props = defineProps({
20
21
  class: { type: null, required: false },
21
22
  showCloseButton: { type: Boolean, required: false, default: true }
22
23
  });
23
- const emits = defineEmits(["escapeKeyDown", "pointerDownOutside", "focusOutside", "interactOutside", "openAutoFocus", "closeAutoFocus"]);
24
+ const emit = defineEmits(["escapeKeyDown", "pointerDownOutside", "focusOutside", "interactOutside", "openAutoFocus", "closeAutoFocus", "after-close"]);
24
25
  const delegatedProps = reactiveOmit(props, "class");
25
- const forwarded = useForwardPropsEmits(delegatedProps, emits);
26
+ const forwarded = useForwardPropsEmits(delegatedProps, emit);
27
+ const contentElement = shallowRef(null);
28
+ let closeFallbackTimer;
29
+ let hasEmittedAfterClose = false;
30
+ function isClosedContentTarget(target) {
31
+ return target instanceof HTMLElement && target.dataset.state === "closed";
32
+ }
33
+ function clearCloseFallbackTimer() {
34
+ if (closeFallbackTimer === void 0) {
35
+ return;
36
+ }
37
+ window.clearTimeout(closeFallbackTimer);
38
+ closeFallbackTimer = void 0;
39
+ }
40
+ function emitAfterClose() {
41
+ if (hasEmittedAfterClose) {
42
+ return;
43
+ }
44
+ hasEmittedAfterClose = true;
45
+ clearCloseFallbackTimer();
46
+ emit("after-close");
47
+ }
48
+ function parseDurationMs(value) {
49
+ const normalizedValue = value.trim();
50
+ if (normalizedValue.endsWith("ms")) {
51
+ const duration = Number.parseFloat(normalizedValue.slice(0, -2));
52
+ return Number.isFinite(duration) ? duration : 0;
53
+ }
54
+ if (normalizedValue.endsWith("s")) {
55
+ const duration = Number.parseFloat(normalizedValue.slice(0, -1));
56
+ return Number.isFinite(duration) ? duration * 1e3 : 0;
57
+ }
58
+ return 0;
59
+ }
60
+ function getLongestMotionMs(element) {
61
+ const style = window.getComputedStyle(element);
62
+ const animationDurations = style.animationDuration.split(",");
63
+ const animationDelays = style.animationDelay.split(",");
64
+ const transitionDurations = style.transitionDuration.split(",");
65
+ const transitionDelays = style.transitionDelay.split(",");
66
+ let longestMotionMs = 0;
67
+ for (const [index, durationValue] of animationDurations.entries()) {
68
+ const durationMs = parseDurationMs(durationValue);
69
+ const delayMs = parseDurationMs(animationDelays[index] ?? animationDelays[0] ?? "0s");
70
+ longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
71
+ }
72
+ for (const [index, durationValue] of transitionDurations.entries()) {
73
+ const durationMs = parseDurationMs(durationValue);
74
+ const delayMs = parseDurationMs(transitionDelays[index] ?? transitionDelays[0] ?? "0s");
75
+ longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
76
+ }
77
+ return longestMotionMs;
78
+ }
79
+ function syncCloseFallback() {
80
+ const element = contentElement.value;
81
+ clearCloseFallbackTimer();
82
+ if (!element) {
83
+ return;
84
+ }
85
+ if (element.dataset.state !== "closed") {
86
+ hasEmittedAfterClose = false;
87
+ return;
88
+ }
89
+ const motionMs = getLongestMotionMs(element);
90
+ closeFallbackTimer = window.setTimeout(() => {
91
+ emitAfterClose();
92
+ }, motionMs > 0 ? motionMs : 0);
93
+ }
94
+ function handleCloseMotionEnd(event) {
95
+ if (hasEmittedAfterClose || event.target !== event.currentTarget || !isClosedContentTarget(event.currentTarget)) {
96
+ return;
97
+ }
98
+ emitAfterClose();
99
+ }
100
+ function setContentElement(target) {
101
+ if (target instanceof HTMLElement) {
102
+ contentElement.value = target;
103
+ syncCloseFallback();
104
+ return;
105
+ }
106
+ if (target && "$el" in target && target.$el instanceof HTMLElement) {
107
+ contentElement.value = target.$el;
108
+ syncCloseFallback();
109
+ return;
110
+ }
111
+ contentElement.value = null;
112
+ clearCloseFallbackTimer();
113
+ }
114
+ watchEffect((onCleanup) => {
115
+ const element = contentElement.value;
116
+ if (!element) {
117
+ return;
118
+ }
119
+ const observer = new MutationObserver(() => {
120
+ syncCloseFallback();
121
+ });
122
+ observer.observe(element, {
123
+ attributes: true,
124
+ attributeFilter: ["data-state"]
125
+ });
126
+ syncCloseFallback();
127
+ onCleanup(() => {
128
+ observer.disconnect();
129
+ });
130
+ });
131
+ onBeforeUnmount(() => {
132
+ clearCloseFallbackTimer();
133
+ });
26
134
  </script>
27
135
 
28
136
  <template>
29
137
  <DialogPortal>
30
138
  <DialogOverlay />
31
139
  <DialogContent
140
+ :ref="setContentElement"
32
141
  data-slot="dialog-content"
33
142
  v-bind="{ ...$attrs, ...forwarded }"
34
143
  :class="
@@ -37,6 +146,8 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
37
146
  props.class
38
147
  )
39
148
  "
149
+ @animationend="handleCloseMotionEnd"
150
+ @transitionend="handleCloseMotionEnd"
40
151
  >
41
152
  <slot />
42
153
 
@@ -4,9 +4,9 @@ type __VLS_Props = DialogContentProps & {
4
4
  class?: HTMLAttributes['class'];
5
5
  showCloseButton?: boolean;
6
6
  };
7
- declare var __VLS_19: {};
7
+ declare var __VLS_22: {};
8
8
  type __VLS_Slots = {} & {
9
- default?: (props: typeof __VLS_19) => any;
9
+ default?: (props: typeof __VLS_22) => any;
10
10
  };
11
11
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
12
  escapeKeyDown: (event: KeyboardEvent) => any;
@@ -15,6 +15,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
15
15
  interactOutside: (event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => any;
16
16
  openAutoFocus: (event: Event) => any;
17
17
  closeAutoFocus: (event: Event) => any;
18
+ "after-close": () => any;
18
19
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
19
20
  onEscapeKeyDown?: ((event: KeyboardEvent) => any) | undefined;
20
21
  onPointerDownOutside?: ((event: import("reka-ui").PointerDownOutsideEvent) => any) | undefined;
@@ -22,6 +23,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
22
23
  onInteractOutside?: ((event: import("reka-ui").PointerDownOutsideEvent | import("reka-ui").FocusOutsideEvent) => any) | undefined;
23
24
  onOpenAutoFocus?: ((event: Event) => any) | undefined;
24
25
  onCloseAutoFocus?: ((event: Event) => any) | undefined;
26
+ "onAfter-close"?: (() => any) | undefined;
25
27
  }>, {
26
28
  showCloseButton: boolean;
27
29
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -3,11 +3,15 @@ type __VLS_Props = {
3
3
  class?: HTMLAttributes['class'];
4
4
  showCloseButton?: boolean;
5
5
  };
6
- declare var __VLS_19: {};
6
+ declare var __VLS_22: {};
7
7
  type __VLS_Slots = {} & {
8
- default?: (props: typeof __VLS_19) => any;
8
+ default?: (props: typeof __VLS_22) => any;
9
9
  };
10
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ "after-close": () => any;
12
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ "onAfter-close"?: (() => any) | undefined;
14
+ }>, {
11
15
  showCloseButton: boolean;
12
16
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
17
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -2,6 +2,7 @@
2
2
  import { reactiveOmit } from "@vueuse/core";
3
3
  import { Icon } from "@iconify/vue";
4
4
  import { useForwardProps } from "reka-ui";
5
+ import { onBeforeUnmount, shallowRef, watchEffect } from "vue";
5
6
  import {
6
7
  DrawerClose,
7
8
  DrawerContent,
@@ -16,14 +17,123 @@ const props = defineProps({
16
17
  class: { type: null, required: false },
17
18
  showCloseButton: { type: Boolean, required: false, default: true }
18
19
  });
20
+ const emit = defineEmits(["after-close"]);
19
21
  const delegatedProps = reactiveOmit(props, "class", "showCloseButton");
20
22
  const forwardedProps = useForwardProps(delegatedProps);
23
+ const contentElement = shallowRef(null);
24
+ let closeFallbackTimer;
25
+ let hasEmittedAfterClose = false;
26
+ function isClosedContentTarget(target) {
27
+ return target instanceof HTMLElement && target.dataset.state === "closed";
28
+ }
29
+ function clearCloseFallbackTimer() {
30
+ if (closeFallbackTimer === void 0) {
31
+ return;
32
+ }
33
+ window.clearTimeout(closeFallbackTimer);
34
+ closeFallbackTimer = void 0;
35
+ }
36
+ function emitAfterClose() {
37
+ if (hasEmittedAfterClose) {
38
+ return;
39
+ }
40
+ hasEmittedAfterClose = true;
41
+ clearCloseFallbackTimer();
42
+ emit("after-close");
43
+ }
44
+ function parseDurationMs(value) {
45
+ const normalizedValue = value.trim();
46
+ if (normalizedValue.endsWith("ms")) {
47
+ const duration = Number.parseFloat(normalizedValue.slice(0, -2));
48
+ return Number.isFinite(duration) ? duration : 0;
49
+ }
50
+ if (normalizedValue.endsWith("s")) {
51
+ const duration = Number.parseFloat(normalizedValue.slice(0, -1));
52
+ return Number.isFinite(duration) ? duration * 1e3 : 0;
53
+ }
54
+ return 0;
55
+ }
56
+ function getLongestMotionMs(element) {
57
+ const style = window.getComputedStyle(element);
58
+ const animationDurations = style.animationDuration.split(",");
59
+ const animationDelays = style.animationDelay.split(",");
60
+ const transitionDurations = style.transitionDuration.split(",");
61
+ const transitionDelays = style.transitionDelay.split(",");
62
+ let longestMotionMs = 0;
63
+ for (const [index, durationValue] of animationDurations.entries()) {
64
+ const durationMs = parseDurationMs(durationValue);
65
+ const delayMs = parseDurationMs(animationDelays[index] ?? animationDelays[0] ?? "0s");
66
+ longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
67
+ }
68
+ for (const [index, durationValue] of transitionDurations.entries()) {
69
+ const durationMs = parseDurationMs(durationValue);
70
+ const delayMs = parseDurationMs(transitionDelays[index] ?? transitionDelays[0] ?? "0s");
71
+ longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
72
+ }
73
+ return longestMotionMs;
74
+ }
75
+ function syncCloseFallback() {
76
+ const element = contentElement.value;
77
+ clearCloseFallbackTimer();
78
+ if (!element) {
79
+ return;
80
+ }
81
+ if (element.dataset.state !== "closed") {
82
+ hasEmittedAfterClose = false;
83
+ return;
84
+ }
85
+ const motionMs = getLongestMotionMs(element);
86
+ closeFallbackTimer = window.setTimeout(() => {
87
+ emitAfterClose();
88
+ }, motionMs > 0 ? motionMs : 0);
89
+ }
90
+ function handleCloseMotionEnd(event) {
91
+ if (hasEmittedAfterClose || event.target !== event.currentTarget || !isClosedContentTarget(event.currentTarget)) {
92
+ return;
93
+ }
94
+ emitAfterClose();
95
+ }
96
+ function setContentElement(target) {
97
+ if (target instanceof HTMLElement) {
98
+ contentElement.value = target;
99
+ syncCloseFallback();
100
+ return;
101
+ }
102
+ if (target && "$el" in target && target.$el instanceof HTMLElement) {
103
+ contentElement.value = target.$el;
104
+ syncCloseFallback();
105
+ return;
106
+ }
107
+ contentElement.value = null;
108
+ clearCloseFallbackTimer();
109
+ }
110
+ watchEffect((onCleanup) => {
111
+ const element = contentElement.value;
112
+ if (!element) {
113
+ return;
114
+ }
115
+ const observer = new MutationObserver(() => {
116
+ syncCloseFallback();
117
+ });
118
+ observer.observe(element, {
119
+ attributes: true,
120
+ attributeFilter: ["data-state"]
121
+ });
122
+ syncCloseFallback();
123
+ onCleanup(() => {
124
+ observer.disconnect();
125
+ });
126
+ });
127
+ onBeforeUnmount(() => {
128
+ clearCloseFallbackTimer();
129
+ });
21
130
  </script>
22
131
 
23
132
  <template>
24
133
  <DrawerPortal>
25
134
  <DrawerOverlay />
26
135
  <DrawerContent
136
+ :ref="setContentElement"
27
137
  data-slot="drawer-content"
28
138
  v-bind="{ ...$attrs, ...forwardedProps }"
29
139
  :class="
@@ -32,6 +142,8 @@ const forwardedProps = useForwardProps(delegatedProps);
32
142
  props.class
33
143
  )
34
144
  "
145
+ @animationend="handleCloseMotionEnd"
146
+ @transitionend="handleCloseMotionEnd"
35
147
  >
36
148
  <div class="mx-auto -mt-2 h-2 w-16 rounded-full bg-zinc-200" />
37
149
 
@@ -3,11 +3,15 @@ type __VLS_Props = {
3
3
  class?: HTMLAttributes['class'];
4
4
  showCloseButton?: boolean;
5
5
  };
6
- declare var __VLS_19: {};
6
+ declare var __VLS_22: {};
7
7
  type __VLS_Slots = {} & {
8
- default?: (props: typeof __VLS_19) => any;
8
+ default?: (props: typeof __VLS_22) => any;
9
9
  };
10
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ "after-close": () => any;
12
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ "onAfter-close"?: (() => any) | undefined;
14
+ }>, {
11
15
  showCloseButton: boolean;
12
16
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
17
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
- "version": "0.11.19",
3
+ "version": "0.11.20",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",