@toife/vue 3.1.4 → 3.1.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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/components/action/action.scss +1 -1
- package/src/components/action/action.vue +5 -5
- package/src/components/app/app.scss +2 -2
- package/src/components/app/app.vue +5 -5
- package/src/components/avatar/avatar.scss +3 -2
- package/src/components/avatar/avatar.vue +6 -6
- package/src/components/button/button.scss +13 -13
- package/src/components/button/button.vue +7 -7
- package/src/components/cable/cable.vue +2 -2
- package/src/components/card/card/card.scss +2 -2
- package/src/components/card/card/card.vue +5 -5
- package/src/components/card/card-body/card-body.scss +2 -2
- package/src/components/card/card-body/card-body.vue +2 -2
- package/src/components/card/card-footer/card-footer.scss +3 -3
- package/src/components/card/card-footer/card-footer.vue +2 -2
- package/src/components/card/card-header/card-header.scss +3 -3
- package/src/components/card/card-header/card-header.vue +2 -2
- package/src/components/checkbox/checkbox.html +1 -1
- package/src/components/checkbox/checkbox.scss +18 -13
- package/src/components/checkbox/checkbox.vue +7 -7
- package/src/components/collapse/collapse.html +1 -1
- package/src/components/collapse/collapse.scss +2 -2
- package/src/components/collapse/collapse.vue +9 -9
- package/src/components/container/container.vue +2 -2
- package/src/components/decision-modal/decision-modal.scss +9 -9
- package/src/components/decision-modal/decision-modal.vue +8 -8
- package/src/components/divider/divider.scss +2 -2
- package/src/components/divider/divider.vue +4 -4
- package/src/components/dropdown/dropdown.scss +3 -3
- package/src/components/dropdown/dropdown.vue +7 -9
- package/src/components/field/field.type.ts +2 -2
- package/src/components/field/outline/outline.scss +15 -13
- package/src/components/field/outline/outline.vue +26 -18
- package/src/components/form-group/form-group.vue +2 -2
- package/src/components/gesture-indicator/gesture-indicator.scss +1 -1
- package/src/components/gesture-indicator/gesture-indicator.vue +4 -4
- package/src/components/image/image.vue +12 -5
- package/src/components/layout/flex/flex.vue +8 -8
- package/src/components/layout/flex-item/flex-item.vue +6 -6
- package/src/components/layout/grid/grid.vue +6 -6
- package/src/components/layout/grid-item/grid-item.vue +6 -6
- package/src/components/modal/modal.scss +1 -1
- package/src/components/modal/modal.vue +68 -5
- package/src/components/page/page.vue +2 -2
- package/src/components/present/present.scss +3 -3
- package/src/components/present/present.vue +14 -14
- package/src/components/radio/radio/radio.html +1 -1
- package/src/components/radio/radio/radio.scss +18 -13
- package/src/components/radio/radio/radio.type.ts +1 -1
- package/src/components/radio/radio/radio.vue +6 -6
- package/src/components/radio/radio-group/radio-group.vue +2 -2
- package/src/components/refresher/refresher.html +0 -3
- package/src/components/refresher/refresher.scss +1 -25
- package/src/components/refresher/refresher.vue +2 -16
- package/src/components/route/route-navigator/route-navigator.scss +2 -2
- package/src/components/route/route-navigator/route-navigator.vue +10 -13
- package/src/components/route/route-wrapper/route-wrapper.composable.ts +5 -15
- package/src/components/route/route-wrapper/route-wrapper.type.ts +0 -4
- package/src/components/route/route-wrapper/route-wrapper.vue +4 -12
- package/src/components/route/route.type.ts +0 -1
- package/src/components/segmented-field/segmented-field.html +1 -1
- package/src/components/segmented-field/segmented-field.scss +2 -2
- package/src/components/segmented-field/segmented-field.vue +8 -8
- package/src/components/select/select.html +2 -2
- package/src/components/select/select.scss +10 -10
- package/src/components/select/select.vue +10 -10
- package/src/components/skeleton/skeleton.vue +7 -7
- package/src/components/slide-range/slide-range.html +3 -4
- package/src/components/slide-range/slide-range.scss +10 -10
- package/src/components/slide-range/slide-range.vue +16 -16
- package/src/components/switch/switch.html +1 -1
- package/src/components/switch/switch.scss +22 -20
- package/src/components/switch/switch.type.ts +1 -0
- package/src/components/switch/switch.vue +23 -9
- package/src/components/tabs/tab/tab.html +1 -1
- package/src/components/tabs/tab/tab.scss +13 -0
- package/src/components/tabs/tab/tab.vue +4 -2
- package/src/components/tabs/tabs/index.ts +1 -0
- package/src/components/tabs/tabs/tabs.scss +81 -49
- package/src/components/tabs/tabs/tabs.type.ts +5 -1
- package/src/components/tabs/tabs/tabs.vue +47 -23
- package/src/components/toast/toast/toast.vue +2 -2
- package/src/components/toast/toast-content/toast-content.scss +3 -3
- package/src/components/toast/toast-content/toast-content.vue +5 -5
- package/src/components/toolbar/toolbar.scss +3 -3
- package/src/components/toolbar/toolbar.vue +5 -5
- package/src/factory.ts +105 -51
- package/src/type.ts +2 -1
- package/src/utils/style/index.ts +9 -9
- package/src/utils/style.md +9 -9
|
@@ -6,7 +6,7 @@ import { gesture as toifeGesture } from "@toife/gesture";
|
|
|
6
6
|
import { Present } from "../present";
|
|
7
7
|
import { GestureIndicator } from "../gesture-indicator";
|
|
8
8
|
import { type ModalProps, type ModalEmit } from "./modal.type";
|
|
9
|
-
import {
|
|
9
|
+
import { cssPrefix } from "../../utils";
|
|
10
10
|
import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
|
|
11
11
|
|
|
12
12
|
// Component setup (props, emits, injects)
|
|
@@ -47,10 +47,10 @@ const modalAttrs = computed(() => {
|
|
|
47
47
|
|
|
48
48
|
return {
|
|
49
49
|
class: [
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
cssPrefix(["layer", "modal"]),
|
|
51
|
+
cssPrefix(["role", role]),
|
|
52
|
+
cssPrefix(["shape", shape]),
|
|
53
|
+
cssPrefix("modal"),
|
|
54
54
|
{
|
|
55
55
|
fullscreen: props.fullscreen,
|
|
56
56
|
[props.placement]: true,
|
|
@@ -67,6 +67,65 @@ const close = (e: string) => {
|
|
|
67
67
|
emit("close", e);
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
const SCROLLABLE_OVERFLOW_VALUES = ["auto", "scroll", "overlay"];
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if the element is scrollable
|
|
74
|
+
* @param el - The element
|
|
75
|
+
* @param axis - The axis of the scroll
|
|
76
|
+
* @returns True if the element is scrollable, false otherwise
|
|
77
|
+
*/
|
|
78
|
+
const isScrollable = (el: HTMLElement, axis: "x" | "y") => {
|
|
79
|
+
const style = getComputedStyle(el);
|
|
80
|
+
if (axis == "y") {
|
|
81
|
+
return (
|
|
82
|
+
el.scrollHeight > el.clientHeight && SCROLLABLE_OVERFLOW_VALUES.includes(style.overflowY)
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return el.scrollWidth > el.clientWidth && SCROLLABLE_OVERFLOW_VALUES.includes(style.overflowX);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if the element has remaining scroll
|
|
91
|
+
* @param el - The element
|
|
92
|
+
* @param direction - The direction of the scroll
|
|
93
|
+
* @returns True if the element has remaining scroll, false otherwise
|
|
94
|
+
*/
|
|
95
|
+
const hasRemainingScroll = (el: HTMLElement, direction: "up" | "down" | "left" | "right") => {
|
|
96
|
+
if (direction == "down") return el.scrollTop > 0;
|
|
97
|
+
if (direction == "up") return el.scrollTop < el.scrollHeight - el.clientHeight;
|
|
98
|
+
if (direction == "right") return el.scrollLeft > 0;
|
|
99
|
+
|
|
100
|
+
return el.scrollLeft < el.scrollWidth - el.clientWidth;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if the gesture can start
|
|
105
|
+
* @param e - The event
|
|
106
|
+
* @returns True if the gesture can start, false otherwise
|
|
107
|
+
*/
|
|
108
|
+
const canStartGesture = (e: unknown) => {
|
|
109
|
+
if (!modal.value || !gestureDir.value) return true;
|
|
110
|
+
|
|
111
|
+
const target = (e as { target?: EventTarget }).target;
|
|
112
|
+
if (!(target instanceof Element)) return true;
|
|
113
|
+
|
|
114
|
+
const axis = gestureDir.value == "left" || gestureDir.value == "right" ? "x" : "y";
|
|
115
|
+
let current: Element | null = target;
|
|
116
|
+
|
|
117
|
+
while (current && current !== modal.value) {
|
|
118
|
+
if (current instanceof HTMLElement && isScrollable(current, axis)) {
|
|
119
|
+
if (hasRemainingScroll(current, gestureDir.value)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
current = current.parentElement;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return true;
|
|
127
|
+
};
|
|
128
|
+
|
|
70
129
|
// Cooldown so rapid gesture events do not fight the sheet animation
|
|
71
130
|
const busy = () => {
|
|
72
131
|
isBusy.value = true;
|
|
@@ -94,6 +153,10 @@ watch(
|
|
|
94
153
|
return false;
|
|
95
154
|
}
|
|
96
155
|
|
|
156
|
+
if (!canStartGesture(e)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
97
160
|
return true;
|
|
98
161
|
},
|
|
99
162
|
|
|
@@ -1,10 +1,10 @@
|
|
|
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 {
|
|
4
|
+
import { cssPrefix } from "../../utils";
|
|
5
5
|
|
|
6
6
|
// Top-level page surface inside the app shell
|
|
7
7
|
const pageAttrs = {
|
|
8
|
-
class: [
|
|
8
|
+
class: [cssPrefix("page")],
|
|
9
9
|
} as const;
|
|
10
10
|
</script>
|
|
@@ -18,7 +18,7 @@ $present-translate-minus: sass.fn-naming-dvar(("translate"), "-100%");
|
|
|
18
18
|
$present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
|
|
19
19
|
|
|
20
20
|
.#{$backdrop} {
|
|
21
|
-
position:
|
|
21
|
+
position: fixed;
|
|
22
22
|
width: 100%;
|
|
23
23
|
height: 100%;
|
|
24
24
|
top: 0;
|
|
@@ -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:
|
|
33
|
+
background-color: rgba(#{$backdrop-background-color});
|
|
34
34
|
opacity: #{$backdrop-opacity};
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -38,7 +38,7 @@ $present-opacity: sass.fn-naming-dvar(("present", "opacity"), 1);
|
|
|
38
38
|
display: flex;
|
|
39
39
|
justify-content: center;
|
|
40
40
|
align-items: center;
|
|
41
|
-
position:
|
|
41
|
+
position: fixed;
|
|
42
42
|
width: fit-content;
|
|
43
43
|
height: fit-content;
|
|
44
44
|
transition: transform #{$transition-duration} ease;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import type { PresentEmit, PresentProps, RenderOptions } from "./present.type";
|
|
5
5
|
import { computed, onMounted, reactive, ref, watch } from "vue";
|
|
6
|
-
import {
|
|
6
|
+
import { cssPrefix, cssProperty } from "../../utils";
|
|
7
7
|
import { usePresent } from "./present.composable";
|
|
8
8
|
|
|
9
9
|
// Component setup (props, emits, injects)
|
|
@@ -28,7 +28,7 @@ const zIndex = ref(0);
|
|
|
28
28
|
const isShow = ref(false);
|
|
29
29
|
const styles = reactive({
|
|
30
30
|
backdropTransitionDuration: "0.2s",
|
|
31
|
-
backdropOpacity:
|
|
31
|
+
backdropOpacity: undefined,
|
|
32
32
|
presentTransitionDuration: "0.2s",
|
|
33
33
|
presentTranslate: "0px",
|
|
34
34
|
presentOpacity: 1,
|
|
@@ -38,11 +38,11 @@ const styles = reactive({
|
|
|
38
38
|
// ----------------------------------------------------------------------------
|
|
39
39
|
const backdropAttrs = computed(() => {
|
|
40
40
|
return {
|
|
41
|
-
class: [
|
|
41
|
+
class: [cssPrefix(["layer", "backdrop"]), cssPrefix("present-backdrop")],
|
|
42
42
|
style: {
|
|
43
43
|
zIndex: zIndex.value - 1,
|
|
44
|
-
[
|
|
45
|
-
[
|
|
44
|
+
[cssProperty("transition-duration")]: styles.backdropTransitionDuration,
|
|
45
|
+
[cssProperty(["backdrop", "opacity"])]:
|
|
46
46
|
props.backdrop === "transparent" ? 0 : styles.backdropOpacity,
|
|
47
47
|
},
|
|
48
48
|
};
|
|
@@ -51,13 +51,13 @@ const backdropAttrs = computed(() => {
|
|
|
51
51
|
// Present attributes
|
|
52
52
|
const presentAttrs = computed(() => {
|
|
53
53
|
return {
|
|
54
|
-
class: [
|
|
54
|
+
class: [cssPrefix("present"), props.class, props.placement],
|
|
55
55
|
style: [
|
|
56
56
|
{
|
|
57
57
|
zIndex: zIndex.value,
|
|
58
|
-
[
|
|
59
|
-
[
|
|
60
|
-
[
|
|
58
|
+
[cssProperty("transition-duration")]: styles.presentTransitionDuration,
|
|
59
|
+
[cssProperty("translate")]: styles.presentTranslate,
|
|
60
|
+
[cssProperty(["present", "opacity"])]: styles.presentOpacity,
|
|
61
61
|
},
|
|
62
62
|
props.style,
|
|
63
63
|
],
|
|
@@ -87,9 +87,9 @@ const render = (data: RenderOptions) => {
|
|
|
87
87
|
if (data.presentTransitionDuration !== undefined) {
|
|
88
88
|
styles.presentTransitionDuration = data.presentTransitionDuration;
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
|
|
91
|
+
styles.backdropOpacity = data.backdropOpacity;
|
|
92
|
+
|
|
93
93
|
if (data.presentTranslate !== undefined) {
|
|
94
94
|
styles.presentTranslate = data.presentTranslate;
|
|
95
95
|
}
|
|
@@ -115,7 +115,7 @@ const open = () => {
|
|
|
115
115
|
|
|
116
116
|
render({
|
|
117
117
|
backdropTransitionDuration: time.value,
|
|
118
|
-
backdropOpacity:
|
|
118
|
+
backdropOpacity: undefined,
|
|
119
119
|
presentTranslate: String(presentTranslate),
|
|
120
120
|
presentTransitionDuration: time.value,
|
|
121
121
|
presentOpacity: 1,
|
|
@@ -128,7 +128,7 @@ const open = () => {
|
|
|
128
128
|
}, props.duration);
|
|
129
129
|
} else {
|
|
130
130
|
render({
|
|
131
|
-
backdropOpacity:
|
|
131
|
+
backdropOpacity: undefined,
|
|
132
132
|
backdropTransitionDuration: time.value,
|
|
133
133
|
presentTranslate: "0px",
|
|
134
134
|
presentTransitionDuration: time.value,
|
|
@@ -11,7 +11,11 @@ $radio-background-color-unchecked: sass.fn-naming-var("radio", "background-color
|
|
|
11
11
|
$radio-background-color-checked: sass.fn-naming-var("radio", "background-color", "checked");
|
|
12
12
|
$radio-background-color-disabled: sass.fn-naming-var("radio", "background-color", "disabled");
|
|
13
13
|
|
|
14
|
-
$radio-color: sass.fn-naming-var("radio", "color");
|
|
14
|
+
$radio-color-unchecked: sass.fn-naming-var("radio", "color", "unchecked");
|
|
15
|
+
$radio-color-checked: sass.fn-naming-var("radio", "color", "checked");
|
|
16
|
+
$radio-color-hover: sass.fn-naming-var("radio", "color", "hover");
|
|
17
|
+
$radio-color-focus: sass.fn-naming-var("radio", "color", "focus");
|
|
18
|
+
$radio-color-disabled: sass.fn-naming-var("radio", "color", "disabled");
|
|
15
19
|
|
|
16
20
|
$radio-border-color-hover: sass.fn-naming-var("radio", "border-color", "hover");
|
|
17
21
|
$radio-border-color-focus: sass.fn-naming-var("radio", "border-color", "focus");
|
|
@@ -42,8 +46,8 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
42
46
|
display: flex;
|
|
43
47
|
align-items: center;
|
|
44
48
|
justify-content: center;
|
|
45
|
-
border: 1px solid rgb(#{$radio-color});
|
|
46
49
|
background-color: transparent;
|
|
50
|
+
border: 1px solid transparent;
|
|
47
51
|
transition:
|
|
48
52
|
box-shadow #{$transition-duration} ease,
|
|
49
53
|
border-color #{$transition-duration} ease,
|
|
@@ -59,7 +63,7 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
59
63
|
width: calc(#{$size-control-mark-size} * 0.5);
|
|
60
64
|
height: calc(#{$size-control-mark-size} * 0.5);
|
|
61
65
|
border-radius: 50%;
|
|
62
|
-
background-color:
|
|
66
|
+
background-color: rgba(#{$radio-color-unchecked});
|
|
63
67
|
transform: scale(0);
|
|
64
68
|
transform-origin: center;
|
|
65
69
|
transition:
|
|
@@ -73,12 +77,12 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
73
77
|
&:not(.on) {
|
|
74
78
|
.#{$radio-icon} {
|
|
75
79
|
background-color: transparent;
|
|
76
|
-
border-color:
|
|
80
|
+
border-color: rgba(#{$radio-border-color-unchecked});
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
&:not(.disabled):not(.readonly):hover {
|
|
80
84
|
.#{$radio-icon} {
|
|
81
|
-
border-color:
|
|
85
|
+
border-color: rgba(#{$radio-border-color-hover});
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
}
|
|
@@ -86,22 +90,23 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
86
90
|
&.on {
|
|
87
91
|
&.fill {
|
|
88
92
|
.#{$radio-icon} {
|
|
89
|
-
background-color:
|
|
90
|
-
border-color:
|
|
93
|
+
background-color: rgba(#{$radio-background-color-checked});
|
|
94
|
+
border-color: rgba(#{$radio-border-color-checked});
|
|
91
95
|
|
|
92
96
|
&::after {
|
|
93
97
|
transform: scale(1);
|
|
98
|
+
background-color: rgba(#{$radio-color-checked});
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
&.outline {
|
|
99
104
|
.#{$radio-icon} {
|
|
100
|
-
border-color:
|
|
105
|
+
border-color: rgba(#{$radio-border-color-checked});
|
|
101
106
|
|
|
102
107
|
&::after {
|
|
103
108
|
transform: scale(1);
|
|
104
|
-
background-color:
|
|
109
|
+
background-color: rgba(#{$radio-background-color-checked});
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
}
|
|
@@ -113,8 +118,8 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
113
118
|
|
|
114
119
|
&.on {
|
|
115
120
|
.#{$radio-icon} {
|
|
116
|
-
background-color:
|
|
117
|
-
border-color:
|
|
121
|
+
background-color: rgba(#{$radio-background-color-disabled});
|
|
122
|
+
border-color: rgba(#{$radio-border-color-disabled});
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
}
|
|
@@ -126,12 +131,12 @@ $size-control-mark-size: sass.fn-naming-var("control-mark-size");
|
|
|
126
131
|
&.focus {
|
|
127
132
|
&.shadow {
|
|
128
133
|
.#{$radio-icon} {
|
|
129
|
-
box-shadow: 0 0 0 0.25rem
|
|
134
|
+
box-shadow: 0 0 0 0.25rem rgba(#{$radio-box-shadow-color-focus}, 0.25);
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
|
|
133
138
|
.#{$radio-icon} {
|
|
134
|
-
border-color:
|
|
139
|
+
border-color: rgba(#{$radio-border-color-focus});
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed, inject, ref } from "vue";
|
|
5
5
|
import type { RadioProps } from "./radio.type";
|
|
6
|
-
import {
|
|
6
|
+
import { cssPrefix } 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
|
|
|
@@ -42,10 +42,10 @@ const radioAttrs = computed(() => {
|
|
|
42
42
|
|
|
43
43
|
return {
|
|
44
44
|
class: [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
cssPrefix(["layer", "radio"]),
|
|
46
|
+
cssPrefix(["role", role]),
|
|
47
|
+
cssPrefix(["size", props.size]),
|
|
48
|
+
cssPrefix("radio"),
|
|
49
49
|
variant,
|
|
50
50
|
{
|
|
51
51
|
on: isChecked,
|
|
@@ -59,7 +59,7 @@ const radioAttrs = computed(() => {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
const radioIconAttrs = {
|
|
62
|
-
class: [
|
|
62
|
+
class: [cssPrefix("radio-icon")],
|
|
63
63
|
} as const;
|
|
64
64
|
|
|
65
65
|
// Methods
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed, inject, provide } from "vue";
|
|
5
5
|
import type { RadioGroupProps, RadioGroupEmit, RadioGroupProviderState } from "./radio-group.type";
|
|
6
|
-
import {
|
|
6
|
+
import { cssPrefix } 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
|
|
|
@@ -37,7 +37,7 @@ const shadow = computed(() => {
|
|
|
37
37
|
|
|
38
38
|
const radioGroupAttrs = computed(() => {
|
|
39
39
|
return {
|
|
40
|
-
class: [
|
|
40
|
+
class: [cssPrefix("radio-group"), props.direction],
|
|
41
41
|
};
|
|
42
42
|
});
|
|
43
43
|
|
|
@@ -1,6 +1,3 @@
|
|
|
1
1
|
<div v-bind="containerAttrs" ref="container">
|
|
2
|
-
<div v-bind="refresherIconAttrs" v-show="calculateOffset > 0">
|
|
3
|
-
<slot name="icon" :offset="calculateOffset" :refreshing="refreshing"></slot>
|
|
4
|
-
</div>
|
|
5
2
|
<slot :offset="calculateOffset" :refreshing="refreshing"></slot>
|
|
6
3
|
</div>
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
@use "@toife/sass-layer" as sass;
|
|
2
2
|
|
|
3
3
|
// Class
|
|
4
|
-
$refresher-icon: sass.fn-naming-prefix("refresher-icon");
|
|
5
4
|
$container: sass.fn-naming-prefix("refresher");
|
|
6
5
|
|
|
7
|
-
// Variables
|
|
8
|
-
$safe-area-top: sass.fn-naming-var("safe-area", "top");
|
|
9
|
-
$transition-duration: sass.fn-naming-var("motion", "duration");
|
|
10
|
-
$offset: sass.fn-naming-var("refresher-offset");
|
|
11
|
-
|
|
12
6
|
.#{$container} {
|
|
13
7
|
width: 100%;
|
|
14
8
|
height: 100%;
|
|
@@ -20,23 +14,5 @@ $offset: sass.fn-naming-var("refresher-offset");
|
|
|
20
14
|
right: 0;
|
|
21
15
|
bottom: 0;
|
|
22
16
|
overflow: auto;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Refresher
|
|
26
|
-
.#{$refresher-icon} {
|
|
27
|
-
display: flex;
|
|
28
|
-
justify-content: center;
|
|
29
|
-
align-items: center;
|
|
30
|
-
overflow: hidden;
|
|
31
|
-
transition: height #{$transition-duration} ease;
|
|
32
|
-
position: absolute;
|
|
33
|
-
top: 0;
|
|
34
|
-
left: 50%;
|
|
35
|
-
transform: translateX(-50%);
|
|
36
|
-
line-height: 0;
|
|
37
|
-
z-index: 1;
|
|
38
|
-
|
|
39
|
-
&.moving {
|
|
40
|
-
top: calc(#{$safe-area-top} + #{$offset});
|
|
41
|
-
}
|
|
17
|
+
overscroll-behavior: none;
|
|
42
18
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ref, onUnmounted, watch, computed } from "vue";
|
|
5
5
|
import { gesture } from "@toife/gesture";
|
|
6
6
|
import type { RefresherProps, RefresherEmit } from "./refresher.type";
|
|
7
|
-
import {
|
|
7
|
+
import { cssProperty, cssPrefix } from "../../utils";
|
|
8
8
|
|
|
9
9
|
// Component setup (props, emits, injects)
|
|
10
10
|
// ----------------------------------------------------------------------------
|
|
@@ -29,23 +29,9 @@ const calculateOffset = computed(() => {
|
|
|
29
29
|
return props.offset !== undefined ? props.offset : moveOffset.value / 2;
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
const refresherIconAttrs = computed(() => {
|
|
33
|
-
return {
|
|
34
|
-
style: {
|
|
35
|
-
[property("refresher-offset")]: `${calculateOffset.value}px`,
|
|
36
|
-
},
|
|
37
|
-
class: [
|
|
38
|
-
withPrefix("refresher-icon"),
|
|
39
|
-
{
|
|
40
|
-
moving: calculateOffset.value > 0,
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
|
|
46
32
|
const containerAttrs = computed(() => {
|
|
47
33
|
return {
|
|
48
|
-
class: [
|
|
34
|
+
class: [cssPrefix("refresher")],
|
|
49
35
|
};
|
|
50
36
|
});
|
|
51
37
|
|
|
@@ -50,7 +50,7 @@ $backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
|
|
|
50
50
|
height: 100%;
|
|
51
51
|
top: 0;
|
|
52
52
|
left: 0;
|
|
53
|
-
background-color:
|
|
53
|
+
background-color: rgba(#{$backdrop-background-color});
|
|
54
54
|
opacity: calc(#{$backdrop-opacity} * (#{$backdrop-percent} / 100));
|
|
55
55
|
transition: opacity #{$transition-duration} ease;
|
|
56
56
|
}
|
|
@@ -64,7 +64,7 @@ $backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
|
|
|
64
64
|
top: 0;
|
|
65
65
|
left: 0;
|
|
66
66
|
flex: none;
|
|
67
|
-
background-color:
|
|
67
|
+
background-color: rgba(#{$background-color});
|
|
68
68
|
transform: translate(0, 0);
|
|
69
69
|
transition:
|
|
70
70
|
transform #{$transition-duration} ease,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed, inject, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
|
5
5
|
import { gesture } from "@toife/gesture";
|
|
6
|
-
import {
|
|
6
|
+
import { cssPrefix, cssProperty } from "../../../utils";
|
|
7
7
|
import type {
|
|
8
8
|
RouteNavigatorEmit,
|
|
9
9
|
RouteNavigatorProps,
|
|
@@ -63,26 +63,26 @@ const navigatorAttrs = computed(() => {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
return {
|
|
66
|
-
class: [
|
|
66
|
+
class: [cssPrefix("route-navigator"), props.direction, props.variant],
|
|
67
67
|
style: {
|
|
68
|
-
[
|
|
69
|
-
[
|
|
70
|
-
[
|
|
71
|
-
[
|
|
72
|
-
[
|
|
68
|
+
[cssProperty("route-navigator-transform-back")]: transform.back + "%",
|
|
69
|
+
[cssProperty("route-navigator-transform-prepare")]: transform.prepare + "%",
|
|
70
|
+
[cssProperty("route-navigator-transform-active")]: transform.active + "%",
|
|
71
|
+
[cssProperty("route-navigator-transition-duration")]: duration,
|
|
72
|
+
[cssProperty("route-navigator-backdrop-percent")]: transform.backdrop,
|
|
73
73
|
},
|
|
74
74
|
};
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
const componentAttrs = computed(() => {
|
|
78
78
|
return {
|
|
79
|
-
class: [
|
|
79
|
+
class: [cssPrefix("route-navigator-component"), props.direction],
|
|
80
80
|
};
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
const backdropAttrs = computed(() => {
|
|
84
84
|
return {
|
|
85
|
-
class: [
|
|
85
|
+
class: [cssPrefix("route-navigator-backdrop"), cssPrefix(["layer", "backdrop"])],
|
|
86
86
|
style: {
|
|
87
87
|
zIndex: backdropIndex.value * 2 - 1,
|
|
88
88
|
},
|
|
@@ -158,7 +158,7 @@ const goBack = () => {
|
|
|
158
158
|
if (activeIndex.value <= 0) return;
|
|
159
159
|
const prev = stack.value[activeIndex.value - 1];
|
|
160
160
|
if (!prev) return;
|
|
161
|
-
router.
|
|
161
|
+
router.back();
|
|
162
162
|
};
|
|
163
163
|
|
|
164
164
|
const resetTransform = () => {
|
|
@@ -230,7 +230,6 @@ onMounted(() => {
|
|
|
230
230
|
|
|
231
231
|
fast({ initialDirection, event }: { initialDirection: string; event: Event }) {
|
|
232
232
|
if (initialDirection !== props.direction) return;
|
|
233
|
-
event.preventDefault();
|
|
234
233
|
goBack();
|
|
235
234
|
},
|
|
236
235
|
|
|
@@ -246,7 +245,6 @@ onMounted(() => {
|
|
|
246
245
|
event: Event;
|
|
247
246
|
}) {
|
|
248
247
|
if (initialDirection !== props.direction) return;
|
|
249
|
-
event.preventDefault();
|
|
250
248
|
move({ deltaX, deltaY });
|
|
251
249
|
},
|
|
252
250
|
|
|
@@ -262,7 +260,6 @@ onMounted(() => {
|
|
|
262
260
|
event: Event;
|
|
263
261
|
}) {
|
|
264
262
|
if (initialDirection !== props.direction) return;
|
|
265
|
-
event.preventDefault();
|
|
266
263
|
up({ deltaX, deltaY });
|
|
267
264
|
},
|
|
268
265
|
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { shallowRef } from "vue";
|
|
2
2
|
import { type RouteComponent, type RouteLocationMatched } from "vue-router";
|
|
3
3
|
import { type RouteStack } from "../route.type";
|
|
4
|
-
import { RouteWrapperOption } from "./route-wrapper.type";
|
|
5
4
|
|
|
6
5
|
const stack = shallowRef<RouteStack[]>([]);
|
|
7
6
|
|
|
8
7
|
/** Recursively builds a nested stack from vue-router `matched` for the navigator. */
|
|
9
|
-
const buildTree = (
|
|
10
|
-
matched: RouteLocationMatched[],
|
|
11
|
-
current: RouteStack[],
|
|
12
|
-
option: RouteWrapperOption
|
|
13
|
-
) => {
|
|
8
|
+
const buildTree = (matched: RouteLocationMatched[], current: RouteStack[]) => {
|
|
14
9
|
if (matched.length === 0) return current;
|
|
15
10
|
|
|
16
11
|
// User navigated back: drop the leaf so we merge into the parent segment
|
|
@@ -25,11 +20,7 @@ const buildTree = (
|
|
|
25
20
|
current[current.length - 1].name === matched[0].name
|
|
26
21
|
) {
|
|
27
22
|
matched.shift();
|
|
28
|
-
current[current.length - 1].stack = buildTree(
|
|
29
|
-
matched,
|
|
30
|
-
current[current.length - 1].stack,
|
|
31
|
-
option
|
|
32
|
-
);
|
|
23
|
+
current[current.length - 1].stack = buildTree(matched, current[current.length - 1].stack);
|
|
33
24
|
}
|
|
34
25
|
// Push a new segment (forward navigation)
|
|
35
26
|
else {
|
|
@@ -39,8 +30,7 @@ const buildTree = (
|
|
|
39
30
|
current.push({
|
|
40
31
|
name,
|
|
41
32
|
component,
|
|
42
|
-
|
|
43
|
-
stack: buildTree(matched, [], option),
|
|
33
|
+
stack: buildTree(matched, []),
|
|
44
34
|
});
|
|
45
35
|
}
|
|
46
36
|
|
|
@@ -48,8 +38,8 @@ const buildTree = (
|
|
|
48
38
|
};
|
|
49
39
|
|
|
50
40
|
export const useRouteWrapper = () => {
|
|
51
|
-
const updateRoutes = (matched: RouteLocationMatched[]
|
|
52
|
-
stack.value = buildTree([...matched], [...stack.value]
|
|
41
|
+
const updateRoutes = (matched: RouteLocationMatched[]) => {
|
|
42
|
+
stack.value = buildTree([...matched], [...stack.value]);
|
|
53
43
|
};
|
|
54
44
|
|
|
55
45
|
return {
|
|
@@ -20,9 +20,7 @@ const router = useRouter();
|
|
|
20
20
|
watch(
|
|
21
21
|
() => route.matched,
|
|
22
22
|
() => {
|
|
23
|
-
updateRoutes(route.matched
|
|
24
|
-
fullPath: route.fullPath,
|
|
25
|
-
});
|
|
23
|
+
updateRoutes(route.matched);
|
|
26
24
|
}
|
|
27
25
|
);
|
|
28
26
|
|
|
@@ -31,22 +29,16 @@ onMounted(() => {
|
|
|
31
29
|
const homeName = props.homeRouteName;
|
|
32
30
|
|
|
33
31
|
if (route.name === homeName) {
|
|
34
|
-
updateRoutes(route.matched
|
|
35
|
-
fullPath: route.fullPath,
|
|
36
|
-
});
|
|
32
|
+
updateRoutes(route.matched);
|
|
37
33
|
} else {
|
|
38
34
|
const homeLocation = router.resolve({ name: homeName });
|
|
39
35
|
if (homeLocation.matched.length > 0) {
|
|
40
|
-
updateRoutes(homeLocation.matched
|
|
41
|
-
fullPath: homeLocation.fullPath,
|
|
42
|
-
});
|
|
36
|
+
updateRoutes(homeLocation.matched);
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
// Apply current route to stack
|
|
46
40
|
setTimeout(() => {
|
|
47
|
-
updateRoutes(route.matched
|
|
48
|
-
fullPath: route.fullPath,
|
|
49
|
-
});
|
|
41
|
+
updateRoutes(route.matched);
|
|
50
42
|
}, 50);
|
|
51
43
|
}
|
|
52
44
|
});
|