From 50ab43b1b49fbe94e6a50ff940cb870747a8f8a4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 05:05:53 +0000 Subject: [PATCH] =?UTF-8?q?docs(mobile):=20shrink=20UNGATED=5FDOCS=20by=20?= =?UTF-8?q?one=20=E2=80=94=20the=20mobile=20README's=2010=20blocks=20compi?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every ts/tsx block in packages/mobile/README.md now compiles --strict against the built dist/*.d.ts, so the document leaves the check-doc-snippet-types coverage ledger (24 entries -> 23). The page did not merely lack self-contained blocks. Six of its examples taught call shapes @object-ui/mobile has never exported: useGesture's onSwipeLeft / onSwipeRight / onPinch (the shipped UseGestureOptions is { type, onGesture }; the callback-shaped hook is useSpecGesture), useBreakpoint's `current` (the field is `breakpoint`), useTouchTarget's { minSize } -> { targetProps } (the shipped shape is { config: TouchTargetConfig } -> { style, className }), ResponsiveContainer's mobile / desktop props (the shipped props are minBreakpoint / maxBreakpoint / showOn / hideOn), registerServiceWorker's cacheStrategy (that concept lives in the generated worker), and useResponsive's { mobile, tablet, desktop } keys, which resolveResponsiveValue never reads, so the documented call returns undefined at every breakpoint. Those were invisible to the gate only because the surrounding blocks never imported the symbols they called. The gate file is edited only inside the UNGATED_DOCS object literal, by removal: numstat 0 2. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_013uAaxiwgYDybsTNV9xwa1M --- packages/mobile/README.md | 207 +++++++++++++++++++++++----- scripts/check-doc-snippet-types.mjs | 2 - 2 files changed, 173 insertions(+), 36 deletions(-) diff --git a/packages/mobile/README.md b/packages/mobile/README.md index dcd2223444..d6d75b794d 100644 --- a/packages/mobile/README.md +++ b/packages/mobile/README.md @@ -25,18 +25,22 @@ npm install @object-ui/mobile ## Quick Start ```tsx -import { MobileProvider, useBreakpoint, useGesture } from '@object-ui/mobile'; +import { MobileProvider, useBreakpoint } from '@object-ui/mobile'; -function App() { - return ( - - - - ); +function MobileNav() { + return ; +} + +function DesktopSidebar() { + return ; +} + +function MainContent() { + return
Main content
; } function ResponsiveApp() { - const { isMobile, isTablet, isDesktop } = useBreakpoint(); + const { isMobile, isDesktop } = useBreakpoint(); return (
@@ -46,84 +50,219 @@ function ResponsiveApp() {
); } + +export function App() { + return ( + + + + ); +} ``` ## API ### MobileProvider -Wraps your application with mobile context: +Wraps your application with mobile context. Both props are optional: `pwa` takes a +`PWAConfig`, `offline` takes a `PWAOfflineConfig`. ```tsx - - - +import { MobileProvider } from '@object-ui/mobile'; + +function App() { + return

Your application

; +} + +export function Root() { + return ( + + + + ); +} ``` ### useBreakpoint -Hook for detecting the current breakpoint: +Hook for detecting the current breakpoint. The current breakpoint name is +`breakpoint` — one of `xs`, `sm`, `md`, `lg`, `xl`, `2xl`: ```tsx -const { isMobile, isTablet, isDesktop, current } = useBreakpoint(); +import { useBreakpoint } from '@object-ui/mobile'; + +export function BreakpointBadge() { + const { isMobile, isTablet, isDesktop, breakpoint, width } = useBreakpoint(); + + return ( + + {breakpoint} at {width}px — mobile {String(isMobile)}, tablet {String(isTablet)}, desktop{' '} + {String(isDesktop)} + + ); +} ``` +`isAbove(bp)` and `isBelow(bp)` are also returned, for comparisons against a named +breakpoint. + ### useResponsive -Hook for responsive values based on screen size: +Hook for responsive values based on screen size. The keys are breakpoint names; a +breakpoint with no entry falls back to the next smaller one that has one: ```tsx -const columns = useResponsive({ mobile: 1, tablet: 2, desktop: 4 }); +import { useResponsive } from '@object-ui/mobile'; + +export function ResponsiveGrid() { + const columns = useResponsive({ xs: 1, md: 2, lg: 4 }); + + return
{columns} column(s)
; +} ``` ### useGesture / useSpecGesture -Hooks for gesture detection on touch devices: +`useGesture` detects one gesture from Object UI's direction-fused vocabulary +(`tap`, `double-tap`, `long-press`, `swipe-left`, `swipe-right`, `swipe-up`, +`swipe-down`, `pinch`, `rotate`, `pan`) per call, and returns a ref to attach: ```tsx -const gestureRef = useGesture({ - onSwipeLeft: () => navigateNext(), - onSwipeRight: () => navigateBack(), - onPinch: (scale) => handleZoom(scale), -}); +import { useGesture } from '@object-ui/mobile'; + +function navigateNext() {} +function navigateBack() {} + +export function SwipeArea() { + const nextRef = useGesture({ + type: 'swipe-left', + onGesture: () => navigateNext(), + }); + const backRef = useGesture({ + type: 'swipe-right', + onGesture: () => navigateBack(), + }); + + return ( +
+
Swipe left for the next record
+
Swipe right to go back
+
+ ); +} +``` + +`useSpecGesture` takes the declarative `SpecGestureConfig` tuning shape instead, and +dispatches to per-gesture callbacks: + +```tsx +import { useSpecGesture } from '@object-ui/mobile'; + +function handleZoom(scale: number) { + return scale; +} + +export function PinchArea() { + const ref = useSpecGesture({ + config: { type: 'pinch', enabled: true, pinch: { minScale: 0.5, maxScale: 3 } }, + onPinch: (scale) => handleZoom(scale), + }); -return
Swipeable content
; + return
Pinchable content
; +} ``` ### usePullToRefresh -Hook for pull-to-refresh behavior: +Hook for pull-to-refresh behavior. Attach the returned `ref` to the scrollable +container: ```tsx -const { isRefreshing } = usePullToRefresh({ - onRefresh: async () => await fetchData(), -}); +import { usePullToRefresh } from '@object-ui/mobile'; + +async function fetchData(): Promise {} + +export function Feed() { + const { ref, isRefreshing, pullDistance } = usePullToRefresh({ + onRefresh: async () => await fetchData(), + }); + + return ( +
+ {isRefreshing ? 'Refreshing…' : 'Pull to refresh'} +
+ ); +} ``` ### useTouchTarget -Hook for ensuring minimum touch target sizes: +Hook for ensuring minimum touch target sizes. It returns the `style` and `className` +to spread onto the element; the defaults follow WCAG 2.5.5 (44×44 CSS pixels): ```tsx -const { targetProps } = useTouchTarget({ minSize: 44 }); -return ; +import { useTouchTarget } from '@object-ui/mobile'; + +export function TapButton() { + const { style, className } = useTouchTarget({ + config: { minWidth: 44, minHeight: 44 }, + }); + + return ( + + ); +} ``` ### ResponsiveContainer -Renders children based on breakpoint: +Renders children based on breakpoint. Pick the range with `minBreakpoint` / +`maxBreakpoint`, or name the breakpoints outright with `showOn` / `hideOn`: ```tsx -} desktop={} /> +import { ResponsiveContainer } from '@object-ui/mobile'; + +function MobileView() { + return

Compact layout

; +} + +function DesktopView() { + return

Full layout

; +} + +export function BreakpointSwitch() { + return ( +
+ + + + + + +
+ ); +} ``` ### PWA Utilities +`PWAConfig` requires `enabled`, `name` and `shortName`. `registerServiceWorker` takes +the script `url` and `scope` plus lifecycle callbacks — the caching strategies live in +the generated worker (`getServiceWorkerSource`), not in this call: + ```tsx import { generatePWAManifest, registerServiceWorker } from '@object-ui/mobile'; -const manifest = generatePWAManifest({ name: 'My App', themeColor: '#000' }); -registerServiceWorker({ cacheStrategy: 'network-first' }); +export const manifest = generatePWAManifest({ + enabled: true, + name: 'My App', + shortName: 'My App', + themeColor: '#000', +}); + +void registerServiceWorker({ url: '/service-worker.js' }); ``` ## Links diff --git a/scripts/check-doc-snippet-types.mjs b/scripts/check-doc-snippet-types.mjs index 5024e6bf9a..ca173879ec 100644 --- a/scripts/check-doc-snippet-types.mjs +++ b/scripts/check-doc-snippet-types.mjs @@ -723,8 +723,6 @@ const UNGATED_DOCS = { '7 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS2554x2 TS2559x2 — candidate real defects, un-triaged', 'packages/layout/README.md': '3 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; 3 unresolved-module diagnostic(s)', - 'packages/mobile/README.md': - '19 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS1108x2 TS2345x1 TS2353x1 — candidate real defects, un-triaged', 'packages/permissions/README.md': '12 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS2322x4 TS2345x1 TS2353x1 — candidate real defects, un-triaged', 'packages/plugin-ai/README.md':