@ithinkdt/ui 4.0.0-19 → 4.0.0-200
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/auto-imports.js +1 -1
- package/dist/components-BoVUU6GJ.js +1736 -0
- package/dist/components.js +5 -0
- package/dist/directives-DUuJW647.js +183 -0
- package/dist/directives.js +3 -0
- package/dist/index.js +1224 -0
- package/dist/page.js +519 -0
- package/dist/use-i18n-Dx7V4KrY.js +6 -0
- package/dist/use-style-DcT-1dj4.js +29 -0
- package/dist/use-style.js +2 -0
- package/{src → esm}/components.d.ts +63 -17
- package/esm/components.js +1 -0
- package/{src → esm}/design.d.ts +9 -0
- package/esm/directives.js +1 -0
- package/esm/index.js +1 -0
- package/{src → esm}/page.d.ts +43 -26
- package/esm/page.js +1 -0
- package/esm/use-style.js +1 -0
- package/locale.d.ts +4 -0
- package/package.json +31 -28
- package/unocss-preset.d.ts +5 -0
- package/unocss-preset.js +163 -0
- package/src/components/Checkboxes.jsx +0 -130
- package/src/components/DataActions.jsx +0 -105
- package/src/components/DataCustom.jsx +0 -172
- package/src/components/DataFilter.jsx +0 -113
- package/src/components/DataForm.jsx +0 -264
- package/src/components/DataLocaleInput.jsx +0 -121
- package/src/components/DataPagination.jsx +0 -62
- package/src/components/DataSelection.jsx +0 -57
- package/src/components/DataTable.jsx +0 -255
- package/src/components/Radios.jsx +0 -134
- package/src/components/UserDept.jsx +0 -643
- package/src/components/assets.jsx +0 -274
- package/src/components/index.js +0 -11
- package/src/design/Account.jsx +0 -152
- package/src/design/Appearance.jsx +0 -89
- package/src/design/Breadcrumb.jsx +0 -67
- package/src/design/Fullscreen.jsx +0 -65
- package/src/design/Language.jsx +0 -45
- package/src/design/Layout.jsx +0 -241
- package/src/design/Logo.jsx +0 -92
- package/src/design/Menu.jsx +0 -133
- package/src/design/MultiTabs.jsx +0 -501
- package/src/design/Notification.jsx +0 -311
- package/src/design/common.jsx +0 -21
- package/src/design/index.js +0 -10
- package/src/directives/index.js +0 -2
- package/src/directives/spin.js +0 -181
- package/src/directives/tooltip.jsx +0 -121
- package/src/index.js +0 -18
- package/src/page.jsx +0 -628
- package/src/use-i18n.js +0 -8
- package/src/use-style.js +0 -58
- package/src/utils.js +0 -20
- package/unocss.d.ts +0 -5
- package/unocss.js +0 -95
- /package/{src → esm}/directives.d.ts +0 -0
- /package/{src → esm}/index.d.ts +0 -0
- /package/{src → esm}/use-style.d.ts +0 -0
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { format } from 'date-fns'
|
|
2
|
-
import { NBadge, NButton, NDrawer, NDrawerContent, NEmpty, NIcon, NList, NListItem, NPagination, NThing } from 'ithinkdt-ui'
|
|
3
|
-
import { defineComponent, reactive, ref, withDirectives } from 'vue'
|
|
4
|
-
|
|
5
|
-
import { useAtomicBroadcast } from '@ithinkdt/common/composables'
|
|
6
|
-
|
|
7
|
-
import { vSpin } from '../directives/spin.js'
|
|
8
|
-
import { vTooltip } from '../directives/tooltip.jsx'
|
|
9
|
-
import { useI18n } from '../use-i18n.js'
|
|
10
|
-
|
|
11
|
-
export const AppNotification = /* @__PURE__ */ defineComponent({
|
|
12
|
-
name: 'AppNotification',
|
|
13
|
-
inheritAttrs: false,
|
|
14
|
-
props: {
|
|
15
|
-
getUnreadCount: Function,
|
|
16
|
-
getPage: Function,
|
|
17
|
-
markRead: Function,
|
|
18
|
-
markDelete: Function,
|
|
19
|
-
interval: { type: Number, default: 30_000 },
|
|
20
|
-
},
|
|
21
|
-
setup(props, { slots, attrs }) {
|
|
22
|
-
const { t } = useI18n()
|
|
23
|
-
|
|
24
|
-
const show = ref(false)
|
|
25
|
-
const currentTab = ref('unread')
|
|
26
|
-
const data = reactive({
|
|
27
|
-
page: 1,
|
|
28
|
-
size: 10,
|
|
29
|
-
loading: false,
|
|
30
|
-
records: [],
|
|
31
|
-
total: 0,
|
|
32
|
-
unread: 0,
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const { sync, post } = useAtomicBroadcast({
|
|
36
|
-
channel: '__ithinkdt_mc_shared_channel',
|
|
37
|
-
onMsg: (msg) => {
|
|
38
|
-
data.unread = msg
|
|
39
|
-
},
|
|
40
|
-
getMsg: () => {
|
|
41
|
-
if (show.value) {
|
|
42
|
-
data.loading = true
|
|
43
|
-
Promise.resolve(props.getPage?.(currentTab.value, data.page, data.size) ?? [])
|
|
44
|
-
.then(({ records, total }) => {
|
|
45
|
-
data.records = records
|
|
46
|
-
if (currentTab.value === 'unread') {
|
|
47
|
-
data.unread = total
|
|
48
|
-
post(total)
|
|
49
|
-
} else {
|
|
50
|
-
data.total = total
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
.finally(() => {
|
|
54
|
-
data.loading = false
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
return props.getUnreadCount?.() ?? 0
|
|
58
|
-
},
|
|
59
|
-
timeout: () => props.interval,
|
|
60
|
-
immediate: true,
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
return () => {
|
|
64
|
-
const trigger = withDirectives(
|
|
65
|
-
<NButton
|
|
66
|
-
{...attrs}
|
|
67
|
-
quaternary
|
|
68
|
-
style="--n-padding: 0 12px"
|
|
69
|
-
onClick={() => {
|
|
70
|
-
show.value = true
|
|
71
|
-
currentTab.value = data.unread > 0 ? 'unread' : 'all'
|
|
72
|
-
setTimeout(sync, 300)
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
{slots.icon
|
|
76
|
-
? (
|
|
77
|
-
slots.icon()
|
|
78
|
-
)
|
|
79
|
-
: (
|
|
80
|
-
<NBadge show={data.unread > 0} dot offset={[-2, 5]} processing>
|
|
81
|
-
<NIcon size="18">
|
|
82
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
|
83
|
-
<g
|
|
84
|
-
fill="none"
|
|
85
|
-
stroke="currentColor"
|
|
86
|
-
stroke-linecap="round"
|
|
87
|
-
stroke-linejoin="round"
|
|
88
|
-
stroke-width="1.5"
|
|
89
|
-
color="currentColor"
|
|
90
|
-
>
|
|
91
|
-
<path d="M2.53 14.77c-.213 1.394.738 2.361 1.902 2.843c4.463 1.85 10.673 1.85 15.136 0c1.164-.482 2.115-1.45 1.902-2.843c-.13-.857-.777-1.57-1.256-2.267c-.627-.924-.689-1.931-.69-3.003C19.525 5.358 16.157 2 12 2S4.475 5.358 4.475 9.5c0 1.072-.062 2.08-.69 3.003c-.478.697-1.124 1.41-1.255 2.267" />
|
|
92
|
-
<path d="M8 19c.458 1.725 2.076 3 4 3c1.925 0 3.541-1.275 4-3" />
|
|
93
|
-
</g>
|
|
94
|
-
</svg>
|
|
95
|
-
</NIcon>
|
|
96
|
-
</NBadge>
|
|
97
|
-
)}
|
|
98
|
-
</NButton>,
|
|
99
|
-
[[vTooltip, t('common.notification.tip', { count: data.unread }), undefined, { bottom: true }]],
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
const header = () => (
|
|
103
|
-
<div style="display: flex; align-items: baseline; gap: 20px">
|
|
104
|
-
<div style="padding-right: 12px">{t('common.notification.title') }</div>
|
|
105
|
-
<NButton
|
|
106
|
-
text
|
|
107
|
-
type={currentTab.value === 'all' ? 'primary' : 'default'}
|
|
108
|
-
onClick={() => {
|
|
109
|
-
currentTab.value = 'all'
|
|
110
|
-
sync()
|
|
111
|
-
}}
|
|
112
|
-
>
|
|
113
|
-
{t('common.notification.all') }
|
|
114
|
-
</NButton>
|
|
115
|
-
<NButton
|
|
116
|
-
text
|
|
117
|
-
type={currentTab.value === 'unread' ? 'primary' : 'default'}
|
|
118
|
-
onClick={() => {
|
|
119
|
-
currentTab.value = 'unread'
|
|
120
|
-
sync()
|
|
121
|
-
}}
|
|
122
|
-
>
|
|
123
|
-
{t('common.notification.unread', { count: data.unread > 99 ? '99+' : data.unread.toString() }) }
|
|
124
|
-
</NButton>
|
|
125
|
-
</div>
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
const renderItem = msg => (
|
|
129
|
-
<NListItem
|
|
130
|
-
key={msg.key}
|
|
131
|
-
onClick={() => {
|
|
132
|
-
if (msg.status === 'unread') {
|
|
133
|
-
props.markRead?.([msg.key]).then(() => {
|
|
134
|
-
msg.status = 'read'
|
|
135
|
-
})
|
|
136
|
-
data.unread--
|
|
137
|
-
}
|
|
138
|
-
if (msg.link) {
|
|
139
|
-
window.open(msg.link, '_target')
|
|
140
|
-
}
|
|
141
|
-
}}
|
|
142
|
-
>
|
|
143
|
-
<NThing
|
|
144
|
-
bordered={false}
|
|
145
|
-
closable
|
|
146
|
-
contentIndented
|
|
147
|
-
size="small"
|
|
148
|
-
onMouseenter={() => (msg.hover = true)}
|
|
149
|
-
onMouseleave={() => (msg.hover = false)}
|
|
150
|
-
style="padding: 0 4px"
|
|
151
|
-
>
|
|
152
|
-
{{
|
|
153
|
-
'avatar': () => (
|
|
154
|
-
<NIcon size={22} color={msg.status === 'unread' ? 'var(--color-primary)' : undefined}>
|
|
155
|
-
<svg
|
|
156
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
157
|
-
width="1em"
|
|
158
|
-
height="1em"
|
|
159
|
-
viewBox="0 0 24 24"
|
|
160
|
-
>
|
|
161
|
-
<path
|
|
162
|
-
fill="currentColor"
|
|
163
|
-
d="M12.3 7.29c.2-.18.44-.29.7-.29c.27 0 .5.11.71.29c.19.21.29.45.29.71c0 .27-.1.5-.29.71c-.21.19-.44.29-.71.29c-.26 0-.5-.1-.7-.29c-.19-.21-.3-.44-.3-.71c0-.26.11-.5.3-.71m-2.5 4.68s2.17-1.72 2.96-1.79c.74-.06.59.79.52 1.23l-.01.06c-.14.53-.31 1.17-.48 1.78c-.38 1.39-.75 2.75-.66 3c.1.34.72-.09 1.17-.39c.06-.04.11-.08.16-.11c0 0 .08-.08.16.03c.02.03.04.06.06.08c.09.14.14.19.02.27l-.04.02c-.22.15-1.16.81-1.54 1.05c-.41.27-1.98 1.17-1.74-.58c.21-1.23.49-2.29.71-3.12c.41-1.5.59-2.18-.33-1.59c-.37.22-.59.36-.72.45c-.11.08-.12.08-.19-.05l-.03-.06l-.05-.08c-.07-.1-.07-.11.03-.2M22 12c0 5.5-4.5 10-10 10S2 17.5 2 12S6.5 2 12 2s10 4.5 10 10m-2 0c0-4.42-3.58-8-8-8s-8 3.58-8 8s3.58 8 8 8s8-3.58 8-8"
|
|
164
|
-
/>
|
|
165
|
-
</svg>
|
|
166
|
-
</NIcon>
|
|
167
|
-
),
|
|
168
|
-
'header': () => msg.title,
|
|
169
|
-
'header-extra': () =>
|
|
170
|
-
msg.hover
|
|
171
|
-
? (
|
|
172
|
-
<div
|
|
173
|
-
style="display: flex; justify-content: end; gap: 12px"
|
|
174
|
-
onClick={(e) => {
|
|
175
|
-
e.preventDefault()
|
|
176
|
-
e.stopPropagation()
|
|
177
|
-
}}
|
|
178
|
-
>
|
|
179
|
-
{msg.status === 'unread'
|
|
180
|
-
? (
|
|
181
|
-
<NButton
|
|
182
|
-
text
|
|
183
|
-
type="primary"
|
|
184
|
-
onClick={() => {
|
|
185
|
-
props.markRead?.([msg.key]).then(() => {
|
|
186
|
-
msg.status = 'read'
|
|
187
|
-
data.unread--
|
|
188
|
-
})
|
|
189
|
-
}}
|
|
190
|
-
>
|
|
191
|
-
{t('common.notification.markRead') }
|
|
192
|
-
</NButton>
|
|
193
|
-
)
|
|
194
|
-
: undefined}
|
|
195
|
-
|
|
196
|
-
<NButton
|
|
197
|
-
text
|
|
198
|
-
type="error"
|
|
199
|
-
onClick={() => {
|
|
200
|
-
if (data.records === 1) {
|
|
201
|
-
data.records = []
|
|
202
|
-
sync()
|
|
203
|
-
} else {
|
|
204
|
-
data.records.splice(
|
|
205
|
-
data.records.findIndex(it => it.key == msg.key),
|
|
206
|
-
1,
|
|
207
|
-
)
|
|
208
|
-
}
|
|
209
|
-
props.markDelete?.([msg.key])
|
|
210
|
-
}}
|
|
211
|
-
>
|
|
212
|
-
{t('common.notification.markDelete') }
|
|
213
|
-
</NButton>
|
|
214
|
-
</div>
|
|
215
|
-
)
|
|
216
|
-
: undefined,
|
|
217
|
-
'default': msg.content,
|
|
218
|
-
'footer': () => (
|
|
219
|
-
<span style="color: gray">
|
|
220
|
-
{msg.hover ? format(msg.date, t('common.notification.time')) : t('common.timeago', { time: msg.date }) }
|
|
221
|
-
</span>
|
|
222
|
-
),
|
|
223
|
-
}}
|
|
224
|
-
</NThing>
|
|
225
|
-
</NListItem>
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
const content = () =>
|
|
229
|
-
withDirectives(
|
|
230
|
-
data.records.length > 0
|
|
231
|
-
? (
|
|
232
|
-
<NList clickable hoverable style="min-height: 50vh">
|
|
233
|
-
{data.records.map(msg => renderItem(msg))}
|
|
234
|
-
</NList>
|
|
235
|
-
)
|
|
236
|
-
: (
|
|
237
|
-
<NEmpty style="margin-top: 30vh" />
|
|
238
|
-
),
|
|
239
|
-
[[vSpin, data.loading]],
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
const footer = () => (
|
|
243
|
-
<div style="display: flex; justify-content: space-between; width: 100%">
|
|
244
|
-
{currentTab.value === 'unread'
|
|
245
|
-
? (
|
|
246
|
-
<NButton
|
|
247
|
-
text
|
|
248
|
-
type="primary"
|
|
249
|
-
disabled={data.records.length === 0}
|
|
250
|
-
onClick={() => {
|
|
251
|
-
const keys = data.records.filter(it => it.status === 'unread').map(it => it.key)
|
|
252
|
-
props.markRead(keys).then(() => {
|
|
253
|
-
while (data.unread - keys.length <= data.size * (data.page - 1)) {
|
|
254
|
-
data.page--
|
|
255
|
-
}
|
|
256
|
-
sync()
|
|
257
|
-
})
|
|
258
|
-
}}
|
|
259
|
-
>
|
|
260
|
-
{{
|
|
261
|
-
icon: () => (
|
|
262
|
-
<NIcon size="20">
|
|
263
|
-
<svg
|
|
264
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
265
|
-
width="1em"
|
|
266
|
-
height="1em"
|
|
267
|
-
viewBox="0 0 24 24"
|
|
268
|
-
>
|
|
269
|
-
<path
|
|
270
|
-
fill="currentColor"
|
|
271
|
-
d="M.41 13.41L6 19l1.41-1.42L1.83 12m20.41-6.42L11.66 16.17L7.5 12l-1.43 1.41L11.66 19l12-12M18 7l-1.41-1.42l-6.35 6.35l1.42 1.41z"
|
|
272
|
-
/>
|
|
273
|
-
</svg>
|
|
274
|
-
</NIcon>
|
|
275
|
-
),
|
|
276
|
-
default: () => t('common.notification.markPageRead'),
|
|
277
|
-
}}
|
|
278
|
-
</NButton>
|
|
279
|
-
)
|
|
280
|
-
: (
|
|
281
|
-
<span />
|
|
282
|
-
)}
|
|
283
|
-
<NPagination
|
|
284
|
-
simple
|
|
285
|
-
pageSize={data.size}
|
|
286
|
-
page={data.page}
|
|
287
|
-
itemCount={currentTab.value === 'unread' ? data.unread : data.total}
|
|
288
|
-
onUpdatePage={(page) => {
|
|
289
|
-
data.page = page
|
|
290
|
-
sync()
|
|
291
|
-
}}
|
|
292
|
-
/>
|
|
293
|
-
</div>
|
|
294
|
-
)
|
|
295
|
-
return (
|
|
296
|
-
<>
|
|
297
|
-
{trigger}
|
|
298
|
-
<NDrawer v-model:show={show.value} showMask={false} width={400}>
|
|
299
|
-
<NDrawerContent title={t('common.notification.title')} closable nativeScrollbar={false} bodyContentStyle={{ padding: '0' }}>
|
|
300
|
-
{{
|
|
301
|
-
header,
|
|
302
|
-
default: content,
|
|
303
|
-
footer,
|
|
304
|
-
}}
|
|
305
|
-
</NDrawerContent>
|
|
306
|
-
</NDrawer>
|
|
307
|
-
</>
|
|
308
|
-
)
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
})
|
package/src/design/common.jsx
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { inject } from 'vue'
|
|
2
|
-
|
|
3
|
-
export const clsPrefix = 'app'
|
|
4
|
-
|
|
5
|
-
export const COLLAPSED_INJECTION_KEY = 'APP_SIDER_COLLAPSED'
|
|
6
|
-
|
|
7
|
-
export const IBookmark = () => (
|
|
8
|
-
<svg
|
|
9
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
-
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
11
|
-
role="img"
|
|
12
|
-
width="1em"
|
|
13
|
-
height="1em"
|
|
14
|
-
viewBox="0 0 24 24"
|
|
15
|
-
>
|
|
16
|
-
<path fill="currentColor" d="m17 18l-5-2.18L7 18V5h10m0-2H7a2 2 0 0 0-2 2v16l7-3l7 3V5a2 2 0 0 0-2-2Z" />
|
|
17
|
-
</svg>
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
export const CTX_INJECTION_KEY = '__APP_CTX__'
|
|
21
|
-
export const getCtx = () => inject(CTX_INJECTION_KEY)
|
package/src/design/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { AppContent, AppFooter, AppHeader, AppLayout, AppSider } from './Layout.jsx'
|
|
2
|
-
export { AppLogo } from './Logo.jsx'
|
|
3
|
-
export { AppMenu } from './Menu.jsx'
|
|
4
|
-
export { AppBreadcrumb } from './Breadcrumb.jsx'
|
|
5
|
-
export { AppAccount } from './Account.jsx'
|
|
6
|
-
export { AppFullscreen } from './Fullscreen.jsx'
|
|
7
|
-
export { AppAppearance } from './Appearance.jsx'
|
|
8
|
-
export { AppLanguage } from './Language.jsx'
|
|
9
|
-
export { AppNotification } from './Notification.jsx'
|
|
10
|
-
export { AppMultiTabs } from './MultiTabs.jsx'
|
package/src/directives/index.js
DELETED
package/src/directives/spin.js
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { Fragment, defineComponent, h, nextTick, ref, toRef, watch } from 'vue'
|
|
2
|
-
|
|
3
|
-
import { useElementIntersectionRect } from '@ithinkdt/common/composables'
|
|
4
|
-
import { string2dom } from '@ithinkdt/common/dom'
|
|
5
|
-
import { debounce } from '@ithinkdt/common/fn'
|
|
6
|
-
|
|
7
|
-
import useStyle, { c, cB, cE, cM } from '../use-style.js'
|
|
8
|
-
|
|
9
|
-
let clsPrefix
|
|
10
|
-
let isDark
|
|
11
|
-
|
|
12
|
-
const style = /* @__PURE__ */ c([
|
|
13
|
-
c(({ props }) => `:where(${props.bPrefix}spin-host)`, {
|
|
14
|
-
position: 'relative',
|
|
15
|
-
}),
|
|
16
|
-
cB(
|
|
17
|
-
'spin-directive',
|
|
18
|
-
{
|
|
19
|
-
zIndex: '999999',
|
|
20
|
-
position: 'absolute',
|
|
21
|
-
color: 'var(--color-primary)',
|
|
22
|
-
display: 'flex',
|
|
23
|
-
flexDirection: 'column',
|
|
24
|
-
justifyContent: 'center',
|
|
25
|
-
alignItems: 'center',
|
|
26
|
-
gap: '4px',
|
|
27
|
-
willChange: 'background-color',
|
|
28
|
-
backgroundColor: 'rgb(var(--host-bg, 255 255 255) / 0)',
|
|
29
|
-
transition: 'background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
30
|
-
},
|
|
31
|
-
[
|
|
32
|
-
cE('tip, icon', {
|
|
33
|
-
willChange: 'opacity',
|
|
34
|
-
opacity: '0',
|
|
35
|
-
transition: 'opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
36
|
-
}),
|
|
37
|
-
cE('tip:empty', { display: 'none' }),
|
|
38
|
-
cM(
|
|
39
|
-
'spining',
|
|
40
|
-
{
|
|
41
|
-
backgroundColor: 'rgb(var(--host-bg, 255 255 255) / 0.5)',
|
|
42
|
-
},
|
|
43
|
-
[cE('tip, icon', { opacity: '1' })],
|
|
44
|
-
),
|
|
45
|
-
],
|
|
46
|
-
),
|
|
47
|
-
])
|
|
48
|
-
|
|
49
|
-
export const SpinDirectiveProvider = /* @__PURE__ */ defineComponent({
|
|
50
|
-
name: 'SpinDirectiveProvider',
|
|
51
|
-
props: {
|
|
52
|
-
dark: Boolean,
|
|
53
|
-
},
|
|
54
|
-
setup(props) {
|
|
55
|
-
clsPrefix = useStyle('-spin-directive', style)
|
|
56
|
-
isDark = toRef(props, 'dark')
|
|
57
|
-
return () => h(Fragment)
|
|
58
|
-
},
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
const Spin = /* @__PURE__ */ Symbol('spin-dir')
|
|
62
|
-
|
|
63
|
-
const updateLoading = (el, { value, modifiers }) => {
|
|
64
|
-
el[Spin].loading.value = !!value
|
|
65
|
-
if (!el[Spin].loading.value) return
|
|
66
|
-
const dark = modifiers.dark || (!modifiers.light && isDark.value)
|
|
67
|
-
el[Spin].spinEl.style.setProperty(
|
|
68
|
-
'--host-bg',
|
|
69
|
-
dark ? '0 0 0' : '255 255 255',
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export const vSpin = {
|
|
74
|
-
beforeMount(el) {
|
|
75
|
-
el.classList.add(`${clsPrefix.value}-spin-host`)
|
|
76
|
-
|
|
77
|
-
if (el[Spin]) return
|
|
78
|
-
|
|
79
|
-
const loading = ref(false)
|
|
80
|
-
|
|
81
|
-
const spinEl = string2dom(
|
|
82
|
-
`
|
|
83
|
-
<div class="${clsPrefix.value}-spin-directive">
|
|
84
|
-
<svg class="${clsPrefix.value}-spin-directive__icon" width="32" height="32" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
85
|
-
<g>
|
|
86
|
-
<animateTransform attributeName="transform" type="rotate" values="0 100 100;270 100 100" begin="0s" dur="1.6s" fill="freeze" repeatCount="indefinite"></animateTransform>
|
|
87
|
-
<circle fill="none" stroke="currentColor" stroke-width="18" stroke-linecap="round" cx="100" cy="100" r="92" stroke-dasharray="567" stroke-dashoffset="1848">
|
|
88
|
-
<animateTransform attributeName="transform" type="rotate" values="0 100 100;135 100 100;450 100 100" begin="0s" dur="1.6s" fill="freeze" repeatCount="indefinite"></animateTransform>
|
|
89
|
-
<animate attributeName="stroke-dashoffset" values="567;142;567" begin="0s" dur="1.6s" fill="freeze" repeatCount="indefinite"></animate>
|
|
90
|
-
</circle>
|
|
91
|
-
</g>
|
|
92
|
-
</svg>
|
|
93
|
-
<div class="${clsPrefix.value}-spin-directive__tip"></div>
|
|
94
|
-
</div>
|
|
95
|
-
`.trim(),
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
let rect
|
|
99
|
-
const { stop: stopEl, update } = useElementIntersectionRect(el, (_rect) => {
|
|
100
|
-
rect = _rect
|
|
101
|
-
Object.assign(spinEl.style, {
|
|
102
|
-
left: 0,
|
|
103
|
-
top: 0,
|
|
104
|
-
width: rect.width + 'px',
|
|
105
|
-
height: rect.height + 'px',
|
|
106
|
-
})
|
|
107
|
-
}, { interval: 1000 / 30 })
|
|
108
|
-
|
|
109
|
-
let timer
|
|
110
|
-
const stopSpin = watch(
|
|
111
|
-
loading,
|
|
112
|
-
debounce(() => {
|
|
113
|
-
if (loading.value) {
|
|
114
|
-
if (timer === undefined) {
|
|
115
|
-
clearTimeout(timer)
|
|
116
|
-
timer = undefined
|
|
117
|
-
}
|
|
118
|
-
update()
|
|
119
|
-
el.append(spinEl)
|
|
120
|
-
requestAnimationFrame(() => {
|
|
121
|
-
if (loading.value) spinEl.classList.add(`${clsPrefix.value}-spin-directive--spining`)
|
|
122
|
-
})
|
|
123
|
-
} else {
|
|
124
|
-
spinEl.classList.remove(`${clsPrefix.value}-spin-directive--spining`)
|
|
125
|
-
const listener = () => {
|
|
126
|
-
spinEl.remove()
|
|
127
|
-
if (timer) clearTimeout(timer)
|
|
128
|
-
timer = null
|
|
129
|
-
spinEl.removeEventListener('transitioncancel', listener)
|
|
130
|
-
spinEl.removeEventListener('transitionend', listener)
|
|
131
|
-
}
|
|
132
|
-
spinEl.addEventListener('transitioncancel', listener)
|
|
133
|
-
spinEl.addEventListener('transitionend', listener)
|
|
134
|
-
let timer = setTimeout(listener, 300)
|
|
135
|
-
}
|
|
136
|
-
}, 30),
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
el[Spin] = {
|
|
140
|
-
loading,
|
|
141
|
-
spinEl,
|
|
142
|
-
updateTip: () => {
|
|
143
|
-
const tipEl = spinEl.querySelector(`.${clsPrefix.value}-spin-directive__tip`)
|
|
144
|
-
tipEl.textContent = el.dataset.spinTip
|
|
145
|
-
},
|
|
146
|
-
stop: () => {
|
|
147
|
-
stopEl()
|
|
148
|
-
stopSpin()
|
|
149
|
-
},
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
mounted(el, binding) {
|
|
154
|
-
updateLoading(el, binding)
|
|
155
|
-
el[Spin].updateTip()
|
|
156
|
-
if (el[Spin].observer) return
|
|
157
|
-
// 创建 MutationObserver 对象
|
|
158
|
-
nextTick().then(() => {
|
|
159
|
-
const observer = (el[Spin].observer = new MutationObserver((mutationsList) => {
|
|
160
|
-
for (const mutation of mutationsList) {
|
|
161
|
-
if (mutation.type === 'attributes' && mutation.attributeName === 'data-spin-tip') {
|
|
162
|
-
el[Spin].updateTip()
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}))
|
|
167
|
-
|
|
168
|
-
// 开始观察目标元素
|
|
169
|
-
observer.observe(el, { attributes: true, attributeFilter: ['data-spin-tip'] })
|
|
170
|
-
})
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
updated: updateLoading,
|
|
174
|
-
|
|
175
|
-
beforeUnmount(el) {
|
|
176
|
-
el[Spin].loading.value = false
|
|
177
|
-
el[Spin].stop()
|
|
178
|
-
el[Spin].observer?.disconnect()
|
|
179
|
-
delete el[Spin]
|
|
180
|
-
},
|
|
181
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { promiseTimeout, useEventListener } from '@vueuse/core'
|
|
2
|
-
import { NTooltip } from 'ithinkdt-ui'
|
|
3
|
-
import { defineComponent, reactive, shallowRef } from 'vue'
|
|
4
|
-
|
|
5
|
-
const Tooltip = /* @__PURE__ */ Symbol('tooltip-dir')
|
|
6
|
-
const current = /* @__PURE__ */ shallowRef()
|
|
7
|
-
|
|
8
|
-
let _update
|
|
9
|
-
export const TooltipDirectiveProvider = /* @__PURE__ */ defineComponent({
|
|
10
|
-
name: 'TooltipDirectiveProvider',
|
|
11
|
-
props: {
|
|
12
|
-
delay: { type: Number, default: 180 },
|
|
13
|
-
},
|
|
14
|
-
setup(props) {
|
|
15
|
-
const tip = shallowRef()
|
|
16
|
-
const data = reactive({ show: false, tip: undefined, placement: 'top', x: 0, y: 0 })
|
|
17
|
-
|
|
18
|
-
_update = async () => {
|
|
19
|
-
if (!current.value) return
|
|
20
|
-
if (props.delay > 0) await promiseTimeout(props.delay)
|
|
21
|
-
const el = current.value
|
|
22
|
-
const tooltip = el?.[Tooltip]
|
|
23
|
-
if (!tooltip) return
|
|
24
|
-
const _tip = tooltip.tip
|
|
25
|
-
tip.value
|
|
26
|
-
= typeof _tip === 'function' ? _tip : () => _tip || el.attributes.getNamedItem('title') || el.textContent
|
|
27
|
-
|
|
28
|
-
const { auto } = tooltip.binding.modifiers
|
|
29
|
-
if (
|
|
30
|
-
!auto
|
|
31
|
-
|| el.firstChild.offsetWidth > el.clientWidth
|
|
32
|
-
|| el.firstChild.offsetHeight > el.clientHeight
|
|
33
|
-
) {
|
|
34
|
-
data.show = true
|
|
35
|
-
|
|
36
|
-
const rect = el.getBoundingClientRect()
|
|
37
|
-
data.placement
|
|
38
|
-
= Object.keys(tooltip.binding.modifiers).find(m =>
|
|
39
|
-
['top', 'right', 'left', 'bottom'].find(k => m.startsWith(k)),
|
|
40
|
-
) ?? 'top'
|
|
41
|
-
switch (data.placement.split('-')[0]) {
|
|
42
|
-
case 'top': {
|
|
43
|
-
data.x = rect.left + rect.width / 2
|
|
44
|
-
data.y = rect.top
|
|
45
|
-
break
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
case 'right': {
|
|
49
|
-
data.x = rect.left + rect.width
|
|
50
|
-
data.y = rect.top + rect.height / 2
|
|
51
|
-
break
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
case 'left': {
|
|
55
|
-
data.x = rect.left
|
|
56
|
-
data.y = rect.top + rect.height / 2
|
|
57
|
-
break
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
case 'bottom': {
|
|
61
|
-
data.x = rect.left + rect.width / 2
|
|
62
|
-
data.y = rect.bottom
|
|
63
|
-
break
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} else if (data.show) {
|
|
67
|
-
data.show = false
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
useEventListener(
|
|
72
|
-
'mouseover',
|
|
73
|
-
(ev) => {
|
|
74
|
-
const el = ev.target
|
|
75
|
-
if (!current.value || current.value?.contains(el)) return
|
|
76
|
-
data.show = false
|
|
77
|
-
current.value = undefined
|
|
78
|
-
},
|
|
79
|
-
{ capture: true },
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
return () => (
|
|
83
|
-
<NTooltip
|
|
84
|
-
trigger="manual"
|
|
85
|
-
show={!!current.value && data.show}
|
|
86
|
-
x={data.x}
|
|
87
|
-
y={data.y}
|
|
88
|
-
placement={data.placement}
|
|
89
|
-
keepAliveOnHover
|
|
90
|
-
>
|
|
91
|
-
{tip.value?.()}
|
|
92
|
-
</NTooltip>
|
|
93
|
-
)
|
|
94
|
-
},
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
const _listener = (ev) => {
|
|
98
|
-
current.value = ev.target
|
|
99
|
-
_update?.()
|
|
100
|
-
}
|
|
101
|
-
export const vTooltip = {
|
|
102
|
-
mounted(el, binding) {
|
|
103
|
-
el[Tooltip] = {
|
|
104
|
-
binding,
|
|
105
|
-
tip: binding.value,
|
|
106
|
-
}
|
|
107
|
-
el.addEventListener('mouseenter', _listener)
|
|
108
|
-
},
|
|
109
|
-
updated(el, binding) {
|
|
110
|
-
el[Tooltip].binding = binding
|
|
111
|
-
el[Tooltip].tip = binding.value
|
|
112
|
-
_update()
|
|
113
|
-
},
|
|
114
|
-
beforeUnmount(el) {
|
|
115
|
-
if (el[Tooltip]) el.removeEventListener('mouseenter', _listener)
|
|
116
|
-
if (current.value === el) {
|
|
117
|
-
current.value = undefined
|
|
118
|
-
}
|
|
119
|
-
delete el[Tooltip]
|
|
120
|
-
},
|
|
121
|
-
}
|
package/src/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineComponent, provide, toRef } from 'vue'
|
|
2
|
-
|
|
3
|
-
import { UI_I18N_INJECTION } from './use-i18n.js'
|
|
4
|
-
|
|
5
|
-
export { SpinDirectiveProvider, TooltipDirectiveProvider, vSpin, vTooltip } from './directives/index.js'
|
|
6
|
-
export * from './design/index.js'
|
|
7
|
-
|
|
8
|
-
export const UIProvider = /* @__PURE__ */ defineComponent({
|
|
9
|
-
name: 'UIProvider',
|
|
10
|
-
props: {
|
|
11
|
-
i18n: Function,
|
|
12
|
-
},
|
|
13
|
-
setup(props, { slots }) {
|
|
14
|
-
provide(UI_I18N_INJECTION, toRef(props, 'i18n'))
|
|
15
|
-
|
|
16
|
-
return () => slots.default()
|
|
17
|
-
},
|
|
18
|
-
})
|