@toife/vue 3.1.4 → 3.1.6
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 +4 -4
- package/src/components/action/action.scss +2 -2
- package/src/components/action/action.vue +5 -5
- package/src/components/app/app.scss +3 -3
- package/src/components/app/app.type.ts +0 -6
- package/src/components/app/app.vue +2 -8
- package/src/components/avatar/avatar.scss +4 -3
- package/src/components/avatar/avatar.vue +6 -6
- package/src/components/button/button.scss +29 -21
- package/src/components/button/button.type.ts +2 -4
- package/src/components/button/button.vue +7 -7
- package/src/components/cable/cable.vue +2 -2
- package/src/components/card/card/card.scss +3 -3
- package/src/components/card/card/card.vue +5 -5
- package/src/components/card/card-body/card-body.scss +3 -3
- package/src/components/card/card-body/card-body.vue +2 -2
- package/src/components/card/card-footer/card-footer.scss +4 -4
- package/src/components/card/card-footer/card-footer.vue +2 -2
- package/src/components/card/card-header/card-header.scss +4 -4
- 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 +19 -14
- package/src/components/checkbox/checkbox.type.ts +1 -3
- package/src/components/checkbox/checkbox.vue +7 -7
- package/src/components/collapse/collapse.html +1 -1
- package/src/components/collapse/collapse.scss +4 -7
- package/src/components/collapse/collapse.vue +9 -9
- package/src/components/container/container.vue +2 -2
- package/src/components/decision-modal/decision-modal.scss +11 -11
- package/src/components/decision-modal/decision-modal.vue +8 -8
- package/src/components/divider/divider.scss +3 -3
- package/src/components/divider/divider.vue +4 -4
- package/src/components/dropdown/dropdown.scss +4 -4
- package/src/components/dropdown/dropdown.type.ts +2 -2
- package/src/components/dropdown/dropdown.vue +7 -9
- package/src/components/field/field.html +28 -9
- package/src/components/field/{outline/outline.scss → field.scss} +29 -125
- package/src/components/field/field.type.ts +4 -4
- package/src/components/field/field.vue +83 -46
- package/src/components/field/index.ts +1 -1
- package/src/components/form-group/form-group.vue +2 -2
- package/src/components/gesture-indicator/gesture-indicator.scss +2 -2
- 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 +2 -2
- package/src/components/modal/modal.vue +68 -5
- package/src/components/page/page.vue +2 -2
- package/src/components/present/present.scss +4 -4
- package/src/components/present/present.vue +14 -14
- package/src/components/radio/radio/radio.html +1 -1
- package/src/components/radio/radio/radio.scss +19 -14
- package/src/components/radio/radio/radio.type.ts +1 -3
- 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.html +1 -1
- package/src/components/route/route-navigator/route-navigator.scss +3 -3
- package/src/components/route/route-navigator/route-navigator.vue +11 -14
- 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 +3 -3
- package/src/components/segmented-field/segmented-field.vue +8 -8
- package/src/components/select/select.html +2 -2
- package/src/components/select/select.scss +11 -11
- package/src/components/select/select.vue +10 -10
- package/src/components/skeleton/skeleton.scss +1 -1
- 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 +17 -14
- package/src/components/slide-range/slide-range.vue +17 -16
- package/src/components/switch/switch.html +1 -1
- package/src/components/switch/switch.scss +23 -21
- package/src/components/switch/switch.type.ts +2 -3
- 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 +82 -54
- package/src/components/tabs/tabs/tabs.type.ts +4 -1
- package/src/components/tabs/tabs/tabs.vue +47 -23
- package/src/components/toast/toast/toast.scss +1 -1
- package/src/components/toast/toast/toast.vue +2 -2
- package/src/components/toast/toast-content/toast-content.scss +4 -4
- package/src/components/toast/toast-content/toast-content.vue +5 -5
- package/src/components/toolbar/toolbar.scss +4 -4
- 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
- package/src/components/field/outline/index.ts +0 -1
- package/src/components/field/outline/outline.html +0 -36
- package/src/components/field/outline/outline.vue +0 -286
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { AppDirection
|
|
1
|
+
import type { AppDirection } from "../app";
|
|
2
2
|
|
|
3
3
|
export type FieldVariant = "outline" | "fill" | "underline";
|
|
4
|
-
export type FieldSize =
|
|
4
|
+
export type FieldSize = string;
|
|
5
5
|
export type FieldType = "text" | "number" | "email" | "password" | "tel" | "url" | "paragraph";
|
|
6
6
|
|
|
7
7
|
// Type definitions
|
|
8
8
|
export type FieldProps = {
|
|
9
9
|
// Wrapper
|
|
10
|
-
modelValue?: string;
|
|
10
|
+
modelValue?: string | number;
|
|
11
11
|
name?: string;
|
|
12
12
|
variant?: FieldVariant;
|
|
13
13
|
role?: string;
|
|
@@ -18,7 +18,7 @@ export type FieldProps = {
|
|
|
18
18
|
|
|
19
19
|
// Input
|
|
20
20
|
id?: string;
|
|
21
|
-
value?: string;
|
|
21
|
+
value?: string | number;
|
|
22
22
|
placeholder?: string;
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
readonly?: boolean;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
<style lang="scss" src="./field.scss" scoped></style>
|
|
1
2
|
<template src="./field.html"></template>
|
|
2
3
|
<script lang="ts" setup>
|
|
3
|
-
import { computed, inject } from "vue";
|
|
4
|
-
import type { FieldProps } from "./field.type";
|
|
5
|
-
import
|
|
6
|
-
import { OutlineField } from "./outline";
|
|
4
|
+
import { computed, inject, nextTick, onMounted, ref, watch } from "vue";
|
|
5
|
+
import type { FieldProps, FieldEmit } from "./field.type";
|
|
6
|
+
import { cssProperty, cssPrefix } from "../../utils";
|
|
7
7
|
import { type AppProviderState, APP_PROVIDER_STATE_KEY } from "../app";
|
|
8
8
|
|
|
9
9
|
// Component setup (props, emits, injects)
|
|
@@ -12,6 +12,8 @@ const props = withDefaults(defineProps<FieldProps>(), {
|
|
|
12
12
|
modelValue: "",
|
|
13
13
|
type: "text",
|
|
14
14
|
size: "standard",
|
|
15
|
+
role: undefined,
|
|
16
|
+
shape: undefined,
|
|
15
17
|
disabled: false,
|
|
16
18
|
readonly: false,
|
|
17
19
|
message: "",
|
|
@@ -21,66 +23,101 @@ const props = withDefaults(defineProps<FieldProps>(), {
|
|
|
21
23
|
shadow: undefined,
|
|
22
24
|
direction: undefined,
|
|
23
25
|
line: 1,
|
|
26
|
+
maxLine: 1,
|
|
24
27
|
});
|
|
25
28
|
const emit = defineEmits<FieldEmit>();
|
|
26
29
|
const appState = inject<AppProviderState>(APP_PROVIDER_STATE_KEY);
|
|
27
30
|
|
|
31
|
+
// Reactive state
|
|
32
|
+
// ----------------------------------------------------------------------------
|
|
33
|
+
const isFocus = ref(false);
|
|
34
|
+
const caret = ref(0);
|
|
35
|
+
const content = ref("");
|
|
36
|
+
|
|
28
37
|
// Computed properties
|
|
29
38
|
// ----------------------------------------------------------------------------
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
const fieldAttrs = computed(() => {
|
|
40
|
+
const role = props.role || appState?.role?.value || "";
|
|
41
|
+
const shape = props.shape || appState?.shape?.value || "";
|
|
42
|
+
const shadow = (props?.shadow !== undefined ? props.shadow : appState?.shadow?.value) ?? false;
|
|
43
|
+
const direction = props.direction || appState?.direction?.value || "left";
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
return {
|
|
46
|
+
class: [
|
|
47
|
+
cssPrefix(["layer", "field"]),
|
|
48
|
+
cssPrefix(["role", role]),
|
|
49
|
+
cssPrefix(["shape", shape]),
|
|
50
|
+
cssPrefix("field"),
|
|
51
|
+
cssPrefix(["size", props.size]),
|
|
52
|
+
cssPrefix(["direction", direction]),
|
|
53
|
+
props.variant,
|
|
54
|
+
props.type,
|
|
55
|
+
{
|
|
56
|
+
disabled: props.disabled,
|
|
57
|
+
focus: isFocus.value,
|
|
58
|
+
shadow,
|
|
59
|
+
readonly: props.readonly,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
style: {
|
|
63
|
+
[cssProperty(["field", "line"])]: props.line,
|
|
64
|
+
[cssProperty(["field", "max-line"])]: props.maxLine || props.line,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
36
67
|
});
|
|
37
68
|
|
|
38
|
-
const
|
|
39
|
-
return
|
|
69
|
+
const rawContent = computed(() => {
|
|
70
|
+
return props.modelValue ?? props.value ?? "";
|
|
40
71
|
});
|
|
41
72
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
});
|
|
73
|
+
const fieldContentAttrs = computed(() => ({
|
|
74
|
+
class: [cssPrefix("field-content")],
|
|
75
|
+
}));
|
|
45
76
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
77
|
+
const fieldInputAttrs = computed(() => ({
|
|
78
|
+
class: [cssPrefix("field-input")],
|
|
79
|
+
name: props.name,
|
|
80
|
+
id: props.id,
|
|
81
|
+
placeholder: props.placeholder,
|
|
82
|
+
autocomplete: props.autocomplete,
|
|
83
|
+
type: props.type,
|
|
84
|
+
readonly: props.readonly,
|
|
85
|
+
disabled: props.disabled,
|
|
86
|
+
}));
|
|
87
|
+
|
|
88
|
+
const fieldMessageAttrs = computed(() => ({
|
|
89
|
+
class: [cssPrefix("field-message")],
|
|
90
|
+
}));
|
|
91
|
+
|
|
92
|
+
const fieldHelpAttrs = computed(() => ({
|
|
93
|
+
class: [cssPrefix("field-help")],
|
|
94
|
+
}));
|
|
59
95
|
|
|
60
96
|
// Methods
|
|
61
97
|
// ----------------------------------------------------------------------------
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
raw = (event.target as HTMLElement).innerText;
|
|
67
|
-
} else {
|
|
68
|
-
raw = (event.target as HTMLInputElement).value;
|
|
69
|
-
}
|
|
70
|
-
const value = raw.trim() === "" ? "" : raw;
|
|
71
|
-
emit("update:modelValue", value as string);
|
|
72
|
-
emit("input", event);
|
|
98
|
+
const onFocus = (ev: FocusEvent) => {
|
|
99
|
+
if (props.disabled) return;
|
|
100
|
+
isFocus.value = true;
|
|
101
|
+
emit("focus", ev);
|
|
73
102
|
};
|
|
74
103
|
|
|
75
|
-
const
|
|
76
|
-
|
|
104
|
+
const onBlur = (ev: FocusEvent) => {
|
|
105
|
+
if (props.disabled) return;
|
|
106
|
+
isFocus.value = false;
|
|
107
|
+
emit("blur", ev);
|
|
77
108
|
};
|
|
78
109
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
110
|
+
watch(
|
|
111
|
+
() => rawContent.value,
|
|
112
|
+
(value) => {
|
|
113
|
+
content.value = value.toString();
|
|
114
|
+
}
|
|
115
|
+
);
|
|
82
116
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
117
|
+
watch(
|
|
118
|
+
() => content.value,
|
|
119
|
+
(value) => {
|
|
120
|
+
emit("update:modelValue", value.toString());
|
|
121
|
+
}
|
|
122
|
+
);
|
|
86
123
|
</script>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as Field } from "./field.vue";
|
|
2
|
-
export
|
|
2
|
+
export * from "./field.type";
|
|
@@ -1,7 +1,7 @@
|
|
|
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 {
|
|
4
|
+
import { cssPrefix } from "../../utils";
|
|
5
5
|
import { computed } from "vue";
|
|
6
6
|
import { type FormGroupProps } from "./form-group.type";
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ const props = withDefaults(defineProps<FormGroupProps>(), {
|
|
|
15
15
|
// ----------------------------------------------------------------------------
|
|
16
16
|
const formGroupAttrs = computed(() => {
|
|
17
17
|
return {
|
|
18
|
-
class: [
|
|
18
|
+
class: [cssPrefix("form-group"), props.direction],
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
</script>
|
|
@@ -7,10 +7,10 @@ $gesture-indicator: sass.fn-naming-prefix("gesture-indicator");
|
|
|
7
7
|
$gesture-indicator-border-color: sass.fn-naming-var("gesture-indicator", "border-color");
|
|
8
8
|
$radius-ratio: sass.fn-naming-var("radius-ratio");
|
|
9
9
|
$radius-size: sass.fn-naming-var("radius-size");
|
|
10
|
-
$transition-duration: sass.fn-naming-var("
|
|
10
|
+
$transition-duration: sass.fn-naming-var("duration");
|
|
11
11
|
|
|
12
12
|
.#{$gesture-indicator} {
|
|
13
|
-
background-color:
|
|
13
|
+
background-color: rgba(#{$gesture-indicator-border-color});
|
|
14
14
|
transition:
|
|
15
15
|
box-shadow #{$transition-duration} ease,
|
|
16
16
|
border-color #{$transition-duration} ease,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<style lang="scss" src="./gesture-indicator.scss" scoped></style>
|
|
2
2
|
<template src="./gesture-indicator.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
|
-
import {
|
|
4
|
+
import { cssPrefix } from "../../utils";
|
|
5
5
|
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";
|
|
@@ -21,9 +21,9 @@ const gestureIndicatorAttrs = computed(() => {
|
|
|
21
21
|
|
|
22
22
|
return {
|
|
23
23
|
class: [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
cssPrefix(["layer", "gesture-indicator"]),
|
|
25
|
+
cssPrefix(["role", role]),
|
|
26
|
+
cssPrefix("gesture-indicator"),
|
|
27
27
|
props.placement,
|
|
28
28
|
],
|
|
29
29
|
};
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
<template src="./image.html"></template>
|
|
2
2
|
<script setup lang="ts">
|
|
3
|
-
import { ref } from "vue";
|
|
3
|
+
import { ref, watch } from "vue";
|
|
4
4
|
import { type ImageProps } from "./image.type";
|
|
5
5
|
|
|
6
6
|
// Component setup (props, emits, injects)
|
|
7
7
|
// ----------------------------------------------------------------------------
|
|
8
|
-
const
|
|
8
|
+
const props = defineProps<ImageProps>();
|
|
9
9
|
|
|
10
10
|
// Reactive state
|
|
11
11
|
// ----------------------------------------------------------------------------
|
|
12
12
|
// Initialize from src to avoid an empty src flash before mount
|
|
13
|
-
const dataSrc = ref<string>(src ?? "");
|
|
13
|
+
const dataSrc = ref<string>(props.src ?? "");
|
|
14
14
|
|
|
15
15
|
// Methods
|
|
16
16
|
// ----------------------------------------------------------------------------
|
|
17
17
|
const handleError = () => {
|
|
18
|
-
if (defaultSrc) {
|
|
19
|
-
dataSrc.value = defaultSrc;
|
|
18
|
+
if (props.defaultSrc) {
|
|
19
|
+
dataSrc.value = props.defaultSrc;
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
+
|
|
23
|
+
watch(
|
|
24
|
+
() => props.src,
|
|
25
|
+
(newVal) => {
|
|
26
|
+
dataSrc.value = newVal ?? "";
|
|
27
|
+
}
|
|
28
|
+
);
|
|
22
29
|
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<template src="./flex.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed } from "vue";
|
|
5
|
-
import {
|
|
5
|
+
import { cssPrefix, cssProperty } from "../../../utils";
|
|
6
6
|
import type { FlexProps } from "./flex.type";
|
|
7
7
|
|
|
8
8
|
// Component setup (props, emits, injects)
|
|
@@ -16,18 +16,18 @@ const props = withDefaults(defineProps<FlexProps>(), {
|
|
|
16
16
|
const flexAttrs = computed(() => {
|
|
17
17
|
const style = props.options.map((option) => {
|
|
18
18
|
return {
|
|
19
|
-
[
|
|
19
|
+
[cssProperty(["flex", "gap", option?.breakpoint || ""])]:
|
|
20
20
|
typeof option.gap === "number" ? `${option.gap}px` : option.gap,
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
[
|
|
25
|
-
[
|
|
21
|
+
[cssProperty(["flex", "direction", option?.breakpoint || ""])]: option.direction,
|
|
22
|
+
[cssProperty(["flex", "wrap", option?.breakpoint || ""])]: option.wrap,
|
|
23
|
+
[cssProperty(["flex", "justify", option?.breakpoint || ""])]: option.justify,
|
|
24
|
+
[cssProperty(["flex", "align", option?.breakpoint || ""])]: option.align,
|
|
25
|
+
[cssProperty(["flex", "align-content", option?.breakpoint || ""])]: option.alignContent,
|
|
26
26
|
};
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
return {
|
|
30
|
-
class: [
|
|
30
|
+
class: [cssPrefix("flex")],
|
|
31
31
|
style,
|
|
32
32
|
};
|
|
33
33
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<template src="./flex-item.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed } from "vue";
|
|
5
|
-
import {
|
|
5
|
+
import { cssPrefix, cssProperty } from "../../../utils";
|
|
6
6
|
import type { FlexItemProps } from "./flex-item.type";
|
|
7
7
|
|
|
8
8
|
const props = withDefaults(defineProps<FlexItemProps>(), {
|
|
@@ -12,15 +12,15 @@ const props = withDefaults(defineProps<FlexItemProps>(), {
|
|
|
12
12
|
const flexItemAttrs = computed(() => {
|
|
13
13
|
const style = props.options.map((option) => {
|
|
14
14
|
return {
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
15
|
+
[cssProperty(["flex-item", "grow", option?.breakpoint || ""])]: option.grow,
|
|
16
|
+
[cssProperty(["flex-item", "shrink", option?.breakpoint || ""])]: option.shrink,
|
|
17
|
+
[cssProperty(["flex-item", "basis", option?.breakpoint || ""])]: option.basis,
|
|
18
|
+
[cssProperty(["flex-item", "order", option?.breakpoint || ""])]: option.order,
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
return {
|
|
23
|
-
class: [
|
|
23
|
+
class: [cssPrefix("flex-item")],
|
|
24
24
|
style,
|
|
25
25
|
};
|
|
26
26
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<template src="./grid.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed } from "vue";
|
|
5
|
-
import {
|
|
5
|
+
import { cssPrefix, cssProperty } from "../../../utils";
|
|
6
6
|
import type { GridProps } from "./grid.type";
|
|
7
7
|
|
|
8
8
|
// Component setup (props, emits, injects)
|
|
@@ -16,16 +16,16 @@ const props = withDefaults(defineProps<GridProps>(), {
|
|
|
16
16
|
const gridAttrs = computed(() => {
|
|
17
17
|
const style = props.options.map((option) => {
|
|
18
18
|
return {
|
|
19
|
-
[
|
|
19
|
+
[cssProperty(["grid", "gap", option?.breakpoint || ""])]:
|
|
20
20
|
typeof option.gap === "number" ? `${option.gap}px` : option.gap,
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
21
|
+
[cssProperty(["grid", "columns", option?.breakpoint || ""])]: option.columns,
|
|
22
|
+
[cssProperty(["grid", "rows", option?.breakpoint || ""])]: option.rows,
|
|
23
|
+
[cssProperty(["grid", "auto-flow", option?.breakpoint || ""])]: option.autoFlow,
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
return {
|
|
28
|
-
class: [
|
|
28
|
+
class: [cssPrefix("grid")],
|
|
29
29
|
style,
|
|
30
30
|
};
|
|
31
31
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<template src="./grid-item.html"></template>
|
|
3
3
|
<script lang="ts" setup>
|
|
4
4
|
import { computed } from "vue";
|
|
5
|
-
import {
|
|
5
|
+
import { cssPrefix, cssProperty } from "../../../utils";
|
|
6
6
|
import type { GridItemProps } from "./grid-item.type";
|
|
7
7
|
|
|
8
8
|
const props = withDefaults(defineProps<GridItemProps>(), {
|
|
@@ -12,15 +12,15 @@ const props = withDefaults(defineProps<GridItemProps>(), {
|
|
|
12
12
|
const gridItemAttrs = computed(() => {
|
|
13
13
|
const style = props.options.map((option) => {
|
|
14
14
|
return {
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
15
|
+
[cssProperty(["grid-item", "row", option?.breakpoint || ""])]: option.row,
|
|
16
|
+
[cssProperty(["grid-item", "column", option?.breakpoint || ""])]: option.column,
|
|
17
|
+
[cssProperty(["grid-item", "justify", option?.breakpoint || ""])]: option.justify,
|
|
18
|
+
[cssProperty(["grid-item", "align", option?.breakpoint || ""])]: option.align,
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
return {
|
|
23
|
-
class: [
|
|
23
|
+
class: [cssPrefix("grid-item")],
|
|
24
24
|
style,
|
|
25
25
|
};
|
|
26
26
|
});
|
|
@@ -15,11 +15,11 @@ $safe-area-top: sass.fn-naming-var("safe-area", "top");
|
|
|
15
15
|
$safe-area-bottom: sass.fn-naming-var("safe-area", "bottom");
|
|
16
16
|
$safe-area-left: sass.fn-naming-var("safe-area", "left");
|
|
17
17
|
$safe-area-right: sass.fn-naming-var("safe-area", "right");
|
|
18
|
-
$transition-duration: sass.fn-naming-var("
|
|
18
|
+
$transition-duration: sass.fn-naming-var("duration");
|
|
19
19
|
$border-radius: calc(min(#{$viewport-width}, #{$radius-size}) * #{$radius-ratio});
|
|
20
20
|
|
|
21
21
|
.#{$modal} {
|
|
22
|
-
background:
|
|
22
|
+
background: rgba(#{$modal-background-color});
|
|
23
23
|
transition:
|
|
24
24
|
box-shadow #{$transition-duration} ease,
|
|
25
25
|
border-color #{$transition-duration} ease,
|
|
@@ -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>
|
|
@@ -7,7 +7,7 @@ $backdrop: sass.fn-naming-prefix("present-backdrop");
|
|
|
7
7
|
// Property name
|
|
8
8
|
$transition-duration: sass.fn-naming-dvar(
|
|
9
9
|
("transition", "duration"),
|
|
10
|
-
sass.fn-naming-var("
|
|
10
|
+
sass.fn-naming-var("duration")
|
|
11
11
|
);
|
|
12
12
|
|
|
13
13
|
$backdrop-background-color: sass.fn-naming-var("backdrop", "background-color");
|
|
@@ -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 as number | 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,
|