@saasmakers/ui 2.1.5 → 2.1.6
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.
|
@@ -48,7 +48,7 @@ const input = ref<HTMLInputElement>()
|
|
|
48
48
|
const showPassword = ref(false)
|
|
49
49
|
const { isDesktopBrowser } = useDevice()
|
|
50
50
|
|
|
51
|
-
const { isTypingOnIos, onBlur: onIosUppercaseBlur, onFocus: onIosUppercaseFocus,
|
|
51
|
+
const { isActiveOnIos, isTypingOnIos, onBlur: onIosUppercaseBlur, onCompositionEnd: onIosUppercaseCompositionEnd, onFocus: onIosUppercaseFocus, onInput: onIosUppercaseInput } = useIosUppercase({
|
|
52
52
|
enabled: () => {
|
|
53
53
|
const isProseField = props.type === 'text' || props.type === 'search'
|
|
54
54
|
|
|
@@ -92,6 +92,7 @@ function onFieldFocus(event: FocusEvent) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function onFieldInput(event: Event) {
|
|
95
|
+
onIosUppercaseInput(event)
|
|
95
96
|
syncModelValueFromTarget(event.target)
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -204,7 +205,7 @@ defineExpose({
|
|
|
204
205
|
:id="id"
|
|
205
206
|
ref="input"
|
|
206
207
|
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
207
|
-
:autocapitalize="
|
|
208
|
+
:autocapitalize="isActiveOnIos ? 'characters' : undefined"
|
|
208
209
|
v-bind="autofocus ? { 'data-autofocus': '' } : {}"
|
|
209
210
|
class="h-full w-full appearance-none items-center rounded-lg font-medium tracking-tight outline-none placeholder-gray-600 dark:placeholder-gray-400"
|
|
210
211
|
:class="{
|
|
@@ -244,6 +245,7 @@ defineExpose({
|
|
|
244
245
|
:type="type === 'password' && showPassword ? 'text' : type"
|
|
245
246
|
:value="modelValue"
|
|
246
247
|
@blur="onFieldBlur"
|
|
248
|
+
@compositionend="onIosUppercaseCompositionEnd"
|
|
247
249
|
@focus="onFieldFocus"
|
|
248
250
|
@input="onFieldInput"
|
|
249
251
|
@keydown="onFieldKeyDown"
|
|
@@ -32,7 +32,7 @@ const modelValue = defineModel<FieldTextarea['modelValue']>({ default: '' })
|
|
|
32
32
|
const textarea = ref<HTMLTextAreaElement>()
|
|
33
33
|
const { isDesktopBrowser } = useDevice()
|
|
34
34
|
|
|
35
|
-
const { isTypingOnIos, onBlur: onIosUppercaseBlur, onFocus: onIosUppercaseFocus,
|
|
35
|
+
const { isActiveOnIos, isTypingOnIos, onBlur: onIosUppercaseBlur, onCompositionEnd: onIosUppercaseCompositionEnd, onFocus: onIosUppercaseFocus, onInput: onIosUppercaseInput } = useIosUppercase({
|
|
36
36
|
enabled: () => props.uppercase,
|
|
37
37
|
modelValue,
|
|
38
38
|
})
|
|
@@ -83,7 +83,7 @@ function syncModelValueFromTarget(target: EventTarget | null) {
|
|
|
83
83
|
ref="textarea"
|
|
84
84
|
v-model="modelValue"
|
|
85
85
|
v-bind="{ 'data-enable-grammarly': 'false' }"
|
|
86
|
-
:autocapitalize="
|
|
86
|
+
:autocapitalize="isActiveOnIos ? 'characters' : undefined"
|
|
87
87
|
class="w-full flex-1 appearance-none rounded-lg text-gray-900 font-medium tracking-tight outline-none dark:text-gray-100 placeholder-gray-600 dark:placeholder-gray-400"
|
|
88
88
|
:class="{
|
|
89
89
|
'uppercase': uppercase && !isTypingOnIos,
|
|
@@ -110,7 +110,9 @@ function syncModelValueFromTarget(target: EventTarget | null) {
|
|
|
110
110
|
spellcheck="false"
|
|
111
111
|
@blur="onFieldBlur"
|
|
112
112
|
@click="onFieldClick"
|
|
113
|
+
@compositionend="onIosUppercaseCompositionEnd"
|
|
113
114
|
@focus="onIosUppercaseFocus"
|
|
115
|
+
@input="onIosUppercaseInput"
|
|
114
116
|
/>
|
|
115
117
|
|
|
116
118
|
<FieldMessage
|
|
@@ -5,32 +5,71 @@ export default function useIosUppercase(options: {
|
|
|
5
5
|
modelValue: Ref<string>
|
|
6
6
|
}) {
|
|
7
7
|
const { isIosDevice } = useDevice()
|
|
8
|
-
const
|
|
8
|
+
const isFocused = ref(false)
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const isActiveOnIos = computed(() => {
|
|
11
11
|
return toValue(options.enabled) && isIosDevice.value
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
const isTypingOnIos = computed(() => {
|
|
15
|
-
return
|
|
15
|
+
return isActiveOnIos.value && isFocused.value
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
function onFocus() {
|
|
19
|
-
if (
|
|
19
|
+
if (isActiveOnIos.value) {
|
|
20
20
|
options.modelValue.value = options.modelValue.value.toUpperCase()
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
isFocused.value = true
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function onBlur() {
|
|
27
|
-
|
|
27
|
+
isFocused.value = false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function onInput(event: Event) {
|
|
31
|
+
// Rewriting the value mid-composition breaks IME and accent input.
|
|
32
|
+
if (event instanceof InputEvent && event.isComposing) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
forceUppercase(event.target)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function onCompositionEnd(event: CompositionEvent) {
|
|
40
|
+
forceUppercase(event.target)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function forceUppercase(target: EventTarget | null) {
|
|
44
|
+
if (!isActiveOnIos.value) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const uppercased = target.value.toUpperCase()
|
|
53
|
+
|
|
54
|
+
if (uppercased === target.value) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { selectionEnd, selectionStart } = target
|
|
59
|
+
|
|
60
|
+
target.value = uppercased
|
|
61
|
+
|
|
62
|
+
target.setSelectionRange(selectionStart ?? uppercased.length, selectionEnd ?? uppercased.length)
|
|
63
|
+
|
|
64
|
+
options.modelValue.value = uppercased
|
|
28
65
|
}
|
|
29
66
|
|
|
30
67
|
return {
|
|
68
|
+
isActiveOnIos,
|
|
31
69
|
isTypingOnIos,
|
|
32
70
|
onBlur,
|
|
71
|
+
onCompositionEnd,
|
|
33
72
|
onFocus,
|
|
34
|
-
|
|
73
|
+
onInput,
|
|
35
74
|
}
|
|
36
75
|
}
|