Files
Native-Router-Vue/packages/preset-native/src/index.ts
2026-07-21 14:54:36 +10:00

69 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineComponent, h, type PropType } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
import { useNativeRouter } from '@native-vue-router/core'
import './style.css'
export type NativePlatform = 'ios' | 'android' | 'desktop'
export function detectNativePlatform(): NativePlatform {
if (typeof navigator === 'undefined') return 'desktop'
if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent) && ('ontouchend' in document)) return 'ios'
if (/Android/.test(navigator.userAgent)) return 'android'
return 'desktop'
}
export const NativeBackButton = defineComponent({
name: 'NativeBackButton',
props: { label: { type: String, default: 'Back' } },
setup(props) {
const native = useNativeRouter()
return () => h('button', {
type: 'button',
class: 'nvr-native-back',
'aria-label': props.label,
onClick: () => void native.pop(),
}, [h('span', { 'aria-hidden': 'true' }, ''), h('span', props.label)])
},
})
export interface NativeTabItem {
label: string
to: RouteLocationRaw
icon?: string
}
export const NativeTabBar = defineComponent({
name: 'NativeTabBar',
props: {
items: { type: Array as PropType<NativeTabItem[]>, required: true },
},
setup(props) {
const native = useNativeRouter()
return () => h('nav', { class: 'nvr-native-tabs', 'aria-label': 'Primary navigation' },
props.items.map((item) => {
const active = native.router.currentRoute.value.path === native.router.resolve(item.to).path
const href = native.router.resolve(item.to).href
return h('a', {
href,
class: ['nvr-native-tab', active && 'nvr-native-tab--active'],
'aria-current': active ? 'page' : undefined,
onClick: (event: MouseEvent) => {
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return
event.preventDefault()
if (active) return
void native.sibling(item.to, { replace: true })
},
}, [
h('span', { class: 'nvr-native-tab__icon', 'aria-hidden': 'true' }, item.icon ?? '•'),
h('span', item.label),
])
}))
},
})
export const nativeMotionTokens = {
ios: { edgeWidth: 28, commitThreshold: 0.36 },
android: { edgeWidth: 24, commitThreshold: 0.32 },
desktop: { edgeWidth: 18, commitThreshold: 0.4 },
} as const