@toife/vue 3.0.3 → 3.0.5

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 (92) hide show
  1. package/package.json +1 -1
  2. package/src/components/action/action.composable.ts +1 -0
  3. package/src/components/action/action.scss +4 -3
  4. package/src/components/action/action.type.ts +10 -1
  5. package/src/components/action/action.vue +12 -10
  6. package/src/components/app/app.scss +4 -4
  7. package/src/components/app/app.type.ts +9 -0
  8. package/src/components/app/app.vue +8 -7
  9. package/src/components/avatar/avatar.scss +2 -2
  10. package/src/components/avatar/avatar.type.ts +1 -1
  11. package/src/components/avatar/avatar.vue +4 -13
  12. package/src/components/button/button.scss +24 -26
  13. package/src/components/button/button.type.ts +1 -1
  14. package/src/components/button/button.vue +8 -8
  15. package/src/components/cable/cable.type.ts +1 -1
  16. package/src/components/cable/cable.vue +8 -8
  17. package/src/components/card/card/card.scss +5 -4
  18. package/src/components/card/card/card.type.ts +1 -1
  19. package/src/components/card/card/card.vue +6 -6
  20. package/src/components/card/card-body/card-body.scss +4 -4
  21. package/src/components/card/card-footer/card-footer.scss +7 -6
  22. package/src/components/card/card-footer/card-footer.vue +4 -4
  23. package/src/components/card/card-header/card-header.scss +7 -6
  24. package/src/components/card/card-header/card-header.vue +4 -4
  25. package/src/components/checkbox/checkbox.html +0 -1
  26. package/src/components/checkbox/checkbox.scss +20 -20
  27. package/src/components/checkbox/checkbox.vue +8 -8
  28. package/src/components/collapse/collapse.scss +7 -7
  29. package/src/components/collapse/collapse.type.ts +1 -1
  30. package/src/components/collapse/collapse.vue +15 -19
  31. package/src/components/container/container.vue +1 -0
  32. package/src/components/decision-modal/decision-modal.composable.ts +1 -0
  33. package/src/components/decision-modal/decision-modal.scss +5 -4
  34. package/src/components/decision-modal/decision-modal.type.ts +1 -1
  35. package/src/components/decision-modal/decision-modal.vue +11 -11
  36. package/src/components/divider/divider.scss +4 -4
  37. package/src/components/divider/divider.vue +4 -4
  38. package/src/components/field/field.type.ts +1 -1
  39. package/src/components/field/field.vue +7 -6
  40. package/src/components/field/outline/outline.scss +13 -12
  41. package/src/components/field/outline/outline.vue +10 -10
  42. package/src/components/form-group/form-group.vue +4 -4
  43. package/src/components/gesture-indicator/gesture-indicator.scss +2 -2
  44. package/src/components/gesture-indicator/gesture-indicator.type.ts +1 -1
  45. package/src/components/gesture-indicator/gesture-indicator.vue +5 -5
  46. package/src/components/image/image.type.ts +1 -1
  47. package/src/components/image/image.vue +10 -13
  48. package/src/components/modal/modal.scss +2 -2
  49. package/src/components/modal/modal.vue +11 -9
  50. package/src/components/page/page.vue +1 -0
  51. package/src/components/present/present.composable.ts +1 -0
  52. package/src/components/present/present.scss +3 -3
  53. package/src/components/present/present.vue +12 -12
  54. package/src/components/radio/radio/radio.scss +26 -21
  55. package/src/components/radio/radio/radio.type.ts +1 -1
  56. package/src/components/radio/radio/radio.vue +8 -8
  57. package/src/components/radio/radio-group/radio-group.vue +6 -6
  58. package/src/components/refresher/refresher.type.ts +1 -1
  59. package/src/components/refresher/refresher.vue +11 -11
  60. package/src/components/route/route-navigator/route-navigator.type.ts +24 -0
  61. package/src/components/route/route-navigator/route-navigator.vue +33 -16
  62. package/src/components/route/route-outlet/route-outlet.vue +20 -11
  63. package/src/components/route/route-provider/route-provider.vue +6 -6
  64. package/src/components/route/route-wrapper/route-wrapper.composable.ts +4 -3
  65. package/src/components/route/route-wrapper/route-wrapper.vue +7 -5
  66. package/src/components/route/route.util.ts +1 -0
  67. package/src/components/segmented-field/segmented-field.scss +4 -3
  68. package/src/components/segmented-field/segmented-field.vue +8 -8
  69. package/src/components/skeleton/skeleton.scss +14 -9
  70. package/src/components/skeleton/skeleton.type.ts +1 -1
  71. package/src/components/skeleton/skeleton.vue +4 -4
  72. package/src/components/switch/switch.html +0 -1
  73. package/src/components/switch/switch.scss +15 -14
  74. package/src/components/switch/switch.type.ts +1 -1
  75. package/src/components/switch/switch.vue +8 -8
  76. package/src/components/tabs/tab/tab.type.ts +1 -1
  77. package/src/components/tabs/tab/tab.vue +6 -6
  78. package/src/components/tabs/tabs/tabs.scss +14 -15
  79. package/src/components/tabs/tabs/tabs.type.ts +1 -1
  80. package/src/components/tabs/tabs/tabs.vue +13 -13
  81. package/src/components/toast/toast/toast.vue +6 -6
  82. package/src/components/toast/toast-content/toast-content.scss +8 -8
  83. package/src/components/toast/toast-content/toast-content.vue +7 -7
  84. package/src/components/toast/toast.composable.ts +1 -1
  85. package/src/components/toolbar/toolbar.scss +2 -2
  86. package/src/components/toolbar/toolbar.type.ts +1 -1
  87. package/src/components/toolbar/toolbar.vue +4 -4
  88. package/src/factory.ts +2 -1
  89. package/src/utils/element.ts +6 -0
  90. package/src/utils/events.ts +8 -2
  91. package/src/utils/style/index.ts +17 -2
  92. package/src/components/image/image.scss +0 -1
@@ -1,4 +1,4 @@
1
- // Define
1
+ // Type definitions
2
2
  export type ImageProps = {
3
3
  defaultSrc?: string;
4
4
  src?: string;
@@ -1,25 +1,22 @@
1
- <style lang="scss" src="./image.scss" scoped></style>
2
1
  <template src="./image.html"></template>
3
2
  <script setup lang="ts">
4
- import { onMounted, ref } from "vue";
3
+ import { ref } from "vue";
5
4
  import { type ImageProps } from "./image.type";
6
5
 
7
- /// Define
8
- /// ------------------------------------------------------------
9
- const dataSrc = ref<unknown>("");
6
+ // Component setup (props, emits, injects)
7
+ // ----------------------------------------------------------------------------
10
8
  const { defaultSrc, src } = defineProps<ImageProps>();
11
9
 
12
- /// Methods
13
- /// ------------------------------------------------------------
10
+ // Reactive state
11
+ // ----------------------------------------------------------------------------
12
+ // Initialize from src to avoid an empty src flash before mount
13
+ const dataSrc = ref<string>(src ?? "");
14
+
15
+ // Methods
16
+ // ----------------------------------------------------------------------------
14
17
  const handleError = () => {
15
18
  if (defaultSrc) {
16
19
  dataSrc.value = defaultSrc;
17
20
  }
18
21
  };
19
-
20
- /// Lifecycle
21
- /// ------------------------------------------------------------
22
- onMounted(() => {
23
- dataSrc.value = src;
24
- });
25
22
  </script>
@@ -4,7 +4,7 @@
4
4
  $modal: sass.fn-naming-prefix("modal");
5
5
 
6
6
  // Property name - layer: modal
7
- $background-color: sass.fn-naming-var("modal", "background-color");
7
+ $modal-background-color: sass.fn-naming-var("modal", "background-color");
8
8
  $viewport-width: sass.fn-naming-var("viewport", "width");
9
9
  $viewport-max-width: sass.fn-naming-var("viewport", "max-width");
10
10
  $viewport-height: sass.fn-naming-var("viewport", "height");
@@ -17,7 +17,7 @@ $safe-area-right: sass.fn-naming-var("safe-area", "right");
17
17
  $transition-duration: sass.fn-naming-var("motion", "duration");
18
18
 
19
19
  .#{$modal} {
20
- background: rgb(#{$background-color});
20
+ background: rgb(#{$modal-background-color});
21
21
  transition:
22
22
  box-shadow #{$transition-duration} ease,
23
23
  border-color #{$transition-duration} ease,
@@ -9,8 +9,8 @@ import { type ModalProps, type ModalEmit } from "./modal.type";
9
9
  import { withPrefix } from "../../utils";
10
10
  import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
11
11
 
12
- /// Define
13
- /// ------------------------------------------------------------
12
+ // Component setup (props, emits, injects)
13
+ // ----------------------------------------------------------------------------
14
14
  const props = withDefaults(defineProps<ModalProps>(), {
15
15
  backdrop: "display",
16
16
  keepalive: true,
@@ -25,15 +25,15 @@ const props = withDefaults(defineProps<ModalProps>(), {
25
25
  const emit = defineEmits<ModalEmit>();
26
26
  const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
27
27
 
28
- /// State
29
- /// ------------------------------------------------------------
28
+ // Reactive state
29
+ // ----------------------------------------------------------------------------
30
30
  const modal = ref();
31
31
  const present = ref();
32
32
  const isBusy = ref(false);
33
33
  const ges = ref<unknown>(null);
34
34
 
35
- /// Computed
36
- /// ------------------------------------------------------------
35
+ // Computed properties
36
+ // ----------------------------------------------------------------------------
37
37
  const gestureDir = computed(() => {
38
38
  if (props.placement == "bottom") return "down";
39
39
  if (props.placement == "top") return "up";
@@ -61,12 +61,13 @@ const modalAttrs = computed(() => {
61
61
  };
62
62
  });
63
63
 
64
- /// Methods
65
- /// ------------------------------------------------------------
64
+ // Methods
65
+ // ----------------------------------------------------------------------------
66
66
  const close = (e: string) => {
67
67
  emit("close", e);
68
68
  };
69
69
 
70
+ // Cooldown so rapid gesture events do not fight the sheet animation
70
71
  const busy = () => {
71
72
  isBusy.value = true;
72
73
  setTimeout(() => {
@@ -75,11 +76,12 @@ const busy = () => {
75
76
  };
76
77
 
77
78
  // Lifecycle
78
- /// ------------------------------------------------------------
79
+ // ----------------------------------------------------------------------------
79
80
  watch(
80
81
  () => modal.value,
81
82
  (val) => {
82
83
  if (val) {
84
+ // Drag-to-dismiss along the placement axis (skipped for centered modals)
83
85
  ges.value = toifeGesture(modal.value, {
84
86
  isMoving: false,
85
87
 
@@ -3,6 +3,7 @@
3
3
  <script lang="ts" setup>
4
4
  import { withPrefix } from "../../utils";
5
5
 
6
+ // Top-level page surface inside the app shell
6
7
  const pageAttrs = {
7
8
  class: [withPrefix("page")],
8
9
  } as const;
@@ -1,5 +1,6 @@
1
1
  import { ref } from "vue";
2
2
 
3
+ // Base z-index for stacked overlays; increments by 2 so backdrop sits one level below its sheet
3
4
  const index = ref(1000);
4
5
 
5
6
  export const usePresent = () => {
@@ -9,8 +9,8 @@ $transition-duration: sass.fn-naming-dvar(
9
9
  ("transition", "duration"),
10
10
  sass.fn-naming-var("motion", "duration")
11
11
  );
12
- // layer: backdrop
13
- $backdrop-bg: sass.fn-naming-var("backdrop", "background-color");
12
+
13
+ $backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
14
14
  $backdrop-opacity: sass.fn-naming-var("backdrop", "opacity");
15
15
 
16
16
  $present-translate-plus: sass.fn-naming-dvar(("translate"), "100%");
@@ -30,7 +30,7 @@ $present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
30
30
  color #{$transition-duration} ease,
31
31
  border-radius #{$transition-duration} ease,
32
32
  opacity #{$transition-duration} ease;
33
- background-color: rgb(#{$backdrop-bg});
33
+ background-color: rgb(#{$backdrop-background-color});
34
34
  opacity: #{$backdrop-opacity};
35
35
  }
36
36
 
@@ -6,10 +6,8 @@ import { computed, onMounted, reactive, ref, watch } from "vue";
6
6
  import { withPrefix, property } from "../../utils";
7
7
  import { usePresent } from "./present.composable";
8
8
 
9
- /// Define
10
- /// ------------------------------------------------------------
11
- const presentIndex = usePresent();
12
- const emit = defineEmits(["close"]) as unknown as PresentEmit;
9
+ // Component setup (props, emits, injects)
10
+ // ----------------------------------------------------------------------------
13
11
  defineOptions({ inheritAttrs: false });
14
12
 
15
13
  const props = withDefaults(defineProps<PresentProps>(), {
@@ -20,9 +18,11 @@ const props = withDefaults(defineProps<PresentProps>(), {
20
18
  placement: "bottom",
21
19
  bounce: false,
22
20
  });
21
+ const emit = defineEmits(["close"]) as unknown as PresentEmit;
22
+ const presentIndex = usePresent();
23
23
 
24
- /// State
25
- /// ------------------------------------------------------------
24
+ // Reactive state
25
+ // ----------------------------------------------------------------------------
26
26
  const isBounced = ref(false);
27
27
  const zIndex = ref(0);
28
28
  const isShow = ref(false);
@@ -34,8 +34,8 @@ const styles = reactive({
34
34
  presentOpacity: 1,
35
35
  });
36
36
 
37
- /// Computed
38
- /// ------------------------------------------------------------
37
+ // Computed properties
38
+ // ----------------------------------------------------------------------------
39
39
  const backdropAttrs = computed(() => {
40
40
  return {
41
41
  class: [withPrefix(["layer", "backdrop"]), withPrefix("present-backdrop")],
@@ -73,7 +73,7 @@ const time = computed(() => {
73
73
  });
74
74
 
75
75
  // Methods
76
- /// ------------------------------------------------------------
76
+ // ----------------------------------------------------------------------------
77
77
  const createIndex = () => {
78
78
  if (zIndex.value === 0 || !props.keepalive) {
79
79
  zIndex.value = presentIndex.newIndex();
@@ -161,7 +161,7 @@ const close = () => {
161
161
  };
162
162
 
163
163
  // Lifecycle
164
- /// ------------------------------------------------------------
164
+ // ----------------------------------------------------------------------------
165
165
  onMounted(() => {
166
166
  if (props.visible) open();
167
167
  else close();
@@ -188,8 +188,8 @@ watch(
188
188
  }
189
189
  );
190
190
 
191
- // Export, Expose
192
- /// ------------------------------------------------------------
191
+ // Provide / expose (public API)
192
+ // ----------------------------------------------------------------------------
193
193
  defineExpose({
194
194
  render,
195
195
  open,
@@ -4,15 +4,20 @@
4
4
  $radio: sass.fn-naming-prefix("radio");
5
5
  $radio-icon: sass.fn-naming-prefix("radio-icon");
6
6
 
7
- // Properties - layer: item
8
- $background-color: sass.fn-naming-var("radio", "background-color");
9
- $background-color-hover: sass.fn-naming-var("radio", "background-color", "subtle");
10
- $background-color-inactive: sass.fn-naming-var("radio", "background-color", "soft");
11
- $background-color-contrast: sass.fn-naming-var("radio", "background-color", "contrast");
12
- $background-color-disabled: sass.fn-naming-var("radio", "background-color", "subtle");
13
-
14
- $border-color: sass.fn-naming-var("radio", "border-color");
15
- $border-color-inactive: sass.fn-naming-var("radio", "border-color", "subtle");
7
+ // Property name - layer: radio (states align with button + checkbox: inactive + contrast)
8
+ $radio-background-color: sass.fn-naming-var("radio", "background-color");
9
+ $radio-background-color-hover: sass.fn-naming-var("radio", "background-color", "hover");
10
+ $radio-background-color-focus: sass.fn-naming-var("radio", "background-color", "focus");
11
+ $radio-background-color-active: sass.fn-naming-var("radio", "background-color", "active");
12
+ $radio-background-color-disabled: sass.fn-naming-var("radio", "background-color", "disabled");
13
+ $radio-background-color-contrast: sass.fn-naming-var("radio", "background-color", "contrast");
14
+
15
+ $radio-border-color: sass.fn-naming-var("radio", "border-color");
16
+ $radio-border-color-hover: sass.fn-naming-var("radio", "border-color", "hover");
17
+ $radio-border-color-focus: sass.fn-naming-var("radio", "border-color", "focus");
18
+ $radio-border-color-active: sass.fn-naming-var("radio", "border-color", "active");
19
+ $radio-border-color-disabled: sass.fn-naming-var("radio", "border-color", "disabled");
20
+ $radio-border-color-inactive: sass.fn-naming-var("radio", "border-color", "inactive");
16
21
 
17
22
  $transition-duration: sass.fn-naming-var("motion", "duration");
18
23
  $border-radius: sass.fn-naming-var("border-radius");
@@ -33,7 +38,7 @@ $border-radius: sass.fn-naming-var("border-radius");
33
38
  display: flex;
34
39
  align-items: center;
35
40
  justify-content: center;
36
- border: 1px solid rgb(#{$border-color-inactive});
41
+ border: 1px solid rgb(#{$radio-border-color-inactive});
37
42
  background-color: transparent;
38
43
  transition:
39
44
  box-shadow #{$transition-duration} ease,
@@ -50,7 +55,7 @@ $border-radius: sass.fn-naming-var("border-radius");
50
55
  width: 0.5rem;
51
56
  height: 0.5rem;
52
57
  border-radius: 50%;
53
- background-color: rgb(#{$background-color-contrast});
58
+ background-color: rgb(#{$radio-background-color-contrast});
54
59
  transform: scale(0);
55
60
  transition:
56
61
  transform #{$transition-duration} ease,
@@ -63,13 +68,13 @@ $border-radius: sass.fn-naming-var("border-radius");
63
68
  &:not(.on) {
64
69
  .#{$radio-icon} {
65
70
  background-color: transparent;
66
- border-color: rgb(#{$border-color-inactive});
71
+ border-color: rgb(#{$radio-border-color-inactive});
67
72
  }
68
73
 
69
74
  &:not(.disabled):not(.readonly):hover {
70
75
  .#{$radio-icon} {
71
- border-color: rgb(#{$border-color});
72
- background-color: rgba(#{$background-color-hover}, 0.2);
76
+ border-color: rgb(#{$radio-border-color-hover});
77
+ background-color: rgba(#{$radio-background-color-hover}, 0.2);
73
78
  }
74
79
  }
75
80
  }
@@ -77,8 +82,8 @@ $border-radius: sass.fn-naming-var("border-radius");
77
82
  &.on {
78
83
  &.fill {
79
84
  .#{$radio-icon} {
80
- background-color: rgb(#{$background-color});
81
- border-color: rgb(#{$background-color});
85
+ background-color: rgb(#{$radio-background-color});
86
+ border-color: rgb(#{$radio-background-color});
82
87
 
83
88
  &::after {
84
89
  transform: scale(1);
@@ -89,11 +94,11 @@ $border-radius: sass.fn-naming-var("border-radius");
89
94
  &.outline {
90
95
  .#{$radio-icon} {
91
96
  background-color: transparent;
92
- border-color: rgb(#{$background-color});
97
+ border-color: rgb(#{$radio-background-color});
93
98
 
94
99
  &::after {
95
100
  transform: scale(1.5);
96
- background-color: rgb(#{$background-color});
101
+ background-color: rgb(#{$radio-background-color});
97
102
  }
98
103
  }
99
104
  }
@@ -105,8 +110,8 @@ $border-radius: sass.fn-naming-var("border-radius");
105
110
 
106
111
  &.on {
107
112
  .#{$radio-icon} {
108
- background-color: rgb(#{$background-color-disabled});
109
- border-color: rgb(#{$background-color-disabled});
113
+ background-color: rgb(#{$radio-background-color-disabled});
114
+ border-color: rgb(#{$radio-border-color-disabled});
110
115
  }
111
116
  }
112
117
  }
@@ -118,7 +123,7 @@ $border-radius: sass.fn-naming-var("border-radius");
118
123
  &.focus {
119
124
  &.shadow {
120
125
  .#{$radio-icon} {
121
- box-shadow: 0 0 0 0.25rem rgb(#{$border-color}, 0.25);
126
+ box-shadow: 0 0 0 0.25rem rgb(#{$radio-border-color-focus}, 0.25);
122
127
  }
123
128
  }
124
129
  }
@@ -1,6 +1,6 @@
1
1
  export type RadioVariant = "fill" | "outline";
2
2
 
3
- // Define
3
+ // Type definitions
4
4
  export type RadioProps = {
5
5
  value: string | number;
6
6
  role?: string;
@@ -7,8 +7,8 @@ import { withPrefix } from "../../../utils";
7
7
  import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../../app";
8
8
  import { type RadioGroupProviderState, RADIO_GROUP_PROVIDER_STATE_KEY } from "../radio-group";
9
9
 
10
- /// Define
11
- /// ------------------------------------------------------------
10
+ // Component setup (props, emits, injects)
11
+ // ----------------------------------------------------------------------------
12
12
  const props = withDefaults(defineProps<RadioProps>(), {
13
13
  disabled: false,
14
14
  shadow: undefined,
@@ -19,12 +19,12 @@ const radioGroupState = inject<RadioGroupProviderState | null>(
19
19
  null
20
20
  );
21
21
 
22
- /// State
23
- /// ------------------------------------------------------------
22
+ // Reactive state
23
+ // ----------------------------------------------------------------------------
24
24
  const isFocused = ref(false);
25
25
 
26
- /// Computed
27
- /// ------------------------------------------------------------
26
+ // Computed properties
27
+ // ----------------------------------------------------------------------------
28
28
  const role = computed(() => {
29
29
  return props.role || radioGroupState?.role.value || appState?.role.value || "";
30
30
  });
@@ -74,8 +74,8 @@ const radioIconAttrs = {
74
74
  class: [withPrefix("radio-icon")],
75
75
  } as const;
76
76
 
77
- /// Methods
78
- /// ------------------------------------------------------------
77
+ // Methods
78
+ // ----------------------------------------------------------------------------
79
79
  const onRadio = () => {
80
80
  if (disabled.value || readonly.value || !radioGroupState) return;
81
81
  radioGroupState.setValue(props.value);
@@ -7,8 +7,8 @@ import { withPrefix } from "../../../utils";
7
7
  import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../../app";
8
8
  import { RADIO_GROUP_PROVIDER_STATE_KEY } from "./radio-group.constants";
9
9
 
10
- /// Define
11
- /// ------------------------------------------------------------
10
+ // Component setup (props, emits, injects)
11
+ // ----------------------------------------------------------------------------
12
12
  const props = withDefaults(defineProps<RadioGroupProps>(), {
13
13
  disabled: false,
14
14
  readonly: false,
@@ -19,8 +19,8 @@ const props = withDefaults(defineProps<RadioGroupProps>(), {
19
19
  const emit = defineEmits<RadioGroupEmit>();
20
20
  const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
21
21
 
22
- /// Computed
23
- /// ------------------------------------------------------------
22
+ // Computed properties
23
+ // ----------------------------------------------------------------------------
24
24
  const modelValue = computed(() => props.modelValue);
25
25
 
26
26
  const role = computed(() => {
@@ -41,8 +41,8 @@ const radioGroupAttrs = computed(() => {
41
41
  };
42
42
  });
43
43
 
44
- /// Provide
45
- /// ------------------------------------------------------------
44
+ // Provide / expose (public API)
45
+ // ----------------------------------------------------------------------------
46
46
  provide<RadioGroupProviderState>(RADIO_GROUP_PROVIDER_STATE_KEY, {
47
47
  modelValue,
48
48
  role,
@@ -1,7 +1,7 @@
1
1
  // Props
2
2
  export type RefresherVariant = "max" | "up";
3
3
 
4
- // Define
4
+ // Type definitions
5
5
  export type RefresherProps = {
6
6
  threshold?: number;
7
7
  variant?: RefresherVariant;
@@ -6,25 +6,25 @@ import { gesture } from "@toife/gesture";
6
6
  import type { RefresherProps, RefresherEmit } from "./refresher.type";
7
7
  import { property, withPrefix } from "../../utils";
8
8
 
9
- /// Define
10
- /// ------------------------------------------------------------
11
- const emit = defineEmits<RefresherEmit>();
9
+ // Component setup (props, emits, injects)
10
+ // ----------------------------------------------------------------------------
12
11
  const props = withDefaults(defineProps<RefresherProps>(), {
13
12
  threshold: 120,
14
13
  variant: "max",
15
14
  offset: undefined,
16
15
  });
16
+ const emit = defineEmits<RefresherEmit>();
17
17
 
18
- /// State
19
- /// ------------------------------------------------------------
18
+ // Reactive state
19
+ // ----------------------------------------------------------------------------
20
20
  const moveOffset = ref(0);
21
21
  const refreshing = ref(false);
22
22
  const container = ref();
23
23
  let cleanup: unknown;
24
24
  let locked = false;
25
25
 
26
- /// Computed
27
- /// ------------------------------------------------------------
26
+ // Computed properties
27
+ // ----------------------------------------------------------------------------
28
28
  const calculateOffset = computed(() => {
29
29
  return props.offset !== undefined ? props.offset : moveOffset.value / 2;
30
30
  });
@@ -49,8 +49,8 @@ const containerAttrs = computed(() => {
49
49
  };
50
50
  });
51
51
 
52
- /// Methods
53
- /// ------------------------------------------------------------
52
+ // Methods
53
+ // ----------------------------------------------------------------------------
54
54
  const close = () => {
55
55
  refreshing.value = false;
56
56
  moveOffset.value = 0;
@@ -71,8 +71,8 @@ const cancel = () => {
71
71
  emit("cancel");
72
72
  };
73
73
 
74
- /// Lifecycle
75
- /// ------------------------------------------------------------
74
+ // Lifecycle
75
+ // ----------------------------------------------------------------------------
76
76
  watch(
77
77
  () => container.value,
78
78
  () => {
@@ -1,12 +1,36 @@
1
1
  export type RouteNavigatorVariant = "none" | "swipe";
2
2
 
3
+ /**
4
+ * Route Navigator Props Type
5
+ */
3
6
  export type RouteNavigatorProps = {
4
7
  direction?: "left" | "right";
5
8
  variant?: RouteNavigatorVariant;
6
9
  keepalive?: boolean;
7
10
  };
8
11
 
12
+ /**
13
+ * Route Navigator Gesture Type
14
+ */
9
15
  export type RouteNavigatorGesture = {
10
16
  deltaX: number;
11
17
  deltaY: number;
12
18
  };
19
+
20
+ /**
21
+ * Route Navigator Emit Type
22
+ */
23
+ export type RouteNavigatorEmit = {
24
+ (e: "transform", value: RouteNavigatorTransformState): void;
25
+ };
26
+
27
+ /**
28
+ * Route Navigator Transform State Type
29
+ */
30
+ export type RouteNavigatorTransformState = {
31
+ back: number;
32
+ prepare: number;
33
+ active: number;
34
+ backdrop: number;
35
+ duration: string | undefined;
36
+ };
@@ -4,7 +4,11 @@
4
4
  import { computed, inject, onMounted, onUnmounted, reactive, ref, watch } from "vue";
5
5
  import { gesture } from "@toife/gesture";
6
6
  import { withPrefix, property } from "../../../utils";
7
- import type { RouteNavigatorProps } from "./route-navigator.type";
7
+ import type {
8
+ RouteNavigatorEmit,
9
+ RouteNavigatorProps,
10
+ RouteNavigatorTransformState,
11
+ } from "./route-navigator.type";
8
12
  import {
9
13
  ROUTE_PROVIDER_STATE_KEY,
10
14
  RouteProvider,
@@ -16,38 +20,40 @@ import type { RouteStack } from "../route.type";
16
20
  import { useRouter } from "vue-router";
17
21
  import { clone } from "../route.util";
18
22
 
23
+ // Component setup (props, emits, injects)
24
+ // ----------------------------------------------------------------------------
19
25
  // Max translate offset (%) for the layer behind the active page during swipe.
20
26
  // Active uses 0–100%; back uses (peek)*(100−percent)/100, so a peek of 40 makes the
21
27
  // back layer move 2.5× slower than the active layer (parallax). Use 100 for 1:1 motion
22
28
  // (no edge peek at rest: back starts at -100%).
23
29
  const BACK_LAYER_PEEK_PCT = 40;
24
30
 
25
- /// Define
26
- /// ------------------------------------------------------------
27
31
  const props = withDefaults(defineProps<RouteNavigatorProps>(), {
28
32
  direction: "right",
29
33
  variant: "none",
30
34
  keepalive: false,
31
35
  });
36
+ const emit = defineEmits<RouteNavigatorEmit>();
32
37
  const provider = inject<RouteProviderState>(ROUTE_PROVIDER_STATE_KEY);
33
38
  const router = useRouter();
34
- /// State
35
- /// ------------------------------------------------------------
39
+
40
+ // Reactive state
41
+ // ----------------------------------------------------------------------------
36
42
  const navigatorRef = ref<HTMLElement>();
37
43
  const ges = ref<unknown>(null);
38
- const transform = reactive({
44
+ const transform = reactive<RouteNavigatorTransformState>({
39
45
  back: BACK_LAYER_PEEK_PCT,
40
46
  prepare: 100,
41
47
  active: 0,
42
48
  backdrop: 0,
43
- duration: undefined as string | undefined,
49
+ duration: undefined,
44
50
  });
45
51
  const stack = ref<RouteStack[]>([]);
46
52
  const activeIndex = ref(0);
47
53
  const backdropIndex = ref(0);
48
54
 
49
- /// Computed
50
- /// ------------------------------------------------------------
55
+ // Computed properties
56
+ // ----------------------------------------------------------------------------
51
57
  const navigatorAttrs = computed(() => {
52
58
  let duration =
53
59
  transform.duration !== undefined ? transform.duration : transform.active > 0 ? "0s" : undefined;
@@ -90,8 +96,8 @@ const prevPage = computed(() => {
90
96
  return null;
91
97
  });
92
98
 
93
- /// Methods
94
- /// ------------------------------------------------------------
99
+ // Methods
100
+ // ----------------------------------------------------------------------------
95
101
  const changeRoute = (value: RouteStack[]) => {
96
102
  const data = clone(value);
97
103
 
@@ -112,10 +118,13 @@ const changeRoute = (value: RouteStack[]) => {
112
118
  resetTransform();
113
119
  activeIndex.value = newIndex;
114
120
  transform.backdrop = 0;
121
+ emit("transform", transform);
122
+
115
123
  setTimeout(() => {
116
124
  stack.value = stack.value.slice(0, -1);
117
125
  backdropIndex.value = newIndex;
118
126
  transform.backdrop = 100;
127
+ emit("transform", transform);
119
128
  }, 250);
120
129
  }
121
130
  // Case: next
@@ -123,32 +132,38 @@ const changeRoute = (value: RouteStack[]) => {
123
132
  stack.value.push(data[data.length - 1]);
124
133
  transform.duration = "0s";
125
134
  transform.backdrop = 0;
135
+ emit("transform", transform);
126
136
 
127
137
  setTimeout(() => {
128
138
  backdropIndex.value = backdropIndex.value + 1;
129
139
  transform.duration = undefined;
140
+ emit("transform", transform);
130
141
  }, 10);
131
142
 
132
143
  setTimeout(() => {
133
144
  transform.backdrop = 100;
134
145
  activeIndex.value = stack.value.length - 1;
146
+ emit("transform", transform);
135
147
  }, 100);
136
148
  }
137
149
  };
138
150
 
139
151
  const goBack = () => {
140
- const url = stack.value[activeIndex.value - 1].fullPath;
141
- router.push(url);
152
+ if (activeIndex.value <= 0) return;
153
+ const prev = stack.value[activeIndex.value - 1];
154
+ if (!prev) return;
155
+ router.push(prev.fullPath);
142
156
  };
143
157
 
144
158
  const resetTransform = () => {
145
159
  transform.back = BACK_LAYER_PEEK_PCT;
146
160
  transform.prepare = 100;
147
161
  transform.active = 0;
162
+
163
+ emit("transform", transform);
148
164
  };
149
165
 
150
166
  const move = (data: RouteNavigatorGesture) => {
151
- console.log(stack.value);
152
167
  const width = navigatorRef.value?.offsetWidth ?? 0;
153
168
  let percent = 0;
154
169
 
@@ -161,6 +176,8 @@ const move = (data: RouteNavigatorGesture) => {
161
176
  transform.back = ((100 - percent) * BACK_LAYER_PEEK_PCT) / 100;
162
177
  transform.active = percent;
163
178
  transform.backdrop = 100 - transform.active;
179
+
180
+ emit("transform", transform);
164
181
  };
165
182
 
166
183
  const up = (data: RouteNavigatorGesture) => {
@@ -180,8 +197,8 @@ const up = (data: RouteNavigatorGesture) => {
180
197
  }
181
198
  };
182
199
 
183
- /// Lifecycle
184
- /// ------------------------------------------------------------
200
+ // Lifecycle
201
+ // ----------------------------------------------------------------------------
185
202
  watch(
186
203
  () => provider?.stack.value,
187
204
  (value) => {