@saasmakers/ui 2.0.78 → 2.0.79

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.
@@ -18,6 +18,7 @@ const visible = defineModel<boolean>({ default: false })
18
18
  const contentRef = ref<HTMLElement>()
19
19
  const panelRef = ref<HTMLElement>()
20
20
  const { release: onAfterLeave } = useDialog(visible, panelRef)
21
+ const { isKeyboardOpen, keyboardInset } = useKeyboardInset()
21
22
 
22
23
  const drag = reactive({
23
24
  closing: false,
@@ -32,6 +33,17 @@ const closeThreshold = computed(() => {
32
33
  return (panelRef.value?.offsetHeight ?? 320) * closeThresholdRatio
33
34
  })
34
35
 
36
+ // Use `bottom` (not transform) so keyboard lift does not fight drag-to-dismiss.
37
+ const panelStyle = computed(() => {
38
+ return {
39
+ bottom: `${keyboardInset.value}px`,
40
+ maxHeight: isKeyboardOpen.value
41
+ ? `calc(100dvh - ${keyboardInset.value}px - env(safe-area-inset-top))`
42
+ : undefined,
43
+ transform: drag.closing ? 'translateY(100%)' : drag.offset > 0 ? `translateY(${drag.offset}px)` : undefined,
44
+ }
45
+ })
46
+
35
47
  function onBackdropClick() {
36
48
  if (props.closeOnBackdrop) {
37
49
  onClose()
@@ -210,15 +222,14 @@ watch(visible, (isVisible) => {
210
222
  ref="panelRef"
211
223
  :aria-label="props['aria-label']"
212
224
  aria-modal="true"
213
- class="layout-bottom-sheet fixed bottom-0 left-0 right-0 z-[60] mx-auto max-h-[85dvh] max-w-screen-md flex flex-col rounded-t-2xl bg-white text-gray-900 app-text shadow-lg outline-none safe-bottom dark:bg-gray-900 dark:text-gray-100"
225
+ class="layout-bottom-sheet fixed bottom-0 left-0 right-0 z-[60] mx-auto max-h-[85dvh] max-w-screen-md flex flex-col rounded-t-2xl bg-white text-gray-900 app-text shadow-lg outline-none dark:bg-gray-900 dark:text-gray-100"
214
226
  :class="{
227
+ 'safe-bottom': !isKeyboardOpen,
215
228
  'transition-none motion-reduce:transition-none': drag.isDragging,
216
- 'transition-transform duration-200 ease motion-reduce:transition-none motion-reduce:duration-0': !drag.isDragging && (drag.closing || drag.offset > 0),
229
+ 'transition-[bottom,max-height,transform] duration-250 ease-out motion-reduce:transition-none motion-reduce:duration-0': !drag.isDragging,
217
230
  }"
231
+ :style="panelStyle"
218
232
  role="dialog"
219
- :style="{
220
- transform: drag.closing ? 'translateY(100%)' : drag.offset > 0 ? `translateY(${drag.offset}px)` : undefined,
221
- }"
222
233
  tabindex="-1"
223
234
  @transitionend="onPanelTransitionEnd"
224
235
  >
@@ -0,0 +1,46 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core'
2
+ import { Keyboard } from '@capacitor/keyboard'
3
+
4
+ // Tracks the on-screen keyboard height on iOS Capacitor only.
5
+ // With Keyboard.resize = 'none', the WebView does not shrink; consumers shift
6
+ // fixed UI (e.g. bottom sheets) with this inset so it moves with the keyboard
7
+ // animation instead of jumping after it finishes. Android keeps soft-input
8
+ // resize, so applying the inset there would double-offset.
9
+ export default function useKeyboardInset() {
10
+ const { isIOS, isPluginAvailable } = useCapacitor()
11
+ const keyboardInset = ref(0)
12
+
13
+ const isKeyboardOpen = computed(() => {
14
+ return keyboardInset.value > 0
15
+ })
16
+
17
+ const listenerHandles: PluginListenerHandle[] = []
18
+
19
+ onMounted(async () => {
20
+ if (!import.meta.client || !isIOS.value || !isPluginAvailable('Keyboard')) {
21
+ return
22
+ }
23
+
24
+ listenerHandles.push(
25
+ await Keyboard.addListener('keyboardWillShow', (info) => {
26
+ keyboardInset.value = info.keyboardHeight
27
+ }),
28
+ await Keyboard.addListener('keyboardWillHide', () => {
29
+ keyboardInset.value = 0
30
+ }),
31
+ )
32
+ })
33
+
34
+ onBeforeUnmount(() => {
35
+ for (const handle of listenerHandles) {
36
+ void handle.remove()
37
+ }
38
+
39
+ listenerHandles.length = 0
40
+ })
41
+
42
+ return {
43
+ isKeyboardOpen,
44
+ keyboardInset,
45
+ }
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.78",
3
+ "version": "2.0.79",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",
@@ -26,6 +26,7 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@capacitor/core": "8.4.0",
29
+ "@capacitor/keyboard": "8.0.6",
29
30
  "@capacitor/preferences": "8.0.1",
30
31
  "@capgo/capacitor-social-login": "8.3.22",
31
32
  "@nuxt/icon": "2.2.3",