@saasmakers/ui 2.1.1 → 2.1.3
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.
|
@@ -46,7 +46,13 @@ const id = useId()
|
|
|
46
46
|
const modelValue = defineModel<FieldInput['modelValue']>({ default: '' })
|
|
47
47
|
const input = ref<HTMLInputElement>()
|
|
48
48
|
const showPassword = ref(false)
|
|
49
|
-
const { isDesktopBrowser } = useDevice()
|
|
49
|
+
const { isDesktopBrowser, isIos } = useDevice()
|
|
50
|
+
|
|
51
|
+
const iosUppercaseTyping = computed(() => {
|
|
52
|
+
const isProseField = props.type === 'text' || props.type === 'search'
|
|
53
|
+
|
|
54
|
+
return props.uppercase && isIos.value && isProseField && !props.lowercaseOnly && !props.slugOnly
|
|
55
|
+
})
|
|
50
56
|
|
|
51
57
|
onMounted(() => {
|
|
52
58
|
if (props.autofocus && input.value && isDesktopBrowser.value) {
|
|
@@ -77,6 +83,14 @@ function onFieldBlur(event: FocusEvent) {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
function onFieldFocus(event: FocusEvent) {
|
|
86
|
+
if (iosUppercaseTyping.value) {
|
|
87
|
+
const uppercased = modelValue.value.toString().toUpperCase()
|
|
88
|
+
|
|
89
|
+
if (uppercased !== modelValue.value) {
|
|
90
|
+
modelValue.value = uppercased
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
emit('focus', event)
|
|
81
95
|
}
|
|
82
96
|
|
|
@@ -193,10 +207,12 @@ defineExpose({
|
|
|
193
207
|
:id="id"
|
|
194
208
|
ref="input"
|
|
195
209
|
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
210
|
+
:autocapitalize="iosUppercaseTyping ? 'characters' : undefined"
|
|
196
211
|
v-bind="autofocus ? { 'data-autofocus': '' } : {}"
|
|
197
212
|
class="h-full w-full appearance-none items-center rounded-lg font-medium tracking-tight outline-none placeholder-gray-600 dark:placeholder-gray-400"
|
|
198
213
|
:class="{
|
|
199
|
-
'uppercase': uppercase,
|
|
214
|
+
'uppercase': uppercase && !iosUppercaseTyping,
|
|
215
|
+
'placeholder:uppercase': iosUppercaseTyping,
|
|
200
216
|
'field-disabled': disabled,
|
|
201
217
|
'focus:placeholder-gray-900 hover:placeholder-gray-900 dark:focus:placeholder-gray-100 dark:hover:placeholder-gray-100': !disabled,
|
|
202
218
|
'text-gray-900 dark:text-gray-100': !lineThrough,
|
|
@@ -26,6 +26,7 @@ const props = withDefaults(defineProps<Omit<FieldSelect, 'modelValue'>>(), {
|
|
|
26
26
|
searchPlaceholder: '',
|
|
27
27
|
size: 'base',
|
|
28
28
|
square: false,
|
|
29
|
+
uppercase: true,
|
|
29
30
|
validation: undefined,
|
|
30
31
|
})
|
|
31
32
|
|
|
@@ -331,6 +332,7 @@ function toggle() {
|
|
|
331
332
|
'cursor-pointer': !disabled,
|
|
332
333
|
'shadow-sm': border === 'full',
|
|
333
334
|
'w-fit': iconOnly || square,
|
|
335
|
+
'field-uppercase': uppercase,
|
|
334
336
|
}"
|
|
335
337
|
>
|
|
336
338
|
<div
|
|
@@ -445,6 +447,7 @@ function toggle() {
|
|
|
445
447
|
'text-xs': size === 'sm',
|
|
446
448
|
'text-sm': size === 'base',
|
|
447
449
|
'text-base': size === 'lg',
|
|
450
|
+
'field-uppercase': uppercase,
|
|
448
451
|
'md:min-w-xl p-1 pb-0': isMultiColumn,
|
|
449
452
|
}"
|
|
450
453
|
role="listbox"
|
|
@@ -30,7 +30,11 @@ const emit = defineEmits<{
|
|
|
30
30
|
const id = useId()
|
|
31
31
|
const modelValue = defineModel<FieldTextarea['modelValue']>({ default: '' })
|
|
32
32
|
const textarea = ref<HTMLTextAreaElement>()
|
|
33
|
-
const { isDesktopBrowser } = useDevice()
|
|
33
|
+
const { isDesktopBrowser, isIos } = useDevice()
|
|
34
|
+
|
|
35
|
+
const iosUppercaseTyping = computed(() => {
|
|
36
|
+
return props.uppercase && isIos.value
|
|
37
|
+
})
|
|
34
38
|
|
|
35
39
|
onMounted(() => {
|
|
36
40
|
if (props.autofocus && textarea.value && isDesktopBrowser.value) {
|
|
@@ -47,6 +51,18 @@ function onFieldClick(event: MouseEvent) {
|
|
|
47
51
|
emit('click', event, modelValue.value || '')
|
|
48
52
|
}
|
|
49
53
|
|
|
54
|
+
function onFieldFocus() {
|
|
55
|
+
if (!iosUppercaseTyping.value) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const uppercased = modelValue.value.toString().toUpperCase()
|
|
60
|
+
|
|
61
|
+
if (uppercased !== modelValue.value) {
|
|
62
|
+
modelValue.value = uppercased
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
function syncModelValueFromTarget(target: EventTarget | null) {
|
|
51
67
|
if (!(target instanceof HTMLTextAreaElement)) {
|
|
52
68
|
return
|
|
@@ -77,9 +93,11 @@ function syncModelValueFromTarget(target: EventTarget | null) {
|
|
|
77
93
|
ref="textarea"
|
|
78
94
|
v-model="modelValue"
|
|
79
95
|
v-bind="{ 'data-enable-grammarly': 'false' }"
|
|
96
|
+
:autocapitalize="iosUppercaseTyping ? 'characters' : undefined"
|
|
80
97
|
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"
|
|
81
98
|
:class="{
|
|
82
|
-
'uppercase': uppercase,
|
|
99
|
+
'uppercase': uppercase && !iosUppercaseTyping,
|
|
100
|
+
'placeholder:uppercase': iosUppercaseTyping,
|
|
83
101
|
'field-disabled': disabled,
|
|
84
102
|
'focus:placeholder-gray-900 hover:placeholder-gray-900 dark:focus:placeholder-gray-100 dark:hover:placeholder-gray-100': !disabled,
|
|
85
103
|
'px-sm py-2.5': padding && size === 'sm',
|
|
@@ -102,6 +120,7 @@ function syncModelValueFromTarget(target: EventTarget | null) {
|
|
|
102
120
|
spellcheck="false"
|
|
103
121
|
@blur="onFieldBlur"
|
|
104
122
|
@click="onFieldClick"
|
|
123
|
+
@focus="onFieldFocus"
|
|
105
124
|
/>
|
|
106
125
|
|
|
107
126
|
<FieldMessage
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export default function useDevice() {
|
|
2
|
-
const { isNative } = useCapacitor()
|
|
2
|
+
const { isIOS, isNative } = useCapacitor()
|
|
3
|
+
|
|
4
|
+
const isIos = ref(false)
|
|
3
5
|
|
|
4
6
|
const isDesktopBrowser = computed(() => {
|
|
5
7
|
if (typeof navigator === 'undefined') {
|
|
@@ -18,5 +20,29 @@ export default function useDevice() {
|
|
|
18
20
|
return !/Android|iPad|iPhone|iPod|Mobile/i.test(navigator.userAgent)
|
|
19
21
|
})
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
onMounted(() => {
|
|
24
|
+
isIos.value = detectIosDevice(isIOS.value)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
isDesktopBrowser,
|
|
29
|
+
isIos,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function detectIosDevice(isNativeIos: boolean) {
|
|
34
|
+
if (isNativeIos) {
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof navigator === 'undefined') {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// iPadOS 13+ uses a Macintosh user agent. Several touch points separate it from a Mac.
|
|
47
|
+
return navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1
|
|
22
48
|
}
|
package/app/types/fields.d.ts
CHANGED