@g9tm/lynxcontrols 1.4.0 → 1.4.2
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 +7 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/base/control.d.ts +24 -0
- package/dist/base/control.d.ts.map +1 -1
- package/dist/base/control.jsx +14 -2
- package/dist/base/control.jsx.map +1 -1
- package/dist/base/index.d.ts +1 -1
- package/dist/base/index.d.ts.map +1 -1
- package/dist/base/index.jsx +1 -1
- package/dist/base/pressable.d.ts.map +1 -1
- package/dist/base/pressable.jsx +1 -1
- package/dist/base/pressable.jsx.map +1 -1
- package/dist/button/button.d.ts.map +1 -1
- package/dist/button/button.jsx +4 -3
- package/dist/button/button.jsx.map +1 -1
- package/dist/button/header-action-button.d.ts.map +1 -1
- package/dist/button/header-action-button.jsx +1 -1
- package/dist/button/header-action-button.jsx.map +1 -1
- package/dist/button/icon-button.d.ts.map +1 -1
- package/dist/button/icon-button.jsx +1 -1
- package/dist/button/icon-button.jsx.map +1 -1
- package/dist/button/nav-card.d.ts.map +1 -1
- package/dist/button/nav-card.jsx +6 -5
- package/dist/button/nav-card.jsx.map +1 -1
- package/dist/button/vertical-icon-text-button.d.ts.map +1 -1
- package/dist/button/vertical-icon-text-button.jsx +1 -1
- package/dist/button/vertical-icon-text-button.jsx.map +1 -1
- package/dist/display/culture-date-time-label.d.ts.map +1 -1
- package/dist/display/culture-date-time-label.jsx +3 -1
- package/dist/display/culture-date-time-label.jsx.map +1 -1
- package/dist/display/progress-bar.jsx +1 -1
- package/dist/display/progress-bar.jsx.map +1 -1
- package/dist/display/separator.jsx +2 -2
- package/dist/display/separator.jsx.map +1 -1
- package/dist/display/title-with-line.jsx +1 -1
- package/dist/display/title-with-line.jsx.map +1 -1
- package/dist/expander/expander.d.ts.map +1 -1
- package/dist/expander/expander.jsx +6 -4
- package/dist/expander/expander.jsx.map +1 -1
- package/dist/fields/fields.css +12 -4
- package/dist/fields/fields.css.map +1 -1
- package/dist/fields/index.d.ts +1 -0
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.jsx +1 -0
- package/dist/fields/notch.d.ts +10 -0
- package/dist/fields/notch.d.ts.map +1 -0
- package/dist/fields/notch.jsx +9 -0
- package/dist/fields/notch.jsx.map +1 -0
- package/dist/fields/outlined-field.d.ts +7 -1
- package/dist/fields/outlined-field.d.ts.map +1 -1
- package/dist/fields/outlined-field.jsx +8 -5
- package/dist/fields/outlined-field.jsx.map +1 -1
- package/dist/fields/pin-entry.d.ts +2 -0
- package/dist/fields/pin-entry.d.ts.map +1 -1
- package/dist/fields/pin-entry.jsx +2 -1
- package/dist/fields/pin-entry.jsx.map +1 -1
- package/dist/fields/text-entry.d.ts.map +1 -1
- package/dist/fields/text-entry.jsx +12 -2
- package/dist/fields/text-entry.jsx.map +1 -1
- package/dist/fields/use-text-input.d.ts.map +1 -1
- package/dist/fields/use-text-input.jsx +11 -1
- package/dist/fields/use-text-input.jsx.map +1 -1
- package/dist/host/hooks.d.ts +5 -0
- package/dist/host/hooks.d.ts.map +1 -1
- package/dist/host/hooks.jsx +4 -1
- package/dist/host/hooks.jsx.map +1 -1
- package/dist/host/index.d.ts +1 -1
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.jsx +1 -1
- package/dist/popup/frame.d.ts.map +1 -1
- package/dist/popup/frame.jsx +11 -3
- package/dist/popup/frame.jsx.map +1 -1
- package/dist/popup/index.d.ts +1 -1
- package/dist/popup/index.d.ts.map +1 -1
- package/dist/popup/popup.css +1 -1
- package/dist/popup/popup.css.map +1 -1
- package/dist/popup/service.d.ts.map +1 -1
- package/dist/popup/service.jsx +12 -4
- package/dist/popup/service.jsx.map +1 -1
- package/dist/popup/types.d.ts +11 -0
- package/dist/popup/types.d.ts.map +1 -1
- package/dist/popup/types.jsx.map +1 -1
- package/dist/selection/selection-sheet.d.ts.map +1 -1
- package/dist/selection/selection-sheet.jsx +7 -3
- package/dist/selection/selection-sheet.jsx.map +1 -1
- package/dist/selection/selection.css +1 -0
- package/dist/selection/selection.css.map +1 -1
- package/dist/sheet/frame.d.ts +2 -0
- package/dist/sheet/frame.d.ts.map +1 -1
- package/dist/sheet/frame.jsx +134 -69
- package/dist/sheet/frame.jsx.map +1 -1
- package/dist/sheet/gesture.d.ts +51 -0
- package/dist/sheet/gesture.d.ts.map +1 -0
- package/dist/sheet/gesture.jsx +107 -0
- package/dist/sheet/gesture.jsx.map +1 -0
- package/dist/sheet/handoff.d.ts +32 -0
- package/dist/sheet/handoff.d.ts.map +1 -0
- package/dist/sheet/handoff.jsx +33 -0
- package/dist/sheet/handoff.jsx.map +1 -0
- package/dist/sheet/header.d.ts +12 -1
- package/dist/sheet/header.d.ts.map +1 -1
- package/dist/sheet/header.jsx +42 -29
- package/dist/sheet/header.jsx.map +1 -1
- package/dist/sheet/index.d.ts +3 -2
- package/dist/sheet/index.d.ts.map +1 -1
- package/dist/sheet/index.jsx +3 -2
- package/dist/sheet/motion.d.ts +59 -0
- package/dist/sheet/motion.d.ts.map +1 -0
- package/dist/sheet/motion.jsx +59 -0
- package/dist/sheet/motion.jsx.map +1 -0
- package/dist/sheet/options.d.ts +34 -2
- package/dist/sheet/options.d.ts.map +1 -1
- package/dist/sheet/options.jsx +2 -1
- package/dist/sheet/options.jsx.map +1 -1
- package/dist/sheet/service.d.ts.map +1 -1
- package/dist/sheet/service.jsx +1 -1
- package/dist/sheet/service.jsx.map +1 -1
- package/dist/sheet/sheet.css +52 -1
- package/dist/sheet/sheet.css.map +1 -1
- package/dist/sheet/sizing.d.ts +21 -3
- package/dist/sheet/sizing.d.ts.map +1 -1
- package/dist/sheet/sizing.jsx +15 -2
- package/dist/sheet/sizing.jsx.map +1 -1
- package/dist/tab-bar/tab-bar.d.ts +5 -0
- package/dist/tab-bar/tab-bar.d.ts.map +1 -1
- package/dist/tab-bar/tab-bar.jsx +5 -2
- package/dist/tab-bar/tab-bar.jsx.map +1 -1
- package/dist/toast/service.d.ts.map +1 -1
- package/dist/toast/service.jsx +58 -21
- package/dist/toast/service.jsx.map +1 -1
- package/dist/toast/store.d.ts +2 -0
- package/dist/toast/store.d.ts.map +1 -1
- package/dist/toast/store.jsx +4 -2
- package/dist/toast/store.jsx.map +1 -1
- package/dist/toast/toast.css +20 -13
- package/dist/toast/toast.css.map +1 -1
- package/dist/toggle/checkbox.d.ts.map +1 -1
- package/dist/toggle/checkbox.jsx +1 -1
- package/dist/toggle/checkbox.jsx.map +1 -1
- package/dist/toggle/chip-group.d.ts.map +1 -1
- package/dist/toggle/chip-group.jsx +5 -5
- package/dist/toggle/chip-group.jsx.map +1 -1
- package/dist/toggle/switch.d.ts.map +1 -1
- package/dist/toggle/switch.jsx +2 -2
- package/dist/toggle/switch.jsx.map +1 -1
- package/dist/toggle/toggle.css +1 -2
- package/dist/toggle/toggle.css.map +1 -1
- package/package.json +2 -2
package/dist/sheet/frame.jsx.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sheet/frame.jsx","sources":["../../src/sheet/frame.tsx"],"sourcesContent":["import './sheet.css';\nimport {\n createAbortController,\n formatColor,\n type G9AbortController,\n type G9AbortSignal,\n tryParseColor,\n withAlpha,\n} from '@g9tm/lynxcontrols-foundation';\nimport { SheetContent, SheetHandle, SheetRoot, SheetView } from '@lynx-js/lynx-ui-sheet';\nimport { createContext, type ReactNode, useContext, useEffect, useRef, useState } from '@lynx-js/react';\nimport { type G9TimerHandle, startTimer, stopTimer } from '../base/timers';\nimport { G9ActivityIndicator } from '../display/activity-indicator';\nimport { G9SheetSkeleton } from '../display/shimmer';\nimport { G9SheetFooter, G9SheetHeader, g9SheetHeaderMetrics } from './header';\nimport type { G9SheetHeightMemo } from './height-memo';\nimport type { G9SheetSettings } from './options';\nimport {\n clampFitHeight,\n currentPlatform,\n g9SheetDragCloseThreshold,\n g9SheetFitLoadingMinHeight,\n parentRecedeOffset,\n platformSheetConstraints,\n resolveSheetLayout,\n scaledSheetDuration,\n sheetOverlayOpacity,\n sheetTopPadding,\n} from './sizing';\nimport type { G9SheetEntry, G9SheetHandle, G9SheetStack } from './stack';\n\n/** What content inside a sheet can read (MAUI `IG9BottomSheetAwareView` + deferred load signals). */\nexport interface G9SheetContextValue {\n /** The sheet-scoped handle: `close()` closes only this sheet. */\n readonly handle: G9SheetHandle;\n /** Aborted when the sheet starts closing (cancel loads with it). */\n readonly signal: G9AbortSignal;\n /** The open motion has finished. */\n readonly opened: boolean;\n /** The sheet is closing. */\n readonly closing: boolean;\n /** Resting body cap of a fit sheet (px), else `null`. */\n readonly maxBodyHeight: number | null;\n}\n\nconst SheetContext = createContext<G9SheetContextValue | null>(null);\n\n/** The enclosing sheet, or `null` outside one. */\nexport function useG9SheetContext(): G9SheetContextValue | null {\n return useContext(SheetContext);\n}\n\n/** Props of {@link G9SheetFrame}. */\nexport interface G9SheetFrameProps {\n readonly entry: G9SheetEntry;\n readonly stack: G9SheetStack;\n /** Host height (px): percentage detents and caps resolve against it. */\n readonly hostHeight: number;\n readonly hostWidth: number;\n readonly topInset: number;\n readonly settings: Required<G9SheetSettings>;\n readonly memo: G9SheetHeightMemo | null;\n /** Culture tag of the memo key. */\n readonly culture: string;\n /** The sheet is the top of the stack (receives scrim input). */\n readonly isTop: boolean;\n /** The sheet came to rest at a new height (px); drives the page recede threshold. */\n readonly onRest?: (heightPx: number) => void;\n}\n\nfunction scrimColor(entry: G9SheetEntry, settings: Required<G9SheetSettings>, opacity: number): string {\n const explicit = entry.options.windowBackgroundColor;\n const parsed = tryParseColor(explicit ?? settings.modalOverlayColor);\n if (!parsed) return explicit ?? settings.modalOverlayColor;\n return formatColor(withAlpha(parsed, explicit ? parsed.a : opacity));\n}\n\n/**\n * One sheet of the stack on lynx-ui `SheetRoot` (motion, drag, snap points from lynx-ui; G9 adds detent mapping,\n * scrim, header/footer, deferred content, recede and results). Rendered by the sheet service in the host's sheets\n * layer; use `useG9Sheets()` to open sheets.\n */\nexport function G9SheetFrame(props: G9SheetFrameProps): ReactNode {\n const { entry, stack, settings } = props;\n const o = entry.options;\n const layout = resolveSheetLayout(o, props.hostHeight);\n const showing = entry.status === 'opening' || entry.status === 'open';\n const closing = entry.status === 'closing';\n const handle = stack.handleOf(entry.id) as G9SheetHandle;\n\n const controller = useRef<G9AbortController | null>(null);\n if (controller.current === null) controller.current = createAbortController();\n useEffect(() => {\n if (closing || entry.status === 'closed') controller.current?.abort();\n }, [closing, entry.status]);\n useEffect(() => () => controller.current?.abort(), []);\n\n // Deferred (factory) content: placeholder until the open motion ended + loadDelayMs, then the body.\n const factory = typeof entry.content === 'function';\n const deferred = (factory || settings.deferPrebuiltContent) && o.deferContent !== false;\n const [revealed, setRevealed] = useState(!deferred);\n const [covering, setCovering] = useState(false);\n const timer = useRef<G9TimerHandle | null>(null);\n const coverTimer = useRef<G9TimerHandle | null>(null);\n useEffect(\n () => () => {\n if (coverTimer.current !== null) stopTimer(coverTimer.current);\n },\n [],\n );\n useEffect(() => {\n if (!deferred || revealed || entry.status !== 'open') return;\n const delay = layout.fullScreen\n ? Math.max(o.loadDelayMs ?? 369, settings.openAnimationDurationMs + 32)\n : (o.loadDelayMs ?? 369);\n timer.current = startTimer(() => {\n setRevealed(true);\n if (o.fadeDeferredContentIn !== false) {\n setCovering(true);\n coverTimer.current = startTimer(() => setCovering(false), 220);\n }\n }, delay);\n return () => {\n if (timer.current !== null) stopTimer(timer.current);\n };\n }, [deferred, revealed, entry.status]);\n\n const memoKey = o.heightMemoKey ? `${o.heightMemoKey}|w${Math.round(props.hostWidth)}|${props.culture}|fs1` : null;\n const placeholderHeight = o.useFullScreenLoadingPlaceholder\n ? props.hostHeight\n : (o.deferredLoadingPlaceholderHeight ??\n (memoKey ? props.memo?.lookup(memoKey) : undefined) ??\n g9SheetFitLoadingMinHeight);\n\n const [bodyHeight, setBodyHeight] = useState(0);\n const onBodyLayout = (e: { detail?: { height?: number } }) => {\n const h = e.detail?.height ?? 0;\n if (h <= 0) return;\n setBodyHeight(h);\n if (memoKey && revealed && !covering) props.memo?.record(memoKey, h);\n };\n\n const placeholder =\n o.loadingSkeleton && o.loadingSkeleton !== 'none' ? (\n <view className=\"g9-sheet__placeholder\" style={{ height: `${placeholderHeight}px` }}>\n <G9SheetSkeleton skeleton={o.loadingSkeleton} rowCount={o.loadingSkeletonRowCount ?? 0} />\n </view>\n ) : (\n <view\n className=\"g9-sheet__placeholder g9-sheet__placeholder--spinner\"\n style={{ height: `${placeholderHeight}px` }}\n >\n <G9ActivityIndicator running size={32} />\n </view>\n );\n const body = revealed ? (factory ? (entry.content as () => ReactNode)() : (entry.content as ReactNode)) : null;\n\n const maxBody = layout.fitMaxHeight;\n const contextValue: G9SheetContextValue = {\n handle,\n signal: (controller.current as G9AbortController).signal,\n opened: entry.status === 'open',\n closing,\n maxBodyHeight: maxBody,\n };\n\n // Scrim: the resting dim of the detent (one detent → max; several → interpolated at the initial detent).\n const ratios = layout.snapPoints.map((p) =>\n typeof p === 'number' ? p / Math.max(1, props.hostHeight) : p === 'fit' ? 0.5 : Number.parseFloat(p) / 100,\n );\n const restingRatio = ratios[layout.initialSnap] ?? 1;\n const opacity = entry.handingOff\n ? 0\n : sheetOverlayOpacity(\n restingRatio,\n ratios,\n settings.modalOverlayMinimumOpacity,\n settings.modalOverlayMaximumOpacity,\n );\n const modal = o.isModal !== false;\n const recede = entry.receded\n ? { transform: `translateY(${parentRecedeOffset(bodyHeight || props.hostHeight * 0.5)}px)`, opacity: 0 }\n : { transform: 'translateY(0px)', opacity: 1 };\n const topPadding = layout.fullScreen ? sheetTopPadding(o, props.topInset) : 0;\n const platform = currentPlatform();\n const openMs = o.openAnimationDurationMs ?? settings.openAnimationDurationMs;\n const closeMs = o.closeAnimationDurationMs ?? settings.closeAnimationDurationMs;\n const corner =\n platform === 'android' && o.androidShouldRemoveExpandedCorners === true && layout.fullScreen\n ? 0\n : (o.cornerRadius ?? 12);\n // Motion: lynx-ui's native spring by default; tweens of the configured durations for the timed style or a per-sheet\n // duration (MAUI `MotionStyle.Timed`, `Open/CloseAnimationDurationMs`).\n const easeOut = (t: number) => 1 - (1 - t) ** 3;\n const timed =\n settings.motionStyle === 'timed' || o.openAnimationDurationMs != null || o.closeAnimationDurationMs != null;\n // Size-scaled: a sheet resting below full height travels (and takes) the matching slice of the duration.\n const enterMs = scaledSheetDuration(openMs, restingRatio, settings.sizeScaledAnimationDuration);\n const exitMs = scaledSheetDuration(closeMs, restingRatio, settings.sizeScaledAnimationDuration);\n const motion = timed\n ? {\n enterAnimation: { type: 'tween' as const, duration: enterMs / 1000, ease: easeOut },\n exitAnimation: { type: 'tween' as const, duration: exitMs / 1000, ease: easeOut },\n snapAnimation: { type: 'tween' as const, duration: openMs / 1000, ease: easeOut },\n }\n : {};\n return (\n <SheetRoot\n show={showing}\n snapPoints={layout.snapPoints}\n initialSnap={layout.initialSnap}\n screenHeight={props.hostHeight}\n dragDisabled={layout.dragDisabled}\n enableDragToClose={layout.enableDragToClose}\n dismissThreshold={g9SheetDragCloseThreshold}\n handleOnly={o.scrollingExpandsSheet === false}\n onShowChange={(open) => {\n if (!open) void stack.requestBack(entry.id, 'drag');\n }}\n onSnapChange={(index, value) => {\n const detents = (o.states && o.states.length > 0 ? o.states : ['medium', 'large']).filter((d) => d);\n const ordered = (['peek', 'medium', 'large'] as const).filter((d) => detents.includes(d));\n props.onRest?.(value);\n o.onStateChanged?.(layout.fit ? 'fit' : (ordered[index] ?? 'large'), value);\n }}\n onOpen={() => stack.markOpened(entry.id)}\n onClose={() => stack.markClosed(entry.id)}\n >\n {/* The view is `position: fixed` without a size; lynx-ui places the sheet at its `top: 100%` and the backdrop at\n its 100 %. Unsized it is 0 × 0 (Lynxtron), so the sheet slid in above the screen: give it the viewport.\n event-through lets taps reach the page around a non-modal sheet; the scrim and the sheet take theirs. */}\n <SheetView className=\"g9-sheet__view\" nativeProps={{ 'event-through': true }}>\n {modal ? (\n <view\n event-through={false}\n className={`g9-sheet__scrim${props.isTop && !closing ? '' : ' g9-sheet__scrim--covered'}`}\n style={{\n backgroundColor: scrimColor(entry, settings, opacity),\n transition:\n platform === 'ios' && o.animateOverlayToColorOnIos === false\n ? 'none'\n : `background-color ${closing ? closeMs : openMs}ms`,\n }}\n bindtap={() => {\n if (layout.closeOnOverlayTap) void stack.requestBack(entry.id, 'overlayTap');\n }}\n />\n ) : null}\n <SheetContent\n className={`g9-sheet g9-sheet--${entry.status}${layout.fit ? ' g9-sheet--fit' : ''}`}\n style={{\n backgroundColor: o.backgroundColor ?? 'var(--g9-surface-container)',\n borderTopLeftRadius: `${corner}px`,\n borderTopRightRadius: `${corner}px`,\n transition: 'transform 220ms ease-out, opacity 220ms ease-out',\n ...recede,\n ...platformSheetConstraints(o),\n }}\n innerStyle={{ paddingTop: `${topPadding}px` }}\n {...motion}\n >\n <SheetContext.Provider value={contextValue}>\n {layout.showHandle ||\n (layout.fullScreen && o.showToolbar && o.showFullScreenDragHandle !== false && !layout.dragDisabled) ? (\n <SheetHandle className=\"g9-sheet__grabber-area\">\n <view className=\"g9-sheet__grabber\" />\n </SheetHandle>\n ) : null}\n <G9SheetHeader options={o} onBack={() => void stack.requestBack(entry.id, 'toolbarButton')} />\n {o.showToolbar && o.useStandardBodyTopGap !== false ? (\n <view className=\"g9-sheet__body-gap\" style={{ height: `${g9SheetHeaderMetrics.bodyTopGap}px` }} />\n ) : null}\n <scroll-view\n className={`g9-sheet__body${layout.fullScreen ? ' g9-sheet__body--fill' : ''}`}\n scroll-orientation=\"vertical\"\n style={{\n padding: `${o.padding ?? 0}px`,\n ...(maxBody !== null ? { maxHeight: `${maxBody}px` } : {}),\n }}\n >\n <view className=\"g9-sheet__content\" key={entry.version} bindlayoutchange={onBodyLayout}>\n {body}\n {!revealed ? placeholder : null}\n {covering ? (\n <view\n className=\"g9-sheet__cover\"\n style={{ height: `${clampFitHeight(placeholderHeight, props.hostHeight, true)}px` }}\n >\n {placeholder}\n </view>\n ) : null}\n </view>\n </scroll-view>\n <G9SheetFooter options={o} />\n </SheetContext.Provider>\n </SheetContent>\n </SheetView>\n </SheetRoot>\n );\n}\n"],"names":["SheetContext","createContext","useG9SheetContext","useContext","scrimColor","entry","settings","opacity","explicit","parsed","tryParseColor","formatColor","withAlpha","G9SheetFrame","props","_ref","_o_loadingSkeletonRowCount","_ratios_layout_initialSnap","_o_openAnimationDurationMs","_o_closeAnimationDurationMs","_o_cornerRadius","_o_backgroundColor","_o_padding","_props_memo","stack","o","layout","resolveSheetLayout","showing","closing","handle","controller","useRef","createAbortController","useEffect","_controller_current","factory","deferred","revealed","setRevealed","useState","covering","setCovering","timer","coverTimer","stopTimer","_o_loadDelayMs","_o_loadDelayMs1","delay","Math","startTimer","memoKey","placeholderHeight","undefined","g9SheetFitLoadingMinHeight","bodyHeight","setBodyHeight","onBodyLayout","e","_e_detail","h","placeholder","view","G9SheetSkeleton","G9ActivityIndicator","body","maxBody","contextValue","ratios","p","Number","restingRatio","sheetOverlayOpacity","modal","recede","parentRecedeOffset","topPadding","sheetTopPadding","platform","currentPlatform","openMs","closeMs","corner","easeOut","t","timed","enterMs","scaledSheetDuration","exitMs","motion","SheetRoot","g9SheetDragCloseThreshold","open","index","value","_ordered_index","detents","d","ordered","SheetView","SheetContent","platformSheetConstraints","SheetHandle","G9SheetHeader","g9SheetHeaderMetrics","scroll-view","clampFitHeight","G9SheetFooter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sheet/frame.jsx","sources":["../../src/sheet/frame.tsx"],"sourcesContent":["import './sheet.css';\nimport {\n createAbortController,\n formatColor,\n type G9AbortController,\n type G9AbortSignal,\n resolveThemeColor,\n tryParseColor,\n withAlpha,\n} from '@g9tm/lynxcontrols-foundation';\nimport { SheetContent, SheetRoot, type SheetRootRef, SheetView } from '@lynx-js/lynx-ui-sheet';\nimport { createContext, type ReactNode, useContext, useEffect, useRef, useState } from '@lynx-js/react';\nimport { g9IdProps } from '../base/control';\nimport { type G9TimerHandle, startTimer, stopTimer } from '../base/timers';\nimport { G9ActivityIndicator } from '../display/activity-indicator';\nimport { G9SheetSkeleton } from '../display/shimmer';\nimport { g9FieldNotchStyle } from '../fields/notch';\nimport { useG9Theme } from '../provider/hooks';\nimport { G9SheetGestureFrame, useSheetBodyGesture, useSheetGestureRefs } from './gesture';\nimport { G9SheetFooter, G9SheetHeader, g9SheetHeaderMetrics } from './header';\nimport type { G9SheetHeightMemo } from './height-memo';\nimport { resolveSheetMotion } from './motion';\nimport type { G9SheetDetent, G9SheetSettings } from './options';\nimport {\n clampFitHeight,\n currentPlatform,\n g9SheetDragCloseThreshold,\n g9SheetFitLoadingMinHeight,\n parentRecedeOffset,\n platformSheetConstraints,\n resolveSheetLayout,\n sheetOverlayOpacity,\n sheetSurfaceBottomPadding,\n sheetSurfaceTopPadding,\n} from './sizing';\nimport type { G9SheetEntry, G9SheetHandle, G9SheetStack } from './stack';\n\n/** What content inside a sheet can read (MAUI `IG9BottomSheetAwareView` + deferred load signals). */\nexport interface G9SheetContextValue {\n /** The sheet-scoped handle: `close()` closes only this sheet. */\n readonly handle: G9SheetHandle;\n /** Aborted when the sheet starts closing (cancel loads with it). */\n readonly signal: G9AbortSignal;\n /** The open motion has finished. */\n readonly opened: boolean;\n /** The sheet is closing. */\n readonly closing: boolean;\n /** Resting body cap of a fit sheet (px), else `null`. */\n readonly maxBodyHeight: number | null;\n}\n\nconst SheetContext = createContext<G9SheetContextValue | null>(null);\n\n/** The enclosing sheet, or `null` outside one. */\nexport function useG9SheetContext(): G9SheetContextValue | null {\n return useContext(SheetContext);\n}\n\n/** Props of {@link G9SheetFrame}. */\nexport interface G9SheetFrameProps {\n readonly entry: G9SheetEntry;\n readonly stack: G9SheetStack;\n /** Host height (px): percentage detents and caps resolve against it. */\n readonly hostHeight: number;\n readonly hostWidth: number;\n readonly topInset: number;\n /** The host's bottom safe inset (a visible navigation bar); the surface pads by it. Default 0. */\n readonly bottomInset?: number;\n readonly settings: Required<G9SheetSettings>;\n readonly memo: G9SheetHeightMemo | null;\n /** Culture tag of the memo key. */\n readonly culture: string;\n /** The sheet is the top of the stack (receives scrim input). */\n readonly isTop: boolean;\n /** The sheet came to rest at a new height (px); drives the page recede threshold. */\n readonly onRest?: (heightPx: number) => void;\n}\n\nfunction scrimColor(entry: G9SheetEntry, settings: Required<G9SheetSettings>, opacity: number): string {\n const explicit = entry.options.windowBackgroundColor;\n const parsed = tryParseColor(explicit ?? settings.modalOverlayColor);\n if (!parsed) return explicit ?? settings.modalOverlayColor;\n return formatColor(withAlpha(parsed, explicit ? parsed.a : opacity));\n}\n\n/** lynx-ui's inner view lays G9's frame out as a column (its default `linear` layout ignores `flex`). */\nconst sheetInnerStyle = { display: 'flex', flexDirection: 'column' } as const;\n/** The receded parent sinks and fades over 220 ms (MAUI `StackParentRecedeDurationMs`, CubicOut). */\nconst g9SheetRecedeTransition = 'transform 220ms ease-out, opacity 220ms ease-out';\n\n/** The sheet's detents, small to large (the order of lynx-ui's snap points). */\nfunction orderedDetents(o: G9SheetEntry['options']): G9SheetDetent[] {\n const requested = o.states && o.states.length > 0 ? o.states : (['medium', 'large'] as const);\n return (['peek', 'medium', 'large'] as const).filter((d) => requested.includes(d));\n}\n\n/** The detent a sheet opens at (`'fit'` for fit-to-content). */\nfunction initialDetent(o: G9SheetEntry['options'], fit: boolean): G9SheetDetent | 'fit' {\n if (fit) return 'fit';\n const ordered = orderedDetents(o);\n const current = o.currentState ?? 'medium';\n return ordered.includes(current) ? current : (ordered[0] ?? 'medium');\n}\n\n/**\n * One sheet of the stack on lynx-ui `SheetRoot` (motion, drag, snap points from lynx-ui; G9 adds detent mapping,\n * scrim, header/footer, deferred content, recede and results). Rendered by the sheet service in the host's sheets\n * layer; use `useG9Sheets()` to open sheets.\n */\nexport function G9SheetFrame(props: G9SheetFrameProps): ReactNode {\n const { entry, stack, settings } = props;\n const palette = useG9Theme().palette;\n const gesture = useSheetGestureRefs();\n const bodyGesture = useSheetBodyGesture(gesture);\n const o = entry.options;\n const layout = resolveSheetLayout(o, props.hostHeight);\n const showing = entry.status === 'opening' || entry.status === 'open';\n const closing = entry.status === 'closing';\n const handle = stack.handleOf(entry.id) as G9SheetHandle;\n\n const controller = useRef<G9AbortController | null>(null);\n if (controller.current === null) controller.current = createAbortController();\n useEffect(() => {\n if (closing || entry.status === 'closed') controller.current?.abort();\n }, [closing, entry.status]);\n useEffect(() => () => controller.current?.abort(), []);\n\n // Deferred (factory) content: placeholder until the open motion ended + loadDelayMs, then the body.\n const factory = typeof entry.content === 'function';\n const deferred = (factory || settings.deferPrebuiltContent) && o.deferContent !== false;\n const [revealed, setRevealed] = useState(!deferred);\n const [covering, setCovering] = useState(false);\n const timer = useRef<G9TimerHandle | null>(null);\n const coverTimer = useRef<G9TimerHandle | null>(null);\n useEffect(\n () => () => {\n if (coverTimer.current !== null) stopTimer(coverTimer.current);\n },\n [],\n );\n useEffect(() => {\n if (!deferred || revealed || entry.status !== 'open') return;\n const delay = layout.fullScreen\n ? Math.max(o.loadDelayMs ?? 369, settings.openAnimationDurationMs + 32)\n : (o.loadDelayMs ?? 369);\n timer.current = startTimer(() => {\n setRevealed(true);\n if (o.fadeDeferredContentIn !== false) {\n setCovering(true);\n coverTimer.current = startTimer(() => setCovering(false), 220);\n }\n }, delay);\n return () => {\n if (timer.current !== null) stopTimer(timer.current);\n };\n }, [deferred, revealed, entry.status]);\n\n const memoKey = o.heightMemoKey ? `${o.heightMemoKey}|w${Math.round(props.hostWidth)}|${props.culture}|fs1` : null;\n const placeholderHeight = o.useFullScreenLoadingPlaceholder\n ? props.hostHeight\n : (o.deferredLoadingPlaceholderHeight ??\n (memoKey ? props.memo?.lookup(memoKey) : undefined) ??\n g9SheetFitLoadingMinHeight);\n\n const [bodyHeight, setBodyHeight] = useState(0);\n // The footer can come and go after the open (a `footerBand` whose buttons wait for data): it counts for the fit too.\n const [footerHeight, setFooterHeight] = useState(0);\n const onFooterLayout = (e: { detail?: { height?: number } }) => setFooterHeight(Math.max(0, e.detail?.height ?? 0));\n const onBodyLayout = (e: { detail?: { height?: number } }) => {\n const h = e.detail?.height ?? 0;\n if (h <= 0) return;\n setBodyHeight(h);\n if (memoKey && revealed && !covering) props.memo?.record(memoKey, h);\n };\n\n const placeholder =\n o.loadingSkeleton && o.loadingSkeleton !== 'none' ? (\n <view className=\"g9-sheet__placeholder\" style={{ height: `${placeholderHeight}px` }}>\n <G9SheetSkeleton skeleton={o.loadingSkeleton} rowCount={o.loadingSkeletonRowCount ?? 0} />\n </view>\n ) : (\n <view\n className=\"g9-sheet__placeholder g9-sheet__placeholder--spinner\"\n style={{ height: `${placeholderHeight}px` }}\n >\n <G9ActivityIndicator running size={32} />\n </view>\n );\n const body = revealed ? (factory ? (entry.content as () => ReactNode)() : (entry.content as ReactNode)) : null;\n\n const maxBody = layout.fitMaxHeight;\n const contextValue: G9SheetContextValue = {\n handle,\n signal: (controller.current as G9AbortController).signal,\n opened: entry.status === 'open',\n closing,\n maxBodyHeight: maxBody,\n };\n\n // Scrim: the resting dim of the detent (one detent → max; several → interpolated at the initial detent). A fit sheet\n // ranges from its content height to full screen (MAUI ResolveModalOverlayOpacity), so at rest it dims at the\n // MINIMUM — unless its content fills the screen (MAUI's single-state range).\n const ratios = layout.snapPoints.map((p) =>\n typeof p === 'number' ? p / Math.max(1, props.hostHeight) : p === 'fit' ? 0.5 : Number.parseFloat(p) / 100,\n );\n const restingRatio = ratios[layout.initialSnap] ?? 1;\n const contentRatio = bodyHeight > 0 ? Math.min(1, bodyHeight / Math.max(1, props.hostHeight)) : 0.5;\n const opacity = entry.handingOff\n ? 0\n : layout.fit\n ? contentRatio >= 0.99\n ? settings.modalOverlayMaximumOpacity\n : settings.modalOverlayMinimumOpacity\n : sheetOverlayOpacity(\n restingRatio,\n ratios,\n settings.modalOverlayMinimumOpacity,\n settings.modalOverlayMaximumOpacity,\n );\n const modal = o.isModal !== false;\n // The receded parent sinks and fades (MAUI stack recede). This runs on G9's own frame view, never on lynx-ui's\n // SheetContent view: lynx-ui moves that one from a main-thread worklet, and an inline style written over it from\n // here put the parent back at its closed offset when the child closed (the parent vanished, its scrim stayed).\n const recede = entry.receded\n ? { transform: `translateY(${parentRecedeOffset(bodyHeight || props.hostHeight * 0.5)}px)`, opacity: 0 }\n : { transform: 'translateY(0px)', opacity: 1 };\n const [resting, setResting] = useState<G9SheetDetent | 'fit'>(() => initialDetent(o, layout.fit));\n\n // A fit sheet whose body grows or shrinks AFTER it opened (rows that load later, a spinner replaced by content):\n // lynx-ui re-measures the 'fit' snap point on layout but leaves the sheet where it was, so a taller body ran off the\n // bottom of the screen (its footer unreachable). Re-snap to the new fit while the sheet rests there.\n const rootRef = useRef<SheetRootRef | null>(null);\n const lastFitBody = useRef(0);\n useEffect(() => {\n if (!layout.fit || bodyHeight <= 0 || entry.status !== 'open' || resting !== 'fit') return;\n // Also right after the open motion: the body may have grown while the sheet was still sliding in.\n const fitHeight = bodyHeight + footerHeight;\n if (Math.abs(lastFitBody.current - fitHeight) < 1) return;\n lastFitBody.current = fitHeight;\n rootRef.current?.snapTo(0, { animate: true });\n }, [bodyHeight, footerHeight, entry.status, resting, layout.fit]);\n const topPadding = sheetSurfaceTopPadding(o, layout, resting, props.topInset, props.hostHeight);\n const bottomPadding = sheetSurfaceBottomPadding(o, props.bottomInset ?? 0);\n const platform = currentPlatform();\n // The body reports its scroll offset to the gesture routing on the main thread (./gesture.tsx) on the phones only:\n // Lynxtron (desktop) drops the WHOLE sheet, no element of it is created, when the body's scroll-view carries\n // `main-thread:bindscroll` (the gallery smoke, Azure build 614). On the desktop a wheel scrolls the body.\n const phone = platform === 'android' || platform === 'ios';\n const openMs = o.openAnimationDurationMs ?? settings.openAnimationDurationMs;\n const closeMs = o.closeAnimationDurationMs ?? settings.closeAnimationDurationMs;\n const corner =\n platform === 'android' && o.androidShouldRemoveExpandedCorners === true && layout.fullScreen\n ? 0\n : (o.cornerRadius ?? 12);\n const surface = o.backgroundColor ?? 'var(--g9-surface-container)';\n // Fields in the sheet hide their outline under a floated label with the sheet's colour, not the page's.\n const notch = g9FieldNotchStyle(resolveThemeColor(surface, palette));\n // Motion (MAUI G9SheetMotionModel, ./motion.ts): Material's settle on Android, the UIKit spring on iOS, or the timed\n // cubic; the travel is the share of the host the sheet covers where it rests (a fit sheet: its measured body).\n const detents = orderedDetents(o);\n const restIndex = layout.fit ? 0 : Math.max(0, detents.indexOf(resting as G9SheetDetent));\n const fitRatio =\n bodyHeight > 0 ? Math.min(1, (bodyHeight + topPadding + bottomPadding) / Math.max(1, props.hostHeight)) : 0.4;\n const openRatio = layout.fit ? fitRatio : (ratios[restIndex] ?? restingRatio);\n const motion = resolveSheetMotion({\n style: settings.motionStyle,\n platform,\n openRatio,\n snapRatio: ratios.length > 1 ? Math.max(...ratios) - Math.min(...ratios) : openRatio,\n openMs,\n closeMs,\n perSheetOpen: o.openAnimationDurationMs != null,\n perSheetClose: o.closeAnimationDurationMs != null,\n sizeScaled: settings.sizeScaledAnimationDuration,\n });\n // The body's content; inside a scroller by default, or filling a static body (`scrollBody: false`).\n const content = (\n <view\n className={`g9-sheet__content${o.scrollBody === false ? ' g9-sheet__content--fill' : ''}`}\n key={entry.version}\n bindlayoutchange={onBodyLayout}\n >\n {body}\n {!revealed ? placeholder : null}\n {covering ? (\n <view\n className=\"g9-sheet__cover\"\n style={{ height: `${clampFitHeight(placeholderHeight, props.hostHeight, true)}px` }}\n >\n {placeholder}\n </view>\n ) : null}\n </view>\n );\n return (\n <SheetRoot\n ref={rootRef}\n show={showing}\n snapPoints={layout.snapPoints}\n initialSnap={layout.initialSnap}\n screenHeight={props.hostHeight}\n dragDisabled={layout.dragDisabled}\n enableDragToClose={layout.enableDragToClose}\n dismissThreshold={g9SheetDragCloseThreshold}\n // G9 routes every touch itself (./gesture.tsx: drag vs. body scroll, N-028); lynx-ui's content handlers stay off.\n handleOnly\n onShowChange={(open) => {\n if (!open) void stack.requestBack(entry.id, 'drag');\n }}\n onSnapChange={(index, value) => {\n const detent = layout.fit ? 'fit' : (detents[index] ?? 'large');\n setResting(detent);\n props.onRest?.(value);\n o.onStateChanged?.(detent, value);\n }}\n onOpen={() => stack.markOpened(entry.id)}\n onClose={() => stack.markClosed(entry.id)}\n >\n {/* The view is `position: fixed` without a size; lynx-ui places the sheet at its `top: 100%` and the backdrop at\n its 100 %. Unsized it is 0 × 0 (Lynxtron), so the sheet slid in above the screen: give it the viewport.\n event-through lets taps reach the page around a modal sheet's scrim-less parts; the scrim and the sheet take theirs.\n A non-modal sheet's view is also `pointer-events: none`: with event-through alone the Lynx view handed a tap\n on it to what lies under the whole Lynx view, so a NATIVE element of the page under the sheet (a map's own\n MotionEvents) never got it. (A native window `container` would do it too, but needs the overlay XElement.) */}\n <SheetView\n className={`g9-sheet__view${modal ? '' : ' g9-sheet__view--passthrough'}`}\n nativeProps={{ 'event-through': modal }}\n >\n {modal ? (\n <view\n event-through={false}\n className={`g9-sheet__scrim${props.isTop && !closing ? '' : ' g9-sheet__scrim--covered'}`}\n style={{\n backgroundColor: scrimColor(entry, settings, opacity),\n transition:\n platform === 'ios' && o.animateOverlayToColorOnIos === false\n ? 'none'\n : `background-color ${closing ? closeMs : openMs}ms`,\n }}\n bindtap={() => {\n if (layout.closeOnOverlayTap) void stack.requestBack(entry.id, 'overlayTap');\n }}\n />\n ) : null}\n {/* SheetContent's own view is lynx-ui's: a worklet writes its transform every motion frame, so its style is\n set once and never changes (a later inline-style write replaces the worklet's transform). Everything that\n changes (recede, paddings, colour) lives on G9's frame and surface inside it. */}\n <SheetContent\n className={`g9-sheet g9-sheet--${entry.status}${layout.fit ? ' g9-sheet--fit' : ''}`}\n style={platformSheetConstraints(o)}\n innerStyle={sheetInnerStyle}\n {...motion}\n >\n <G9SheetGestureFrame\n refs={gesture}\n canDrag={!layout.dragDisabled}\n bodyDrags={o.scrollingExpandsSheet !== false}\n className=\"g9-sheet__frame\"\n style={{ ...recede, transition: g9SheetRecedeTransition }}\n >\n <view\n className=\"g9-sheet__surface\"\n {...g9IdProps(o.automationId)}\n style={{\n backgroundColor: surface,\n borderTopLeftRadius: `${corner}px`,\n borderTopRightRadius: `${corner}px`,\n paddingTop: `${topPadding}px`,\n paddingBottom: `${bottomPadding}px`,\n ...notch,\n }}\n >\n <SheetContext.Provider value={contextValue}>\n {layout.showHandle ||\n (layout.fullScreen && o.showToolbar && o.showFullScreenDragHandle !== false && !layout.dragDisabled) ? (\n <view className=\"g9-sheet__grabber-area\">\n <view className=\"g9-sheet__grabber\" />\n </view>\n ) : null}\n <G9SheetHeader options={o} onBack={() => void stack.requestBack(entry.id, 'toolbarButton')} />\n {o.showToolbar && o.useStandardBodyTopGap !== false ? (\n <view className=\"g9-sheet__body-gap\" style={{ height: `${g9SheetHeaderMetrics.bodyTopGap}px` }} />\n ) : null}\n {o.scrollBody === false ? (\n <view\n className={`g9-sheet__body g9-sheet__body--static${layout.fullScreen ? ' g9-sheet__body--fill' : ''}`}\n style={{ padding: `${o.padding ?? 0}px` }}\n >\n {content}\n </view>\n ) : (\n <scroll-view\n className={`g9-sheet__body${layout.fullScreen ? ' g9-sheet__body--fill' : ''}`}\n scroll-orientation=\"vertical\"\n main-thread:ref={gesture.body}\n main-thread:bindscroll={phone ? bodyGesture.onScrollMT : undefined}\n main-thread:bindtouchstart={bodyGesture.onTouchStartMT}\n style={{\n padding: `${o.padding ?? 0}px`,\n ...(maxBody !== null ? { maxHeight: `${maxBody}px` } : {}),\n }}\n >\n {content}\n </scroll-view>\n )}\n <view className=\"g9-sheet__footer-slot\" bindlayoutchange={onFooterLayout}>\n <G9SheetFooter options={o} />\n </view>\n </SheetContext.Provider>\n </view>\n {/* Below the surface, so a drag past the top detent (rubber band) never shows the page under it. */}\n <view className=\"g9-sheet__skirt\" style={{ backgroundColor: surface }} />\n </G9SheetGestureFrame>\n </SheetContent>\n </SheetView>\n </SheetRoot>\n );\n}\n"],"names":["SheetContext","createContext","useG9SheetContext","useContext","scrimColor","entry","settings","opacity","explicit","parsed","tryParseColor","formatColor","withAlpha","sheetInnerStyle","g9SheetRecedeTransition","orderedDetents","o","requested","d","initialDetent","fit","_o_currentState","_ordered_","ordered","current","G9SheetFrame","props","_ref","_o_loadingSkeletonRowCount","_ratios_layout_initialSnap","_props_bottomInset","_o_openAnimationDurationMs","_o_closeAnimationDurationMs","_o_cornerRadius","_o_backgroundColor","_ratios_restIndex","_o_padding","_o_padding1","_props_memo","stack","palette","useG9Theme","gesture","useSheetGestureRefs","bodyGesture","useSheetBodyGesture","layout","resolveSheetLayout","showing","closing","handle","controller","useRef","createAbortController","useEffect","_controller_current","factory","deferred","revealed","setRevealed","useState","covering","setCovering","timer","coverTimer","stopTimer","_o_loadDelayMs","_o_loadDelayMs1","delay","Math","startTimer","memoKey","placeholderHeight","undefined","g9SheetFitLoadingMinHeight","bodyHeight","setBodyHeight","footerHeight","setFooterHeight","onFooterLayout","e","_e_detail","onBodyLayout","h","placeholder","view","G9SheetSkeleton","G9ActivityIndicator","body","maxBody","contextValue","ratios","p","Number","restingRatio","contentRatio","sheetOverlayOpacity","modal","recede","parentRecedeOffset","resting","setResting","rootRef","lastFitBody","_rootRef_current","fitHeight","topPadding","sheetSurfaceTopPadding","bottomPadding","sheetSurfaceBottomPadding","platform","currentPlatform","phone","openMs","closeMs","corner","surface","notch","g9FieldNotchStyle","resolveThemeColor","detents","restIndex","fitRatio","openRatio","motion","resolveSheetMotion","content","clampFitHeight","SheetRoot","g9SheetDragCloseThreshold","open","index","value","_detents_index","detent","SheetView","SheetContent","platformSheetConstraints","G9SheetGestureFrame","g9IdProps","G9SheetHeader","g9SheetHeaderMetrics","scroll-view","G9SheetFooter"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type MainThreadRef, type ReactNode } from '@lynx-js/react';
|
|
2
|
+
import type { MainThread } from '@lynx-js/types';
|
|
3
|
+
import { type G9SheetGestureMode } from './handoff.js';
|
|
4
|
+
/** Main-thread state shared by the gesture frame, the grabber and the scrolling body of one sheet. */
|
|
5
|
+
export interface G9SheetGestureRefs {
|
|
6
|
+
readonly mode: MainThreadRef<G9SheetGestureMode>;
|
|
7
|
+
readonly start: MainThreadRef<{
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
}>;
|
|
11
|
+
readonly lastY: MainThreadRef<number>;
|
|
12
|
+
/** The body's scroll offset (from its `scroll` event). */
|
|
13
|
+
readonly scrollTop: MainThreadRef<number>;
|
|
14
|
+
/** The current touch started inside the body. */
|
|
15
|
+
readonly inBody: MainThreadRef<boolean>;
|
|
16
|
+
/** The body's scroll view (its `enable-scroll` is turned off while the sheet owns a gesture that began in it). */
|
|
17
|
+
readonly body: MainThreadRef<MainThread.Element | null>;
|
|
18
|
+
}
|
|
19
|
+
/** Creates the refs of one sheet's gesture routing. */
|
|
20
|
+
export declare function useSheetGestureRefs(): G9SheetGestureRefs;
|
|
21
|
+
/** Main-thread handlers for the sheet body's `<scroll-view>` (its offset, and touches that start in it). */
|
|
22
|
+
export interface G9SheetBodyGesture {
|
|
23
|
+
readonly onScrollMT: (e: {
|
|
24
|
+
detail?: {
|
|
25
|
+
scrollTop?: number;
|
|
26
|
+
};
|
|
27
|
+
}) => void;
|
|
28
|
+
readonly onTouchStartMT: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The body's side of the routing: bind `main-thread:ref={refs.body}`, `main-thread:bindscroll={onScrollMT}` and
|
|
32
|
+
* `main-thread:bindtouchstart={onTouchStartMT}` on the body's `<scroll-view>`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function useSheetBodyGesture(refs: G9SheetGestureRefs): G9SheetBodyGesture;
|
|
35
|
+
/** Props of {@link G9SheetGestureFrame}. */
|
|
36
|
+
export interface G9SheetGestureFrameProps {
|
|
37
|
+
readonly refs: G9SheetGestureRefs;
|
|
38
|
+
/** The sheet can be dragged (draggable and not intercepted by `onBackRequested`). */
|
|
39
|
+
readonly canDrag: boolean;
|
|
40
|
+
/** `scrollingExpandsSheet` (default true): a drag that starts in the body may move the sheet. */
|
|
41
|
+
readonly bodyDrags: boolean;
|
|
42
|
+
readonly className: string;
|
|
43
|
+
readonly style: Record<string, string | number>;
|
|
44
|
+
readonly children?: ReactNode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The view that receives every touch on a sheet and routes it: to lynx-ui's drag (the sheet moves), to the body's
|
|
48
|
+
* native scrolling, or to neither (a horizontal gesture). Rendered inside lynx-ui `SheetContent`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function G9SheetGestureFrame(props: G9SheetGestureFrameProps): ReactNode;
|
|
51
|
+
//# sourceMappingURL=gesture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gesture.d.ts","sourceRoot":"","sources":["../../src/sheet/gesture.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAgC,MAAM,gBAAgB,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAwB,KAAK,kBAAkB,EAA2B,MAAM,WAAW,CAAC;AAMnG,sGAAsG;AACtG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,kHAAkH;IAClH,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CACzD;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,kBAAkB,CASxD;AAED,4GAA4G;AAC5G,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAWhF;AAED,4CAA4C;AAC5C,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,SAAS,CA6E9E"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { SheetDragContext, useSheetContext } from "@lynx-js/lynx-ui-sheet/dist/context/index.jsx";
|
|
2
|
+
import { useContext, useMainThreadRef } from "@lynx-js/react";
|
|
3
|
+
import { decideSheetGestureMT, scrollHandsOffToSheetMT } from "./handoff.jsx";
|
|
4
|
+
function noTouchMT(_e) {
|
|
5
|
+
'main thread';
|
|
6
|
+
}
|
|
7
|
+
function useSheetGestureRefs() {
|
|
8
|
+
return {
|
|
9
|
+
mode: useMainThreadRef('ignore'),
|
|
10
|
+
start: useMainThreadRef({
|
|
11
|
+
x: 0,
|
|
12
|
+
y: 0
|
|
13
|
+
}),
|
|
14
|
+
lastY: useMainThreadRef(0),
|
|
15
|
+
scrollTop: useMainThreadRef(0),
|
|
16
|
+
inBody: useMainThreadRef(false),
|
|
17
|
+
body: useMainThreadRef(null)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function useSheetBodyGesture(refs) {
|
|
21
|
+
const { scrollTop, inBody } = refs;
|
|
22
|
+
function onScrollMT(e) {
|
|
23
|
+
var _ref;
|
|
24
|
+
'main thread';
|
|
25
|
+
var _e_detail;
|
|
26
|
+
scrollTop.current = null != (_ref = null == (_e_detail = e.detail) ? void 0 : _e_detail.scrollTop) ? _ref : 0;
|
|
27
|
+
}
|
|
28
|
+
function onTouchStartMT() {
|
|
29
|
+
'main thread';
|
|
30
|
+
inBody.current = true;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
onScrollMT,
|
|
34
|
+
onTouchStartMT
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function G9SheetGestureFrame(props) {
|
|
38
|
+
var _ref, _ref1, _ref2, _useSheetContext_sheetProgress;
|
|
39
|
+
var _useContext;
|
|
40
|
+
const handlers = null == (_useContext = useContext(SheetDragContext)) ? void 0 : _useContext.dragHandlers;
|
|
41
|
+
const startDrag = null != (_ref = null == handlers ? void 0 : handlers.handleTouchStartMT) ? _ref : noTouchMT;
|
|
42
|
+
const moveDrag = null != (_ref1 = null == handlers ? void 0 : handlers.handleTouchMoveMT) ? _ref1 : noTouchMT;
|
|
43
|
+
const endDrag = null != (_ref2 = null == handlers ? void 0 : handlers.handleTouchEndMT) ? _ref2 : noTouchMT;
|
|
44
|
+
const noProgress = useMainThreadRef(null);
|
|
45
|
+
const progress = null != (_useSheetContext_sheetProgress = useSheetContext().sheetProgress) ? _useSheetContext_sheetProgress : noProgress;
|
|
46
|
+
const { mode, start, lastY, scrollTop, inBody, body } = props.refs;
|
|
47
|
+
const canDrag = props.canDrag;
|
|
48
|
+
const bodyDrags = props.bodyDrags;
|
|
49
|
+
function atTopMT() {
|
|
50
|
+
'main thread';
|
|
51
|
+
const value = progress.current;
|
|
52
|
+
return !value || value.get() >= 0.995;
|
|
53
|
+
}
|
|
54
|
+
function setBodyScrollMT(enabled) {
|
|
55
|
+
'main thread';
|
|
56
|
+
var _body_current;
|
|
57
|
+
null == (_body_current = body.current) || _body_current.setAttribute('enable-scroll', enabled);
|
|
58
|
+
}
|
|
59
|
+
function onStartMT(e) {
|
|
60
|
+
'main thread';
|
|
61
|
+
start.current = {
|
|
62
|
+
x: e.detail.x,
|
|
63
|
+
y: e.detail.y
|
|
64
|
+
};
|
|
65
|
+
lastY.current = e.detail.y;
|
|
66
|
+
mode.current = 'pending';
|
|
67
|
+
if (canDrag) startDrag(e);
|
|
68
|
+
}
|
|
69
|
+
function onMoveMT(e) {
|
|
70
|
+
'main thread';
|
|
71
|
+
const y = e.detail.y;
|
|
72
|
+
const step = y - lastY.current;
|
|
73
|
+
lastY.current = y;
|
|
74
|
+
if ('pending' === mode.current) {
|
|
75
|
+
const decided = decideSheetGestureMT({
|
|
76
|
+
dx: e.detail.x - start.current.x,
|
|
77
|
+
dy: y - start.current.y,
|
|
78
|
+
atTop: atTopMT(),
|
|
79
|
+
scrollTop: scrollTop.current,
|
|
80
|
+
inBody: inBody.current,
|
|
81
|
+
canDrag,
|
|
82
|
+
bodyDrags
|
|
83
|
+
});
|
|
84
|
+
if ('pending' === decided) return;
|
|
85
|
+
mode.current = decided;
|
|
86
|
+
if ('sheet' === decided && inBody.current) setBodyScrollMT(false);
|
|
87
|
+
} else if ('scroll' === mode.current && scrollHandsOffToSheetMT(atTopMT(), scrollTop.current, step, canDrag, bodyDrags)) {
|
|
88
|
+
mode.current = 'sheet';
|
|
89
|
+
setBodyScrollMT(false);
|
|
90
|
+
startDrag(e);
|
|
91
|
+
}
|
|
92
|
+
if ('sheet' === mode.current) moveDrag(e);
|
|
93
|
+
}
|
|
94
|
+
function onEndMT(e) {
|
|
95
|
+
'main thread';
|
|
96
|
+
if ('sheet' === mode.current) endDrag(e);
|
|
97
|
+
if (inBody.current) setBodyScrollMT(true);
|
|
98
|
+
mode.current = 'ignore';
|
|
99
|
+
inBody.current = false;
|
|
100
|
+
}
|
|
101
|
+
return <view className={props.className} style={props.style} main-thread:bindtouchstart={onStartMT} main-thread:bindtouchmove={onMoveMT} main-thread:bindtouchend={onEndMT} main-thread:bindtouchcancel={onEndMT}>
|
|
102
|
+
{props.children}
|
|
103
|
+
</view>;
|
|
104
|
+
}
|
|
105
|
+
export { G9SheetGestureFrame, useSheetBodyGesture, useSheetGestureRefs };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=gesture.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet/gesture.jsx","sources":["../../src/sheet/gesture.tsx"],"sourcesContent":["// The sheet's own gesture routing (ledger N-028): G9 owns every touch on the sheet and forwards to lynx-ui's drag\n// handlers only when the sheet owns the gesture (./handoff.ts has the rule and its tests). lynx-ui's SheetContent runs\n// with `handleOnly`, so its content handlers are off and nothing drags twice.\n//\n// lynx-ui 3.139 keeps the drag handlers and the sheet progress in contexts its package index does not export; they are\n// read from the module SheetContent itself imports (`dist/context`), so they are the same context objects.\nimport { SheetDragContext, useSheetContext } from '@lynx-js/lynx-ui-sheet/dist/context/index.jsx';\nimport { type MainThreadRef, type ReactNode, useContext, useMainThreadRef } from '@lynx-js/react';\nimport type { MainThread } from '@lynx-js/types';\nimport { decideSheetGestureMT, type G9SheetGestureMode, scrollHandsOffToSheetMT } from './handoff';\n\nfunction noTouchMT(_e: MainThread.TouchEvent): void {\n 'main thread';\n}\n\n/** Main-thread state shared by the gesture frame, the grabber and the scrolling body of one sheet. */\nexport interface G9SheetGestureRefs {\n readonly mode: MainThreadRef<G9SheetGestureMode>;\n readonly start: MainThreadRef<{ x: number; y: number }>;\n readonly lastY: MainThreadRef<number>;\n /** The body's scroll offset (from its `scroll` event). */\n readonly scrollTop: MainThreadRef<number>;\n /** The current touch started inside the body. */\n readonly inBody: MainThreadRef<boolean>;\n /** The body's scroll view (its `enable-scroll` is turned off while the sheet owns a gesture that began in it). */\n readonly body: MainThreadRef<MainThread.Element | null>;\n}\n\n/** Creates the refs of one sheet's gesture routing. */\nexport function useSheetGestureRefs(): G9SheetGestureRefs {\n return {\n mode: useMainThreadRef<G9SheetGestureMode>('ignore'),\n start: useMainThreadRef({ x: 0, y: 0 }),\n lastY: useMainThreadRef(0),\n scrollTop: useMainThreadRef(0),\n inBody: useMainThreadRef(false),\n body: useMainThreadRef<MainThread.Element | null>(null),\n };\n}\n\n/** Main-thread handlers for the sheet body's `<scroll-view>` (its offset, and touches that start in it). */\nexport interface G9SheetBodyGesture {\n readonly onScrollMT: (e: { detail?: { scrollTop?: number } }) => void;\n readonly onTouchStartMT: () => void;\n}\n\n/**\n * The body's side of the routing: bind `main-thread:ref={refs.body}`, `main-thread:bindscroll={onScrollMT}` and\n * `main-thread:bindtouchstart={onTouchStartMT}` on the body's `<scroll-view>`.\n */\nexport function useSheetBodyGesture(refs: G9SheetGestureRefs): G9SheetBodyGesture {\n const { scrollTop, inBody } = refs;\n function onScrollMT(e: { detail?: { scrollTop?: number } }) {\n 'main thread';\n scrollTop.current = e.detail?.scrollTop ?? 0;\n }\n function onTouchStartMT() {\n 'main thread';\n inBody.current = true;\n }\n return { onScrollMT, onTouchStartMT };\n}\n\n/** Props of {@link G9SheetGestureFrame}. */\nexport interface G9SheetGestureFrameProps {\n readonly refs: G9SheetGestureRefs;\n /** The sheet can be dragged (draggable and not intercepted by `onBackRequested`). */\n readonly canDrag: boolean;\n /** `scrollingExpandsSheet` (default true): a drag that starts in the body may move the sheet. */\n readonly bodyDrags: boolean;\n readonly className: string;\n readonly style: Record<string, string | number>;\n readonly children?: ReactNode;\n}\n\n/**\n * The view that receives every touch on a sheet and routes it: to lynx-ui's drag (the sheet moves), to the body's\n * native scrolling, or to neither (a horizontal gesture). Rendered inside lynx-ui `SheetContent`.\n */\nexport function G9SheetGestureFrame(props: G9SheetGestureFrameProps): ReactNode {\n // Worklets capture what they read when they are created, so nothing here may be undefined: an absent lynx-ui\n // context (outside SheetContent) falls back to no-op handlers and an \"at the top\" progress.\n const handlers = useContext(SheetDragContext)?.dragHandlers;\n const startDrag = handlers?.handleTouchStartMT ?? noTouchMT;\n const moveDrag = handlers?.handleTouchMoveMT ?? noTouchMT;\n const endDrag = handlers?.handleTouchEndMT ?? noTouchMT;\n const noProgress = useMainThreadRef<{ get(): number } | null>(null);\n const progress = useSheetContext().sheetProgress ?? noProgress;\n const { mode, start, lastY, scrollTop, inBody, body } = props.refs;\n const canDrag = props.canDrag;\n const bodyDrags = props.bodyDrags;\n\n function atTopMT(): boolean {\n 'main thread';\n const value = progress.current;\n return !value || value.get() >= 0.995;\n }\n function setBodyScrollMT(enabled: boolean) {\n 'main thread';\n body.current?.setAttribute('enable-scroll', enabled);\n }\n function onStartMT(e: MainThread.TouchEvent) {\n 'main thread';\n start.current = { x: e.detail.x, y: e.detail.y };\n lastY.current = e.detail.y;\n mode.current = 'pending';\n if (canDrag) startDrag(e);\n }\n function onMoveMT(e: MainThread.TouchEvent) {\n 'main thread';\n const y = e.detail.y;\n const step = y - lastY.current;\n lastY.current = y;\n if (mode.current === 'pending') {\n const decided = decideSheetGestureMT({\n dx: e.detail.x - start.current.x,\n dy: y - start.current.y,\n atTop: atTopMT(),\n scrollTop: scrollTop.current,\n inBody: inBody.current,\n canDrag,\n bodyDrags,\n });\n if (decided === 'pending') return;\n mode.current = decided;\n if (decided === 'sheet' && inBody.current) setBodyScrollMT(false);\n } else if (\n mode.current === 'scroll' &&\n scrollHandsOffToSheetMT(atTopMT(), scrollTop.current, step, canDrag, bodyDrags)\n ) {\n // The body reached its top while the finger pulls down: the sheet takes the rest of the gesture.\n mode.current = 'sheet';\n setBodyScrollMT(false);\n startDrag(e);\n }\n if (mode.current === 'sheet') moveDrag(e);\n }\n function onEndMT(e: MainThread.TouchEvent) {\n 'main thread';\n if (mode.current === 'sheet') endDrag(e);\n if (inBody.current) setBodyScrollMT(true);\n mode.current = 'ignore';\n inBody.current = false;\n }\n return (\n <view\n className={props.className}\n style={props.style}\n main-thread:bindtouchstart={onStartMT}\n main-thread:bindtouchmove={onMoveMT}\n main-thread:bindtouchend={onEndMT}\n main-thread:bindtouchcancel={onEndMT}\n >\n {props.children}\n </view>\n );\n}\n"],"names":["noTouchMT","_e","useSheetGestureRefs","useMainThreadRef","useSheetBodyGesture","refs","scrollTop","inBody","onScrollMT","e","_e_detail","onTouchStartMT","G9SheetGestureFrame","props","_useSheetContext_sheetProgress","_useContext","handlers","SheetDragContext","startDrag","moveDrag","endDrag","noProgress","progress","mode","start","lastY","body","canDrag","bodyDrags","atTopMT","value","setBodyScrollMT","enabled","_body_current","onStartMT","onMoveMT","y","step","decided","decideSheetGestureMT","scrollHandsOffToSheetMT","onEndMT","view"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Finger travel before a gesture is classified (lynx-ui's `GESTURE_THRESHOLD`). */
|
|
2
|
+
export declare const g9SheetGestureSlop = 8;
|
|
3
|
+
/** Who owns a gesture that started on a sheet. */
|
|
4
|
+
export type G9SheetGestureMode = 'pending' | 'sheet' | 'scroll' | 'ignore';
|
|
5
|
+
/** What the classification needs, as plain numbers and flags (main-thread friendly). */
|
|
6
|
+
export interface G9SheetGestureInput {
|
|
7
|
+
/** Finger travel since the touch started (px); positive `dy` = downwards. */
|
|
8
|
+
readonly dx: number;
|
|
9
|
+
readonly dy: number;
|
|
10
|
+
/** The sheet rests at (or above) its top detent. */
|
|
11
|
+
readonly atTop: boolean;
|
|
12
|
+
/** The body's scroll offset (px); ≤ 0 = at its top. */
|
|
13
|
+
readonly scrollTop: number;
|
|
14
|
+
/** The touch started inside the scrolling body (not on the grabber, header or footer). */
|
|
15
|
+
readonly inBody: boolean;
|
|
16
|
+
/** The sheet can be dragged at all (draggable, not intercepted). */
|
|
17
|
+
readonly canDrag: boolean;
|
|
18
|
+
/** `scrollingExpandsSheet` (default true): a drag in the body may move the sheet. */
|
|
19
|
+
readonly bodyDrags: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Classifies a gesture once it travelled past the slop (else `'pending'`). See the module comment. */
|
|
22
|
+
export declare function decideSheetGesture(input: G9SheetGestureInput): G9SheetGestureMode;
|
|
23
|
+
/** Main-thread twin of {@link decideSheetGesture}. */
|
|
24
|
+
export declare function decideSheetGestureMT(input: G9SheetGestureInput): G9SheetGestureMode;
|
|
25
|
+
/**
|
|
26
|
+
* Mid-scroll hand-off: a body scroll at the top detent becomes a sheet drag once the body is at its top and the finger
|
|
27
|
+
* moves down (MAUI nested scrolling). `stepDy` is the travel since the previous move.
|
|
28
|
+
*/
|
|
29
|
+
export declare function scrollHandsOffToSheet(atTop: boolean, scrollTop: number, stepDy: number, canDrag: boolean, bodyDrags: boolean): boolean;
|
|
30
|
+
/** Main-thread twin of {@link scrollHandsOffToSheet}. */
|
|
31
|
+
export declare function scrollHandsOffToSheetMT(atTop: boolean, scrollTop: number, stepDy: number, canDrag: boolean, bodyDrags: boolean): boolean;
|
|
32
|
+
//# sourceMappingURL=handoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/sheet/handoff.ts"],"names":[],"mappings":"AAWA,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,kDAAkD;AAClD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3E,wFAAwF;AACxF,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,kBAAkB,CASjF;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,kBAAkB,CAWnF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAET;AAED,yDAAyD;AACzD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAGT"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const g9SheetGestureSlop = 8;
|
|
2
|
+
function decideSheetGesture(input) {
|
|
3
|
+
const { dx, dy } = input;
|
|
4
|
+
if (Math.sqrt(dx * dx + dy * dy) <= g9SheetGestureSlop) return 'pending';
|
|
5
|
+
if (Math.abs(dy) < Math.abs(dx)) return 'ignore';
|
|
6
|
+
if (!input.canDrag) return input.inBody ? 'scroll' : 'ignore';
|
|
7
|
+
if (!input.inBody) return 'sheet';
|
|
8
|
+
if (!input.bodyDrags) return 'scroll';
|
|
9
|
+
if (!input.atTop) return 'sheet';
|
|
10
|
+
return dy > 0 && input.scrollTop <= 0 ? 'sheet' : 'scroll';
|
|
11
|
+
}
|
|
12
|
+
function decideSheetGestureMT(input) {
|
|
13
|
+
'main thread';
|
|
14
|
+
const dx = input.dx;
|
|
15
|
+
const dy = input.dy;
|
|
16
|
+
if (Math.sqrt(dx * dx + dy * dy) <= 8) return 'pending';
|
|
17
|
+
if (Math.abs(dy) < Math.abs(dx)) return 'ignore';
|
|
18
|
+
if (!input.canDrag) return input.inBody ? 'scroll' : 'ignore';
|
|
19
|
+
if (!input.inBody) return 'sheet';
|
|
20
|
+
if (!input.bodyDrags) return 'scroll';
|
|
21
|
+
if (!input.atTop) return 'sheet';
|
|
22
|
+
return dy > 0 && input.scrollTop <= 0 ? 'sheet' : 'scroll';
|
|
23
|
+
}
|
|
24
|
+
function scrollHandsOffToSheet(atTop, scrollTop, stepDy, canDrag, bodyDrags) {
|
|
25
|
+
return canDrag && bodyDrags && atTop && scrollTop <= 0 && stepDy > 0;
|
|
26
|
+
}
|
|
27
|
+
function scrollHandsOffToSheetMT(atTop, scrollTop, stepDy, canDrag, bodyDrags) {
|
|
28
|
+
'main thread';
|
|
29
|
+
return canDrag && bodyDrags && atTop && scrollTop <= 0 && stepDy > 0;
|
|
30
|
+
}
|
|
31
|
+
export { decideSheetGesture, decideSheetGestureMT, g9SheetGestureSlop, scrollHandsOffToSheet, scrollHandsOffToSheetMT };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=handoff.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet/handoff.jsx","sources":["../../src/sheet/handoff.ts"],"sourcesContent":["// Nested scroll hand-off between a sheet and its scrolling body (ledger N-028; MAUI G9SheetView nested scrolling).\n//\n// lynx-ui's SheetContent drags the sheet on every vertical move inside it and knows nothing of the scroll view in\n// the body, so a list in a `medium` sheet scrolled AND dragged the sheet at once. G9 decides per gesture instead, on\n// the main thread (frame.tsx forwards to lynx-ui's drag handlers only when the sheet owns the gesture):\n// • below the top detent, a vertical drag in the body moves the sheet (it expands first) and the body stays put;\n// • at the top detent, the body scrolls; pulling down with the body at its top hands the gesture to the sheet\n// (it collapses or closes), also in the middle of a scroll that reaches the top;\n// • a touch outside the body (grabber, header, footer) always drags the sheet; `scrollingExpandsSheet: false` limits\n// dragging to those; horizontal gestures (swipe rows, sliders, chips) are never taken.\n\n/** Finger travel before a gesture is classified (lynx-ui's `GESTURE_THRESHOLD`). */\nexport const g9SheetGestureSlop = 8;\n\n/** Who owns a gesture that started on a sheet. */\nexport type G9SheetGestureMode = 'pending' | 'sheet' | 'scroll' | 'ignore';\n\n/** What the classification needs, as plain numbers and flags (main-thread friendly). */\nexport interface G9SheetGestureInput {\n /** Finger travel since the touch started (px); positive `dy` = downwards. */\n readonly dx: number;\n readonly dy: number;\n /** The sheet rests at (or above) its top detent. */\n readonly atTop: boolean;\n /** The body's scroll offset (px); ≤ 0 = at its top. */\n readonly scrollTop: number;\n /** The touch started inside the scrolling body (not on the grabber, header or footer). */\n readonly inBody: boolean;\n /** The sheet can be dragged at all (draggable, not intercepted). */\n readonly canDrag: boolean;\n /** `scrollingExpandsSheet` (default true): a drag in the body may move the sheet. */\n readonly bodyDrags: boolean;\n}\n\n/** Classifies a gesture once it travelled past the slop (else `'pending'`). See the module comment. */\nexport function decideSheetGesture(input: G9SheetGestureInput): G9SheetGestureMode {\n const { dx, dy } = input;\n if (Math.sqrt(dx * dx + dy * dy) <= g9SheetGestureSlop) return 'pending';\n if (Math.abs(dy) < Math.abs(dx)) return 'ignore';\n if (!input.canDrag) return input.inBody ? 'scroll' : 'ignore';\n if (!input.inBody) return 'sheet';\n if (!input.bodyDrags) return 'scroll';\n if (!input.atTop) return 'sheet';\n return dy > 0 && input.scrollTop <= 0 ? 'sheet' : 'scroll';\n}\n\n/** Main-thread twin of {@link decideSheetGesture}. */\nexport function decideSheetGestureMT(input: G9SheetGestureInput): G9SheetGestureMode {\n 'main thread';\n const dx = input.dx;\n const dy = input.dy;\n if (Math.sqrt(dx * dx + dy * dy) <= 8) return 'pending';\n if (Math.abs(dy) < Math.abs(dx)) return 'ignore';\n if (!input.canDrag) return input.inBody ? 'scroll' : 'ignore';\n if (!input.inBody) return 'sheet';\n if (!input.bodyDrags) return 'scroll';\n if (!input.atTop) return 'sheet';\n return dy > 0 && input.scrollTop <= 0 ? 'sheet' : 'scroll';\n}\n\n/**\n * Mid-scroll hand-off: a body scroll at the top detent becomes a sheet drag once the body is at its top and the finger\n * moves down (MAUI nested scrolling). `stepDy` is the travel since the previous move.\n */\nexport function scrollHandsOffToSheet(\n atTop: boolean,\n scrollTop: number,\n stepDy: number,\n canDrag: boolean,\n bodyDrags: boolean,\n): boolean {\n return canDrag && bodyDrags && atTop && scrollTop <= 0 && stepDy > 0;\n}\n\n/** Main-thread twin of {@link scrollHandsOffToSheet}. */\nexport function scrollHandsOffToSheetMT(\n atTop: boolean,\n scrollTop: number,\n stepDy: number,\n canDrag: boolean,\n bodyDrags: boolean,\n): boolean {\n 'main thread';\n return canDrag && bodyDrags && atTop && scrollTop <= 0 && stepDy > 0;\n}\n"],"names":["g9SheetGestureSlop","decideSheetGesture","input","dx","dy","Math","decideSheetGestureMT","scrollHandsOffToSheet","atTop","scrollTop","stepDy","canDrag","bodyDrags","scrollHandsOffToSheetMT"],"mappings":"AAYO,MAAMA,qBAAqB;AAuB3B,SAASC,mBAAmBC,KAA0B;IAC3D,MAAM,EAAEC,EAAE,EAAEC,EAAE,EAAE,GAAGF;IACnB,IAAIG,KAAK,IAAI,CAACF,KAAKA,KAAKC,KAAKA,OAAOJ,oBAAoB,OAAO;IAC/D,IAAIK,KAAK,GAAG,CAACD,MAAMC,KAAK,GAAG,CAACF,KAAK,OAAO;IACxC,IAAI,CAACD,MAAM,OAAO,EAAE,OAAOA,MAAM,MAAM,GAAG,WAAW;IACrD,IAAI,CAACA,MAAM,MAAM,EAAE,OAAO;IAC1B,IAAI,CAACA,MAAM,SAAS,EAAE,OAAO;IAC7B,IAAI,CAACA,MAAM,KAAK,EAAE,OAAO;IACzB,OAAOE,KAAK,KAAKF,MAAM,SAAS,IAAI,IAAI,UAAU;AACpD;AAGO,SAASI,qBAAqBJ,KAA0B;IAC7D;IACA,MAAMC,KAAKD,MAAM,EAAE;IACnB,MAAME,KAAKF,MAAM,EAAE;IACnB,IAAIG,KAAK,IAAI,CAACF,KAAKA,KAAKC,KAAKA,OAAO,GAAG,OAAO;IAC9C,IAAIC,KAAK,GAAG,CAACD,MAAMC,KAAK,GAAG,CAACF,KAAK,OAAO;IACxC,IAAI,CAACD,MAAM,OAAO,EAAE,OAAOA,MAAM,MAAM,GAAG,WAAW;IACrD,IAAI,CAACA,MAAM,MAAM,EAAE,OAAO;IAC1B,IAAI,CAACA,MAAM,SAAS,EAAE,OAAO;IAC7B,IAAI,CAACA,MAAM,KAAK,EAAE,OAAO;IACzB,OAAOE,KAAK,KAAKF,MAAM,SAAS,IAAI,IAAI,UAAU;AACpD;AAMO,SAASK,sBACdC,KAAc,EACdC,SAAiB,EACjBC,MAAc,EACdC,OAAgB,EAChBC,SAAkB;IAElB,OAAOD,WAAWC,aAAaJ,SAASC,aAAa,KAAKC,SAAS;AACrE;AAGO,SAASG,wBACdL,KAAc,EACdC,SAAiB,EACjBC,MAAc,EACdC,OAAgB,EAChBC,SAAkB;IAElB;IACA,OAAOD,WAAWC,aAAaJ,SAASC,aAAa,KAAKC,SAAS;AACrE"}
|
package/dist/sheet/header.d.ts
CHANGED
|
@@ -30,6 +30,17 @@ export interface G9SheetFooterProps {
|
|
|
30
30
|
}
|
|
31
31
|
/** Rows of footer buttons: equal-width columns, wrapping every `perRow` (MAUI footer template). */
|
|
32
32
|
export declare function footerRows<T>(buttons: ReadonlyArray<T>, perRow: number): T[][];
|
|
33
|
-
/** The sheet footer: `
|
|
33
|
+
/** The sheet footer: `footerBand`, else `footerView` in the band, else `footerButtons` in equal columns (3 per row by default), with a divider. */
|
|
34
34
|
export declare function G9SheetFooter(props: G9SheetFooterProps): ReactNode;
|
|
35
|
+
/** Props of {@link G9SheetFooterBar}. */
|
|
36
|
+
export interface G9SheetFooterBarProps {
|
|
37
|
+
readonly buttons: ReadonlyArray<ReactNode>;
|
|
38
|
+
/** Default 3. */
|
|
39
|
+
readonly maxButtonsPerRow?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The footer band (divider, padding, equal-width button columns); nothing at all without buttons (MAUI
|
|
43
|
+
* `SheetFooterBar` hides with no visible button). Render it from a `footerBand` whose buttons come and go.
|
|
44
|
+
*/
|
|
45
|
+
export declare function G9SheetFooterBar(props: G9SheetFooterBarProps): ReactNode;
|
|
35
46
|
//# sourceMappingURL=header.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/sheet/header.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAM1D,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,WAAW,CAAC;AAEpE,mEAAmE;AACnE,eAAO,MAAM,oBAAoB;;;;;;;;;EAS/B,CAAC;
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/sheet/header.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAM1D,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,WAAW,CAAC;AAEpE,mEAAmE;AACnE,eAAO,MAAM,oBAAoB;;;;;;;;;EAS/B,CAAC;AAkCH,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAgIlE;AAED,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC;AAED,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAK9E;AAED,mJAAmJ;AACnJ,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAUlE;AAED,yCAAyC;AACzC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC3C,iBAAiB;IACjB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,CAkBxE"}
|
package/dist/sheet/header.jsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { G9StringKey } from "@g9tm/lynxcontrols-foundation";
|
|
1
|
+
import { G9StringKey, formatColor, withAlpha } from "@g9tm/lynxcontrols-foundation";
|
|
2
2
|
import { useState } from "@lynx-js/react";
|
|
3
|
-
import { g9RowStyle } from "../base/control.jsx";
|
|
3
|
+
import { g9ChildId, g9IdProps, g9RowStyle, g9SafeId } from "../base/control.jsx";
|
|
4
4
|
import { useG9Press } from "../base/press.jsx";
|
|
5
5
|
import { G9HeaderActionButton } from "../button/header-action-button.jsx";
|
|
6
6
|
import { G9IconSlot } from "../icon/slot.jsx";
|
|
7
|
-
import { useG9Direction, useG9Settings, useG9Strings } from "../provider/hooks.jsx";
|
|
7
|
+
import { useG9Direction, useG9Settings, useG9Strings, useG9Theme } from "../provider/hooks.jsx";
|
|
8
8
|
const g9SheetHeaderMetrics = Object.freeze({
|
|
9
9
|
minHeight: 64,
|
|
10
10
|
verticalGap: 10,
|
|
@@ -16,6 +16,7 @@ const g9SheetHeaderMetrics = Object.freeze({
|
|
|
16
16
|
footerMaxButtonsPerRow: 3
|
|
17
17
|
});
|
|
18
18
|
function ToolbarItemButton(props) {
|
|
19
|
+
var _item_accessibilityLabel;
|
|
19
20
|
const { item } = props;
|
|
20
21
|
const [running, setRunning] = useState(false);
|
|
21
22
|
const busy = true === item.isBusy || running;
|
|
@@ -30,20 +31,22 @@ function ToolbarItemButton(props) {
|
|
|
30
31
|
};
|
|
31
32
|
return <G9HeaderActionButton {...void 0 !== item.icon ? {
|
|
32
33
|
icon: item.icon
|
|
33
|
-
} :
|
|
34
|
+
} : item.text ? {
|
|
34
35
|
buttonText: item.text
|
|
35
36
|
} : {}} isBusy={busy && true === item.showBusyIndicator} isActive={true === item.isActive} showActiveBadge={true === item.showActiveBadge} animatePress={false !== item.animatePress} {...item.iconSize ? {
|
|
36
37
|
iconSize: item.iconSize
|
|
37
|
-
} : {}} {...item.accessibilityLabel ? {
|
|
38
|
-
accessibilityLabel: item.accessibilityLabel
|
|
39
|
-
} : {}} disabled={busy && false !== item.disableWhileBusy && true !== item.showBusyIndicator} onPress={onPress}/>;
|
|
38
|
+
} : {}} {...item.accessibilityLabel || item.text ? {
|
|
39
|
+
accessibilityLabel: null != (_item_accessibilityLabel = item.accessibilityLabel) ? _item_accessibilityLabel : item.text
|
|
40
|
+
} : {}} {...g9IdProps(props.id)} disabled={busy && false !== item.disableWhileBusy && true !== item.showBusyIndicator} onPress={onPress}/>;
|
|
40
41
|
}
|
|
41
42
|
function G9SheetHeader(props) {
|
|
42
43
|
var _o_headerLeadingView, _o_headerTitleView, _ref, _o_toolbarItems, _o_headerTrailingView, _o_headerTitlePlacement;
|
|
43
44
|
var _o_toolbarItemsFactory;
|
|
44
45
|
const o = props.options;
|
|
45
46
|
const direction = useG9Direction();
|
|
46
|
-
const
|
|
47
|
+
const settings = useG9Settings();
|
|
48
|
+
const glyphs = settings.glyphs;
|
|
49
|
+
const palette = useG9Theme().palette;
|
|
47
50
|
const strings = useG9Strings();
|
|
48
51
|
const back = useG9Press(props.onBack, {
|
|
49
52
|
source: 'G9SheetHeader'
|
|
@@ -51,16 +54,17 @@ function G9SheetHeader(props) {
|
|
|
51
54
|
if (true !== o.showToolbar) return null;
|
|
52
55
|
if (void 0 !== o.headerView && null !== o.headerView) return <view className="g9-sheet-header g9-sheet-header--custom">{o.headerView}</view>;
|
|
53
56
|
const m = g9SheetHeaderMetrics;
|
|
54
|
-
const leading = null != (_o_headerLeadingView = o.headerLeadingView) ? _o_headerLeadingView : o.showCloseButton ? <view className="g9-sheet-header__back" style={{
|
|
57
|
+
const leading = null != (_o_headerLeadingView = o.headerLeadingView) ? _o_headerLeadingView : o.showCloseButton ? <view className="g9-sheet-header__back" {...g9IdProps(g9ChildId(o.automationId, 'Back'))} style={{
|
|
55
58
|
width: `${m.backButton}px`,
|
|
56
|
-
height: `${m.backButton}px
|
|
59
|
+
height: `${m.backButton}px`,
|
|
60
|
+
...g9RowStyle(direction)
|
|
57
61
|
}} accessibility-element={true} accessibility-traits="button" accessibility-label={o.useCloseIcon ? strings.get(G9StringKey.Close) : strings.get(G9StringKey.Back)} hit-slop={{
|
|
58
62
|
top: `${m.backHitSlop}px`,
|
|
59
63
|
left: `${m.backHitSlop}px`,
|
|
60
64
|
right: `${m.backHitSlop}px`,
|
|
61
65
|
bottom: `${m.backHitSlop}px`
|
|
62
66
|
}} bindtap={back}>
|
|
63
|
-
<G9IconSlot icon={o.useCloseIcon ? glyphs.clear : 'rtl' === direction ? glyphs.arrowForward : glyphs.arrowBack} size={m.backGlyph} color="var(--g9-
|
|
67
|
+
<G9IconSlot icon={o.useCloseIcon ? glyphs.clear : 'rtl' === direction ? glyphs.arrowForward : glyphs.arrowBack} size={m.backGlyph} color="var(--g9-secondary)"/>
|
|
64
68
|
</view> : null;
|
|
65
69
|
const title = null != (_o_headerTitleView = o.headerTitleView) ? _o_headerTitleView : o.title ? <text className="g9-sheet-header__title" text-maxline="1" style={{
|
|
66
70
|
fontSize: `${m.titleSize}px`
|
|
@@ -70,15 +74,15 @@ function G9SheetHeader(props) {
|
|
|
70
74
|
const items = null != (_ref = null != (_o_toolbarItems = o.toolbarItems) ? _o_toolbarItems : null == (_o_toolbarItemsFactory = o.toolbarItemsFactory) ? void 0 : _o_toolbarItemsFactory.call(o)) ? _ref : [];
|
|
71
75
|
const trailing = null != (_o_headerTrailingView = o.headerTrailingView) ? _o_headerTrailingView : items.length > 0 ? <view className="g9-sheet-header__items" style={g9RowStyle(direction)}>
|
|
72
76
|
{items.map((item, i)=>{
|
|
73
|
-
var _item_key;
|
|
74
|
-
return <ToolbarItemButton key={null != (_item_key = item.key) ? _item_key : String(i)} item={item}/>;
|
|
77
|
+
var _item_key, _item_key1;
|
|
78
|
+
return <ToolbarItemButton key={null != (_item_key = item.key) ? _item_key : String(i)} item={item} id={item.automationId ? g9SafeId(item.automationId) : g9ChildId(o.automationId, `ToolbarItem_${null != (_item_key1 = item.key) ? _item_key1 : i}`)}/>;
|
|
75
79
|
})}
|
|
76
80
|
</view> : null;
|
|
77
81
|
const spanned = null != o.headerLeadingAndTitleView || null != o.headerTitleAndTrailingView;
|
|
78
82
|
const center = (null != (_o_headerTitlePlacement = o.headerTitlePlacement) ? _o_headerTitlePlacement : 'center') === 'center' && false !== o.reserveEmptyHeaderSlots && !spanned;
|
|
79
83
|
let slots;
|
|
80
84
|
slots = null != o.headerLeadingAndTitleView ? [
|
|
81
|
-
<view key="lt" className="g9-sheet-header__grow">
|
|
85
|
+
<view key="lt" className="g9-sheet-header__grow" style={g9RowStyle(direction)}>
|
|
82
86
|
{o.headerLeadingAndTitleView}
|
|
83
87
|
</view>,
|
|
84
88
|
<view key="t" className="g9-sheet-header__end">
|
|
@@ -88,24 +92,24 @@ function G9SheetHeader(props) {
|
|
|
88
92
|
<view key="l" className="g9-sheet-header__start">
|
|
89
93
|
{leading}
|
|
90
94
|
</view>,
|
|
91
|
-
<view key="tt" className="g9-sheet-header__grow">
|
|
95
|
+
<view key="tt" className="g9-sheet-header__grow" style={g9RowStyle(direction)}>
|
|
92
96
|
{o.headerTitleAndTrailingView}
|
|
93
97
|
</view>
|
|
94
98
|
] : center ? [
|
|
95
|
-
<view key="l" className="g9-sheet-header__side g9-sheet-header__start">
|
|
99
|
+
<view key="l" className="g9-sheet-header__side g9-sheet-header__start" style={g9RowStyle(direction)}>
|
|
96
100
|
{leading}
|
|
97
101
|
</view>,
|
|
98
102
|
<view key="t" className="g9-sheet-header__title-slot">
|
|
99
103
|
{title}
|
|
100
104
|
</view>,
|
|
101
|
-
<view key="r" className="g9-sheet-header__side g9-sheet-header__end">
|
|
105
|
+
<view key="r" className="g9-sheet-header__side g9-sheet-header__end" style={g9RowStyle(direction)}>
|
|
102
106
|
{trailing}
|
|
103
107
|
</view>
|
|
104
108
|
] : [
|
|
105
109
|
<view key="l" className="g9-sheet-header__start">
|
|
106
110
|
{leading}
|
|
107
111
|
</view>,
|
|
108
|
-
<view key="t" className="g9-sheet-header__grow g9-sheet-header__title-near">
|
|
112
|
+
<view key="t" className="g9-sheet-header__grow g9-sheet-header__title-near" style={g9RowStyle(direction)}>
|
|
109
113
|
{title}
|
|
110
114
|
</view>,
|
|
111
115
|
<view key="r" className="g9-sheet-header__end">
|
|
@@ -113,7 +117,10 @@ function G9SheetHeader(props) {
|
|
|
113
117
|
</view>
|
|
114
118
|
];
|
|
115
119
|
return <view className={`g9-sheet-header g9-dir-${direction}`} style={{
|
|
116
|
-
minHeight: `${m.minHeight}px`,
|
|
120
|
+
minHeight: `${m.minHeight + 1}px`,
|
|
121
|
+
paddingLeft: `${settings.sheets.headerEdgeSpacing}px`,
|
|
122
|
+
paddingRight: `${settings.sheets.headerEdgeSpacing}px`,
|
|
123
|
+
borderBottomColor: formatColor(withAlpha(palette.OutlineVariant, 0.35)),
|
|
117
124
|
...g9RowStyle(direction)
|
|
118
125
|
}}>
|
|
119
126
|
{slots}
|
|
@@ -126,20 +133,26 @@ function footerRows(buttons, perRow) {
|
|
|
126
133
|
return rows;
|
|
127
134
|
}
|
|
128
135
|
function G9SheetFooter(props) {
|
|
129
|
-
var _o_footerButtons
|
|
130
|
-
const direction = useG9Direction();
|
|
136
|
+
var _o_footerButtons;
|
|
131
137
|
const o = props.options;
|
|
138
|
+
if (null != o.footerBand) return o.footerBand;
|
|
132
139
|
if (null != o.footerView) return <view className="g9-sheet-footer">{o.footerView}</view>;
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
return <G9SheetFooterBar buttons={null != (_o_footerButtons = o.footerButtons) ? _o_footerButtons : []} {...void 0 !== o.footerMaxButtonsPerRow ? {
|
|
141
|
+
maxButtonsPerRow: o.footerMaxButtonsPerRow
|
|
142
|
+
} : {}}/>;
|
|
143
|
+
}
|
|
144
|
+
function G9SheetFooterBar(props) {
|
|
145
|
+
var _props_maxButtonsPerRow;
|
|
146
|
+
const direction = useG9Direction();
|
|
147
|
+
if (0 === props.buttons.length) return null;
|
|
135
148
|
return <view className="g9-sheet-footer">
|
|
136
|
-
{footerRows(buttons, null != (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
149
|
+
{footerRows(props.buttons, null != (_props_maxButtonsPerRow = props.maxButtonsPerRow) ? _props_maxButtonsPerRow : g9SheetHeaderMetrics.footerMaxButtonsPerRow).map((row, r)=><view key={r} className="g9-sheet-footer__row" style={g9RowStyle(direction)}>
|
|
150
|
+
{row.map((button, i)=><view key={i} className="g9-sheet-footer__cell">
|
|
151
|
+
{button}
|
|
152
|
+
</view>)}
|
|
153
|
+
</view>)}
|
|
141
154
|
</view>;
|
|
142
155
|
}
|
|
143
|
-
export { G9SheetFooter, G9SheetHeader, footerRows, g9SheetHeaderMetrics };
|
|
156
|
+
export { G9SheetFooter, G9SheetFooterBar, G9SheetHeader, footerRows, g9SheetHeaderMetrics };
|
|
144
157
|
|
|
145
158
|
//# sourceMappingURL=header.jsx.map
|