webcake-ui-kit 1.1.33 → 1.1.35
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 +1 -1
- package/src/components/alert-dialog/AlertDialog.vue +15 -4
- package/src/components/badge/badge.css +16 -10
- package/src/components/button/Button.vue +2 -1
- package/src/components/button/button.css +21 -2
- package/src/components/button-group/button-group.css +4 -0
- package/src/components/date-picker/DatePicker.vue +10 -1
- package/src/components/date-picker/calendar.js +6 -1
- package/src/components/date-picker/time-panel.css +1 -1
- package/src/components/dialog/Dialog.vue +4 -2
- package/src/components/input/input.css +1 -0
- package/src/components/menu/menu.css +0 -1
- package/src/components/message/Message.vue +36 -13
- package/src/components/message/MessageContainer.vue +7 -1
- package/src/components/message/message.css +31 -1
- package/src/components/message/message.js +2 -0
- package/src/components/select/Select.vue +10 -2
- package/src/components/select-option/SelectOption.vue +4 -0
- package/src/components/slider/Slider.vue +9 -1
- package/src/components/slider/slider.css +14 -0
- package/src/components/toggle/toggle.css +8 -1
- package/src/components/tooltip/Tooltip.vue +75 -12
- package/src/components/date-picker/dayjs.js +0 -34
package/package.json
CHANGED
|
@@ -25,10 +25,21 @@
|
|
|
25
25
|
</div>
|
|
26
26
|
<template #footer>
|
|
27
27
|
<slot name="footer">
|
|
28
|
-
<Button
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
<Button
|
|
29
|
+
size="sm"
|
|
30
|
+
:variant="cancelVariant"
|
|
31
|
+
class="ui-alert-dialog-btn"
|
|
32
|
+
@click="handleCancel"
|
|
33
|
+
:label="cancelText"
|
|
34
|
+
/>
|
|
35
|
+
<Button
|
|
36
|
+
size="sm"
|
|
37
|
+
:variant="okVariant"
|
|
38
|
+
:loading="confirmLoading"
|
|
39
|
+
class="ui-alert-dialog-btn"
|
|
40
|
+
@click="handleOk"
|
|
41
|
+
:label="okText"
|
|
42
|
+
/>
|
|
32
43
|
</slot>
|
|
33
44
|
</template>
|
|
34
45
|
</Dialog>
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
font-weight: var(--paragraph-bold-font-weight);
|
|
12
12
|
white-space: nowrap;
|
|
13
13
|
transition: box-shadow 0.15s ease;
|
|
14
|
+
border-width: 1px;
|
|
15
|
+
border-style: solid;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
.ui-badge--round-default {
|
|
@@ -21,35 +23,39 @@
|
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
.ui-badge--primary {
|
|
24
|
-
background: var(--
|
|
25
|
-
color: var(--
|
|
26
|
+
background: var(--positive-subtle);
|
|
27
|
+
color: var(--primary-brand-fg);
|
|
28
|
+
border-color: var(--positive-border-subtle);
|
|
26
29
|
}
|
|
27
30
|
.ui-badge--secondary {
|
|
28
31
|
background: var(--secondary-bg);
|
|
29
32
|
color: var(--secondary-fg);
|
|
33
|
+
border: none;
|
|
30
34
|
}
|
|
31
35
|
.ui-badge--outline {
|
|
32
36
|
background: var(--outline);
|
|
33
37
|
color: var(--primary-fg);
|
|
34
|
-
border-width: 1px;
|
|
35
|
-
border-style: solid;
|
|
36
38
|
border-color: var(--border-primary);
|
|
37
39
|
}
|
|
38
40
|
.ui-badge--ghost {
|
|
39
41
|
background: var(--ghost);
|
|
40
42
|
color: var(--primary-fg);
|
|
43
|
+
border: none;
|
|
41
44
|
}
|
|
42
45
|
.ui-badge--destructive {
|
|
43
|
-
background: var(--destructive);
|
|
44
|
-
color: var(--destructive
|
|
46
|
+
background: var(--destructive-subtle);
|
|
47
|
+
color: var(--destructive);
|
|
48
|
+
border-color: var(--destructive-border-subtle);
|
|
45
49
|
}
|
|
46
50
|
.ui-badge--info {
|
|
47
|
-
background: var(--
|
|
48
|
-
color: var(--
|
|
51
|
+
background: var(--infor-subtle);
|
|
52
|
+
color: var(--infor);
|
|
53
|
+
border-color: var(--infor-border-subtle);
|
|
49
54
|
}
|
|
50
55
|
.ui-badge--warning {
|
|
51
|
-
background: var(--
|
|
52
|
-
color: var(--
|
|
56
|
+
background: var(--warning-subtle);
|
|
57
|
+
color: var(--warning);
|
|
58
|
+
border-color: var(--warning-border-subtle);
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
.ui-badge:focus-visible {
|
|
@@ -48,7 +48,8 @@ export default {
|
|
|
48
48
|
variant: {
|
|
49
49
|
type: String,
|
|
50
50
|
default: 'primary',
|
|
51
|
-
validator: v =>
|
|
51
|
+
validator: v =>
|
|
52
|
+
['primary', 'neutral', 'secondary', 'outline', 'ghost', 'destructive', 'link', 'ghost-destructive'].includes(v)
|
|
52
53
|
},
|
|
53
54
|
size: {
|
|
54
55
|
type: String,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
cursor: pointer;
|
|
10
10
|
font-family: var(--font-family-body);
|
|
11
11
|
font-weight: var(--paragraph-medium-font-weight);
|
|
12
|
+
justify-content: center;
|
|
12
13
|
text-align: center;
|
|
13
14
|
white-space: nowrap;
|
|
14
15
|
transition:
|
|
@@ -20,7 +21,6 @@
|
|
|
20
21
|
|
|
21
22
|
.ui-btn__label {
|
|
22
23
|
display: inline-flex;
|
|
23
|
-
flex: 1;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.ui-btn__icon {
|
|
@@ -218,6 +218,17 @@
|
|
|
218
218
|
background: var(--destructive-hover);
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/* ghost-destructive */
|
|
222
|
+
.ui-btn--ghost-destructive {
|
|
223
|
+
background: var(--ghost);
|
|
224
|
+
color: var(--destructive);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.ui-btn--ghost-destructive:hover,
|
|
228
|
+
.ui-btn--ghost-destructive:active {
|
|
229
|
+
background: var(--destructive-subtle);
|
|
230
|
+
}
|
|
231
|
+
|
|
221
232
|
/* Link — text-only button on transparent ghost bg, brand-colored. */
|
|
222
233
|
.ui-btn--link {
|
|
223
234
|
background: var(--ghost);
|
|
@@ -252,7 +263,8 @@
|
|
|
252
263
|
border-color: var(--border-focus);
|
|
253
264
|
}
|
|
254
265
|
|
|
255
|
-
.ui-btn--destructive:focus-visible
|
|
266
|
+
.ui-btn--destructive:focus-visible,
|
|
267
|
+
.ui-btn--ghost-destructive:focus-visible {
|
|
256
268
|
box-shadow: 0 0 0 3px var(--focus-ring-error);
|
|
257
269
|
}
|
|
258
270
|
|
|
@@ -265,6 +277,13 @@
|
|
|
265
277
|
pointer-events: none;
|
|
266
278
|
}
|
|
267
279
|
|
|
280
|
+
.ui-btn:not(.ui-btn--ghost):not(.ui-btn--link):disabled {
|
|
281
|
+
background: var(--muted-bg);
|
|
282
|
+
color: var(--muted-fg);
|
|
283
|
+
border: 1px solid var(--border-primary);
|
|
284
|
+
box-shadow: var(--shadow-xs);
|
|
285
|
+
}
|
|
286
|
+
|
|
268
287
|
/* ============================================================
|
|
269
288
|
Icon-only — square button, uniform padding per size.
|
|
270
289
|
Width = height; default slot content rendered in .ui-btn__icon
|
|
@@ -127,7 +127,16 @@
|
|
|
127
127
|
*/
|
|
128
128
|
import Menu from '../menu/Menu.vue'
|
|
129
129
|
import CalendarPanel from './CalendarPanel.vue'
|
|
130
|
-
import dayjs from '
|
|
130
|
+
import dayjs from 'dayjs'
|
|
131
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
|
132
|
+
import localeData from 'dayjs/plugin/localeData'
|
|
133
|
+
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
|
134
|
+
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
|
135
|
+
|
|
136
|
+
dayjs.extend(customParseFormat)
|
|
137
|
+
dayjs.extend(localeData)
|
|
138
|
+
dayjs.extend(isSameOrBefore)
|
|
139
|
+
dayjs.extend(isSameOrAfter)
|
|
131
140
|
import { ISO, toDayjs, toISO, isDateDisabled, weekdayLabels, buildDayMatrix, orderISO } from './calendar.js'
|
|
132
141
|
import { WkiCalendar, WkiX } from '../../icons'
|
|
133
142
|
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
// its selection as ISO strings internally (stable identity, no deep-reactive
|
|
7
7
|
// Day.js objects in `data`) and only converts to Date/formatted output at the
|
|
8
8
|
// component boundary.
|
|
9
|
-
import dayjs from '
|
|
9
|
+
import dayjs from 'dayjs'
|
|
10
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
|
11
|
+
import localeData from 'dayjs/plugin/localeData'
|
|
12
|
+
|
|
13
|
+
dayjs.extend(customParseFormat)
|
|
14
|
+
dayjs.extend(localeData)
|
|
10
15
|
|
|
11
16
|
export const ISO = 'YYYY-MM-DD'
|
|
12
17
|
|
|
@@ -81,8 +81,10 @@
|
|
|
81
81
|
>
|
|
82
82
|
<div class="ui-dialog-footer__inner">
|
|
83
83
|
<slot name="footer">
|
|
84
|
-
<Button :variant="cancelVariant" @click="handleCancel">{{ cancelText }}</Button>
|
|
85
|
-
<Button :variant="okVariant" :loading="confirmLoading" @click="handleOk">{{
|
|
84
|
+
<Button size="sm" :variant="cancelVariant" @click="handleCancel">{{ cancelText }}</Button>
|
|
85
|
+
<Button size="sm" :variant="okVariant" :loading="confirmLoading" @click="handleOk">{{
|
|
86
|
+
okText
|
|
87
|
+
}}</Button>
|
|
86
88
|
</slot>
|
|
87
89
|
</div>
|
|
88
90
|
</div>
|
|
@@ -1,25 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="ui-message" :class="`ui-message--${type}`" role="status" aria-live="polite">
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<
|
|
3
|
+
<div class="ui-message__row">
|
|
4
|
+
<div v-if="imgSrc" class="ui-message__file-upload__preview">
|
|
5
|
+
<img :src="imgSrc" alt="" />
|
|
6
|
+
</div>
|
|
7
|
+
<span v-else class="ui-message__icon">
|
|
8
|
+
<WkSpinner v-if="type === 'loading'" size="sm" />
|
|
9
|
+
<component :is="iconComponent" v-else :size="18" />
|
|
10
10
|
</span>
|
|
11
|
-
<
|
|
11
|
+
<div class="ui-message__wrapper">
|
|
12
|
+
<span class="ui-message__content">
|
|
13
|
+
<slot>{{ content }}</slot>
|
|
14
|
+
</span>
|
|
15
|
+
<span v-if="description" class="ui-message__description">{{ description }}</span>
|
|
16
|
+
</div>
|
|
17
|
+
<WkButton
|
|
18
|
+
v-if="action"
|
|
19
|
+
size="mini"
|
|
20
|
+
:variant="progress ? 'ghost' : action.variant || 'primary'"
|
|
21
|
+
@click="handleAction"
|
|
22
|
+
:label="action.label"
|
|
23
|
+
>
|
|
24
|
+
<template #icon>
|
|
25
|
+
<WkiPause />
|
|
26
|
+
</template>
|
|
27
|
+
</WkButton>
|
|
12
28
|
</div>
|
|
13
|
-
<
|
|
14
|
-
action.label
|
|
15
|
-
}}</WkButton>
|
|
29
|
+
<WkProgress v-if="progress !== null" :value="progress" />
|
|
16
30
|
</div>
|
|
17
31
|
</template>
|
|
18
32
|
|
|
19
33
|
<script>
|
|
20
34
|
import WkSpinner from '../spinner/Spinner.vue'
|
|
21
35
|
import WkButton from '../button/Button.vue'
|
|
22
|
-
import
|
|
36
|
+
import WkProgress from '../progress/Progress.vue'
|
|
37
|
+
import { WkiCircleCheck, WkiCircleX, WkiTriangleAlert, WkiInfo, WkiPause } from '../../icons'
|
|
23
38
|
|
|
24
39
|
const ICON_BY_TYPE = {
|
|
25
40
|
success: 'WkiCircleCheck',
|
|
@@ -30,7 +45,7 @@ const ICON_BY_TYPE = {
|
|
|
30
45
|
|
|
31
46
|
export default {
|
|
32
47
|
name: 'Message',
|
|
33
|
-
components: { WkSpinner, WkButton, WkiCircleCheck, WkiCircleX, WkiTriangleAlert, WkiInfo },
|
|
48
|
+
components: { WkSpinner, WkButton, WkProgress, WkiCircleCheck, WkiCircleX, WkiTriangleAlert, WkiInfo, WkiPause },
|
|
34
49
|
props: {
|
|
35
50
|
type: {
|
|
36
51
|
type: String,
|
|
@@ -50,6 +65,14 @@ export default {
|
|
|
50
65
|
action: {
|
|
51
66
|
type: Object,
|
|
52
67
|
default: null
|
|
68
|
+
},
|
|
69
|
+
progress: {
|
|
70
|
+
type: Number,
|
|
71
|
+
default: null
|
|
72
|
+
},
|
|
73
|
+
imgSrc: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: ''
|
|
53
76
|
}
|
|
54
77
|
},
|
|
55
78
|
emits: ['close'],
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
:content="item.content"
|
|
14
14
|
:description="item.description"
|
|
15
15
|
:action="item.action"
|
|
16
|
+
:progress="item.progress"
|
|
17
|
+
:img-src="item.imgSrc"
|
|
16
18
|
@close="remove(item.key)"
|
|
17
19
|
/>
|
|
18
20
|
</div>
|
|
@@ -145,7 +147,9 @@ export default {
|
|
|
145
147
|
existing.content = config.content != null ? config.content : ''
|
|
146
148
|
existing.description = config.description || null
|
|
147
149
|
existing.action = config.action || null
|
|
148
|
-
existing.
|
|
150
|
+
;((existing.progress = config.progress != null ? config.progress : null),
|
|
151
|
+
(existing.imgSrc = config.imgSrc),
|
|
152
|
+
(existing.onClose = config.onClose || null))
|
|
149
153
|
this.scheduleRemoval(key, config.duration)
|
|
150
154
|
return key
|
|
151
155
|
}
|
|
@@ -155,6 +159,8 @@ export default {
|
|
|
155
159
|
content: config.content != null ? config.content : '',
|
|
156
160
|
description: config.description || null,
|
|
157
161
|
action: config.action || null,
|
|
162
|
+
progress: config.progress != null ? config.progress : null,
|
|
163
|
+
imgSrc: config.imgSrc,
|
|
158
164
|
onClose: config.onClose || null
|
|
159
165
|
})
|
|
160
166
|
// Enforce maxCount by evicting the oldest entries.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
.ui-message {
|
|
2
2
|
pointer-events: auto;
|
|
3
3
|
display: inline-flex;
|
|
4
|
-
|
|
4
|
+
flex-direction: column;
|
|
5
5
|
gap: var(--spacing-sm);
|
|
6
6
|
max-width: 480px;
|
|
7
7
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
box-shadow: var(--shadow-sonner);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
.ui-message__row {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: var(--spacing-sm);
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
.ui-message__icon {
|
|
15
21
|
display: inline-flex;
|
|
16
22
|
align-items: center;
|
|
@@ -35,6 +41,9 @@
|
|
|
35
41
|
line-height: var(--paragraph-small-line-height);
|
|
36
42
|
letter-spacing: var(--paragraph-small-letter-spacing, 0);
|
|
37
43
|
word-break: break-word;
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
text-overflow: ellipsis;
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
.ui-message__description {
|
|
@@ -46,6 +55,27 @@
|
|
|
46
55
|
line-height: var(--paragraph-small-line-height);
|
|
47
56
|
letter-spacing: var(--paragraph-small-letter-spacing);
|
|
48
57
|
word-break: break-word;
|
|
58
|
+
-webkit-line-clamp: 2;
|
|
59
|
+
line-clamp: 2;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ui-message--file-upload {
|
|
64
|
+
width: 360px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ui-message__file-upload__preview {
|
|
68
|
+
width: 32px;
|
|
69
|
+
height: 32px;
|
|
70
|
+
border-radius: var(--rounded-sm);
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
flex-shrink: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ui-message__file-upload__preview img {
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
object-fit: cover;
|
|
49
79
|
}
|
|
50
80
|
|
|
51
81
|
.ui-message--success .ui-message__icon {
|
|
@@ -176,7 +176,7 @@ export default {
|
|
|
176
176
|
default: false
|
|
177
177
|
},
|
|
178
178
|
listHeight: {
|
|
179
|
-
type: Number,
|
|
179
|
+
type: [Number, String],
|
|
180
180
|
default: 256
|
|
181
181
|
},
|
|
182
182
|
mode: {
|
|
@@ -282,7 +282,8 @@ export default {
|
|
|
282
282
|
return !!((this.$scopedSlots && this.$scopedSlots['icon']) || this.$slots['icon'])
|
|
283
283
|
},
|
|
284
284
|
listStyle() {
|
|
285
|
-
return { maxHeight: this.listHeight + 'px' }
|
|
285
|
+
if (typeof this.listHeight === 'number') return { maxHeight: this.listHeight + 'px' }
|
|
286
|
+
return { maxHeight: this.listHeight }
|
|
286
287
|
},
|
|
287
288
|
externalClass() {
|
|
288
289
|
// Vue 3: class is in $attrs (inheritAttrs:false keeps it off the root)
|
|
@@ -423,9 +424,16 @@ export default {
|
|
|
423
424
|
}
|
|
424
425
|
},
|
|
425
426
|
registerOption(value, label) {
|
|
427
|
+
// Guard: SelectOption.updated() calls this on every re-render. Reassigning
|
|
428
|
+
// labelCache to a new object each time invalidates dependent computeds
|
|
429
|
+
// (selectedLabel, option.isHidden), forcing another render → updated() →
|
|
430
|
+
// registerOption → … an infinite loop that lags typing in searchable mode.
|
|
431
|
+
// Skip when the label is unchanged so the reference stays stable.
|
|
432
|
+
if (this.labelCache[value] === label) return
|
|
426
433
|
this.labelCache = Object.assign({}, this.labelCache, { [value]: label })
|
|
427
434
|
},
|
|
428
435
|
setSlotOptionVisible(value, visible) {
|
|
436
|
+
if (this.slotOptionVisible[value] === visible) return
|
|
429
437
|
this.slotOptionVisible = Object.assign({}, this.slotOptionVisible, { [value]: visible })
|
|
430
438
|
},
|
|
431
439
|
removeSlotOption(value) {
|
|
@@ -85,6 +85,10 @@ export default {
|
|
|
85
85
|
if (this.select) this.select.removeSlotOption(this.value)
|
|
86
86
|
},
|
|
87
87
|
|
|
88
|
+
// eslint-disable-next-line vue/no-deprecated-destroyed-lifecycle, vue/no-dupe-keys
|
|
89
|
+
beforeDestroy() {
|
|
90
|
+
if (this.select) this.select.removeSlotOption(this.value)
|
|
91
|
+
},
|
|
88
92
|
watch: {
|
|
89
93
|
isHidden(val) {
|
|
90
94
|
if (this.select) this.select.setSlotOptionVisible(this.value, !val)
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
:class="{
|
|
5
5
|
'ui-slider--vertical': orientation === 'vertical',
|
|
6
6
|
'ui-slider--disabled': disabled,
|
|
7
|
-
'ui-slider--range': range
|
|
7
|
+
'ui-slider--range': range,
|
|
8
|
+
[`ui-slider--${variant}`]: variant
|
|
8
9
|
}"
|
|
9
10
|
:style="rootStyle"
|
|
10
11
|
>
|
|
@@ -88,6 +89,13 @@ export default {
|
|
|
88
89
|
return ['horizontal', 'vertical'].indexOf(v) !== -1
|
|
89
90
|
}
|
|
90
91
|
},
|
|
92
|
+
variant: {
|
|
93
|
+
type: String,
|
|
94
|
+
default: 'neutral',
|
|
95
|
+
validator: function (v) {
|
|
96
|
+
return ['neutral', 'primary'].indexOf(v) !== -1
|
|
97
|
+
}
|
|
98
|
+
},
|
|
91
99
|
disabled: { type: Boolean, default: false },
|
|
92
100
|
width: { type: [String, Number], default: null },
|
|
93
101
|
stepRanges: {
|
|
@@ -45,6 +45,10 @@
|
|
|
45
45
|
pointer-events: none;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
.ui-slider--neutral .ui-slider__fill {
|
|
49
|
+
background: var(--primary-fg);
|
|
50
|
+
}
|
|
51
|
+
|
|
48
52
|
.ui-slider--vertical .ui-slider__fill {
|
|
49
53
|
top: auto;
|
|
50
54
|
left: 0;
|
|
@@ -67,6 +71,10 @@
|
|
|
67
71
|
transition: box-shadow 0.1s ease;
|
|
68
72
|
}
|
|
69
73
|
|
|
74
|
+
.ui-slider--neutral .ui-slider__thumb {
|
|
75
|
+
background: var(--primary-fg);
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
.ui-slider--vertical .ui-slider__thumb {
|
|
71
79
|
top: auto;
|
|
72
80
|
left: 50%;
|
|
@@ -79,6 +87,12 @@
|
|
|
79
87
|
0 0 0 5px color-mix(in srgb, var(--primary-brand-bg) 20%, transparent);
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
.ui-slider--neutral .ui-slider__thumb:hover {
|
|
91
|
+
box-shadow:
|
|
92
|
+
var(--shadow-xs),
|
|
93
|
+
0 0 0 5px color-mix(in srgb, var(--primary-fg) 20%, transparent);
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
.ui-slider__thumb:focus-visible {
|
|
83
97
|
box-shadow: var(--shadow-xs), var(--shadow-focus-ring);
|
|
84
98
|
}
|
|
@@ -132,7 +132,6 @@
|
|
|
132
132
|
}
|
|
133
133
|
.ui-toggle--variant-outlined.ui-toggle--active {
|
|
134
134
|
background: var(--outline-active);
|
|
135
|
-
color: var(--primary-fg);
|
|
136
135
|
}
|
|
137
136
|
|
|
138
137
|
/* ============================================================
|
|
@@ -165,6 +164,14 @@
|
|
|
165
164
|
pointer-events: none;
|
|
166
165
|
}
|
|
167
166
|
|
|
167
|
+
.ui-toggle--variant-outlined:disabled {
|
|
168
|
+
background: var(--secondary-bg);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.ui-toggle--variant-outlined.ui-toggle--active:disabled {
|
|
172
|
+
background: var(--tertiary-bg);
|
|
173
|
+
}
|
|
174
|
+
|
|
168
175
|
/* ============================================================
|
|
169
176
|
Icon-only — square button per size
|
|
170
177
|
============================================================ */
|
|
@@ -26,7 +26,12 @@
|
|
|
26
26
|
<span class="ui-tooltip__text">
|
|
27
27
|
<slot name="content">{{ title }}</slot>
|
|
28
28
|
</span>
|
|
29
|
-
<span
|
|
29
|
+
<span
|
|
30
|
+
v-if="arrow"
|
|
31
|
+
:class="['ui-tooltip__arrow', `ui-tooltip__arrow--${side}`]"
|
|
32
|
+
:style="arrowStyle"
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
></span>
|
|
30
35
|
</span>
|
|
31
36
|
</span>
|
|
32
37
|
</template>
|
|
@@ -36,6 +41,7 @@ import { acquire, release } from '../../floating/portal-root.js'
|
|
|
36
41
|
import { nextZIndex } from '../../floating/layer-manager.js'
|
|
37
42
|
|
|
38
43
|
const GAP = 4
|
|
44
|
+
const EDGE_PAD = 4
|
|
39
45
|
|
|
40
46
|
export default {
|
|
41
47
|
name: 'Tooltip',
|
|
@@ -61,12 +67,14 @@ export default {
|
|
|
61
67
|
data() {
|
|
62
68
|
return {
|
|
63
69
|
hovered: false,
|
|
64
|
-
|
|
70
|
+
triggerInView: true,
|
|
71
|
+
positionStyle: {},
|
|
72
|
+
arrowStyle: {}
|
|
65
73
|
}
|
|
66
74
|
},
|
|
67
75
|
computed: {
|
|
68
76
|
isVisible() {
|
|
69
|
-
return this.open || this.hovered
|
|
77
|
+
return (this.open || this.hovered) && this.triggerInView
|
|
70
78
|
},
|
|
71
79
|
hasMaxWidth() {
|
|
72
80
|
return this.maxWidth !== '' && this.maxWidth !== null && this.maxWidth !== undefined
|
|
@@ -81,22 +89,42 @@ export default {
|
|
|
81
89
|
},
|
|
82
90
|
watch: {
|
|
83
91
|
isVisible(v) {
|
|
84
|
-
if (v)
|
|
92
|
+
if (v) {
|
|
93
|
+
this.$nextTick(() => {
|
|
94
|
+
this._mountToPortal()
|
|
95
|
+
this.updatePosition()
|
|
96
|
+
})
|
|
97
|
+
} else {
|
|
98
|
+
this._unmountFromPortal()
|
|
99
|
+
}
|
|
85
100
|
},
|
|
86
101
|
side() {
|
|
87
102
|
if (this.isVisible) this.$nextTick(this.updatePosition)
|
|
88
103
|
}
|
|
89
104
|
},
|
|
90
105
|
mounted() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
const tip = this.$refs.tooltip
|
|
107
|
+
if (tip) {
|
|
108
|
+
this._originalParent = tip.parentNode
|
|
109
|
+
this._originalNextSibling = tip.nextSibling
|
|
110
|
+
}
|
|
111
|
+
if (typeof IntersectionObserver !== 'undefined' && this.$refs.trigger) {
|
|
112
|
+
this._triggerObserver = new IntersectionObserver(
|
|
113
|
+
([entry]) => {
|
|
114
|
+
this.triggerInView = entry.isIntersecting
|
|
115
|
+
},
|
|
116
|
+
{ threshold: 0 }
|
|
117
|
+
)
|
|
118
|
+
this._triggerObserver.observe(this.$refs.trigger)
|
|
96
119
|
}
|
|
97
120
|
window.addEventListener('scroll', this.onScrollOrResize, true)
|
|
98
121
|
window.addEventListener('resize', this.onScrollOrResize)
|
|
99
|
-
if (this.open)
|
|
122
|
+
if (this.open) {
|
|
123
|
+
this.$nextTick(() => {
|
|
124
|
+
this._mountToPortal()
|
|
125
|
+
this.updatePosition()
|
|
126
|
+
})
|
|
127
|
+
}
|
|
100
128
|
if (typeof this.$on === 'function') {
|
|
101
129
|
// eslint-disable-next-line vue/no-deprecated-events-api
|
|
102
130
|
this.$on('hook:beforeDestroy', this.cleanup)
|
|
@@ -141,6 +169,17 @@ export default {
|
|
|
141
169
|
top = t.top + (t.height - th) / 2
|
|
142
170
|
left = t.right + GAP
|
|
143
171
|
}
|
|
172
|
+
const vw = window.innerWidth
|
|
173
|
+
const vh = window.innerHeight
|
|
174
|
+
left = Math.max(EDGE_PAD, Math.min(left, vw - tw - EDGE_PAD))
|
|
175
|
+
top = Math.max(EDGE_PAD, Math.min(top, vh - th - EDGE_PAD))
|
|
176
|
+
|
|
177
|
+
if (this.side === 'top' || this.side === 'bottom') {
|
|
178
|
+
this.arrowStyle = { left: t.left + t.width / 2 - left + 'px' }
|
|
179
|
+
} else {
|
|
180
|
+
this.arrowStyle = { top: t.top + t.height / 2 - top + 'px' }
|
|
181
|
+
}
|
|
182
|
+
|
|
144
183
|
this.positionStyle = {
|
|
145
184
|
position: 'fixed',
|
|
146
185
|
top: top + 'px',
|
|
@@ -148,11 +187,35 @@ export default {
|
|
|
148
187
|
zIndex: nextZIndex()
|
|
149
188
|
}
|
|
150
189
|
},
|
|
190
|
+
_mountToPortal() {
|
|
191
|
+
const tip = this.$refs.tooltip
|
|
192
|
+
if (typeof document === 'undefined' || !tip) return
|
|
193
|
+
if (!this._tooltipPortalRoot) {
|
|
194
|
+
this._tooltipPortalRoot = acquire()
|
|
195
|
+
}
|
|
196
|
+
if (this._tooltipPortalRoot && tip.parentNode !== this._tooltipPortalRoot) {
|
|
197
|
+
this._tooltipPortalRoot.appendChild(tip)
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
_unmountFromPortal() {
|
|
201
|
+
const tip = this.$refs.tooltip
|
|
202
|
+
if (!tip || !this._tooltipPortalRoot) return
|
|
203
|
+
if (tip.parentNode === this._tooltipPortalRoot && this._originalParent) {
|
|
204
|
+
this._originalParent.insertBefore(tip, this._originalNextSibling || null)
|
|
205
|
+
}
|
|
206
|
+
release()
|
|
207
|
+
this._tooltipPortalRoot = null
|
|
208
|
+
},
|
|
151
209
|
cleanup() {
|
|
210
|
+
if (this._triggerObserver) {
|
|
211
|
+
this._triggerObserver.disconnect()
|
|
212
|
+
this._triggerObserver = null
|
|
213
|
+
}
|
|
152
214
|
window.removeEventListener('scroll', this.onScrollOrResize, true)
|
|
153
215
|
window.removeEventListener('resize', this.onScrollOrResize)
|
|
154
|
-
|
|
155
|
-
|
|
216
|
+
const tip = this.$refs.tooltip
|
|
217
|
+
if (tip && tip.parentNode && tip.parentNode !== this._originalParent) {
|
|
218
|
+
tip.parentNode.removeChild(tip)
|
|
156
219
|
}
|
|
157
220
|
if (this._tooltipPortalRoot) {
|
|
158
221
|
release()
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Configured Day.js singleton for the date-picker.
|
|
2
|
-
//
|
|
3
|
-
// Day.js ships as a tiny core; every feature the picker needs (custom format
|
|
4
|
-
// parsing, locale-aware week start, week/quarter numbers, inclusive comparisons)
|
|
5
|
-
// lives in an opt-in plugin. We register them ONCE here and re-export the same
|
|
6
|
-
// instance so every date-picker file shares one configured dayjs — importing
|
|
7
|
-
// `dayjs` directly elsewhere would get the unconfigured core.
|
|
8
|
-
//
|
|
9
|
-
// `dayjs.extend` is idempotent (re-extending with the same plugin is a no-op),
|
|
10
|
-
// so this module is safe to import from multiple files under both the Vite
|
|
11
|
-
// (Vue 3) and webpack (Vue 2) bundlers.
|
|
12
|
-
import dayjs from 'dayjs'
|
|
13
|
-
|
|
14
|
-
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
|
|
15
|
-
import localeData from 'dayjs/plugin/localeData.js'
|
|
16
|
-
import weekday from 'dayjs/plugin/weekday.js'
|
|
17
|
-
import weekOfYear from 'dayjs/plugin/weekOfYear.js'
|
|
18
|
-
import isoWeek from 'dayjs/plugin/isoWeek.js'
|
|
19
|
-
import advancedFormat from 'dayjs/plugin/advancedFormat.js'
|
|
20
|
-
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js'
|
|
21
|
-
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js'
|
|
22
|
-
import quarterOfYear from 'dayjs/plugin/quarterOfYear.js'
|
|
23
|
-
|
|
24
|
-
dayjs.extend(customParseFormat)
|
|
25
|
-
dayjs.extend(localeData)
|
|
26
|
-
dayjs.extend(weekday)
|
|
27
|
-
dayjs.extend(weekOfYear)
|
|
28
|
-
dayjs.extend(isoWeek)
|
|
29
|
-
dayjs.extend(advancedFormat)
|
|
30
|
-
dayjs.extend(isSameOrBefore)
|
|
31
|
-
dayjs.extend(isSameOrAfter)
|
|
32
|
-
dayjs.extend(quarterOfYear)
|
|
33
|
-
|
|
34
|
-
export default dayjs
|