webcake-ui-kit 1.1.29 → 1.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -2
- package/src/components/date-picker/CalendarPanel.vue +154 -0
- package/src/components/date-picker/CalendarView.vue +104 -0
- package/src/components/date-picker/DatePicker.vue +587 -0
- package/src/components/date-picker/PanelFooter.vue +45 -0
- package/src/components/date-picker/PanelHeader.vue +102 -0
- package/src/components/date-picker/TimePanel.vue +98 -0
- package/src/components/date-picker/calendar-panel.css +36 -0
- package/src/components/date-picker/calendar-view.css +134 -0
- package/src/components/date-picker/calendar.js +116 -0
- package/src/components/date-picker/date-picker.css +95 -0
- package/src/components/date-picker/dayjs.js +34 -0
- package/src/components/date-picker/panel-footer.css +42 -0
- package/src/components/date-picker/panel-header.css +71 -0
- package/src/components/date-picker/time-panel.css +63 -0
- package/src/components/input/input.css +5 -0
- package/src/components/menu/menu.css +0 -1
- package/src/components/message/Message.vue +72 -0
- package/src/components/message/MessageContainer.vue +200 -0
- package/src/components/message/message-container.css +108 -0
- package/src/components/message/message.css +69 -0
- package/src/components/message/message.js +133 -0
- package/src/components/progress/Progress.vue +42 -0
- package/src/components/progress/progress.css +15 -0
- package/src/components/radio/Radio.vue +1 -1
- package/src/components/radio-group/RadioGroup.vue +2 -2
- package/src/components/table/Table.vue +30 -21
- package/src/components/table/table.css +18 -2
- package/src/index.js +5 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Global message service — an Ant-Design-style singleton.
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// import { wkMessage } from 'webcake-ui-kit'
|
|
5
|
+
// wkMessage.success('Saved')
|
|
6
|
+
// const hide = wkMessage.loading('Uploading...') // sticky; call hide() to dismiss
|
|
7
|
+
// wkMessage.config({ placement: 'bottom', maxCount: 3, duration: 5000 })
|
|
8
|
+
//
|
|
9
|
+
// A single MessageContainer is lazily mounted to document.body the first time a
|
|
10
|
+
// message is shown; consumers never render it themselves.
|
|
11
|
+
//
|
|
12
|
+
// Dual-compat note: the library ships raw SFCs consumed by both Vue 2.7 and
|
|
13
|
+
// Vue 3.4. We namespace-import `vue` (which never errors on a missing member)
|
|
14
|
+
// and branch at runtime to avoid static import errors in Vue 2.
|
|
15
|
+
// eslint-disable-next-line no-restricted-imports
|
|
16
|
+
import * as VueRuntime from 'vue'
|
|
17
|
+
import MessageContainer from './MessageContainer.vue'
|
|
18
|
+
|
|
19
|
+
const DEFAULTS = { duration: 3000, placement: 'top', offset: 24, maxCount: 0 }
|
|
20
|
+
|
|
21
|
+
let globalConfig = { ...DEFAULTS }
|
|
22
|
+
let app = null // Vue 3 application instance (needed for unmount)
|
|
23
|
+
let containerVm = null // MessageContainer instance we drive imperatively
|
|
24
|
+
let hostEl = null
|
|
25
|
+
|
|
26
|
+
function ensureContainer() {
|
|
27
|
+
if (containerVm) return containerVm
|
|
28
|
+
if (typeof document === 'undefined') return null
|
|
29
|
+
|
|
30
|
+
hostEl = document.createElement('div')
|
|
31
|
+
hostEl.setAttribute('data-wk-message-host', '')
|
|
32
|
+
document.body.appendChild(hostEl)
|
|
33
|
+
|
|
34
|
+
// Bypass strict static analysis in bundlers (e.g. Webpack 5)
|
|
35
|
+
const createAppKey = 'createApp'
|
|
36
|
+
const defaultKey = 'default'
|
|
37
|
+
|
|
38
|
+
if (typeof VueRuntime[createAppKey] === 'function') {
|
|
39
|
+
app = VueRuntime[createAppKey](MessageContainer)
|
|
40
|
+
containerVm = app.mount(hostEl)
|
|
41
|
+
} else {
|
|
42
|
+
const Vue = VueRuntime[defaultKey] || VueRuntime
|
|
43
|
+
const vm = new Vue({
|
|
44
|
+
render: h => h(MessageContainer)
|
|
45
|
+
}).$mount(hostEl)
|
|
46
|
+
containerVm = vm.$children[0]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
containerVm.configure(globalConfig)
|
|
50
|
+
return containerVm
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Accept either a config object, (content, optsObj), or (content, duration?, onClose?).
|
|
54
|
+
function toConfig(content, durationOrOpts, onClose) {
|
|
55
|
+
const cfg = content && typeof content === 'object' ? { ...content } : { content }
|
|
56
|
+
if (durationOrOpts && typeof durationOrOpts === 'object') {
|
|
57
|
+
Object.assign(cfg, durationOrOpts)
|
|
58
|
+
} else if (typeof durationOrOpts === 'function') {
|
|
59
|
+
cfg.onClose = durationOrOpts
|
|
60
|
+
} else {
|
|
61
|
+
if (durationOrOpts !== undefined) cfg.duration = durationOrOpts
|
|
62
|
+
if (onClose !== undefined) cfg.onClose = onClose
|
|
63
|
+
}
|
|
64
|
+
return cfg
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Show a message. Returns a function that dismisses it early.
|
|
68
|
+
function open(config) {
|
|
69
|
+
const vm = ensureContainer()
|
|
70
|
+
if (!vm) return function () {}
|
|
71
|
+
|
|
72
|
+
// Per-call placement/offset override (applied before add so the container
|
|
73
|
+
// is positioned correctly when the message enters).
|
|
74
|
+
if (config.placement != null || config.offset != null) {
|
|
75
|
+
vm.configure({
|
|
76
|
+
placement: config.placement,
|
|
77
|
+
offset: config.offset
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const type = config.type || 'info'
|
|
82
|
+
const duration = config.duration !== undefined ? config.duration : type === 'loading' ? 0 : globalConfig.duration
|
|
83
|
+
|
|
84
|
+
const key = vm.add({
|
|
85
|
+
key: config.key,
|
|
86
|
+
type,
|
|
87
|
+
content: config.content,
|
|
88
|
+
description: config.description,
|
|
89
|
+
action: config.action,
|
|
90
|
+
duration,
|
|
91
|
+
onClose: config.onClose
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return function close() {
|
|
95
|
+
vm.remove(key)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function makeOpener(type) {
|
|
100
|
+
return function (content, duration, onClose) {
|
|
101
|
+
const cfg = toConfig(content, duration, onClose)
|
|
102
|
+
cfg.type = type
|
|
103
|
+
return open(cfg)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const wkMessage = {
|
|
108
|
+
open,
|
|
109
|
+
success: makeOpener('success'),
|
|
110
|
+
error: makeOpener('error'),
|
|
111
|
+
info: makeOpener('info'),
|
|
112
|
+
warning: makeOpener('warning'),
|
|
113
|
+
loading: makeOpener('loading'),
|
|
114
|
+
// destroy(key) removes one message; destroy() with no key removes all.
|
|
115
|
+
destroy(key) {
|
|
116
|
+
if (!containerVm) return
|
|
117
|
+
if (key === undefined) {
|
|
118
|
+
containerVm.clear()
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
containerVm.remove(key)
|
|
122
|
+
},
|
|
123
|
+
destroyAll() {
|
|
124
|
+
if (containerVm) containerVm.clear()
|
|
125
|
+
},
|
|
126
|
+
// Update global defaults (placement/offset/maxCount/duration). Applies live.
|
|
127
|
+
config(options) {
|
|
128
|
+
globalConfig = { ...globalConfig, ...options }
|
|
129
|
+
if (containerVm) containerVm.configure(globalConfig)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default wkMessage
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ui-progress" role="progressbar" :aria-valuemin="0" :aria-valuemax="max" :aria-valuenow="clampedValue">
|
|
3
|
+
<div class="ui-progress__bar" :style="{ width: percent + '%' }" />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'Progress',
|
|
10
|
+
|
|
11
|
+
props: {
|
|
12
|
+
// Current progress value, clamped to the [0, max] range.
|
|
13
|
+
value: {
|
|
14
|
+
type: Number,
|
|
15
|
+
default: 0
|
|
16
|
+
},
|
|
17
|
+
// Upper bound of the progress scale (value === max renders a full bar).
|
|
18
|
+
max: {
|
|
19
|
+
type: Number,
|
|
20
|
+
default: 100,
|
|
21
|
+
validator: function (v) {
|
|
22
|
+
return v > 0
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
emits: [],
|
|
28
|
+
|
|
29
|
+
computed: {
|
|
30
|
+
clampedValue() {
|
|
31
|
+
if (this.value < 0) return 0
|
|
32
|
+
if (this.value > this.max) return this.max
|
|
33
|
+
return this.value
|
|
34
|
+
},
|
|
35
|
+
percent() {
|
|
36
|
+
return (this.clampedValue / this.max) * 100
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style src="./progress.css" scoped></style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.ui-progress {
|
|
2
|
+
position: relative;
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: 6px;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
background: var(--accent-2);
|
|
7
|
+
border-radius: var(--rounded-xl);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.ui-progress__bar {
|
|
11
|
+
height: 100%;
|
|
12
|
+
background: var(--primary-fg);
|
|
13
|
+
border-radius: var(--rounded-md) 0 0 var(--rounded-md);
|
|
14
|
+
transition: width 0.2s ease;
|
|
15
|
+
}
|
|
@@ -113,12 +113,7 @@
|
|
|
113
113
|
'ui-table__row',
|
|
114
114
|
'ui-table__row--body',
|
|
115
115
|
row._selected && 'ui-table__row--selected',
|
|
116
|
-
hasDrag && dragState && row._index === dragState.
|
|
117
|
-
hasDrag &&
|
|
118
|
-
row._index === dragOverIndex &&
|
|
119
|
-
dragState &&
|
|
120
|
-
row._index !== dragState.fromIndex &&
|
|
121
|
-
'ui-table__row--drag-over'
|
|
116
|
+
hasDrag && dragState && row._index === dragState.currentIndex && 'ui-table__row--dragging'
|
|
122
117
|
]"
|
|
123
118
|
:style="[{ height: toCssSize(rowHeight) }, rowScrollStyle]"
|
|
124
119
|
v-bind="row._attrs"
|
|
@@ -263,7 +258,8 @@ export default {
|
|
|
263
258
|
resizeState: null,
|
|
264
259
|
columnWidths: {},
|
|
265
260
|
dragState: null,
|
|
266
|
-
dragOverIndex: null
|
|
261
|
+
dragOverIndex: null,
|
|
262
|
+
internalData: this.dataSource.slice()
|
|
267
263
|
}
|
|
268
264
|
},
|
|
269
265
|
computed: {
|
|
@@ -380,7 +376,7 @@ export default {
|
|
|
380
376
|
return this.columns.length + (this.hasDrag ? 1 : 0) + (this.hasSelection ? 1 : 0)
|
|
381
377
|
},
|
|
382
378
|
rows() {
|
|
383
|
-
const data = this.
|
|
379
|
+
const data = this.internalData.slice()
|
|
384
380
|
if (!this.sortField || !this.sortOrder) return data
|
|
385
381
|
const col = this.normalizedColumns.find(c => c._field === this.sortField)
|
|
386
382
|
if (!col || !col.sorter) return data
|
|
@@ -485,6 +481,11 @@ export default {
|
|
|
485
481
|
watch: {
|
|
486
482
|
selectedRowKeys(next) {
|
|
487
483
|
this.internalSelected = (next || []).slice()
|
|
484
|
+
},
|
|
485
|
+
dataSource(next) {
|
|
486
|
+
if (!this.dragState) {
|
|
487
|
+
this.internalData = (next || []).slice()
|
|
488
|
+
}
|
|
488
489
|
}
|
|
489
490
|
},
|
|
490
491
|
mounted() {
|
|
@@ -665,7 +666,7 @@ export default {
|
|
|
665
666
|
this.emitSelection()
|
|
666
667
|
},
|
|
667
668
|
onDragStart(e, row) {
|
|
668
|
-
this.dragState = { fromIndex: row._index, record: row._record }
|
|
669
|
+
this.dragState = { fromIndex: row._index, currentIndex: row._index, record: row._record }
|
|
669
670
|
e.dataTransfer.effectAllowed = 'move'
|
|
670
671
|
|
|
671
672
|
const tr = e.currentTarget.closest('tr')
|
|
@@ -704,7 +705,20 @@ export default {
|
|
|
704
705
|
},
|
|
705
706
|
onDragOver(e, index) {
|
|
706
707
|
if (!this.dragState) return
|
|
707
|
-
this.
|
|
708
|
+
if (index === this.dragState.currentIndex) return
|
|
709
|
+
// Only reorder once the pointer crosses the row's midpoint to prevent oscillation.
|
|
710
|
+
const rect = e.currentTarget.getBoundingClientRect()
|
|
711
|
+
const midY = rect.top + rect.height / 1.5
|
|
712
|
+
if (index > this.dragState.currentIndex && e.clientY < midY) return
|
|
713
|
+
if (index < this.dragState.currentIndex && e.clientY > midY) return
|
|
714
|
+
// FLIP — snapshot "First" positions before the data changes.
|
|
715
|
+
const firstRects = this.snapshotRowRects()
|
|
716
|
+
const data = this.internalData.slice()
|
|
717
|
+
const [moved] = data.splice(this.dragState.currentIndex, 1)
|
|
718
|
+
data.splice(index, 0, moved)
|
|
719
|
+
this.internalData = data
|
|
720
|
+
this.dragState = { ...this.dragState, currentIndex: index }
|
|
721
|
+
this.$nextTick(() => this.flipAnimateRows(firstRects))
|
|
708
722
|
},
|
|
709
723
|
onDragLeave(e) {
|
|
710
724
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
@@ -713,21 +727,16 @@ export default {
|
|
|
713
727
|
},
|
|
714
728
|
onDrop(e, toIndex) {
|
|
715
729
|
if (!this.dragState) return
|
|
716
|
-
const { fromIndex, record } = this.dragState
|
|
717
|
-
|
|
718
|
-
this.dragState = null
|
|
719
|
-
this.dragOverIndex = null
|
|
720
|
-
return
|
|
721
|
-
}
|
|
722
|
-
// FLIP — snapshot "First" positions before the data changes.
|
|
723
|
-
const firstRects = this.snapshotRowRects()
|
|
724
|
-
this.$emit('drag-record', { record, fromIndex, toIndex }, e)
|
|
730
|
+
const { fromIndex, record, currentIndex } = this.dragState
|
|
731
|
+
this.$emit('drag-record', { record, fromIndex, toIndex: currentIndex }, e)
|
|
725
732
|
this.dragState = null
|
|
726
733
|
this.dragOverIndex = null
|
|
727
|
-
// After Vue re-renders with the new order, run the Invert+Play phase.
|
|
728
|
-
this.$nextTick(() => this.flipAnimateRows(firstRects))
|
|
729
734
|
},
|
|
730
735
|
onDragEnd() {
|
|
736
|
+
if (this.dragState) {
|
|
737
|
+
// Drag cancelled (no drop) — revert live reorder.
|
|
738
|
+
this.internalData = this.dataSource.slice()
|
|
739
|
+
}
|
|
731
740
|
this.dragState = null
|
|
732
741
|
this.dragOverIndex = null
|
|
733
742
|
},
|
|
@@ -161,6 +161,10 @@
|
|
|
161
161
|
cursor: col-resize;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
.ui-table__resize-handle:hover {
|
|
165
|
+
height: 100%;
|
|
166
|
+
}
|
|
167
|
+
|
|
164
168
|
.ui-table__resize-handle--left {
|
|
165
169
|
right: auto;
|
|
166
170
|
left: -4px;
|
|
@@ -179,8 +183,8 @@
|
|
|
179
183
|
|
|
180
184
|
.ui-table__resize-handle:hover::before,
|
|
181
185
|
.ui-table__resize-handle.resizing::before {
|
|
182
|
-
width:
|
|
183
|
-
background:
|
|
186
|
+
width: 3px;
|
|
187
|
+
background: #3f8dff;
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
.ui-table__th-inner {
|
|
@@ -275,6 +279,18 @@
|
|
|
275
279
|
border-right: none;
|
|
276
280
|
}
|
|
277
281
|
|
|
282
|
+
@keyframes ui-table-sticky-border-hide {
|
|
283
|
+
to {
|
|
284
|
+
border-right-width: 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.ui-table--bordered .ui-table__cell--fixed-left-last {
|
|
289
|
+
animation: ui-table-sticky-border-hide linear both;
|
|
290
|
+
animation-timeline: scroll(nearest x);
|
|
291
|
+
animation-range: 0px 1px;
|
|
292
|
+
}
|
|
293
|
+
|
|
278
294
|
/* With a scrollbar spacer present, the last real header column is second-to-last. */
|
|
279
295
|
.ui-table--bordered .ui-table__row--has-scrollbar .ui-table__cell:nth-last-child(2) {
|
|
280
296
|
border-right: none;
|
package/src/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export { default as WkInput } from './components/input/Input.vue'
|
|
|
20
20
|
export { default as WkInputNumber } from './components/input-number/InputNumber.vue'
|
|
21
21
|
export { default as WkMenu } from './components/menu/Menu.vue'
|
|
22
22
|
export { default as WkPagination } from './components/pagination/Pagination.vue'
|
|
23
|
+
export { default as WkProgress } from './components/progress/Progress.vue'
|
|
23
24
|
export { default as WkRadio } from './components/radio/Radio.vue'
|
|
24
25
|
export { default as WkRadioGroup } from './components/radio-group/RadioGroup.vue'
|
|
25
26
|
export { default as WkRichCheckboxGroup } from './components/rich-checkbox-group/RichCheckboxGroup.vue'
|
|
@@ -40,3 +41,7 @@ export { default as WkToggle } from './components/toggle/Toggle.vue'
|
|
|
40
41
|
export { default as WkToggleGroup } from './components/toggle-group/ToggleGroup.vue'
|
|
41
42
|
export { default as WkTooltip } from './components/tooltip/Tooltip.vue'
|
|
42
43
|
export { default as WkTypography } from './components/typography/Typography.vue'
|
|
44
|
+
export { default as WkDatePicker } from './components/date-picker/DatePicker.vue'
|
|
45
|
+
|
|
46
|
+
// Imperative singleton service (no SFC export — mounts its own container to body).
|
|
47
|
+
export { wkMessage } from './components/message/message.js'
|