@object-ui/mobile 2.0.0 → 3.0.1
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.
- package/README.md +132 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/useResponsiveConfig.d.ts +60 -0
- package/dist/useResponsiveConfig.d.ts.map +1 -0
- package/dist/useResponsiveConfig.js +41 -0
- package/dist/useSpecGesture.d.ts +33 -0
- package/dist/useSpecGesture.d.ts.map +1 -0
- package/dist/useSpecGesture.js +59 -0
- package/dist/useTouchTarget.d.ts +36 -0
- package/dist/useTouchTarget.d.ts.map +1 -0
- package/dist/useTouchTarget.js +33 -0
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @object-ui/mobile
|
|
2
|
+
|
|
3
|
+
Mobile optimization for Object UI — responsive hooks, gesture support, touch targets, and PWA utilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📱 **Responsive Hooks** - `useBreakpoint` and `useResponsive` for adaptive layouts
|
|
8
|
+
- 👆 **Gesture Support** - `useGesture` and `useSpecGesture` for swipe, pinch, and long-press detection
|
|
9
|
+
- 🔄 **Pull to Refresh** - Native pull-to-refresh behavior with `usePullToRefresh`
|
|
10
|
+
- 🎯 **Touch Targets** - `useTouchTarget` for accessible minimum-size touch areas
|
|
11
|
+
- 📐 **Responsive Containers** - `ResponsiveContainer` for breakpoint-aware rendering
|
|
12
|
+
- 🏗️ **MobileProvider** - Context provider for mobile-aware applications
|
|
13
|
+
- 📲 **PWA Support** - Manifest generation and service worker registration
|
|
14
|
+
- ⚙️ **Configurable Breakpoints** - Customizable breakpoint definitions
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @object-ui/mobile
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Peer Dependencies:**
|
|
23
|
+
- `react` ^18.0.0 || ^19.0.0
|
|
24
|
+
- `react-dom` ^18.0.0 || ^19.0.0
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { MobileProvider, useBreakpoint, useGesture } from '@object-ui/mobile';
|
|
30
|
+
|
|
31
|
+
function App() {
|
|
32
|
+
return (
|
|
33
|
+
<MobileProvider>
|
|
34
|
+
<ResponsiveApp />
|
|
35
|
+
</MobileProvider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function ResponsiveApp() {
|
|
40
|
+
const { isMobile, isTablet, isDesktop } = useBreakpoint();
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div>
|
|
44
|
+
{isMobile && <MobileNav />}
|
|
45
|
+
{isDesktop && <DesktopSidebar />}
|
|
46
|
+
<MainContent />
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API
|
|
53
|
+
|
|
54
|
+
### MobileProvider
|
|
55
|
+
|
|
56
|
+
Wraps your application with mobile context:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<MobileProvider>
|
|
60
|
+
<App />
|
|
61
|
+
</MobileProvider>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### useBreakpoint
|
|
65
|
+
|
|
66
|
+
Hook for detecting the current breakpoint:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
const { isMobile, isTablet, isDesktop, current } = useBreakpoint();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### useResponsive
|
|
73
|
+
|
|
74
|
+
Hook for responsive values based on screen size:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
const columns = useResponsive({ mobile: 1, tablet: 2, desktop: 4 });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### useGesture / useSpecGesture
|
|
81
|
+
|
|
82
|
+
Hooks for gesture detection on touch devices:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
const gestureRef = useGesture({
|
|
86
|
+
onSwipeLeft: () => navigateNext(),
|
|
87
|
+
onSwipeRight: () => navigateBack(),
|
|
88
|
+
onPinch: (scale) => handleZoom(scale),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return <div ref={gestureRef}>Swipeable content</div>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### usePullToRefresh
|
|
95
|
+
|
|
96
|
+
Hook for pull-to-refresh behavior:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
const { isRefreshing } = usePullToRefresh({
|
|
100
|
+
onRefresh: async () => await fetchData(),
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### useTouchTarget
|
|
105
|
+
|
|
106
|
+
Hook for ensuring minimum touch target sizes:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const { targetProps } = useTouchTarget({ minSize: 44 });
|
|
110
|
+
return <button {...targetProps}>Tap me</button>;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### ResponsiveContainer
|
|
114
|
+
|
|
115
|
+
Renders children based on breakpoint:
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<ResponsiveContainer mobile={<MobileView />} desktop={<DesktopView />} />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### PWA Utilities
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { generatePWAManifest, registerServiceWorker } from '@object-ui/mobile';
|
|
125
|
+
|
|
126
|
+
const manifest = generatePWAManifest({ name: 'My App', themeColor: '#000' });
|
|
127
|
+
registerServiceWorker({ cacheStrategy: 'network-first' });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -19,12 +19,15 @@
|
|
|
19
19
|
*/
|
|
20
20
|
export { useBreakpoint, type BreakpointState } from './useBreakpoint';
|
|
21
21
|
export { useResponsive } from './useResponsive';
|
|
22
|
+
export { useResponsiveConfig, type SpecResponsiveConfig, type ResolvedResponsiveState } from './useResponsiveConfig';
|
|
22
23
|
export { useGesture, type UseGestureOptions } from './useGesture';
|
|
24
|
+
export { useSpecGesture, type UseSpecGestureOptions } from './useSpecGesture';
|
|
25
|
+
export { useTouchTarget, type UseTouchTargetOptions, type TouchTargetResult } from './useTouchTarget';
|
|
23
26
|
export { usePullToRefresh, type PullToRefreshOptions } from './usePullToRefresh';
|
|
24
27
|
export { MobileProvider, type MobileProviderProps } from './MobileProvider';
|
|
25
28
|
export { ResponsiveContainer, type ResponsiveContainerProps } from './ResponsiveContainer';
|
|
26
29
|
export { generatePWAManifest } from './pwa';
|
|
27
30
|
export { registerServiceWorker, type ServiceWorkerConfig } from './serviceWorker';
|
|
28
31
|
export { BREAKPOINTS, resolveResponsiveValue } from './breakpoints';
|
|
29
|
-
export type { BreakpointName, ResponsiveValue, ResponsiveConfig, MobileOverrides, PWAConfig, PWAIcon, CacheStrategy, OfflineConfig, OfflineRoute, GestureType, GestureConfig, GestureContext, MobileComponentConfig, } from '@object-ui/types';
|
|
32
|
+
export type { BreakpointName, ResponsiveValue, ResponsiveConfig, MobileOverrides, PWAConfig, PWAIcon, CacheStrategy, OfflineConfig, OfflineRoute, GestureType, GestureConfig, GestureContext, MobileComponentConfig, SpecGestureConfig, SwipeGestureConfig, PinchGestureConfig, LongPressGestureConfig, TouchInteraction, TouchTargetConfig, } from '@object-ui/types';
|
|
30
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAGpE,YAAY,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrH,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAGpE,YAAY,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
*/
|
|
20
20
|
export { useBreakpoint } from './useBreakpoint';
|
|
21
21
|
export { useResponsive } from './useResponsive';
|
|
22
|
+
export { useResponsiveConfig } from './useResponsiveConfig';
|
|
22
23
|
export { useGesture } from './useGesture';
|
|
24
|
+
export { useSpecGesture } from './useSpecGesture';
|
|
25
|
+
export { useTouchTarget } from './useTouchTarget';
|
|
23
26
|
export { usePullToRefresh } from './usePullToRefresh';
|
|
24
27
|
export { MobileProvider } from './MobileProvider';
|
|
25
28
|
export { ResponsiveContainer } from './ResponsiveContainer';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import type { BreakpointName } from '@object-ui/types';
|
|
9
|
+
/**
|
|
10
|
+
* Spec-aligned ResponsiveConfig (mirrors @objectstack/spec ResponsiveConfigSchema).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const config: SpecResponsiveConfig = {
|
|
15
|
+
* columns: { xs: 12, sm: 6, lg: 4 },
|
|
16
|
+
* hiddenOn: ['xs'],
|
|
17
|
+
* order: { xs: 2, lg: 1 },
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export interface SpecResponsiveConfig {
|
|
22
|
+
/** The target breakpoint for this config */
|
|
23
|
+
breakpoint?: BreakpointName;
|
|
24
|
+
/** Breakpoints on which the component is hidden */
|
|
25
|
+
hiddenOn?: BreakpointName[];
|
|
26
|
+
/** Grid column counts per breakpoint (1-12) */
|
|
27
|
+
columns?: Partial<Record<BreakpointName, number>>;
|
|
28
|
+
/** Display order per breakpoint */
|
|
29
|
+
order?: Partial<Record<BreakpointName, number>>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolved responsive state from a SpecResponsiveConfig.
|
|
33
|
+
*/
|
|
34
|
+
export interface ResolvedResponsiveState {
|
|
35
|
+
/** Whether the component is hidden at the current breakpoint */
|
|
36
|
+
hidden: boolean;
|
|
37
|
+
/** Resolved column count for the current breakpoint */
|
|
38
|
+
columns: number | undefined;
|
|
39
|
+
/** Resolved display order for the current breakpoint */
|
|
40
|
+
order: number | undefined;
|
|
41
|
+
/** Current active breakpoint name */
|
|
42
|
+
breakpoint: BreakpointName;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Hook that consumes @objectstack/spec ResponsiveConfigSchema and
|
|
46
|
+
* resolves breakpoint-aware layout state.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* const { hidden, columns, order } = useResponsiveConfig({
|
|
51
|
+
* columns: { xs: 12, sm: 6, lg: 4 },
|
|
52
|
+
* hiddenOn: ['xs'],
|
|
53
|
+
* order: { xs: 2, lg: 1 },
|
|
54
|
+
* });
|
|
55
|
+
* if (hidden) return null;
|
|
56
|
+
* return <div style={{ gridColumn: `span ${columns}`, order }}>...</div>;
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function useResponsiveConfig(config?: SpecResponsiveConfig): ResolvedResponsiveState;
|
|
60
|
+
//# sourceMappingURL=useResponsiveConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResponsiveConfig.d.ts","sourceRoot":"","sources":["../src/useResponsiveConfig.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,qCAAqC;IACrC,UAAU,EAAE,cAAc,CAAC;CAC5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,uBAAuB,CAoB1F"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { useMemo } from 'react';
|
|
9
|
+
import { useBreakpoint } from './useBreakpoint';
|
|
10
|
+
import { resolveResponsiveValue } from './breakpoints';
|
|
11
|
+
/**
|
|
12
|
+
* Hook that consumes @objectstack/spec ResponsiveConfigSchema and
|
|
13
|
+
* resolves breakpoint-aware layout state.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const { hidden, columns, order } = useResponsiveConfig({
|
|
18
|
+
* columns: { xs: 12, sm: 6, lg: 4 },
|
|
19
|
+
* hiddenOn: ['xs'],
|
|
20
|
+
* order: { xs: 2, lg: 1 },
|
|
21
|
+
* });
|
|
22
|
+
* if (hidden) return null;
|
|
23
|
+
* return <div style={{ gridColumn: `span ${columns}`, order }}>...</div>;
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function useResponsiveConfig(config) {
|
|
27
|
+
const { breakpoint } = useBreakpoint();
|
|
28
|
+
return useMemo(() => {
|
|
29
|
+
if (!config) {
|
|
30
|
+
return { hidden: false, columns: undefined, order: undefined, breakpoint };
|
|
31
|
+
}
|
|
32
|
+
const hidden = config.hiddenOn?.includes(breakpoint) ?? false;
|
|
33
|
+
const columns = config.columns
|
|
34
|
+
? resolveResponsiveValue(config.columns, breakpoint)
|
|
35
|
+
: undefined;
|
|
36
|
+
const order = config.order
|
|
37
|
+
? resolveResponsiveValue(config.order, breakpoint)
|
|
38
|
+
: undefined;
|
|
39
|
+
return { hidden, columns, order, breakpoint };
|
|
40
|
+
}, [config, breakpoint]);
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import type { SpecGestureConfig } from '@object-ui/types';
|
|
9
|
+
export interface UseSpecGestureOptions {
|
|
10
|
+
/** Spec gesture configuration */
|
|
11
|
+
config: SpecGestureConfig;
|
|
12
|
+
/** Callback when a swipe gesture is detected */
|
|
13
|
+
onSwipe?: (direction: string) => void;
|
|
14
|
+
/** Callback when a pinch gesture is detected */
|
|
15
|
+
onPinch?: (scale: number) => void;
|
|
16
|
+
/** Callback when a long-press gesture is detected */
|
|
17
|
+
onLongPress?: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Spec-aware gesture hook that maps an @objectstack/spec GestureConfig
|
|
21
|
+
* to the existing useGesture hook.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const ref = useSpecGesture({
|
|
26
|
+
* config: { type: 'swipe', enabled: true, swipe: { direction: 'left', threshold: 80 } },
|
|
27
|
+
* onSwipe: (dir) => console.log('Swiped', dir),
|
|
28
|
+
* });
|
|
29
|
+
* return <div ref={ref}>Swipe me</div>;
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useSpecGesture<T extends HTMLElement = HTMLElement>(options: UseSpecGestureOptions): import("react").RefObject<T | null>;
|
|
33
|
+
//# sourceMappingURL=useSpecGesture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSpecGesture.d.ts","sourceRoot":"","sources":["../src/useSpecGesture.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,WAAW,qBAAqB;IACpC,iCAAiC;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAChE,OAAO,EAAE,qBAAqB,uCAiC/B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { useGesture } from './useGesture';
|
|
9
|
+
const SWIPE_DIRECTION_MAP = {
|
|
10
|
+
left: 'swipe-left',
|
|
11
|
+
right: 'swipe-right',
|
|
12
|
+
up: 'swipe-up',
|
|
13
|
+
down: 'swipe-down',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Spec-aware gesture hook that maps an @objectstack/spec GestureConfig
|
|
17
|
+
* to the existing useGesture hook.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const ref = useSpecGesture({
|
|
22
|
+
* config: { type: 'swipe', enabled: true, swipe: { direction: 'left', threshold: 80 } },
|
|
23
|
+
* onSwipe: (dir) => console.log('Swiped', dir),
|
|
24
|
+
* });
|
|
25
|
+
* return <div ref={ref}>Swipe me</div>;
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function useSpecGesture(options) {
|
|
29
|
+
const { config, onSwipe, onPinch, onLongPress } = options;
|
|
30
|
+
const enabled = config.enabled ?? true;
|
|
31
|
+
let gestureType = 'tap';
|
|
32
|
+
let threshold;
|
|
33
|
+
let longPressDuration;
|
|
34
|
+
let onGesture = () => { };
|
|
35
|
+
if (config.swipe && onSwipe) {
|
|
36
|
+
const dir = Array.isArray(config.swipe.direction)
|
|
37
|
+
? config.swipe.direction[0]
|
|
38
|
+
: config.swipe.direction;
|
|
39
|
+
gestureType = (dir && SWIPE_DIRECTION_MAP[dir]) ?? 'swipe-left';
|
|
40
|
+
threshold = config.swipe.threshold;
|
|
41
|
+
onGesture = (ctx) => onSwipe(ctx.direction ?? dir ?? 'left');
|
|
42
|
+
}
|
|
43
|
+
else if (config.longPress && onLongPress) {
|
|
44
|
+
gestureType = 'long-press';
|
|
45
|
+
longPressDuration = config.longPress.duration;
|
|
46
|
+
onGesture = () => onLongPress();
|
|
47
|
+
}
|
|
48
|
+
else if (config.pinch && onPinch) {
|
|
49
|
+
gestureType = 'pinch';
|
|
50
|
+
onGesture = (ctx) => onPinch(ctx.scale ?? 1);
|
|
51
|
+
}
|
|
52
|
+
return useGesture({
|
|
53
|
+
type: gestureType,
|
|
54
|
+
onGesture,
|
|
55
|
+
threshold,
|
|
56
|
+
longPressDuration,
|
|
57
|
+
enabled,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import type { TouchTargetConfig } from '@object-ui/types';
|
|
9
|
+
export interface UseTouchTargetOptions {
|
|
10
|
+
/** Spec touch target configuration */
|
|
11
|
+
config?: TouchTargetConfig;
|
|
12
|
+
}
|
|
13
|
+
export interface TouchTargetResult {
|
|
14
|
+
/** CSS style properties enforcing minimum touch target sizes */
|
|
15
|
+
style: {
|
|
16
|
+
minWidth: string;
|
|
17
|
+
minHeight: string;
|
|
18
|
+
padding: string | undefined;
|
|
19
|
+
};
|
|
20
|
+
/** CSS class for touch-action optimization */
|
|
21
|
+
className: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Hook that returns style and className props enforcing minimum
|
|
25
|
+
* touch target sizes per the @objectstack/spec TouchTargetConfig.
|
|
26
|
+
*
|
|
27
|
+
* Defaults follow WCAG 2.5.5 (44×44 CSS pixels).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const target = useTouchTarget({ config: { minWidth: 48, minHeight: 48 } });
|
|
32
|
+
* return <button style={target.style} className={target.className}>Tap</button>;
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function useTouchTarget(options?: UseTouchTargetOptions): TouchTargetResult;
|
|
36
|
+
//# sourceMappingURL=useTouchTarget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTouchTarget.d.ts","sourceRoot":"","sources":["../src/useTouchTarget.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;KAC7B,CAAC;IACF,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,iBAAiB,CAcrF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Hook that returns style and className props enforcing minimum
|
|
10
|
+
* touch target sizes per the @objectstack/spec TouchTargetConfig.
|
|
11
|
+
*
|
|
12
|
+
* Defaults follow WCAG 2.5.5 (44×44 CSS pixels).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const target = useTouchTarget({ config: { minWidth: 48, minHeight: 48 } });
|
|
17
|
+
* return <button style={target.style} className={target.className}>Tap</button>;
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function useTouchTarget(options = {}) {
|
|
21
|
+
const { config } = options;
|
|
22
|
+
const minWidth = config?.minWidth ?? 44;
|
|
23
|
+
const minHeight = config?.minHeight ?? 44;
|
|
24
|
+
const padding = config?.padding ?? 0;
|
|
25
|
+
return {
|
|
26
|
+
style: {
|
|
27
|
+
minWidth: `${minWidth}px`,
|
|
28
|
+
minHeight: `${minHeight}px`,
|
|
29
|
+
padding: padding > 0 ? `${padding}px` : undefined,
|
|
30
|
+
},
|
|
31
|
+
className: 'touch-manipulation',
|
|
32
|
+
};
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/mobile",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Mobile optimization for Object UI with responsive components, PWA support, and touch gesture handling.",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"react": "^18.0.0 || ^19.0.0"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@object-ui/types": "
|
|
29
|
+
"@object-ui/types": "3.0.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/react": "
|
|
33
|
-
"react": "
|
|
32
|
+
"@types/react": "19.2.13",
|
|
33
|
+
"react": "19.2.4",
|
|
34
34
|
"typescript": "^5.9.3",
|
|
35
35
|
"vitest": "^4.0.18"
|
|
36
36
|
},
|