sykj 0.1.8 → 0.2.0
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 +10 -10
- package/lib/common.ts +33 -12
- package/main/index.ts +1 -1
- package/main/utils/withInstall.ts +10 -0
- package/package.json +67 -53
- package/packages/button/index.ts +5 -0
- package/packages/button/src/index.vue +138 -0
- package/packages/dialog/index.ts +5 -0
- package/packages/dialog/src/index.vue +142 -0
- package/packages/keyboard/index.ts +11 -6
- package/packages/keyboard/src/Keyboardcon.vue +464 -401
- package/packages/keyboard/src/theme.scss +2 -2
- package/packages/keyboard/src/utils/focus.ts +34 -0
- package/packages/keyboard/src/utils/store.ts +19 -0
- package/packages/loading/index.ts +5 -12
- package/packages/loading/{Loading1.vue → src/Loading1.vue} +2 -2
- package/packages/loading/{Loading2.vue → src/Loading2.vue} +6 -6
- package/packages/loading/src/index.vue +38 -0
- package/packages/message/index.ts +128 -0
- package/packages/message/src/index.vue +177 -0
- package/packages/message-box/index.ts +59 -0
- package/packages/message-box/src/assets/error.png +0 -0
- package/packages/message-box/src/assets/error.svg +3 -0
- package/packages/message-box/src/assets/tip.png +0 -0
- package/packages/message-box/src/assets/tip.svg +3 -0
- package/packages/message-box/src/assets/warning.png +0 -0
- package/packages/message-box/src/assets/warning.svg +3 -0
- package/packages/message-box/src/index.vue +195 -0
- package/types/component.d.ts +9 -3
- package/types/global.d.ts +3 -3
- package/types/index.d.ts +1 -1
- package/lib/focus.ts +0 -40
- package/lib/store.ts +0 -5
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<teleport to="body">
|
|
3
|
+
<!-- 单一外层 transition:mask + box 同步动画,使用 appear 支持首次入场 -->
|
|
4
|
+
<transition name="sy-fade" appear @after-leave="onAfterLeave">
|
|
5
|
+
<div v-if="visible" class="sy-mask" role="dialog" aria-modal="true">
|
|
6
|
+
<div class="sy-box">
|
|
7
|
+
<div class="sy-header" v-if="title">
|
|
8
|
+
<div class="icon">
|
|
9
|
+
<img
|
|
10
|
+
v-if="props.icon"
|
|
11
|
+
:src="getIcons(props.icon)"
|
|
12
|
+
:alt="props.icon"
|
|
13
|
+
/>
|
|
14
|
+
</div>
|
|
15
|
+
{{ title }}
|
|
16
|
+
</div>
|
|
17
|
+
<div class="sy-content">
|
|
18
|
+
<div
|
|
19
|
+
v-if="message"
|
|
20
|
+
class="sy-message"
|
|
21
|
+
v-html="message"
|
|
22
|
+
></div>
|
|
23
|
+
<input
|
|
24
|
+
v-if="type === 'prompt'"
|
|
25
|
+
v-model="inputValue"
|
|
26
|
+
class="sy-input"
|
|
27
|
+
:placeholder="inputPlaceholder"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="sy-footer">
|
|
31
|
+
<!-- <button
|
|
32
|
+
v-if="type !== 'alert'"
|
|
33
|
+
class="sy-btn sy-btn--cancel"
|
|
34
|
+
@click="onCancel"
|
|
35
|
+
>
|
|
36
|
+
{{ cancelText }}
|
|
37
|
+
</button> -->
|
|
38
|
+
<sy-button
|
|
39
|
+
v-if="type !== 'alert'"
|
|
40
|
+
@click="onCancel"
|
|
41
|
+
type="info"
|
|
42
|
+
>
|
|
43
|
+
{{ cancelText }}
|
|
44
|
+
</sy-button>
|
|
45
|
+
<sy-button type="primary" @click="onConfirm">
|
|
46
|
+
{{ confirmText }}
|
|
47
|
+
</sy-button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</transition>
|
|
52
|
+
</teleport>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
import { ref } from 'vue'
|
|
57
|
+
import { SyButton } from '../../button/index'
|
|
58
|
+
|
|
59
|
+
interface Props {
|
|
60
|
+
type?: 'alert' | 'confirm' | 'prompt'
|
|
61
|
+
title?: string
|
|
62
|
+
message?: string
|
|
63
|
+
confirmText?: string
|
|
64
|
+
cancelText?: string
|
|
65
|
+
inputPlaceholder?: string
|
|
66
|
+
inputValue?: string
|
|
67
|
+
icon?: 'tip' | 'warning' | 'error'
|
|
68
|
+
}
|
|
69
|
+
const props = defineProps<Props>()
|
|
70
|
+
const emit = defineEmits(['requestClose', 'closed'])
|
|
71
|
+
|
|
72
|
+
const visible = ref(true)
|
|
73
|
+
const inputValue = ref(props.inputValue || '')
|
|
74
|
+
const closeResult = ref<{ type: 'confirm' | 'cancel'; value?: any } | null>(
|
|
75
|
+
null
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
const confirmText = props.confirmText || '确定'
|
|
79
|
+
const cancelText = props.cancelText || '取消'
|
|
80
|
+
|
|
81
|
+
function onConfirm() {
|
|
82
|
+
closeResult.value = { type: 'confirm', value: inputValue.value ?? true }
|
|
83
|
+
visible.value = false
|
|
84
|
+
emit('requestClose', closeResult.value) // optional: notify service
|
|
85
|
+
}
|
|
86
|
+
function onCancel() {
|
|
87
|
+
closeResult.value = { type: 'cancel' }
|
|
88
|
+
visible.value = false
|
|
89
|
+
emit('requestClose', closeResult.value)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 当 leave 完成(动画播完)时触发
|
|
93
|
+
function onAfterLeave() {
|
|
94
|
+
emit('closed', closeResult.value)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getIcons(icon: string) {
|
|
98
|
+
return new URL(`./assets/${icon}.png`, import.meta.url).href
|
|
99
|
+
}
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<style scoped lang="scss">
|
|
103
|
+
/* 遮罩 */
|
|
104
|
+
.sy-mask {
|
|
105
|
+
position: fixed;
|
|
106
|
+
inset: 0;
|
|
107
|
+
background: rgba(0, 0, 0, 0.45);
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
z-index: 2000;
|
|
112
|
+
color: black;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* 弹窗主体 */
|
|
116
|
+
.sy-box {
|
|
117
|
+
min-width: 60%;
|
|
118
|
+
max-width: 80%;
|
|
119
|
+
background: #fff;
|
|
120
|
+
border-radius: 8px;
|
|
121
|
+
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
|
|
122
|
+
padding: 30px 20px;
|
|
123
|
+
}
|
|
124
|
+
.sy-header {
|
|
125
|
+
font-weight: 600;
|
|
126
|
+
margin-bottom: 8px;
|
|
127
|
+
/* font-size: 16px; */
|
|
128
|
+
font-size: 1.6rem;
|
|
129
|
+
text-align: center;
|
|
130
|
+
letter-spacing: 0.4rem;
|
|
131
|
+
|
|
132
|
+
.icon {
|
|
133
|
+
// border: 1px solid red;
|
|
134
|
+
// height: 60px;
|
|
135
|
+
// padding: 10px;
|
|
136
|
+
display: flex;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
align-items: center;
|
|
139
|
+
|
|
140
|
+
padding-bottom: 20px;
|
|
141
|
+
img {
|
|
142
|
+
// width: 60px;
|
|
143
|
+
height: 60px;
|
|
144
|
+
object-fit: contain;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
.sy-content {
|
|
149
|
+
margin-bottom: 14px;
|
|
150
|
+
text-align: center;
|
|
151
|
+
font-size: 1.2rem;
|
|
152
|
+
opacity: 0.8;
|
|
153
|
+
padding: 10px 0;
|
|
154
|
+
}
|
|
155
|
+
.sy-message {
|
|
156
|
+
margin-bottom: 8px;
|
|
157
|
+
color: #333;
|
|
158
|
+
}
|
|
159
|
+
.sy-input {
|
|
160
|
+
width: 100%;
|
|
161
|
+
padding: 6px 10px;
|
|
162
|
+
border: 1px solid #ddd;
|
|
163
|
+
border-radius: 6px;
|
|
164
|
+
}
|
|
165
|
+
input::placeholder {
|
|
166
|
+
color: #00000090;
|
|
167
|
+
}
|
|
168
|
+
.sy-footer {
|
|
169
|
+
display: flex;
|
|
170
|
+
justify-content: center;
|
|
171
|
+
gap: 28px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* --- transition (外层 transition 控制遮罩,同时通过后代选择器让 box 做缩放) --- */
|
|
175
|
+
/* mask 的透明度动画 */
|
|
176
|
+
.sy-fade-enter-from,
|
|
177
|
+
.sy-fade-leave-to {
|
|
178
|
+
opacity: 0;
|
|
179
|
+
}
|
|
180
|
+
.sy-fade-enter-active,
|
|
181
|
+
.sy-fade-leave-active {
|
|
182
|
+
transition: opacity 250ms ease;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* 同步为内层 sy-box 添加缩放效果(通过选择器在 transition 的不同阶段作用到子元素) */
|
|
186
|
+
.sy-fade-enter-from .sy-box,
|
|
187
|
+
.sy-fade-leave-to .sy-box {
|
|
188
|
+
transform: scale(0.92);
|
|
189
|
+
opacity: 0;
|
|
190
|
+
}
|
|
191
|
+
.sy-fade-enter-active .sy-box,
|
|
192
|
+
.sy-fade-leave-active .sy-box {
|
|
193
|
+
transition: all 250ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
194
|
+
}
|
|
195
|
+
</style>
|
package/types/component.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { App } from 'vue'
|
|
2
|
+
|
|
3
|
+
declare module '*.vue' {
|
|
4
|
+
import type { DefineComponent } from 'vue'
|
|
5
|
+
const component: DefineComponent<{}, {}, any>
|
|
6
|
+
export default component
|
|
7
|
+
}
|
|
2
8
|
|
|
3
9
|
/** ElementUI component common definition */
|
|
4
|
-
export declare class ElementUIComponent
|
|
10
|
+
export declare class ElementUIComponent {
|
|
5
11
|
/** Install component into Vue */
|
|
6
|
-
static install(
|
|
12
|
+
static install(app: App): void
|
|
7
13
|
}
|
package/types/global.d.ts
CHANGED
package/types/index.d.ts
CHANGED
package/lib/focus.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// import { useKeyStore } from "./store";
|
|
2
|
-
// console.log("🚀 ~ file: focus.ts:3 ~ useKeyStore:", useKeyStore)
|
|
3
|
-
const globalKey = window.$sy.key;
|
|
4
|
-
// const keyStore = useKeyStore()
|
|
5
|
-
|
|
6
|
-
let st: any = null;
|
|
7
|
-
|
|
8
|
-
document.addEventListener("focusin", (event) => {
|
|
9
|
-
const target = event.target as HTMLElement;
|
|
10
|
-
if (target?.tagName === "INPUT" || target?.tagName === "TEXTAREA") {
|
|
11
|
-
if (!isEditableFormComponent(target)) return;
|
|
12
|
-
clearTimeout(st);
|
|
13
|
-
globalKey.open();
|
|
14
|
-
globalKey.currentElement = event.target;
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
document.addEventListener("focusout", (event) => {
|
|
19
|
-
globalKey.close();
|
|
20
|
-
|
|
21
|
-
// st = setTimeout(() => {
|
|
22
|
-
// // globalKey.currentElement = null;
|
|
23
|
-
// }, 100);
|
|
24
|
-
// const target = event.target as HTMLElement;
|
|
25
|
-
// if (target?.tagName === "INPUT" || target?.tagName === "TEXTAREA") {
|
|
26
|
-
// // window.showKeyboard()
|
|
27
|
-
// //
|
|
28
|
-
// }
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// 是否展示输入法
|
|
32
|
-
const isEditableFormComponent = (el: HTMLElement): boolean => {
|
|
33
|
-
const notType: Array<string> = ["checkbox", "radio"];
|
|
34
|
-
if (!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement))
|
|
35
|
-
return false; // 类型守卫
|
|
36
|
-
if (el.readOnly || notType.includes(el.type)) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
return true;
|
|
40
|
-
};
|