@toife/vue 3.0.2 → 3.0.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 +1 -1
- package/src/components/action/action.composable.ts +1 -0
- package/src/components/action/action.type.ts +10 -1
- package/src/components/action/action.vue +12 -10
- package/src/components/app/app.type.ts +9 -0
- package/src/components/app/app.vue +8 -7
- package/src/components/avatar/avatar.type.ts +1 -1
- package/src/components/avatar/avatar.vue +4 -13
- package/src/components/button/button.type.ts +1 -1
- package/src/components/button/button.vue +8 -8
- package/src/components/cable/cable.type.ts +1 -1
- package/src/components/cable/cable.vue +8 -8
- package/src/components/card/card/card.type.ts +1 -1
- package/src/components/card/card/card.vue +6 -6
- package/src/components/card/card-footer/card-footer.vue +4 -4
- package/src/components/card/card-header/card-header.vue +4 -4
- package/src/components/checkbox/checkbox.vue +8 -8
- package/src/components/collapse/collapse.type.ts +1 -1
- package/src/components/collapse/collapse.vue +15 -19
- package/src/components/container/container.vue +1 -0
- package/src/components/decision-modal/decision-modal.composable.ts +1 -0
- package/src/components/decision-modal/decision-modal.type.ts +1 -1
- package/src/components/decision-modal/decision-modal.vue +11 -11
- package/src/components/divider/divider.vue +4 -4
- package/src/components/field/field.type.ts +1 -1
- package/src/components/field/field.vue +7 -6
- package/src/components/field/outline/outline.vue +10 -10
- package/src/components/form-group/form-group.vue +5 -5
- package/src/components/gesture-indicator/gesture-indicator.type.ts +1 -1
- package/src/components/gesture-indicator/gesture-indicator.vue +5 -5
- package/src/components/image/image.type.ts +1 -1
- package/src/components/image/image.vue +10 -12
- package/src/components/modal/modal.vue +11 -9
- package/src/components/page/page.vue +2 -1
- package/src/components/present/present.composable.ts +1 -0
- package/src/components/present/present.vue +12 -12
- package/src/components/radio/radio/radio.type.ts +1 -1
- package/src/components/radio/radio/radio.vue +8 -8
- package/src/components/radio/radio-group/radio-group.vue +6 -6
- package/src/components/refresher/refresher.type.ts +1 -1
- package/src/components/refresher/refresher.vue +11 -11
- package/src/components/route/route-navigator/route-navigator.type.ts +24 -0
- package/src/components/route/route-navigator/route-navigator.vue +33 -16
- package/src/components/route/route-outlet/route-outlet.vue +20 -11
- package/src/components/route/route-provider/route-provider.vue +6 -6
- package/src/components/route/route-wrapper/route-wrapper.composable.ts +4 -3
- package/src/components/route/route-wrapper/route-wrapper.vue +7 -5
- package/src/components/route/route.util.ts +1 -0
- package/src/components/segmented-field/segmented-field.vue +8 -8
- package/src/components/skeleton/skeleton.type.ts +1 -1
- package/src/components/skeleton/skeleton.vue +4 -4
- package/src/components/switch/switch.type.ts +1 -1
- package/src/components/switch/switch.vue +8 -8
- package/src/components/tabs/tab/tab.type.ts +1 -1
- package/src/components/tabs/tab/tab.vue +6 -6
- package/src/components/tabs/tabs/tabs.type.ts +1 -1
- package/src/components/tabs/tabs/tabs.vue +13 -13
- package/src/components/toast/toast/toast.vue +6 -6
- package/src/components/toast/toast-content/toast-content.vue +7 -7
- package/src/components/toast/toast.composable.ts +1 -1
- package/src/components/toolbar/toolbar.type.ts +1 -1
- package/src/components/toolbar/toolbar.vue +4 -4
- package/src/factory.ts +2 -1
- package/src/utils/element.ts +6 -0
- package/src/utils/events.ts +8 -2
- package/src/utils/style/index.ts +17 -2
|
@@ -5,8 +5,8 @@ import { computed, nextTick, ref, watch } from "vue";
|
|
|
5
5
|
import type { FieldProps, FieldEmit } from "../field.type";
|
|
6
6
|
import { property, withPrefix } from "../../../utils";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Component setup (props, emits, injects)
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
10
|
const props = withDefaults(defineProps<FieldProps>(), {
|
|
11
11
|
modelValue: "",
|
|
12
12
|
type: "text",
|
|
@@ -22,15 +22,15 @@ const props = withDefaults(defineProps<FieldProps>(), {
|
|
|
22
22
|
});
|
|
23
23
|
const emit = defineEmits<FieldEmit>();
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// Reactive state
|
|
26
|
+
// ----------------------------------------------------------------------------
|
|
27
27
|
const isFocus = ref(false);
|
|
28
28
|
const contentRef = ref<HTMLElement>();
|
|
29
29
|
const caret = ref(0);
|
|
30
30
|
const isComposing = ref(false);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Computed properties
|
|
33
|
+
// ----------------------------------------------------------------------------
|
|
34
34
|
const content = computed(() => {
|
|
35
35
|
return props.value || props.modelValue;
|
|
36
36
|
});
|
|
@@ -87,8 +87,8 @@ const fieldHelpAttrs = computed(() => ({
|
|
|
87
87
|
class: [withPrefix("field-help")],
|
|
88
88
|
}));
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// Methods
|
|
91
|
+
// ----------------------------------------------------------------------------
|
|
92
92
|
const isBr = (node: Node): node is HTMLBRElement =>
|
|
93
93
|
node.nodeType === 1 && (node as HTMLElement).tagName === "BR";
|
|
94
94
|
|
|
@@ -226,8 +226,8 @@ const onBeforeinput = (ev: Event) => {
|
|
|
226
226
|
emit("beforeinput", ev);
|
|
227
227
|
};
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
// Lifecycle
|
|
230
|
+
// ----------------------------------------------------------------------------
|
|
231
231
|
watch(
|
|
232
232
|
() => content.value,
|
|
233
233
|
async (val) => {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<style lang="scss" src="./form-group.scss" scoped></style>
|
|
2
2
|
<template src="./form-group.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
|
-
import { withPrefix } from "
|
|
4
|
+
import { withPrefix } from "../../utils";
|
|
5
5
|
import { computed } from "vue";
|
|
6
6
|
import { type FormGroupProps } from "./form-group.type";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Component setup (props, emits, injects)
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
10
|
const props = withDefaults(defineProps<FormGroupProps>(), {
|
|
11
11
|
orientation: "horizontal",
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// Computed properties
|
|
15
|
+
// ----------------------------------------------------------------------------
|
|
16
16
|
const formGroupAttrs = computed(() => {
|
|
17
17
|
return {
|
|
18
18
|
class: [withPrefix("form-group"), props.orientation],
|
|
@@ -6,15 +6,15 @@ import { type GestureIndicatorProps } from "./gesture-indicator.type";
|
|
|
6
6
|
import { computed, inject } from "vue";
|
|
7
7
|
import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
|
|
9
|
+
// Component setup (props, emits, injects)
|
|
10
|
+
// ----------------------------------------------------------------------------
|
|
12
11
|
const props = withDefaults(defineProps<GestureIndicatorProps>(), {
|
|
13
12
|
placement: "bottom",
|
|
14
13
|
});
|
|
14
|
+
const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// Computed properties
|
|
17
|
+
// ----------------------------------------------------------------------------
|
|
18
18
|
const gestureIndicatorAttrs = computed(() => {
|
|
19
19
|
const role = appState?.role.value || "";
|
|
20
20
|
return {
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
<style lang="scss" src="./image.scss" scoped></style>
|
|
2
2
|
<template src="./image.html"></template>
|
|
3
3
|
<script setup lang="ts">
|
|
4
|
-
import {
|
|
4
|
+
import { ref } from "vue";
|
|
5
5
|
import { type ImageProps } from "./image.type";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const dataSrc = ref<unknown>("");
|
|
7
|
+
// Component setup (props, emits, injects)
|
|
8
|
+
// ----------------------------------------------------------------------------
|
|
10
9
|
const { defaultSrc, src } = defineProps<ImageProps>();
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
// Reactive state
|
|
12
|
+
// ----------------------------------------------------------------------------
|
|
13
|
+
// Initialize from src to avoid an empty src flash before mount
|
|
14
|
+
const dataSrc = ref<string>(src ?? "");
|
|
15
|
+
|
|
16
|
+
// Methods
|
|
17
|
+
// ----------------------------------------------------------------------------
|
|
14
18
|
const handleError = () => {
|
|
15
19
|
if (defaultSrc) {
|
|
16
20
|
dataSrc.value = defaultSrc;
|
|
17
21
|
}
|
|
18
22
|
};
|
|
19
|
-
|
|
20
|
-
/// Lifecycle
|
|
21
|
-
/// ------------------------------------------------------------
|
|
22
|
-
onMounted(() => {
|
|
23
|
-
dataSrc.value = src;
|
|
24
|
-
});
|
|
25
23
|
</script>
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template src="./page.html"></template>
|
|
2
2
|
<style lang="scss" src="./page.scss" scoped></style>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
|
-
import { withPrefix } from "
|
|
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;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
192
|
-
|
|
191
|
+
// Provide / expose (public API)
|
|
192
|
+
// ----------------------------------------------------------------------------
|
|
193
193
|
defineExpose({
|
|
194
194
|
render,
|
|
195
195
|
open,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
22
|
+
// Reactive state
|
|
23
|
+
// ----------------------------------------------------------------------------
|
|
24
24
|
const isFocused = ref(false);
|
|
25
25
|
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
|
|
44
|
+
// Provide / expose (public API)
|
|
45
|
+
// ----------------------------------------------------------------------------
|
|
46
46
|
provide<RadioGroupProviderState>(RADIO_GROUP_PROVIDER_STATE_KEY, {
|
|
47
47
|
modelValue,
|
|
48
48
|
role,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|
-
|
|
184
|
-
|
|
200
|
+
// Lifecycle
|
|
201
|
+
// ----------------------------------------------------------------------------
|
|
185
202
|
watch(
|
|
186
203
|
() => provider?.stack.value,
|
|
187
204
|
(value) => {
|