@saasmakers/ui 2.0.61 → 2.0.62

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.
@@ -4,6 +4,16 @@ html,
4
4
  body {
5
5
  scrollbar-gutter: stable;
6
6
  touch-action: manipulation;
7
+ -webkit-touch-callout: none;
8
+ -webkit-user-select: none;
9
+ user-select: none;
10
+ }
11
+
12
+ input,
13
+ textarea,
14
+ [contenteditable='true'] {
15
+ -webkit-user-select: text;
16
+ user-select: text;
7
17
  }
8
18
 
9
19
  /* Theme backgrounds */
@@ -67,6 +67,9 @@ function focus() {
67
67
  }
68
68
 
69
69
  function onFieldBlur(event: FocusEvent) {
70
+ // iOS keyboard paste can update the DOM without firing `input` before blur
71
+ syncModelValueFromTarget(event.target)
72
+
70
73
  if (props.trim) {
71
74
  modelValue.value = modelValue.value.toString().trim()
72
75
  }
@@ -79,23 +82,13 @@ function onFieldFocus(event: FocusEvent) {
79
82
  }
80
83
 
81
84
  function onFieldInput(event: Event) {
82
- let value = (event.target as HTMLInputElement).value
83
-
84
- if (props.type === 'number' && props.max && Number.parseInt(value) > props.max) {
85
- value = props.max.toString()
86
- }
87
-
88
- if (props.slugOnly) {
89
- value = value.toString().toLowerCase().replace(/[^a-z0-9_-]/g, '')
90
- }
91
- else if (props.lowercaseOnly) {
92
- value = value.toString().toLowerCase()
93
- }
94
-
95
- modelValue.value = value
85
+ syncModelValueFromTarget(event.target)
96
86
  }
97
87
 
98
88
  function onFieldKeyDown(event: KeyboardEvent) {
89
+ // iOS keyboard paste can update the DOM without firing `input` before keydown
90
+ syncModelValueFromTarget(event.target)
91
+
99
92
  const value = (event.target as HTMLInputElement).value
100
93
 
101
94
  if (['Control', 'Escape'].includes(event.key)) {
@@ -138,6 +131,31 @@ function onTogglePasswordVisibility() {
138
131
  showPassword.value = !showPassword.value
139
132
  }
140
133
 
134
+ function syncModelValueFromTarget(target: EventTarget | null) {
135
+ if (!(target instanceof HTMLInputElement)) {
136
+ return
137
+ }
138
+
139
+ modelValue.value = transformFieldValue(target.value)
140
+ }
141
+
142
+ function transformFieldValue(value: string) {
143
+ let nextValue = value
144
+
145
+ if (props.type === 'number' && props.max && Number.parseInt(nextValue) > props.max) {
146
+ nextValue = props.max.toString()
147
+ }
148
+
149
+ if (props.slugOnly) {
150
+ nextValue = nextValue.toString().toLowerCase().replace(/[^a-z0-9_-]/g, '')
151
+ }
152
+ else if (props.lowercaseOnly) {
153
+ nextValue = nextValue.toString().toLowerCase()
154
+ }
155
+
156
+ return nextValue
157
+ }
158
+
141
159
  defineExpose({
142
160
  blur,
143
161
  focus,
@@ -39,12 +39,22 @@ onMounted(() => {
39
39
  })
40
40
 
41
41
  function onFieldBlur(event: FocusEvent) {
42
+ // iOS keyboard paste can update the DOM without syncing v-model before blur
43
+ syncModelValueFromTarget(event.target)
42
44
  emit('blur', event, modelValue.value || '')
43
45
  }
44
46
 
45
47
  function onFieldClick(event: MouseEvent) {
46
48
  emit('click', event, modelValue.value || '')
47
49
  }
50
+
51
+ function syncModelValueFromTarget(target: EventTarget | null) {
52
+ if (!(target instanceof HTMLTextAreaElement)) {
53
+ return
54
+ }
55
+
56
+ modelValue.value = target.value
57
+ }
48
58
  </script>
49
59
 
50
60
  <template>
@@ -1,10 +1,21 @@
1
1
  export default function useDevice() {
2
+ const { isNative } = useCapacitor()
3
+
2
4
  const isDesktopBrowser = computed(() => {
3
5
  if (typeof navigator === 'undefined') {
4
6
  return true
5
7
  }
6
8
 
7
- return !navigator.userAgentData?.mobile
9
+ if (isNative.value) {
10
+ return false
11
+ }
12
+
13
+ // Chromium Client Hints — unavailable on Safari / Firefox / iOS WebKit
14
+ if (navigator.userAgentData) {
15
+ return !navigator.userAgentData.mobile
16
+ }
17
+
18
+ return !/Android|iPad|iPhone|iPod|Mobile/i.test(navigator.userAgent)
8
19
  })
9
20
 
10
21
  return { isDesktopBrowser }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.61",
3
+ "version": "2.0.62",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",