@ditojs/ui 3.2.0 → 3.3.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/dist/dito-ui.css +1 -1
- package/dist/dito-ui.es.js +1350 -3294
- package/dist/dito-ui.umd.js +1 -7
- package/package.json +15 -9
- package/src/components/DitoButton.vue +91 -16
- package/src/components/DitoCalendar.vue +318 -248
- package/src/components/DitoDatePicker.vue +36 -147
- package/src/components/DitoDateTimePicker.vue +75 -181
- package/src/components/DitoInput.vue +5 -3
- package/src/components/DitoMenuButton.vue +226 -0
- package/src/components/DitoPagination.vue +9 -3
- package/src/components/DitoPickerInput.vue +285 -0
- package/src/components/DitoSwitch.vue +4 -6
- package/src/components/DitoTimePanel.vue +264 -0
- package/src/components/DitoTimePicker.vue +47 -454
- package/src/components/DitoTrigger.vue +293 -97
- package/src/components/index.js +1 -0
- package/src/styles/components/_button.scss +7 -9
- package/src/styles/components/_resize.scss +8 -0
- package/src/styles/mixins/_input.scss +6 -0
- package/src/utils/button.js +24 -0
- package/src/utils/date.js +18 -0
- package/src/utils/event.js +18 -9
- package/src/utils/index.js +1 -0
- package/src/utils/time.js +107 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
DitoTrigger.dito-menu-button(
|
|
3
|
+
v-model:show="isOpen"
|
|
4
|
+
trigger="click"
|
|
5
|
+
:placement="placement"
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
:matchTargetWidth="false"
|
|
8
|
+
:cover="cover"
|
|
9
|
+
:transition="null"
|
|
10
|
+
:class=`{
|
|
11
|
+
'dito-menu-button--open': isOpen,
|
|
12
|
+
'dito-menu-button--offset': offset
|
|
13
|
+
}`
|
|
14
|
+
)
|
|
15
|
+
template(#trigger)
|
|
16
|
+
DitoButton(
|
|
17
|
+
ref="button"
|
|
18
|
+
aria-haspopup="menu"
|
|
19
|
+
:aria-expanded="isOpen ? 'true' : 'false'"
|
|
20
|
+
:disabled="disabled"
|
|
21
|
+
v-bind="$attrs"
|
|
22
|
+
@keydown="onButtonKeyDown"
|
|
23
|
+
@keyup="onKeyUp"
|
|
24
|
+
)
|
|
25
|
+
slot
|
|
26
|
+
template(#popup)
|
|
27
|
+
ul.dito-menu-button__menu(
|
|
28
|
+
role="menu"
|
|
29
|
+
@keydown="onMenuKeyDown"
|
|
30
|
+
@keyup="onKeyUp"
|
|
31
|
+
)
|
|
32
|
+
li(
|
|
33
|
+
v-for="item in items"
|
|
34
|
+
:key="item.value"
|
|
35
|
+
role="none"
|
|
36
|
+
)
|
|
37
|
+
button.dito-menu-button__item(
|
|
38
|
+
:ref="element => setItemElement(item, element)"
|
|
39
|
+
type="button"
|
|
40
|
+
role="menuitem"
|
|
41
|
+
tabindex="-1"
|
|
42
|
+
:aria-disabled="item.disabled ? 'true' : null"
|
|
43
|
+
:class="{ 'dito-menu-button__item--disabled': item.disabled }"
|
|
44
|
+
@click="selectItem(item)"
|
|
45
|
+
) {{ item.label }}
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
import DitoTrigger from './DitoTrigger.vue'
|
|
50
|
+
import DitoButton from './DitoButton.vue'
|
|
51
|
+
|
|
52
|
+
// A button that opens a menu of `items`, each `{ value, label, disabled }`,
|
|
53
|
+
// and emits `select` with the item that is chosen, by mouse or keyboard.
|
|
54
|
+
// Attributes, e.g. `class` or the `verb` and `text` of `DitoButton`, go to the
|
|
55
|
+
// button, its content to the default slot.
|
|
56
|
+
export default {
|
|
57
|
+
components: { DitoTrigger, DitoButton },
|
|
58
|
+
inheritAttrs: false,
|
|
59
|
+
emits: ['select'],
|
|
60
|
+
|
|
61
|
+
props: {
|
|
62
|
+
items: { type: Array, required: true },
|
|
63
|
+
placement: { type: String, default: 'bottom' },
|
|
64
|
+
// Whether the menu opens over the button, like native menus do.
|
|
65
|
+
cover: { type: Boolean, default: true },
|
|
66
|
+
// Whether the menu opens one item padding below the top of the button,
|
|
67
|
+
// e.g. to line up with text inside a taller button.
|
|
68
|
+
offset: { type: Boolean, default: false },
|
|
69
|
+
disabled: { type: Boolean, default: false }
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
data() {
|
|
73
|
+
return {
|
|
74
|
+
isOpen: false
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
created() {
|
|
79
|
+
// The elements of the rendered items, by item.
|
|
80
|
+
this.itemElements = new Map()
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
methods: {
|
|
84
|
+
setItemElement(item, element) {
|
|
85
|
+
if (element) {
|
|
86
|
+
this.itemElements.set(item, element)
|
|
87
|
+
} else {
|
|
88
|
+
this.itemElements.delete(item)
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
getFocusedItemIndex() {
|
|
93
|
+
return this.items.findIndex(
|
|
94
|
+
item => this.itemElements.get(item) === document.activeElement
|
|
95
|
+
)
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
focusItemAt(index) {
|
|
99
|
+
this.itemElements.get(this.items[index])?.focus()
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async open(focusIndex) {
|
|
103
|
+
this.isOpen = true
|
|
104
|
+
// Wait for the menu to be rendered, so its items can be focused.
|
|
105
|
+
await this.$nextTick()
|
|
106
|
+
this.focusItemAt(focusIndex)
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
close() {
|
|
110
|
+
this.isOpen = false
|
|
111
|
+
this.focusButton()
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
focusButton() {
|
|
115
|
+
this.$refs.button.$el.focus()
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
selectItem(item) {
|
|
119
|
+
if (!item.disabled) {
|
|
120
|
+
this.close()
|
|
121
|
+
this.$emit('select', item)
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
onButtonKeyDown(event) {
|
|
126
|
+
const { key } = event
|
|
127
|
+
if (key === 'Enter' || key === ' ' || key === 'ArrowDown') {
|
|
128
|
+
event.preventDefault()
|
|
129
|
+
this.open(0)
|
|
130
|
+
} else if (key === 'ArrowUp') {
|
|
131
|
+
event.preventDefault()
|
|
132
|
+
this.open(this.items.length - 1)
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
onMenuKeyDown(event) {
|
|
137
|
+
const { key } = event
|
|
138
|
+
const count = this.items.length
|
|
139
|
+
const index = this.getFocusedItemIndex()
|
|
140
|
+
if (key === 'Escape') {
|
|
141
|
+
// `DitoTrigger` closes the menu, return the focus to the button.
|
|
142
|
+
this.focusButton()
|
|
143
|
+
} else if (key === 'Enter' || key === ' ') {
|
|
144
|
+
event.preventDefault()
|
|
145
|
+
const item = this.items[index]
|
|
146
|
+
if (item) {
|
|
147
|
+
this.selectItem(item)
|
|
148
|
+
}
|
|
149
|
+
} else if (key === 'Tab') {
|
|
150
|
+
// Let the focus move on as usual, but close the menu.
|
|
151
|
+
this.isOpen = false
|
|
152
|
+
} else {
|
|
153
|
+
const targetIndex = {
|
|
154
|
+
ArrowDown: (index + 1) % count,
|
|
155
|
+
ArrowUp: (index - 1 + count) % count,
|
|
156
|
+
Home: 0,
|
|
157
|
+
End: count - 1
|
|
158
|
+
}[key]
|
|
159
|
+
if (targetIndex !== undefined) {
|
|
160
|
+
event.preventDefault()
|
|
161
|
+
this.focusItemAt(targetIndex)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
onKeyUp(event) {
|
|
167
|
+
// Firefox clicks buttons on the keyup of Space even if its keydown was
|
|
168
|
+
// prevented, which would toggle the menu again or select an item, see
|
|
169
|
+
// `onButtonKeyDown()` and `onMenuKeyDown()`.
|
|
170
|
+
if (event.key === ' ') {
|
|
171
|
+
event.preventDefault()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<style lang="scss">
|
|
179
|
+
@import '../styles/_imports';
|
|
180
|
+
|
|
181
|
+
$menu-button-radius: 0.5em;
|
|
182
|
+
$menu-button-padding-ver: 0.5em;
|
|
183
|
+
$menu-button-padding: $menu-button-padding-ver 1em;
|
|
184
|
+
|
|
185
|
+
.dito-menu-button {
|
|
186
|
+
display: inline-block;
|
|
187
|
+
|
|
188
|
+
&__menu {
|
|
189
|
+
margin: 0;
|
|
190
|
+
padding: 0;
|
|
191
|
+
list-style: none;
|
|
192
|
+
border-radius: $menu-button-radius;
|
|
193
|
+
box-shadow: $shadow-window;
|
|
194
|
+
overflow: hidden;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&--offset &__menu {
|
|
198
|
+
margin-top: $menu-button-padding-ver;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
&__item {
|
|
202
|
+
display: block;
|
|
203
|
+
width: 100%;
|
|
204
|
+
padding: $menu-button-padding;
|
|
205
|
+
border: 0;
|
|
206
|
+
font: inherit;
|
|
207
|
+
line-height: 1;
|
|
208
|
+
text-align: left;
|
|
209
|
+
white-space: nowrap;
|
|
210
|
+
color: inherit;
|
|
211
|
+
background: $button-color;
|
|
212
|
+
@include user-select(none);
|
|
213
|
+
|
|
214
|
+
&--disabled {
|
|
215
|
+
color: $color-disabled;
|
|
216
|
+
cursor: default;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
&:not(&--disabled):is(:hover, :focus-visible) {
|
|
220
|
+
background: $color-active;
|
|
221
|
+
color: $color-white;
|
|
222
|
+
outline: none;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
</style>
|
|
@@ -10,8 +10,9 @@ nav.dito-pagination(aria-label="Pagination")
|
|
|
10
10
|
.dito-buttons.dito-buttons--round(
|
|
11
11
|
v-if="numPages > 1"
|
|
12
12
|
)
|
|
13
|
-
|
|
13
|
+
DitoButton(
|
|
14
14
|
v-for="button in buttons"
|
|
15
|
+
:key="button.type || button.index"
|
|
15
16
|
:class="getButtonClasses(button)"
|
|
16
17
|
:disabled="button.disabled"
|
|
17
18
|
:aria-label="getButtonLabel(button)"
|
|
@@ -24,7 +25,10 @@ nav.dito-pagination(aria-label="Pagination")
|
|
|
24
25
|
</template>
|
|
25
26
|
|
|
26
27
|
<script>
|
|
28
|
+
import DitoButton from './DitoButton.vue'
|
|
29
|
+
|
|
27
30
|
export default {
|
|
31
|
+
components: { DitoButton },
|
|
28
32
|
emits: ['update:page'],
|
|
29
33
|
|
|
30
34
|
props: {
|
|
@@ -120,8 +124,10 @@ export default {
|
|
|
120
124
|
},
|
|
121
125
|
|
|
122
126
|
pageSize() {
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
// Without items there are no pages, but page 1 remains valid.
|
|
128
|
+
const lastPage = Math.max(1, this.numPages)
|
|
129
|
+
if (this.currentPage > lastPage) {
|
|
130
|
+
this.currentPage = lastPage
|
|
125
131
|
}
|
|
126
132
|
},
|
|
127
133
|
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
DitoTrigger.dito-picker-input(
|
|
3
|
+
ref="trigger"
|
|
4
|
+
trigger="focus"
|
|
5
|
+
v-bind="{ show, transition, placement, disabled, target }"
|
|
6
|
+
@update:show="onUpdateShow"
|
|
7
|
+
)
|
|
8
|
+
template(#trigger)
|
|
9
|
+
slot(
|
|
10
|
+
v-if="$slots.trigger"
|
|
11
|
+
name="trigger"
|
|
12
|
+
)
|
|
13
|
+
DitoInput(
|
|
14
|
+
v-else
|
|
15
|
+
ref="input"
|
|
16
|
+
v-model="currentText"
|
|
17
|
+
type="text"
|
|
18
|
+
:class="inputClass"
|
|
19
|
+
v-bind="{ placeholder, disabled, focused: isFocused, ...inputAttributes }"
|
|
20
|
+
@focus="onInputFocus"
|
|
21
|
+
@blur="isInputFocused = false"
|
|
22
|
+
@click="onInputClick"
|
|
23
|
+
@keydown="onInputKeyDown"
|
|
24
|
+
@keyup="updateCaretPart"
|
|
25
|
+
)
|
|
26
|
+
template(#prefix)
|
|
27
|
+
slot(name="prefix")
|
|
28
|
+
template(#suffix)
|
|
29
|
+
button.dito-picker-input__toggle(
|
|
30
|
+
type="button"
|
|
31
|
+
:aria-label="toggleLabel"
|
|
32
|
+
aria-haspopup="dialog"
|
|
33
|
+
:aria-expanded="isPopupShown ? 'true' : 'false'"
|
|
34
|
+
:disabled="disabled"
|
|
35
|
+
@mousedown.stop.prevent
|
|
36
|
+
@click="onToggleClick"
|
|
37
|
+
)
|
|
38
|
+
DitoIcon(
|
|
39
|
+
:name="icon"
|
|
40
|
+
:disabled="disabled"
|
|
41
|
+
)
|
|
42
|
+
slot(name="suffix")
|
|
43
|
+
template(#popup)
|
|
44
|
+
slot(
|
|
45
|
+
name="popup"
|
|
46
|
+
:value="currentValue"
|
|
47
|
+
:setValue="setValue"
|
|
48
|
+
:close="close"
|
|
49
|
+
)
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
import { format } from '@ditojs/utils'
|
|
54
|
+
import DitoTrigger from './DitoTrigger.vue'
|
|
55
|
+
import DitoInput from './DitoInput.vue'
|
|
56
|
+
import DitoIcon from './DitoIcon.vue'
|
|
57
|
+
import { parseDate, getDatePartAtPosition } from '../utils/date.js'
|
|
58
|
+
import { getSelection, setSelection } from '../utils/selection.js'
|
|
59
|
+
import { getKeyNavigation } from '../utils/event.js'
|
|
60
|
+
import { isTimePartName, editTimeText } from '../utils/time.js'
|
|
61
|
+
|
|
62
|
+
// The input of the date and time pickers, with the icon button that toggles
|
|
63
|
+
// their popup. It owns the picked value, the text that represents it and the
|
|
64
|
+
// focus state of input and popup together. The popup's panel is rendered
|
|
65
|
+
// through the `popup` slot, and navigated with the keyboard through
|
|
66
|
+
// `handlePanelKey()`.
|
|
67
|
+
export default {
|
|
68
|
+
components: { DitoTrigger, DitoInput, DitoIcon },
|
|
69
|
+
emits: [
|
|
70
|
+
'update:modelValue',
|
|
71
|
+
'update:show',
|
|
72
|
+
'change',
|
|
73
|
+
'focus',
|
|
74
|
+
'blur',
|
|
75
|
+
'caretPartChange'
|
|
76
|
+
],
|
|
77
|
+
|
|
78
|
+
props: {
|
|
79
|
+
modelValue: { type: Date, default: null },
|
|
80
|
+
formatOptions: { type: Object, required: true },
|
|
81
|
+
icon: { type: String, required: true },
|
|
82
|
+
toggleLabel: { type: String, required: true },
|
|
83
|
+
placeholder: { type: String, default: null },
|
|
84
|
+
show: { type: Boolean, default: false },
|
|
85
|
+
disabled: { type: Boolean, default: false },
|
|
86
|
+
transition: { type: String, default: 'slide' },
|
|
87
|
+
placement: { type: String, default: 'bottom-left' },
|
|
88
|
+
target: { type: [String, HTMLElement], default: 'trigger' },
|
|
89
|
+
inputClass: { type: String, default: null },
|
|
90
|
+
// The attributes and listeners of the native input.
|
|
91
|
+
inputAttributes: { type: Object, default: () => ({}) },
|
|
92
|
+
// Values that can't be picked, also not by typing them.
|
|
93
|
+
isValueDisabled: { type: Function, default: () => false },
|
|
94
|
+
// Called with the keydown event of the input and the date part at the
|
|
95
|
+
// caret, returning whether the panel handled it.
|
|
96
|
+
handlePanelKey: { type: Function, default: () => false }
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
data() {
|
|
100
|
+
return {
|
|
101
|
+
currentValue: this.modelValue,
|
|
102
|
+
isPopupShown: this.show,
|
|
103
|
+
isInputFocused: false,
|
|
104
|
+
caretPartName: null
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
computed: {
|
|
109
|
+
isFocused() {
|
|
110
|
+
return this.isInputFocused || this.isPopupShown
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
currentText: {
|
|
114
|
+
get() {
|
|
115
|
+
return format(this.currentValue, this.formatOptions) || ''
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
set(text) {
|
|
119
|
+
const date = parseDate(text, this.formatOptions)
|
|
120
|
+
if (date) {
|
|
121
|
+
// Keep the caret in place while the text is replaced with the one
|
|
122
|
+
// of the new value.
|
|
123
|
+
const input = this.getInputElement()
|
|
124
|
+
const selection = getSelection(input)
|
|
125
|
+
if (this.setValue(date) && selection) {
|
|
126
|
+
this.$nextTick(() => setSelection(input, selection))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
watch: {
|
|
134
|
+
modelValue(to, from) {
|
|
135
|
+
if (+to !== +from) {
|
|
136
|
+
this.currentValue = to
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
isFocused(to, from) {
|
|
141
|
+
if (to ^ from) {
|
|
142
|
+
this.$emit(to ? 'focus' : 'blur')
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
methods: {
|
|
148
|
+
getInputElement() {
|
|
149
|
+
return this.$refs.input?.input ?? null
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// All changes of the value go through here, so disabled values are never
|
|
153
|
+
// set. Returns whether the value was set.
|
|
154
|
+
setValue(value) {
|
|
155
|
+
if (value && this.isValueDisabled(value)) {
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
if (+value !== +this.currentValue) {
|
|
159
|
+
this.currentValue = value
|
|
160
|
+
if (+value !== +this.modelValue) {
|
|
161
|
+
this.$emit('update:modelValue', value)
|
|
162
|
+
this.$emit('change', value)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
open() {
|
|
169
|
+
this.$refs.trigger.open()
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
close() {
|
|
173
|
+
this.$refs.trigger.close()
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
focus() {
|
|
177
|
+
this.$refs.input?.focus()
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
blur() {
|
|
181
|
+
this.$refs.input?.blur()
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
getCaretPart() {
|
|
185
|
+
const position = getSelection(this.getInputElement())?.start
|
|
186
|
+
return position != null
|
|
187
|
+
? getDatePartAtPosition(this.currentText, position, this.formatOptions)
|
|
188
|
+
: null
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
updateCaretPart() {
|
|
192
|
+
const name = this.getCaretPart()?.name ?? null
|
|
193
|
+
if (name !== this.caretPartName) {
|
|
194
|
+
this.caretPartName = name
|
|
195
|
+
this.$emit('caretPartChange', name)
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
onUpdateShow(show) {
|
|
200
|
+
// `DitoTrigger` owns the popup's state, this only mirrors it.
|
|
201
|
+
this.isPopupShown = show
|
|
202
|
+
this.$emit('update:show', show)
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
onInputFocus() {
|
|
206
|
+
this.isInputFocused = true
|
|
207
|
+
this.updateCaretPart()
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
onInputClick() {
|
|
211
|
+
this.updateCaretPart()
|
|
212
|
+
// Reopen the popup when clicking into the focused input after it was
|
|
213
|
+
// closed, e.g. with Escape.
|
|
214
|
+
this.open()
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
onToggleClick() {
|
|
218
|
+
if (this.isPopupShown) {
|
|
219
|
+
this.close()
|
|
220
|
+
} else {
|
|
221
|
+
this.open()
|
|
222
|
+
this.focus()
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
onInputKeyDown(event) {
|
|
227
|
+
const { ver: step, enter } = getKeyNavigation(event)
|
|
228
|
+
const part = this.getCaretPart()
|
|
229
|
+
if (step || enter) {
|
|
230
|
+
event.preventDefault()
|
|
231
|
+
if (!this.isPopupShown) {
|
|
232
|
+
if (step) {
|
|
233
|
+
this.open()
|
|
234
|
+
}
|
|
235
|
+
} else if (this.handlePanelKey(event, part) && part) {
|
|
236
|
+
// Select the changed part again, once the text was updated.
|
|
237
|
+
const input = this.getInputElement()
|
|
238
|
+
this.$nextTick(() => {
|
|
239
|
+
const changedPart = getDatePartAtPosition(
|
|
240
|
+
this.currentText,
|
|
241
|
+
part.start,
|
|
242
|
+
this.formatOptions
|
|
243
|
+
)
|
|
244
|
+
if (changedPart) {
|
|
245
|
+
setSelection(input, changedPart)
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
} else if (isTimePartName(part?.name)) {
|
|
250
|
+
editTimeText(event, this.getInputElement(), this.currentText.length)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
</script>
|
|
256
|
+
|
|
257
|
+
<style lang="scss">
|
|
258
|
+
@import '../styles/_imports';
|
|
259
|
+
|
|
260
|
+
.dito-picker-input {
|
|
261
|
+
.dito-input {
|
|
262
|
+
font-variant-numeric: tabular-nums;
|
|
263
|
+
width: 100%;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
&__toggle {
|
|
267
|
+
display: flex;
|
|
268
|
+
padding: 0;
|
|
269
|
+
border: 0;
|
|
270
|
+
border-radius: $border-radius;
|
|
271
|
+
font: inherit;
|
|
272
|
+
color: inherit;
|
|
273
|
+
background: none;
|
|
274
|
+
|
|
275
|
+
&:disabled {
|
|
276
|
+
cursor: default;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
&:focus-visible {
|
|
280
|
+
outline: none;
|
|
281
|
+
box-shadow: $shadow-focus;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
</style>
|
|
@@ -62,8 +62,8 @@ export default {
|
|
|
62
62
|
|
|
63
63
|
styles() {
|
|
64
64
|
const { labels: { checked, unchecked } = {} } = this
|
|
65
|
-
// Calculate `--switch-width` in `rem`, based on
|
|
66
|
-
const length = Math.max(
|
|
65
|
+
// Calculate `--switch-width` in `rem`, based on the given labels' length.
|
|
66
|
+
const length = Math.max(checked?.length ?? 0, unchecked?.length ?? 0)
|
|
67
67
|
return {
|
|
68
68
|
'--switch-width': length ? `${length * 1.5}rem` : null
|
|
69
69
|
}
|
|
@@ -191,10 +191,8 @@ export default {
|
|
|
191
191
|
@extend %button-disabled;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
box-shadow: $shadow-focus;
|
|
197
|
-
}
|
|
194
|
+
input:focus-visible + #{$self}__button {
|
|
195
|
+
box-shadow: $shadow-focus;
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
198
|
</style>
|