@g9tm/lynxcontrols 1.4.5 → 1.4.11

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.
Files changed (167) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/base/index.d.ts +1 -1
  3. package/dist/base/index.d.ts.map +1 -1
  4. package/dist/base/index.jsx +1 -1
  5. package/dist/base/pressable.d.ts.map +1 -1
  6. package/dist/base/pressable.jsx +2 -1
  7. package/dist/base/pressable.jsx.map +1 -1
  8. package/dist/base/selection-item.d.ts +9 -1
  9. package/dist/base/selection-item.d.ts.map +1 -1
  10. package/dist/base/selection-item.jsx +10 -1
  11. package/dist/base/selection-item.jsx.map +1 -1
  12. package/dist/button/button.css +20 -0
  13. package/dist/button/button.css.map +1 -1
  14. package/dist/button/header-action-button.d.ts +5 -0
  15. package/dist/button/header-action-button.d.ts.map +1 -1
  16. package/dist/button/header-action-button.jsx +6 -1
  17. package/dist/button/header-action-button.jsx.map +1 -1
  18. package/dist/button/visuals.d.ts.map +1 -1
  19. package/dist/button/visuals.jsx +1 -1
  20. package/dist/button/visuals.jsx.map +1 -1
  21. package/dist/cascade/cascade-panel.d.ts.map +1 -1
  22. package/dist/cascade/cascade-panel.jsx +2 -2
  23. package/dist/cascade/cascade-panel.jsx.map +1 -1
  24. package/dist/edge-panel/edge-panel.jsx +5 -5
  25. package/dist/edge-panel/edge-panel.jsx.map +1 -1
  26. package/dist/expander/expander.d.ts.map +1 -1
  27. package/dist/expander/expander.jsx +2 -1
  28. package/dist/expander/expander.jsx.map +1 -1
  29. package/dist/fields/editor.d.ts.map +1 -1
  30. package/dist/fields/editor.jsx +2 -2
  31. package/dist/fields/editor.jsx.map +1 -1
  32. package/dist/fields/fields.css +21 -0
  33. package/dist/fields/fields.css.map +1 -1
  34. package/dist/fields/index.d.ts +1 -1
  35. package/dist/fields/index.d.ts.map +1 -1
  36. package/dist/fields/index.jsx +1 -1
  37. package/dist/fields/outlined-field.d.ts +27 -1
  38. package/dist/fields/outlined-field.d.ts.map +1 -1
  39. package/dist/fields/outlined-field.jsx +29 -2
  40. package/dist/fields/outlined-field.jsx.map +1 -1
  41. package/dist/fields/text-entry.d.ts.map +1 -1
  42. package/dist/fields/text-entry.jsx +2 -2
  43. package/dist/fields/text-entry.jsx.map +1 -1
  44. package/dist/host/host.css.map +1 -1
  45. package/dist/host/host.d.ts +3 -2
  46. package/dist/host/host.d.ts.map +1 -1
  47. package/dist/host/host.jsx +2 -2
  48. package/dist/host/host.jsx.map +1 -1
  49. package/dist/pickers/combo-box.d.ts +8 -0
  50. package/dist/pickers/combo-box.d.ts.map +1 -1
  51. package/dist/pickers/combo-box.jsx +51 -9
  52. package/dist/pickers/combo-box.jsx.map +1 -1
  53. package/dist/pickers/date-time-picker.d.ts +2 -2
  54. package/dist/pickers/date-time-picker.d.ts.map +1 -1
  55. package/dist/pickers/date-time-picker.jsx +4 -3
  56. package/dist/pickers/date-time-picker.jsx.map +1 -1
  57. package/dist/pickers/date-time.d.ts +5 -2
  58. package/dist/pickers/date-time.d.ts.map +1 -1
  59. package/dist/pickers/date-time.jsx +1 -1
  60. package/dist/pickers/date-time.jsx.map +1 -1
  61. package/dist/pickers/picker-sheet.d.ts +6 -2
  62. package/dist/pickers/picker-sheet.d.ts.map +1 -1
  63. package/dist/pickers/picker-sheet.jsx +2 -3
  64. package/dist/pickers/picker-sheet.jsx.map +1 -1
  65. package/dist/pickers/picker.d.ts.map +1 -1
  66. package/dist/pickers/picker.jsx +3 -2
  67. package/dist/pickers/picker.jsx.map +1 -1
  68. package/dist/pickers/pickers.css +27 -0
  69. package/dist/pickers/pickers.css.map +1 -1
  70. package/dist/pickers/timespan-picker.d.ts.map +1 -1
  71. package/dist/pickers/timespan-picker.jsx +3 -2
  72. package/dist/pickers/timespan-picker.jsx.map +1 -1
  73. package/dist/pickers/trigger.d.ts +3 -1
  74. package/dist/pickers/trigger.d.ts.map +1 -1
  75. package/dist/pickers/trigger.jsx +6 -1
  76. package/dist/pickers/trigger.jsx.map +1 -1
  77. package/dist/plus-button/model.d.ts.map +1 -1
  78. package/dist/plus-button/model.jsx +5 -1
  79. package/dist/plus-button/model.jsx.map +1 -1
  80. package/dist/popup/frame.jsx +2 -2
  81. package/dist/popup/frame.jsx.map +1 -1
  82. package/dist/popup/service.d.ts.map +1 -1
  83. package/dist/popup/service.jsx +2 -2
  84. package/dist/popup/service.jsx.map +1 -1
  85. package/dist/provider/provider.css +4 -0
  86. package/dist/provider/provider.css.map +1 -1
  87. package/dist/provider/provider.d.ts.map +1 -1
  88. package/dist/provider/provider.jsx +4 -2
  89. package/dist/provider/provider.jsx.map +1 -1
  90. package/dist/provider/settings.d.ts +12 -0
  91. package/dist/provider/settings.d.ts.map +1 -1
  92. package/dist/provider/settings.jsx +6 -3
  93. package/dist/provider/settings.jsx.map +1 -1
  94. package/dist/provider/theme.css +4 -0
  95. package/dist/provider/theme.css.map +1 -1
  96. package/dist/range-slider/math.d.ts +14 -4
  97. package/dist/range-slider/math.d.ts.map +1 -1
  98. package/dist/range-slider/math.jsx +16 -4
  99. package/dist/range-slider/math.jsx.map +1 -1
  100. package/dist/range-slider/range-slider.css +17 -0
  101. package/dist/range-slider/range-slider.css.map +1 -1
  102. package/dist/range-slider/range-slider.d.ts +11 -0
  103. package/dist/range-slider/range-slider.d.ts.map +1 -1
  104. package/dist/range-slider/range-slider.jsx +35 -13
  105. package/dist/range-slider/range-slider.jsx.map +1 -1
  106. package/dist/selection/index.d.ts +2 -1
  107. package/dist/selection/index.d.ts.map +1 -1
  108. package/dist/selection/index.jsx +2 -1
  109. package/dist/selection/selection-sheet.d.ts +8 -1
  110. package/dist/selection/selection-sheet.d.ts.map +1 -1
  111. package/dist/selection/selection-sheet.jsx +64 -11
  112. package/dist/selection/selection-sheet.jsx.map +1 -1
  113. package/dist/selection/selection.css +7 -0
  114. package/dist/selection/selection.css.map +1 -1
  115. package/dist/selection/window.d.ts +29 -0
  116. package/dist/selection/window.d.ts.map +1 -0
  117. package/dist/selection/window.jsx +24 -0
  118. package/dist/selection/window.jsx.map +1 -0
  119. package/dist/sheet/frame.d.ts.map +1 -1
  120. package/dist/sheet/frame.jsx +35 -9
  121. package/dist/sheet/frame.jsx.map +1 -1
  122. package/dist/sheet/header.d.ts.map +1 -1
  123. package/dist/sheet/header.jsx +3 -1
  124. package/dist/sheet/header.jsx.map +1 -1
  125. package/dist/sheet/index.d.ts +2 -1
  126. package/dist/sheet/index.d.ts.map +1 -1
  127. package/dist/sheet/index.jsx +2 -1
  128. package/dist/sheet/motion.d.ts.map +1 -1
  129. package/dist/sheet/motion.jsx +14 -0
  130. package/dist/sheet/motion.jsx.map +1 -1
  131. package/dist/sheet/options.d.ts +26 -0
  132. package/dist/sheet/options.d.ts.map +1 -1
  133. package/dist/sheet/options.jsx +2 -1
  134. package/dist/sheet/options.jsx.map +1 -1
  135. package/dist/sheet/scroll-indicator.d.ts +33 -0
  136. package/dist/sheet/scroll-indicator.d.ts.map +1 -0
  137. package/dist/sheet/scroll-indicator.jsx +84 -0
  138. package/dist/sheet/scroll-indicator.jsx.map +1 -0
  139. package/dist/sheet/service.d.ts +8 -0
  140. package/dist/sheet/service.d.ts.map +1 -1
  141. package/dist/sheet/service.jsx +15 -4
  142. package/dist/sheet/service.jsx.map +1 -1
  143. package/dist/sheet/sheet.css +14 -0
  144. package/dist/sheet/sheet.css.map +1 -1
  145. package/dist/sheet/sizing.d.ts +2 -0
  146. package/dist/sheet/sizing.d.ts.map +1 -1
  147. package/dist/sheet/sizing.jsx +2 -1
  148. package/dist/sheet/sizing.jsx.map +1 -1
  149. package/dist/tab-bar/tab-bar.d.ts.map +1 -1
  150. package/dist/tab-bar/tab-bar.jsx +11 -6
  151. package/dist/tab-bar/tab-bar.jsx.map +1 -1
  152. package/dist/toast/service.jsx +3 -3
  153. package/dist/toast/service.jsx.map +1 -1
  154. package/dist/toast/store.d.ts.map +1 -1
  155. package/dist/toast/store.jsx +3 -2
  156. package/dist/toast/store.jsx.map +1 -1
  157. package/dist/toggle/chip-group.d.ts +9 -1
  158. package/dist/toggle/chip-group.d.ts.map +1 -1
  159. package/dist/toggle/chip-group.jsx +51 -12
  160. package/dist/toggle/chip-group.jsx.map +1 -1
  161. package/dist/toggle/switch.d.ts +1 -1
  162. package/dist/toggle/switch.d.ts.map +1 -1
  163. package/dist/toggle/switch.jsx +3 -2
  164. package/dist/toggle/switch.jsx.map +1 -1
  165. package/dist/toggle/toggle.css +20 -0
  166. package/dist/toggle/toggle.css.map +1 -1
  167. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"sheet/options.jsx","sources":["../../src/sheet/options.ts"],"sourcesContent":["import type { ReactNode } from '@lynx-js/react';\nimport type { G9BottomSheetLoadingSkeleton } from '../display/shimmer';\nimport type { G9IconInput } from '../icon/icon';\n\n// MAUI `G9BottomSheetOptions` / `G9BottomSheetSettings` and their enums (BottomSheet/G9BottomSheetOptions.cs).\n\n/** Detents (MAUI `G9BottomSheetState`): peek (collapsed height), medium (half), large (full). */\nexport type G9SheetDetent = 'peek' | 'medium' | 'large';\n/** Detent sizing or fit-to-content (MAUI `G9BottomSheetSizeMode`). */\nexport type G9SheetSizeMode = 'states' | 'fitToContent';\n/** Header title anchor (MAUI `G9BottomSheetHeaderTitlePlacement`). */\nexport type G9SheetHeaderTitlePlacement = 'center' | 'nearBack';\n/** Where a back request came from (MAUI `G9BottomSheetBackRequestSource` + drag-to-close). */\nexport type G9SheetBackSource = 'toolbarButton' | 'hardwareButton' | 'overlayTap' | 'drag';\n/** What `onBackRequested` decides (MAUI `G9BottomSheetBackAction`). */\nexport type G9SheetBackAction = 'close' | 'doNothing';\n/** Content width (MAUI `G9SheetViewContentWidthMode`). */\nexport type G9SheetContentWidthMode = 'full' | 'custom';\n\n/** A header toolbar action (MAUI `G9BottomSheetToolbarItem`). */\nexport interface G9SheetToolbarItem {\n /** Glyph/icon. */\n readonly icon?: G9IconInput;\n /** Text (when there is no icon). */\n readonly text?: string;\n /** The action (MAUI `AsyncAction`/`Command`); a returned promise keeps the item busy while `disableWhileBusy`. */\n readonly onPress?: () => unknown;\n readonly isBusy?: boolean;\n /** Spinner while busy. Default false. */\n readonly showBusyIndicator?: boolean;\n readonly isActive?: boolean;\n /** Dot while active. Default false. */\n readonly showActiveBadge?: boolean;\n /** Ignore presses while busy. Default true. */\n readonly disableWhileBusy?: boolean;\n /** Default true. */\n readonly animatePress?: boolean;\n /** 0 → 24. */\n readonly iconSize?: number;\n readonly accessibilityLabel?: string;\n /** Element id of the item (default `${sheet automationId}_ToolbarItem_${key or index}` when the sheet has one). */\n readonly automationId?: string;\n /** Stable key (default the index). */\n readonly key?: string;\n}\n\n/** Lifecycle callbacks of one sheet (MAUI `Opening/Opened/Closing/ClosedCommand`). */\nexport interface G9SheetLifecycle {\n /** When the sheet starts opening. */\n readonly onOpening?: () => void;\n /** After the open motion (or its timer fallback). */\n readonly onOpened?: () => void;\n /** Once, when closing starts (not on an in-place replace). */\n readonly onClosing?: () => void;\n /** Once, at cleanup. */\n readonly onClosed?: () => void;\n /** The sheet came to rest at another detent (MAUI `G9SheetView.StateChanged`), with its height in px. */\n readonly onStateChanged?: (detent: G9SheetDetent | 'fit', heightPx: number) => void;\n}\n\n/** Everything a sheet can be opened with (MAUI `G9BottomSheetOptions`; 77 properties + presets). */\nexport interface G9SheetOptions extends G9SheetLifecycle {\n // State and sizing\n /** Initial detent. Default `'medium'`. */\n readonly currentState?: G9SheetDetent;\n /** Allowed detents. Default `['medium', 'large']`. */\n readonly states?: ReadonlyArray<G9SheetDetent>;\n /** Default `'states'`. */\n readonly sizeMode?: G9SheetSizeMode;\n /** Dim scrim that blocks the page. Default true. */\n readonly isModal?: boolean;\n /** Overlay tap / drag may close. Default true. */\n readonly isCancelable?: boolean;\n /** Default true. */\n readonly isDraggable?: boolean;\n /** Grabber. Default true. */\n readonly hasHandle?: boolean;\n /** Peek height (dp). Default 100 (with `collapsedHeight`). */\n readonly peekHeight?: number | null;\n /** Alias of `peekHeight` (MAUI `CollapsedHeight`); wins when both are set. */\n readonly collapsedHeight?: number | null;\n /** Medium = host × ratio (0.1–0.9). Default 0.5. */\n readonly halfExpandedRatio?: number | null;\n /** Large = host × ratio (0.1–1). Default 1. */\n readonly fullExpandedRatio?: number | null;\n /** Cap of a fit sheet (0.2–1). Default 0.75. */\n readonly maxFitToContentHeightRatio?: number;\n /** The largest detent is sized to the content (states mode). Default false. */\n readonly expandedFitsContent?: boolean;\n /**\n * Grabber on a draggable sheet with ONE detent, which (as in MAUI) has none by default. For a sheet that has one detent\n * only here — MAUI's peek of a short content followed it down to the content, so MAUI showed two detents of one height\n * and a grabber; lynx-ui resolves its detents once, so the host asks for one fit detent and keeps the grabber with this.\n * Default false.\n */\n readonly handleOnSingleDetent?: boolean;\n /** A drag on a scroller expands the sheet first. Default true. */\n readonly scrollingExpandsSheet?: boolean;\n /**\n * The body is a vertical scroller (default true). `false` for content that scrolls itself — a `<list>` page, a map:\n * the body becomes a flex column and the content fills it, so the content's own scroller gets a definite height (MAUI\n * puts the content in the body as is; a CollectionView body scrolls itself). Lynx-only, additive. Use it with a\n * detent-sized sheet (full screen / states); a fit-to-content sheet has no height to give.\n */\n readonly scrollBody?: boolean;\n /** Height memory key (needed for factory content). */\n readonly heightMemoKey?: string | null;\n // Visual\n /** Body padding. Default 0. */\n readonly padding?: number;\n /** 10 px gap under the header hairline. Default true. */\n readonly useStandardBodyTopGap?: boolean;\n /** Top corners. Default 12. */\n readonly cornerRadius?: number;\n /** Body background. Default `var(--g9-surface-container)`. */\n readonly backgroundColor?: string | null;\n /** Scrim colour; its alpha replaces the maximum opacity. */\n readonly windowBackgroundColor?: string | null;\n /** Default `'full'`. */\n readonly contentWidthMode?: G9SheetContentWidthMode;\n /** Width in `'custom'` mode (MAUI `G9BottomSheetContentWidth`). */\n readonly contentWidth?: number | null;\n /**\n * Full-screen sheets, and detent sheets resting at a `large` detent that reaches under the top inset, reserve the\n * top inset (MAUI state-aware top padding). Default true.\n */\n readonly useTopSafeAreaPadding?: boolean;\n /**\n * The surface reserves the host's bottom safe inset (a visible navigation bar or gesture handle) below the content\n * and footer. 0 on an immersive host. Default true.\n */\n readonly useBottomSafeAreaPadding?: boolean;\n /** Default 0. */\n readonly additionalTopSafeAreaPadding?: number;\n /** Replaces the top padding (0 = flush). */\n readonly topSafeAreaPaddingOverride?: number | null;\n /** Grabber on full-screen toolbar sheets. Default true. */\n readonly showFullScreenDragHandle?: boolean;\n /** Page recede behind a tall primary sheet. Default true. */\n readonly enableBackdropCardEffect?: boolean;\n /** Visible ratio where the recede starts. Default 0.75. */\n readonly backdropCardEffectThreshold?: number;\n // Animation and loading\n /** Per-sheet open duration (ms); default the settings value. */\n readonly openAnimationDurationMs?: number | null;\n readonly closeAnimationDurationMs?: number | null;\n /** Factory content builds after the open motion (spinner/skeleton first). Default true. */\n readonly deferContent?: boolean;\n /** Delay before deferred content swaps in. Default 369. */\n readonly loadDelayMs?: number;\n /** The placeholder uses the full height. Default false. */\n readonly useFullScreenLoadingPlaceholder?: boolean;\n /** Known final body height for the placeholder. */\n readonly deferredLoadingPlaceholderHeight?: number | null;\n /** Covered crossfade reveal of deferred content. Default true. */\n readonly fadeDeferredContentIn?: boolean;\n /** Placeholder shape. Default `'none'` (spinner). */\n readonly loadingSkeleton?: G9BottomSheetLoadingSkeleton;\n /** 0 → the shape's default. */\n readonly loadingSkeletonRowCount?: number;\n // Stack and replace\n /** The parent sinks and fades when this sheet stacks on it. Default true. */\n readonly recedeParentOnStack?: boolean;\n /** Hand-off: replaces the one open sheet once this one is ready. Default false. */\n readonly replaceCurrentSheet?: boolean;\n // Header and footer\n /** Three-slot header. Default false. */\n readonly showToolbar?: boolean;\n /** Leading back (or close) button. Default false. */\n readonly showCloseButton?: boolean;\n /** × instead of the back arrow. Default false. */\n readonly useCloseIcon?: boolean;\n /**\n * Automation id of the sheet (MAUI `AutomationId`): the surface gets it, the header's back/close button\n * `${id}_Back`, toolbar items `${id}_ToolbarItem_${key or index}` (see `g9ChildId`). Keep it to `[A-Za-z0-9_-]`.\n */\n readonly automationId?: string;\n readonly title?: string | null;\n readonly toolbarItems?: ReadonlyArray<G9SheetToolbarItem> | null;\n /** Items built from the content once it exists. */\n readonly toolbarItemsFactory?: (() => ReadonlyArray<G9SheetToolbarItem>) | null;\n /** Default `'center'`. */\n readonly headerTitlePlacement?: G9SheetHeaderTitlePlacement;\n /** Star/Auto/Star columns. Default true. */\n readonly reserveEmptyHeaderSlots?: boolean;\n readonly headerView?: ReactNode;\n readonly headerLeadingView?: ReactNode;\n readonly headerTitleView?: ReactNode;\n readonly headerTrailingView?: ReactNode;\n readonly headerLeadingAndTitleView?: ReactNode;\n readonly headerTitleAndTrailingView?: ReactNode;\n /**\n * A footer that draws its own band (usually a component rendering {@link G9SheetFooterBar}, or nothing) — for\n * buttons that come and go while the sheet is open. Wins over `footerView` and `footerButtons`.\n */\n readonly footerBand?: ReactNode;\n /** Custom footer inside the standard band; wins over `footerButtons`. */\n readonly footerView?: ReactNode;\n /** Equal-width footer buttons. */\n readonly footerButtons?: ReadonlyArray<ReactNode> | null;\n /** Default 3. */\n readonly footerMaxButtonsPerRow?: number;\n /** Hardware back closes. Default true. */\n readonly hardwareBackCloses?: boolean;\n /** Intercepts every back request (disables drag). */\n readonly onBackRequested?: ((source: G9SheetBackSource) => G9SheetBackAction | Promise<G9SheetBackAction>) | null;\n // Platform specific (accepted; applied where Lynx has an equivalent)\n /** Max sheet width on Android (px). */\n readonly androidMaxWidth?: number | null;\n /** Max sheet height on Android (px). */\n readonly androidMaxHeight?: number | null;\n /** Margin around the sheet on Android `[l, t, r, b]`. */\n readonly androidMargin?: readonly [number, number, number, number] | null;\n /** Android half-expanded ratio override. */\n readonly androidHalfExpandedRatio?: number | null;\n /** Square the expanded corners on Android. */\n readonly androidShouldRemoveExpandedCorners?: boolean | null;\n readonly windowsMaxWidth?: number | null;\n readonly windowsMaxHeight?: number | null;\n readonly windowsMinWidth?: number | null;\n readonly windowsMinHeight?: number | null;\n /** Animate the scrim colour on iOS. Default true. */\n readonly animateOverlayToColorOnIos?: boolean;\n}\n\n/** App-wide sheet settings (MAUI `G9BottomSheetSettings`), `<G9Provider settings={{ sheets }}>`. */\nexport interface G9SheetSettings {\n /** Default black. */\n readonly modalOverlayColor?: string;\n /** Dim at the smallest detent (0–1). Default 0.3. */\n readonly modalOverlayMinimumOpacity?: number;\n /** Dim at full screen (0–1). Default 0.9. */\n readonly modalOverlayMaximumOpacity?: number;\n /** Default 300. */\n readonly openAnimationDurationMs?: number;\n /** Default 300. */\n readonly closeAnimationDurationMs?: number;\n /** Partial traversals take a proportional slice. Default true. */\n readonly sizeScaledAnimationDuration?: boolean;\n /** Global switch of the page recede. Default true. */\n readonly enableBackdropCardEffect?: boolean;\n /** Colour behind the receded page. Default black. */\n readonly backdropCardColor?: string;\n /** Staged pipeline: a `replaceCurrentSheet` successor hands off once it is ready. Default true. */\n readonly stageBeforeShow?: boolean;\n /** Longest a hand-off waits for the successor to open before the old sheet closes anyway (0–5000). Default 250. */\n readonly preOpenMaxHoldMs?: number;\n /** Prebuilt (non-factory) content also waits behind the loading placeholder until after the open motion. Default false. */\n readonly deferPrebuiltContent?: boolean;\n /** `'platformNative'` (lynx-ui's motion) or `'timed'` (tween over the durations). Default platformNative. */\n readonly motionStyle?: 'platformNative' | 'timed';\n /** The app version the persisted sheet heights belong to; another version discards them. Default `'0'`. */\n readonly heightMemoVersion?: string;\n /**\n * Side padding of the header band (MAUI `G9LayoutMetrics.EdgeSpacing`, which an app may scale — AgriPad's 10 × 1.3\n * = 13). Default 16.\n */\n readonly headerEdgeSpacing?: number;\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));\nconst finite = (v: number | undefined, fallback: number) =>\n typeof v === 'number' && Number.isFinite(v) ? v : fallback;\n\n/** {@link G9SheetSettings} with defaults, clamped like MAUI `G9BottomSheetSettings.Normalize`. */\nexport function resolveSheetSettings(settings: G9SheetSettings | undefined): Required<G9SheetSettings> {\n const s = settings ?? {};\n let min = clamp(finite(s.modalOverlayMinimumOpacity, 0.3), 0, 1);\n let max = clamp(finite(s.modalOverlayMaximumOpacity, 0.9), 0, 1);\n if (min > max) [min, max] = [max, min];\n return Object.freeze({\n modalOverlayColor: s.modalOverlayColor ?? '#000000',\n modalOverlayMinimumOpacity: min,\n modalOverlayMaximumOpacity: max,\n openAnimationDurationMs: Math.max(0, finite(s.openAnimationDurationMs, 300)),\n closeAnimationDurationMs: Math.max(0, finite(s.closeAnimationDurationMs, 300)),\n sizeScaledAnimationDuration: s.sizeScaledAnimationDuration ?? true,\n enableBackdropCardEffect: s.enableBackdropCardEffect ?? true,\n backdropCardColor: s.backdropCardColor ?? '#000000',\n stageBeforeShow: s.stageBeforeShow ?? true,\n preOpenMaxHoldMs: clamp(finite(s.preOpenMaxHoldMs, 250), 0, 5000),\n deferPrebuiltContent: s.deferPrebuiltContent ?? false,\n motionStyle: s.motionStyle ?? 'platformNative',\n heightMemoVersion: s.heightMemoVersion ?? '0',\n headerEdgeSpacing: Math.max(0, finite(s.headerEdgeSpacing, 16)),\n });\n}\n\n/** MAUI `DefaultOptions()`: medium, `[medium, large]`, modal, cancelable, handle, draggable. */\nexport function defaultSheetOptions(): G9SheetOptions {\n return {\n currentState: 'medium',\n states: ['medium', 'large'],\n sizeMode: 'states',\n halfExpandedRatio: 0.5,\n fullExpandedRatio: 1,\n };\n}\n\n/** MAUI `FitToContentOptions()`: sized to a non-scrolling body, capped at 75 % of the host. */\nexport function fitToContentSheetOptions(): G9SheetOptions {\n return { sizeMode: 'fitToContent', isCancelable: true, hasHandle: true, isDraggable: true, deferContent: true };\n}\n\n/** MAUI `FullScreenWithoutHandleOptions()`. */\nexport function fullScreenWithoutHandleSheetOptions(): G9SheetOptions {\n return {\n currentState: 'large',\n states: ['large'],\n isCancelable: false,\n isDraggable: false,\n hasHandle: false,\n deferContent: true,\n };\n}\n\n/** MAUI `FullScreenModalOptions(title, showCloseButton, hardwareBackCloses, toolbarItems)`. */\nexport function fullScreenModalSheetOptions(\n title?: string | null,\n showCloseButton = true,\n hardwareBackCloses = true,\n toolbarItems?: ReadonlyArray<G9SheetToolbarItem> | null,\n): G9SheetOptions {\n return {\n currentState: 'large',\n states: ['large'],\n sizeMode: 'states',\n isCancelable: false,\n isDraggable: false,\n hasHandle: false,\n cornerRadius: 0,\n backgroundColor: 'var(--g9-background)',\n showToolbar: true,\n showCloseButton,\n title: title ?? null,\n toolbarItems: toolbarItems ?? null,\n hardwareBackCloses,\n };\n}\n\n/** MAUI `FullScreenEdgeToEdgeModalOptions(hardwareBackCloses)`: no header, flush top. */\nexport function fullScreenEdgeToEdgeModalSheetOptions(hardwareBackCloses = true): G9SheetOptions {\n return {\n ...fullScreenModalSheetOptions(null, false, hardwareBackCloses),\n showToolbar: false,\n useTopSafeAreaPadding: false,\n topSafeAreaPaddingOverride: 0,\n additionalTopSafeAreaPadding: 0,\n };\n}\n"],"names":["clamp","v","lo","hi","Math","finite","fallback","Number","resolveSheetSettings","settings","_s_modalOverlayColor","_s_sizeScaledAnimationDuration","_s_enableBackdropCardEffect","_s_backdropCardColor","_s_stageBeforeShow","_s_deferPrebuiltContent","_s_motionStyle","_s_heightMemoVersion","s","min","max","Object","defaultSheetOptions","fitToContentSheetOptions","fullScreenWithoutHandleSheetOptions","fullScreenModalSheetOptions","title","showCloseButton","hardwareBackCloses","toolbarItems","fullScreenEdgeToEdgeModalSheetOptions"],"mappings":"AAoQA,MAAMA,QAAQ,CAACC,GAAWC,IAAYC,KAAeC,KAAK,GAAG,CAACD,IAAIC,KAAK,GAAG,CAACF,IAAID;AAC/E,MAAMI,SAAS,CAACJ,GAAuBK,WACrC,AAAa,YAAb,OAAOL,KAAkBM,OAAO,QAAQ,CAACN,KAAKA,IAAIK;AAG7C,SAASE,qBAAqBC,QAAqC;QAMnDC,sBAKUC,gCACHC,6BACPC,sBACFC,oBAEKC,yBACTC,gBACMC;IAjBrB,MAAMC,IAAIT,QAAAA,WAAAA,WAAY,CAAC;IACvB,IAAIU,MAAMnB,MAAMK,OAAOa,EAAE,0BAA0B,EAAE,MAAM,GAAG;IAC9D,IAAIE,MAAMpB,MAAMK,OAAOa,EAAE,0BAA0B,EAAE,MAAM,GAAG;IAC9D,IAAIC,MAAMC,KAAK,CAACD,KAAKC,IAAI,GAAG;QAACA;QAAKD;KAAI;IACtC,OAAOE,OAAO,MAAM,CAAC;QACnB,mBAAmB,QAAAX,CAAAA,uBAAAA,EAAE,iBAAiB,AAAD,IAAlBA,uBAAuB;QAC1C,4BAA4BS;QAC5B,4BAA4BC;QAC5B,yBAAyBhB,KAAK,GAAG,CAAC,GAAGC,OAAOa,EAAE,uBAAuB,EAAE;QACvE,0BAA0Bd,KAAK,GAAG,CAAC,GAAGC,OAAOa,EAAE,wBAAwB,EAAE;QACzE,6BAA6B,QAAAP,CAAAA,iCAAAA,EAAE,2BAA2B,AAAD,IAA5BA,iCAAiC;QAC9D,0BAA0B,QAAAC,CAAAA,8BAAAA,EAAE,wBAAwB,AAAD,IAAzBA,8BAA8B;QACxD,mBAAmB,QAAAC,CAAAA,uBAAAA,EAAE,iBAAiB,AAAD,IAAlBA,uBAAuB;QAC1C,iBAAiB,QAAAC,CAAAA,qBAAAA,EAAE,eAAe,AAAD,IAAhBA,qBAAqB;QACtC,kBAAkBd,MAAMK,OAAOa,EAAE,gBAAgB,EAAE,MAAM,GAAG;QAC5D,sBAAsB,QAAAH,CAAAA,0BAAAA,EAAE,oBAAoB,AAAD,IAArBA,0BAA0B;QAChD,aAAa,QAAAC,CAAAA,iBAAAA,EAAE,WAAW,AAAD,IAAZA,iBAAiB;QAC9B,mBAAmB,QAAAC,CAAAA,uBAAAA,EAAE,iBAAiB,AAAD,IAAlBA,uBAAuB;QAC1C,mBAAmBb,KAAK,GAAG,CAAC,GAAGC,OAAOa,EAAE,iBAAiB,EAAE;IAC7D;AACF;AAGO,SAASI;IACd,OAAO;QACL,cAAc;QACd,QAAQ;YAAC;YAAU;SAAQ;QAC3B,UAAU;QACV,mBAAmB;QACnB,mBAAmB;IACrB;AACF;AAGO,SAASC;IACd,OAAO;QAAE,UAAU;QAAgB,cAAc;QAAM,WAAW;QAAM,aAAa;QAAM,cAAc;IAAK;AAChH;AAGO,SAASC;IACd,OAAO;QACL,cAAc;QACd,QAAQ;YAAC;SAAQ;QACjB,cAAc;QACd,aAAa;QACb,WAAW;QACX,cAAc;IAChB;AACF;AAGO,SAASC,4BACdC,KAAqB,EACrBC,kBAAkB,IAAI,EACtBC,qBAAqB,IAAI,EACzBC,YAAuD;IAEvD,OAAO;QACL,cAAc;QACd,QAAQ;YAAC;SAAQ;QACjB,UAAU;QACV,cAAc;QACd,aAAa;QACb,WAAW;QACX,cAAc;QACd,iBAAiB;QACjB,aAAa;QACbF;QACA,OAAOD,QAAAA,QAAAA,QAAS;QAChB,cAAcG,QAAAA,eAAAA,eAAgB;QAC9BD;IACF;AACF;AAGO,SAASE,sCAAsCF,qBAAqB,IAAI;IAC7E,OAAO;QACL,GAAGH,4BAA4B,MAAM,OAAOG,mBAAmB;QAC/D,aAAa;QACb,uBAAuB;QACvB,4BAA4B;QAC5B,8BAA8B;IAChC;AACF"}
1
+ {"version":3,"file":"sheet/options.jsx","sources":["../../src/sheet/options.ts"],"sourcesContent":["import type { ReactNode } from '@lynx-js/react';\nimport type { G9BottomSheetLoadingSkeleton } from '../display/shimmer';\nimport type { G9IconInput } from '../icon/icon';\n\n// MAUI `G9BottomSheetOptions` / `G9BottomSheetSettings` and their enums (BottomSheet/G9BottomSheetOptions.cs).\n\n/** Detents (MAUI `G9BottomSheetState`): peek (collapsed height), medium (half), large (full). */\nexport type G9SheetDetent = 'peek' | 'medium' | 'large';\n/** Detent sizing or fit-to-content (MAUI `G9BottomSheetSizeMode`). */\nexport type G9SheetSizeMode = 'states' | 'fitToContent';\n/** Header title anchor (MAUI `G9BottomSheetHeaderTitlePlacement`). */\nexport type G9SheetHeaderTitlePlacement = 'center' | 'nearBack';\n/** Where a back request came from (MAUI `G9BottomSheetBackRequestSource` + drag-to-close). */\nexport type G9SheetBackSource = 'toolbarButton' | 'hardwareButton' | 'overlayTap' | 'drag';\n/** What `onBackRequested` decides (MAUI `G9BottomSheetBackAction`). */\nexport type G9SheetBackAction = 'close' | 'doNothing';\n/** Content width (MAUI `G9SheetViewContentWidthMode`). */\nexport type G9SheetContentWidthMode = 'full' | 'custom';\n\n/** A header toolbar action (MAUI `G9BottomSheetToolbarItem`). */\nexport interface G9SheetToolbarItem {\n /** Glyph/icon. */\n readonly icon?: G9IconInput;\n /** Text (when there is no icon). */\n readonly text?: string;\n /** The action (MAUI `AsyncAction`/`Command`); a returned promise keeps the item busy while `disableWhileBusy`. */\n readonly onPress?: () => unknown;\n readonly isBusy?: boolean;\n /** Spinner while busy. Default false. */\n readonly showBusyIndicator?: boolean;\n readonly isActive?: boolean;\n /** Dot while active. Default false. */\n readonly showActiveBadge?: boolean;\n /**\n * A count on the action (MAUI 1.4.9 `BadgeText`: AgriPad's site filter shows its «۲» active filters): a small pill\n * with this text, shown whatever `showActiveBadge` / `isActive` say. Null / empty: the plain dot (or nothing).\n */\n readonly badgeText?: string | null;\n /** Ignore presses while busy. Default true. */\n readonly disableWhileBusy?: boolean;\n /** Default true. */\n readonly animatePress?: boolean;\n /** 0 → 24. */\n readonly iconSize?: number;\n readonly accessibilityLabel?: string;\n /** Element id of the item (default `${sheet automationId}_ToolbarItem_${key or index}` when the sheet has one). */\n readonly automationId?: string;\n /** Stable key (default the index). */\n readonly key?: string;\n}\n\n/** Lifecycle callbacks of one sheet (MAUI `Opening/Opened/Closing/ClosedCommand`). */\nexport interface G9SheetLifecycle {\n /** When the sheet starts opening. */\n readonly onOpening?: () => void;\n /** After the open motion (or its timer fallback). */\n readonly onOpened?: () => void;\n /** Once, when closing starts (not on an in-place replace). */\n readonly onClosing?: () => void;\n /** Once, at cleanup. */\n readonly onClosed?: () => void;\n /** The sheet came to rest at another detent (MAUI `G9SheetView.StateChanged`), with its height in px. */\n readonly onStateChanged?: (detent: G9SheetDetent | 'fit', heightPx: number) => void;\n}\n\n/** Everything a sheet can be opened with (MAUI `G9BottomSheetOptions`; 77 properties + presets). */\nexport interface G9SheetOptions extends G9SheetLifecycle {\n // State and sizing\n /** Initial detent. Default `'medium'`. */\n readonly currentState?: G9SheetDetent;\n /** Allowed detents. Default `['medium', 'large']`. */\n readonly states?: ReadonlyArray<G9SheetDetent>;\n /** Default `'states'`. */\n readonly sizeMode?: G9SheetSizeMode;\n /** Dim scrim that blocks the page. Default true. */\n readonly isModal?: boolean;\n /** Overlay tap / drag may close. Default true. */\n readonly isCancelable?: boolean;\n /** Default true. */\n readonly isDraggable?: boolean;\n /** Grabber. Default true. */\n readonly hasHandle?: boolean;\n /** Peek height (dp). Default 100 (with `collapsedHeight`). */\n readonly peekHeight?: number | null;\n /** Alias of `peekHeight` (MAUI `CollapsedHeight`); wins when both are set. */\n readonly collapsedHeight?: number | null;\n /** Medium = host × ratio (0.1–0.9). Default 0.5. */\n readonly halfExpandedRatio?: number | null;\n /** Large = host × ratio (0.1–1). Default 1. */\n readonly fullExpandedRatio?: number | null;\n /** Cap of a fit sheet (0.2–1). Default 0.75. */\n readonly maxFitToContentHeightRatio?: number;\n /** The largest detent is sized to the content (states mode). Default false. */\n readonly expandedFitsContent?: boolean;\n /**\n * Grabber on a draggable sheet with ONE detent, which (as in MAUI) has none by default. For a sheet that has one detent\n * only here — MAUI's peek of a short content followed it down to the content, so MAUI showed two detents of one height\n * and a grabber; lynx-ui resolves its detents once, so the host asks for one fit detent and keeps the grabber with this.\n * Default false.\n */\n readonly handleOnSingleDetent?: boolean;\n /** A drag on a scroller expands the sheet first. Default true. */\n readonly scrollingExpandsSheet?: boolean;\n /**\n * The body is a vertical scroller (default true). `false` for content that scrolls itself — a `<list>` page, a map:\n * the body becomes a flex column and the content fills it, so the content's own scroller gets a definite height (MAUI\n * puts the content in the body as is; a CollectionView body scrolls itself). Lynx-only, additive. Use it with a\n * detent-sized sheet (full screen / states); a fit-to-content sheet has no height to give.\n */\n readonly scrollBody?: boolean;\n /**\n * The body's scroll bar: `'system'` (default) — the platform's, shown while a finger scrolls, then faded; `'always'` —\n * a thin thumb in the body's side inset at the inline end, visible whenever the content is taller than the body and\n * moving with it (a menu of full-width cards whose last card is cut off says «more below»). Lynx-only, additive.\n */\n readonly scrollIndicator?: 'system' | 'always';\n /**\n * Called when the scrolling body comes within {@link scrollToEndThreshold} of its end — a body that renders a window\n * of a long list grows it here (the selection sheet's next page, MAUI 1.4.8 `OnItemsScrolled`). Not called for a\n * static body (`scrollBody: false`). Lynx-only, additive.\n */\n readonly onScrollToEnd?: () => void;\n /** Distance from the end (px) that counts as «at the end» for {@link onScrollToEnd}. Default 208 (four 52 px rows). */\n readonly scrollToEndThreshold?: number;\n /** Height memory key (needed for factory content). */\n readonly heightMemoKey?: string | null;\n // Visual\n /** Body padding. Default 0. */\n readonly padding?: number;\n /** 10 px gap under the header hairline. Default true. */\n readonly useStandardBodyTopGap?: boolean;\n /** Top corners. Default 12. */\n readonly cornerRadius?: number;\n /** Body background. Default `var(--g9-surface-container)`. */\n readonly backgroundColor?: string | null;\n /** Scrim colour; its alpha replaces the maximum opacity. */\n readonly windowBackgroundColor?: string | null;\n /** Default `'full'`. */\n readonly contentWidthMode?: G9SheetContentWidthMode;\n /** Width in `'custom'` mode (MAUI `G9BottomSheetContentWidth`). */\n readonly contentWidth?: number | null;\n /**\n * Full-screen sheets, and detent sheets resting at a `large` detent that reaches under the top inset, reserve the\n * top inset (MAUI state-aware top padding). Default true.\n */\n readonly useTopSafeAreaPadding?: boolean;\n /**\n * The surface reserves the host's bottom safe inset (a visible navigation bar or gesture handle) below the content\n * and footer. 0 on an immersive host. Default true.\n */\n readonly useBottomSafeAreaPadding?: boolean;\n /** Default 0. */\n readonly additionalTopSafeAreaPadding?: number;\n /** Replaces the top padding (0 = flush). */\n readonly topSafeAreaPaddingOverride?: number | null;\n /** Grabber on full-screen toolbar sheets. Default true. */\n readonly showFullScreenDragHandle?: boolean;\n /** Page recede behind a tall primary sheet. Default true. */\n readonly enableBackdropCardEffect?: boolean;\n /** Visible ratio where the recede starts. Default 0.75. */\n readonly backdropCardEffectThreshold?: number;\n // Animation and loading\n /** Per-sheet open duration (ms); default the settings value. */\n readonly openAnimationDurationMs?: number | null;\n readonly closeAnimationDurationMs?: number | null;\n /** Factory content builds after the open motion (spinner/skeleton first). Default true. */\n readonly deferContent?: boolean;\n /** Delay before deferred content swaps in. Default 369. */\n readonly loadDelayMs?: number;\n /** The placeholder uses the full height. Default false. */\n readonly useFullScreenLoadingPlaceholder?: boolean;\n /** Known final body height for the placeholder. */\n readonly deferredLoadingPlaceholderHeight?: number | null;\n /** Covered crossfade reveal of deferred content. Default true. */\n readonly fadeDeferredContentIn?: boolean;\n /** Placeholder shape. Default `'none'` (spinner). */\n readonly loadingSkeleton?: G9BottomSheetLoadingSkeleton;\n /** 0 → the shape's default. */\n readonly loadingSkeletonRowCount?: number;\n // Stack and replace\n /** The parent sinks and fades when this sheet stacks on it. Default true. */\n readonly recedeParentOnStack?: boolean;\n /** Hand-off: replaces the one open sheet once this one is ready. Default false. */\n readonly replaceCurrentSheet?: boolean;\n // Header and footer\n /** Three-slot header. Default false. */\n readonly showToolbar?: boolean;\n /** Leading back (or close) button. Default false. */\n readonly showCloseButton?: boolean;\n /** × instead of the back arrow. Default false. */\n readonly useCloseIcon?: boolean;\n /**\n * Automation id of the sheet (MAUI `AutomationId`): the surface gets it, the header's back/close button\n * `${id}_Back`, toolbar items `${id}_ToolbarItem_${key or index}` (see `g9ChildId`). Keep it to `[A-Za-z0-9_-]`.\n */\n readonly automationId?: string;\n readonly title?: string | null;\n readonly toolbarItems?: ReadonlyArray<G9SheetToolbarItem> | null;\n /** Items built from the content once it exists. */\n readonly toolbarItemsFactory?: (() => ReadonlyArray<G9SheetToolbarItem>) | null;\n /** Default `'center'`. */\n readonly headerTitlePlacement?: G9SheetHeaderTitlePlacement;\n /** Star/Auto/Star columns. Default true. */\n readonly reserveEmptyHeaderSlots?: boolean;\n readonly headerView?: ReactNode;\n readonly headerLeadingView?: ReactNode;\n readonly headerTitleView?: ReactNode;\n readonly headerTrailingView?: ReactNode;\n readonly headerLeadingAndTitleView?: ReactNode;\n readonly headerTitleAndTrailingView?: ReactNode;\n /**\n * A footer that draws its own band (usually a component rendering {@link G9SheetFooterBar}, or nothing) — for\n * buttons that come and go while the sheet is open. Wins over `footerView` and `footerButtons`.\n */\n readonly footerBand?: ReactNode;\n /** Custom footer inside the standard band; wins over `footerButtons`. */\n readonly footerView?: ReactNode;\n /** Equal-width footer buttons. */\n readonly footerButtons?: ReadonlyArray<ReactNode> | null;\n /** Default 3. */\n readonly footerMaxButtonsPerRow?: number;\n /** Hardware back closes. Default true. */\n readonly hardwareBackCloses?: boolean;\n /** Intercepts every back request (disables drag). */\n readonly onBackRequested?: ((source: G9SheetBackSource) => G9SheetBackAction | Promise<G9SheetBackAction>) | null;\n // Platform specific (accepted; applied where Lynx has an equivalent)\n /** Max sheet width on Android (px). */\n readonly androidMaxWidth?: number | null;\n /** Max sheet height on Android (px). */\n readonly androidMaxHeight?: number | null;\n /** Margin around the sheet on Android `[l, t, r, b]`. */\n readonly androidMargin?: readonly [number, number, number, number] | null;\n /** Android half-expanded ratio override. */\n readonly androidHalfExpandedRatio?: number | null;\n /** Square the expanded corners on Android. */\n readonly androidShouldRemoveExpandedCorners?: boolean | null;\n readonly windowsMaxWidth?: number | null;\n readonly windowsMaxHeight?: number | null;\n readonly windowsMinWidth?: number | null;\n readonly windowsMinHeight?: number | null;\n /** Animate the scrim colour on iOS. Default true. */\n readonly animateOverlayToColorOnIos?: boolean;\n}\n\n/** App-wide sheet settings (MAUI `G9BottomSheetSettings`), `<G9Provider settings={{ sheets }}>`. */\nexport interface G9SheetSettings {\n /** Default black. */\n readonly modalOverlayColor?: string;\n /** Dim at the smallest detent (0–1). Default 0.3. */\n readonly modalOverlayMinimumOpacity?: number;\n /** Dim at full screen (0–1). Default 0.9. */\n readonly modalOverlayMaximumOpacity?: number;\n /** Default 300. */\n readonly openAnimationDurationMs?: number;\n /** Default 300. */\n readonly closeAnimationDurationMs?: number;\n /** Partial traversals take a proportional slice. Default true. */\n readonly sizeScaledAnimationDuration?: boolean;\n /** Global switch of the page recede. Default true. */\n readonly enableBackdropCardEffect?: boolean;\n /**\n * The sheets rise above the soft keyboard (MAUI KeyboardInsetScope; G9MAUIControls 1.4.11 rule «every input in a bottom\n * sheet takes the keyboard shift»): while the keyboard is up the sheet layer ends at its top edge, so a fit sheet's field and\n * footer stay visible and a tall sheet gives up height. Only what the host has not already resized is lifted — a host that\n * pads its view by the IME inset (the gallery's `GalleryActivity`) shrinks the window itself. Default true.\n */\n readonly avoidKeyboard?: boolean;\n /** Colour behind the receded page. Default black. */\n readonly backdropCardColor?: string;\n /** Staged pipeline: a `replaceCurrentSheet` successor hands off once it is ready. Default true. */\n readonly stageBeforeShow?: boolean;\n /** Longest a hand-off waits for the successor to open before the old sheet closes anyway (0–5000). Default 250. */\n readonly preOpenMaxHoldMs?: number;\n /** Prebuilt (non-factory) content also waits behind the loading placeholder until after the open motion. Default false. */\n readonly deferPrebuiltContent?: boolean;\n /** `'platformNative'` (lynx-ui's motion) or `'timed'` (tween over the durations). Default platformNative. */\n readonly motionStyle?: 'platformNative' | 'timed';\n /** The app version the persisted sheet heights belong to; another version discards them. Default `'0'`. */\n readonly heightMemoVersion?: string;\n /**\n * Side padding of the header band (MAUI `G9LayoutMetrics.EdgeSpacing`, which an app may scale — AgriPad's 10 × 1.3\n * = 13). Default 16.\n */\n readonly headerEdgeSpacing?: number;\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));\nconst finite = (v: number | undefined, fallback: number) =>\n typeof v === 'number' && Number.isFinite(v) ? v : fallback;\n\n/** {@link G9SheetSettings} with defaults, clamped like MAUI `G9BottomSheetSettings.Normalize`. */\nexport function resolveSheetSettings(settings: G9SheetSettings | undefined): Required<G9SheetSettings> {\n const s = settings ?? {};\n let min = clamp(finite(s.modalOverlayMinimumOpacity, 0.3), 0, 1);\n let max = clamp(finite(s.modalOverlayMaximumOpacity, 0.9), 0, 1);\n if (min > max) [min, max] = [max, min];\n return Object.freeze({\n modalOverlayColor: s.modalOverlayColor ?? '#000000',\n modalOverlayMinimumOpacity: min,\n modalOverlayMaximumOpacity: max,\n openAnimationDurationMs: Math.max(0, finite(s.openAnimationDurationMs, 300)),\n closeAnimationDurationMs: Math.max(0, finite(s.closeAnimationDurationMs, 300)),\n sizeScaledAnimationDuration: s.sizeScaledAnimationDuration ?? true,\n enableBackdropCardEffect: s.enableBackdropCardEffect ?? true,\n avoidKeyboard: s.avoidKeyboard ?? true,\n backdropCardColor: s.backdropCardColor ?? '#000000',\n stageBeforeShow: s.stageBeforeShow ?? true,\n preOpenMaxHoldMs: clamp(finite(s.preOpenMaxHoldMs, 250), 0, 5000),\n deferPrebuiltContent: s.deferPrebuiltContent ?? false,\n motionStyle: s.motionStyle ?? 'platformNative',\n heightMemoVersion: s.heightMemoVersion ?? '0',\n headerEdgeSpacing: Math.max(0, finite(s.headerEdgeSpacing, 16)),\n });\n}\n\n/** MAUI `DefaultOptions()`: medium, `[medium, large]`, modal, cancelable, handle, draggable. */\nexport function defaultSheetOptions(): G9SheetOptions {\n return {\n currentState: 'medium',\n states: ['medium', 'large'],\n sizeMode: 'states',\n halfExpandedRatio: 0.5,\n fullExpandedRatio: 1,\n };\n}\n\n/** MAUI `FitToContentOptions()`: sized to a non-scrolling body, capped at 75 % of the host. */\nexport function fitToContentSheetOptions(): G9SheetOptions {\n return { sizeMode: 'fitToContent', isCancelable: true, hasHandle: true, isDraggable: true, deferContent: true };\n}\n\n/** MAUI `FullScreenWithoutHandleOptions()`. */\nexport function fullScreenWithoutHandleSheetOptions(): G9SheetOptions {\n return {\n currentState: 'large',\n states: ['large'],\n isCancelable: false,\n isDraggable: false,\n hasHandle: false,\n deferContent: true,\n };\n}\n\n/** MAUI `FullScreenModalOptions(title, showCloseButton, hardwareBackCloses, toolbarItems)`. */\nexport function fullScreenModalSheetOptions(\n title?: string | null,\n showCloseButton = true,\n hardwareBackCloses = true,\n toolbarItems?: ReadonlyArray<G9SheetToolbarItem> | null,\n): G9SheetOptions {\n return {\n currentState: 'large',\n states: ['large'],\n sizeMode: 'states',\n isCancelable: false,\n isDraggable: false,\n hasHandle: false,\n cornerRadius: 0,\n backgroundColor: 'var(--g9-background)',\n showToolbar: true,\n showCloseButton,\n title: title ?? null,\n toolbarItems: toolbarItems ?? null,\n hardwareBackCloses,\n };\n}\n\n/** MAUI `FullScreenEdgeToEdgeModalOptions(hardwareBackCloses)`: no header, flush top. */\nexport function fullScreenEdgeToEdgeModalSheetOptions(hardwareBackCloses = true): G9SheetOptions {\n return {\n ...fullScreenModalSheetOptions(null, false, hardwareBackCloses),\n showToolbar: false,\n useTopSafeAreaPadding: false,\n topSafeAreaPaddingOverride: 0,\n additionalTopSafeAreaPadding: 0,\n };\n}\n"],"names":["clamp","v","lo","hi","Math","finite","fallback","Number","resolveSheetSettings","settings","_s_modalOverlayColor","_s_sizeScaledAnimationDuration","_s_enableBackdropCardEffect","_s_avoidKeyboard","_s_backdropCardColor","_s_stageBeforeShow","_s_deferPrebuiltContent","_s_motionStyle","_s_heightMemoVersion","s","min","max","Object","defaultSheetOptions","fitToContentSheetOptions","fullScreenWithoutHandleSheetOptions","fullScreenModalSheetOptions","title","showCloseButton","hardwareBackCloses","toolbarItems","fullScreenEdgeToEdgeModalSheetOptions"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type ReactNode } from '@lynx-js/react';
2
+ /** The thumb's smallest length (dp), so a very long content still has something to see. */
3
+ export declare const SHEET_THUMB_MIN = 24;
4
+ /** The thumb's width and its gap to the body's edge (dp). */
5
+ export declare const SHEET_THUMB_WIDTH = 3;
6
+ export declare const SHEET_THUMB_INSET = 3;
7
+ /** Where the thumb is: its length and its offset from the body's top (dp), or null when nothing overflows. */
8
+ export declare function sheetThumb(viewport: number, content: number, scrollTop: number): {
9
+ readonly length: number;
10
+ readonly offset: number;
11
+ } | null;
12
+ interface IndicatorState {
13
+ readonly viewport: number;
14
+ readonly content: number;
15
+ readonly top: number;
16
+ }
17
+ /** What the frame feeds (the body's height, the content's height, the scroll offset) and the thumb reads. */
18
+ export declare class G9SheetScrollModel {
19
+ private state;
20
+ private readonly listeners;
21
+ readonly get: () => IndicatorState;
22
+ readonly subscribe: (listener: () => void) => (() => void);
23
+ setViewport(height: number): void;
24
+ setContent(height: number): void;
25
+ setTop(top: number): void;
26
+ private update;
27
+ }
28
+ /** The thumb at the body's inline END (left in a right-to-left sheet), in the side inset; touches pass through. */
29
+ export declare function G9SheetScrollIndicator(props: {
30
+ readonly model: G9SheetScrollModel;
31
+ }): ReactNode;
32
+ export {};
33
+ //# sourceMappingURL=scroll-indicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-indicator.d.ts","sourceRoot":"","sources":["../../src/sheet/scroll-indicator.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,SAAS,EAAwB,MAAM,gBAAgB,CAAC;AAGtE,2FAA2F;AAC3F,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,8GAA8G;AAC9G,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM7D;AAED,UAAU,cAAc;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,6GAA6G;AAC7G,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IAEnD,QAAQ,CAAC,GAAG,QAAO,cAAc,CAAe;IAEhD,QAAQ,CAAC,SAAS,GAAI,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAGvD;IAEF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIjC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIhC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,OAAO,CAAC,MAAM;CAOf;AAED,mHAAmH;AACnH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CAiB/F"}
@@ -0,0 +1,84 @@
1
+ import { useSyncExternalStore } from "@lynx-js/react";
2
+ import { useG9Direction } from "../provider/hooks.jsx";
3
+ function _define_property(obj, key, value) {
4
+ if (key in obj) Object.defineProperty(obj, key, {
5
+ value: value,
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true
9
+ });
10
+ else obj[key] = value;
11
+ return obj;
12
+ }
13
+ const SHEET_THUMB_MIN = 24;
14
+ const SHEET_THUMB_WIDTH = 3;
15
+ const SHEET_THUMB_INSET = 3;
16
+ function sheetThumb(viewport, content, scrollTop) {
17
+ if (!(viewport > 0) || !(content > viewport + 1)) return null;
18
+ const length = Math.min(viewport, Math.max(SHEET_THUMB_MIN, viewport * viewport / content));
19
+ const travel = content - viewport;
20
+ const share = Math.min(1, Math.max(0, scrollTop / travel));
21
+ return {
22
+ length,
23
+ offset: (viewport - length) * share
24
+ };
25
+ }
26
+ class G9SheetScrollModel {
27
+ setViewport(height) {
28
+ this.update({
29
+ viewport: height
30
+ });
31
+ }
32
+ setContent(height) {
33
+ this.update({
34
+ content: height
35
+ });
36
+ }
37
+ setTop(top) {
38
+ this.update({
39
+ top
40
+ });
41
+ }
42
+ update(patch) {
43
+ const next = {
44
+ ...this.state,
45
+ ...patch
46
+ };
47
+ if (next.viewport === this.state.viewport && next.content === this.state.content && next.top === this.state.top) return;
48
+ this.state = next;
49
+ for (const l of this.listeners)l();
50
+ }
51
+ constructor(){
52
+ _define_property(this, "state", {
53
+ viewport: 0,
54
+ content: 0,
55
+ top: 0
56
+ });
57
+ _define_property(this, "listeners", new Set());
58
+ _define_property(this, "get", ()=>this.state);
59
+ _define_property(this, "subscribe", (listener)=>{
60
+ this.listeners.add(listener);
61
+ return ()=>this.listeners.delete(listener);
62
+ });
63
+ }
64
+ }
65
+ function G9SheetScrollIndicator(props) {
66
+ const rtl = 'rtl' === useG9Direction();
67
+ const s = useSyncExternalStore(props.model.subscribe, props.model.get, props.model.get);
68
+ const thumb = sheetThumb(s.viewport, s.content, s.top);
69
+ if (!thumb) return null;
70
+ return <view className="g9-sheet__scroll-thumb" style={{
71
+ top: `${thumb.offset}px`,
72
+ height: `${thumb.length}px`,
73
+ width: `${SHEET_THUMB_WIDTH}px`,
74
+ borderRadius: `${SHEET_THUMB_WIDTH / 2}px`,
75
+ ...rtl ? {
76
+ left: `${SHEET_THUMB_INSET}px`
77
+ } : {
78
+ right: `${SHEET_THUMB_INSET}px`
79
+ }
80
+ }}/>;
81
+ }
82
+ export { G9SheetScrollIndicator, G9SheetScrollModel, SHEET_THUMB_INSET, SHEET_THUMB_MIN, SHEET_THUMB_WIDTH, sheetThumb };
83
+
84
+ //# sourceMappingURL=scroll-indicator.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet/scroll-indicator.jsx","sources":["../../src/sheet/scroll-indicator.tsx"],"sourcesContent":["// The sheet body's always-visible scroll indicator (`scrollIndicator: 'always'`). A sheet menu of full-width cards whose\n// last card is cut off does not say «more below»; the platform's own bar (Lynx `scroll-bar-enable`) only shows while a\n// finger scrolls and then fades. This thumb is drawn in the body's side inset, never over the content, only while the\n// content is taller than the body, and moves with the scroll. Its own small store: a scroll event repaints the thumb,\n// never the sheet.\nimport { type ReactNode, useSyncExternalStore } from '@lynx-js/react';\nimport { useG9Direction } from '../provider/hooks';\n\n/** The thumb's smallest length (dp), so a very long content still has something to see. */\nexport const SHEET_THUMB_MIN = 24;\n/** The thumb's width and its gap to the body's edge (dp). */\nexport const SHEET_THUMB_WIDTH = 3;\nexport const SHEET_THUMB_INSET = 3;\n\n/** Where the thumb is: its length and its offset from the body's top (dp), or null when nothing overflows. */\nexport function sheetThumb(\n viewport: number,\n content: number,\n scrollTop: number,\n): { readonly length: number; readonly offset: number } | null {\n if (!(viewport > 0) || !(content > viewport + 1)) return null;\n const length = Math.min(viewport, Math.max(SHEET_THUMB_MIN, (viewport * viewport) / content));\n const travel = content - viewport;\n const share = Math.min(1, Math.max(0, scrollTop / travel));\n return { length, offset: (viewport - length) * share };\n}\n\ninterface IndicatorState {\n readonly viewport: number;\n readonly content: number;\n readonly top: number;\n}\n\n/** What the frame feeds (the body's height, the content's height, the scroll offset) and the thumb reads. */\nexport class G9SheetScrollModel {\n private state: IndicatorState = { viewport: 0, content: 0, top: 0 };\n private readonly listeners = new Set<() => void>();\n\n readonly get = (): IndicatorState => this.state;\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n setViewport(height: number): void {\n this.update({ viewport: height });\n }\n\n setContent(height: number): void {\n this.update({ content: height });\n }\n\n setTop(top: number): void {\n this.update({ top });\n }\n\n private update(patch: Partial<IndicatorState>): void {\n const next = { ...this.state, ...patch };\n if (next.viewport === this.state.viewport && next.content === this.state.content && next.top === this.state.top)\n return;\n this.state = next;\n for (const l of this.listeners) l();\n }\n}\n\n/** The thumb at the body's inline END (left in a right-to-left sheet), in the side inset; touches pass through. */\nexport function G9SheetScrollIndicator(props: { readonly model: G9SheetScrollModel }): ReactNode {\n const rtl = useG9Direction() === 'rtl';\n const s = useSyncExternalStore(props.model.subscribe, props.model.get, props.model.get);\n const thumb = sheetThumb(s.viewport, s.content, s.top);\n if (!thumb) return null;\n return (\n <view\n className=\"g9-sheet__scroll-thumb\"\n style={{\n top: `${thumb.offset}px`,\n height: `${thumb.length}px`,\n width: `${SHEET_THUMB_WIDTH}px`,\n borderRadius: `${SHEET_THUMB_WIDTH / 2}px`,\n ...(rtl ? { left: `${SHEET_THUMB_INSET}px` } : { right: `${SHEET_THUMB_INSET}px` }),\n }}\n />\n );\n}\n"],"names":["SHEET_THUMB_MIN","SHEET_THUMB_WIDTH","SHEET_THUMB_INSET","sheetThumb","viewport","content","scrollTop","length","Math","travel","share","G9SheetScrollModel","height","top","patch","next","l","Set","listener","G9SheetScrollIndicator","props","rtl","useG9Direction","s","useSyncExternalStore","thumb","view"],"mappings":";;;;;;;;;;;;AASO,MAAMA,kBAAkB;AAExB,MAAMC,oBAAoB;AAC1B,MAAMC,oBAAoB;AAG1B,SAASC,WACdC,QAAgB,EAChBC,OAAe,EACfC,SAAiB;IAEjB,IAAI,CAAEF,CAAAA,WAAW,MAAM,CAAEC,CAAAA,UAAUD,WAAW,IAAI,OAAO;IACzD,MAAMG,SAASC,KAAK,GAAG,CAACJ,UAAUI,KAAK,GAAG,CAACR,iBAAkBI,WAAWA,WAAYC;IACpF,MAAMI,SAASJ,UAAUD;IACzB,MAAMM,QAAQF,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGF,YAAYG;IAClD,OAAO;QAAEF;QAAQ,QAASH,AAAAA,CAAAA,WAAWG,MAAK,IAAKG;IAAM;AACvD;AASO,MAAMC;IAWX,YAAYC,MAAc,EAAQ;QAChC,IAAI,CAAC,MAAM,CAAC;YAAE,UAAUA;QAAO;IACjC;IAEA,WAAWA,MAAc,EAAQ;QAC/B,IAAI,CAAC,MAAM,CAAC;YAAE,SAASA;QAAO;IAChC;IAEA,OAAOC,GAAW,EAAQ;QACxB,IAAI,CAAC,MAAM,CAAC;YAAEA;QAAI;IACpB;IAEQ,OAAOC,KAA8B,EAAQ;QACnD,MAAMC,OAAO;YAAE,GAAG,IAAI,CAAC,KAAK;YAAE,GAAGD,KAAK;QAAC;QACvC,IAAIC,KAAK,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAIA,KAAK,OAAO,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,IAAIA,KAAK,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,EAC7G;QACF,IAAI,CAAC,KAAK,GAAGA;QACb,KAAK,MAAMC,KAAK,IAAI,CAAC,SAAS,CAAEA;IAClC;;QA5BA,uBAAQ,SAAwB;YAAE,UAAU;YAAG,SAAS;YAAG,KAAK;QAAE;QAClE,uBAAiB,aAAY,IAAIC;QAEjC,uBAAS,OAAM,IAAsB,IAAI,CAAC,KAAK;QAE/C,uBAAS,aAAY,CAACC;YACpB,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA;YACnB,OAAO,IAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAACA;QACrC;;AAqBF;AAGO,SAASC,uBAAuBC,KAA6C;IAClF,MAAMC,MAAMC,AAAqB,UAArBA;IACZ,MAAMC,IAAIC,qBAAqBJ,MAAM,KAAK,CAAC,SAAS,EAAEA,MAAM,KAAK,CAAC,GAAG,EAAEA,MAAM,KAAK,CAAC,GAAG;IACtF,MAAMK,QAAQtB,WAAWoB,EAAE,QAAQ,EAAEA,EAAE,OAAO,EAAEA,EAAE,GAAG;IACrD,IAAI,CAACE,OAAO,OAAO;IACnB,QACGC,KACC,UAAU,yBACV,OAAO;QACL,KAAK,GAAGD,MAAM,MAAM,CAAC,EAAE,CAAC;QACxB,QAAQ,GAAGA,MAAM,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,GAAGxB,kBAAkB,EAAE,CAAC;QAC/B,cAAc,GAAGA,oBAAoB,EAAE,EAAE,CAAC;QAC1C,GAAIoB,MAAM;YAAE,MAAM,GAAGnB,kBAAkB,EAAE,CAAC;QAAC,IAAI;YAAE,OAAO,GAAGA,kBAAkB,EAAE,CAAC;QAAC,CAAC;IACpF;AAGN"}
@@ -40,6 +40,14 @@ export interface G9SheetService {
40
40
  /** The stack (advanced: rendering, tests). */
41
41
  readonly stack: G9SheetStack;
42
42
  }
43
+ /**
44
+ * How far the sheet layer rises above the soft keyboard: its height, less what the host already took off the window
45
+ * (`baselineHeight` = the window while the keyboard was hidden). 0 while hidden; never negative; never more than the window.
46
+ */
47
+ export declare function keyboardLift(keyboard: {
48
+ readonly visible: boolean;
49
+ readonly height: number;
50
+ }, baselineHeight: number, windowHeight: number): number;
43
51
  /** The sheet service of a host, created on first use. */
44
52
  export declare function sheetServiceOf(host: G9HostHandle, settings?: Required<G9SheetSettings>, preferences?: G9SheetMemoPreferences): G9SheetService;
45
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/sheet/service.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAW,MAAM,kBAAkB,CAAC;AAG9D,OAAO,EAAyB,KAAK,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC3G,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,eAAe,EAErB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAA4B,MAAM,cAAc,CAAC;AAE/G,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAAC;IAC9E,iGAAiG;IACjG,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC5F,uHAAuH;IACvH,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAAC;IACjF;;;;OAIG;IACH,cAAc,CACZ,KAAK,EAAE,iBAAiB,EACxB,OAAO,CAAC,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,wBAAwB,EAClC,aAAa,CAAC,EAAE,MAAM,GACrB,aAAa,GAAG,IAAI,CAAC;IACxB,2EAA2E;IAC3E,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IACjF,gEAAgE;IAChE,QAAQ,IAAI,IAAI,CAAC;IACjB,sDAAsD;IACtD,QAAQ,IAAI,IAAI,CAAC;IACjB,8CAA8C;IAC9C,YAAY,IAAI,MAAM,CAAC;IACvB,2GAA2G;IAC3G,kBAAkB,IAAI,OAAO,CAAC;IAC9B,0FAA0F;IAC1F,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;IACnE,2EAA2E;IAC3E,oBAAoB,IAAI,MAAM,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;CAC9B;AA+ID,yDAAyD;AACzD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,EACpC,WAAW,CAAC,EAAE,sBAAsB,GACnC,cAAc,CAIhB;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,cAAc,CAI5C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,cAAc,CAEzC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/sheet/service.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAW,MAAM,kBAAkB,CAAC;AAU9D,OAAO,EAAyB,KAAK,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC3G,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,eAAe,EAErB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAA4B,MAAM,cAAc,CAAC;AAE/G,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAAC;IAC9E,iGAAiG;IACjG,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAC5F,uHAAuH;IACvH,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAAC;IACjF;;;;OAIG;IACH,cAAc,CACZ,KAAK,EAAE,iBAAiB,EACxB,OAAO,CAAC,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,wBAAwB,EAClC,aAAa,CAAC,EAAE,MAAM,GACrB,aAAa,GAAG,IAAI,CAAC;IACxB,2EAA2E;IAC3E,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IACjF,gEAAgE;IAChE,QAAQ,IAAI,IAAI,CAAC;IACjB,sDAAsD;IACtD,QAAQ,IAAI,IAAI,CAAC;IACjB,8CAA8C;IAC9C,YAAY,IAAI,MAAM,CAAC;IACvB,2GAA2G;IAC3G,kBAAkB,IAAI,OAAO,CAAC;IAC9B,0FAA0F;IAC1F,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;IACnE,2EAA2E;IAC3E,oBAAoB,IAAI,MAAM,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;CAC9B;AAsFD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAChE,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,GACnB,MAAM,CAIR;AAkED,yDAAyD;AACzD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,EACpC,WAAW,CAAC,EAAE,sBAAsB,GACnC,cAAc,CAIhB;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,cAAc,CAI5C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,cAAc,CAEzC"}
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState, useSyncExternalStore } from "@lynx-js/reac
2
2
  import { startTimer, stopTimer } from "../base/timers.jsx";
3
3
  import { useG9Host, useG9HostInsets } from "../host/hooks.jsx";
4
4
  import { g9Hosts } from "../host/registry.jsx";
5
- import { useG9Culture, useG9Preferences, useG9Settings, useG9Theme, useG9Window } from "../provider/hooks.jsx";
5
+ import { useG9Culture, useG9Keyboard, useG9Preferences, useG9Settings, useG9Theme, useG9Window } from "../provider/hooks.jsx";
6
6
  import { G9SheetFrame } from "./frame.jsx";
7
7
  import { createSheetHeightMemo } from "./height-memo.jsx";
8
8
  import { fitToContentSheetOptions, fullScreenModalSheetOptions, resolveSheetSettings } from "./options.jsx";
@@ -17,6 +17,10 @@ function StackView(props) {
17
17
  const win = useG9Window();
18
18
  const insets = useG9HostInsets();
19
19
  const culture = useG9Culture();
20
+ const keyboard = useG9Keyboard();
21
+ const baseline = useRef(win.height);
22
+ if (!keyboard.visible) baseline.current = win.height;
23
+ const lift = state.settings.avoidKeyboard ? keyboardLift(keyboard, baseline.current, win.height) : 0;
20
24
  const stack = state.service.stack;
21
25
  const entries = useSyncExternalStore((l)=>stack.subscribe(l), ()=>stack.getSnapshot());
22
26
  const host = useG9Host();
@@ -51,13 +55,20 @@ function StackView(props) {
51
55
  const top = [
52
56
  ...entries
53
57
  ].reverse().find((e)=>'opening' === e.status || 'open' === e.status);
54
- return <view className="g9-sheet-stack">
55
- {entries.map((entry)=><G9SheetFrame key={entry.frameKey} entry={entry} stack={stack} hostHeight={win.height} hostWidth={win.width} topInset={insets.top} bottomInset={insets.bottom} settings={state.settings} memo={state.service.heightMemo} culture={culture.locale} isTop={entry === top} onRest={(heightPx)=>setRest({
58
+ return <view className="g9-sheet-stack" style={{
59
+ bottom: `${lift}px`
60
+ }}>
61
+ {entries.map((entry)=><G9SheetFrame key={entry.frameKey} entry={entry} stack={stack} hostHeight={win.height - lift} hostWidth={win.width} topInset={insets.top} bottomInset={lift > 0 ? 0 : insets.bottom} settings={state.settings} memo={state.service.heightMemo} culture={culture.locale} isTop={entry === top} onRest={(heightPx)=>setRest({
56
62
  id: entry.id,
57
63
  heightPx
58
64
  })}/>)}
59
65
  </view>;
60
66
  }
67
+ function keyboardLift(keyboard, baselineHeight, windowHeight) {
68
+ if (!keyboard.visible || !(keyboard.height > 0)) return 0;
69
+ const resized = Math.max(0, baselineHeight - windowHeight);
70
+ return Math.round(Math.min(Math.max(0, windowHeight - 1), Math.max(0, keyboard.height - resized)));
71
+ }
61
72
  function createSheetService(host, settings, preferences) {
62
73
  const clock = host.services.clock;
63
74
  const state = {
@@ -138,6 +149,6 @@ function useG9Sheets() {
138
149
  function g9Sheets() {
139
150
  return sheetServiceOf(g9Hosts.require());
140
151
  }
141
- export { g9Sheets, sheetServiceOf, useG9Sheets };
152
+ export { g9Sheets, keyboardLift, sheetServiceOf, useG9Sheets };
142
153
 
143
154
  //# sourceMappingURL=service.jsx.map
@@ -1 +1 @@
1
- {"version":3,"file":"sheet/service.jsx","sources":["../../src/sheet/service.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState, useSyncExternalStore } from '@lynx-js/react';\nimport { startTimer, stopTimer } from '../base/timers';\nimport { useG9Host, useG9HostInsets } from '../host/hooks';\nimport { type G9HostHandle, g9Hosts } from '../host/registry';\nimport { useG9Culture, useG9Preferences, useG9Settings, useG9Theme, useG9Window } from '../provider/hooks';\nimport { G9SheetFrame } from './frame';\nimport { createSheetHeightMemo, type G9SheetHeightMemo, type G9SheetMemoPreferences } from './height-memo';\nimport {\n fitToContentSheetOptions,\n fullScreenModalSheetOptions,\n type G9SheetOptions,\n type G9SheetSettings,\n resolveSheetSettings,\n} from './options';\nimport { type G9ProcessingBuild, type G9ProcessingErrorHandler, G9ProcessingSheetContent } from './processing';\nimport { backdropCardTransform, sheetVisibleRatio } from './sizing';\nimport { type G9SheetContent, type G9SheetHandle, G9SheetStack } from './stack';\n\n/** The sheet API of one host (MAUI `G9BottomSheetHelper` + `G9BottomSheetExtensions`). */\nexport interface G9SheetService {\n /**\n * Opens a sheet (MAUI `ShowG9BottomSheet`): auto-stacks over an open sheet, hands off with `replaceCurrentSheet`,\n * otherwise opens as primary. `content` may be a factory, built after the open motion (`deferContent`). Returns the\n * sheet-scoped handle, or `null` when throttled (a second show/replace within 369 ms).\n */\n show(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle | null;\n /** `show` as a promise (MAUI `ShowG9BottomSheetAsync`): resolves with the handle (or `null`). */\n showAsync(content: G9SheetContent, options?: G9SheetOptions): Promise<G9SheetHandle | null>;\n /** Replaces the open sheet in place when it can morph, else back-closes it and opens (MAUI `ReplaceG9BottomSheet`). */\n replace(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle | null;\n /**\n * Opens at once with a spinner, then builds the body (MAUI `ShowProcessingG9BottomSheet`): `build(handle, signal)`\n * returns the body (the sheet grows to fit), `null` (closes quietly) or throws (`onError`, else error popup + close).\n * Default options: fit to content, not deferred.\n */\n showProcessing(\n build: G9ProcessingBuild,\n options?: G9SheetOptions,\n onError?: G9ProcessingErrorHandler,\n loadingHeight?: number,\n ): G9SheetHandle | null;\n /** Full-screen modal sheet, not throttled (MAUI `ShowFullScreenAsync`). */\n showFullScreen(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle;\n /** Back-routes the top sheet (MAUI `CloseTopG9BottomSheet`). */\n closeTop(): void;\n /** Closes every sheet (MAUI `CloseG9BottomSheet`). */\n closeAll(): void;\n /** Open sheets (MAUI `GetOpenSheetCount`). */\n getOpenCount(): number;\n /** Routes hardware back to the top sheet; `false` when none is open (MAUI `HandleHardwareBackPressed`). */\n handleHardwareBack(): boolean;\n /** `true` while a hand-off successor is replacing this sheet (MAUI `IsBeingReplaced`). */\n isBeingReplaced(handle: G9SheetHandle | null | undefined): boolean;\n /** The scrim colour behind receded pages (MAUI `GetBackdropCardColor`). */\n getBackdropCardColor(): string;\n /** The height memory of this host's sheets. */\n readonly heightMemo: G9SheetHeightMemo;\n /** The stack (advanced: rendering, tests). */\n readonly stack: G9SheetStack;\n}\n\nconst FEATURE = 'g9.sheets';\n\ninterface ServiceState {\n readonly service: G9SheetService;\n settings: Required<G9SheetSettings>;\n}\n\nfunction StackView(props: { readonly state: ServiceState }): ReactNode {\n const { state } = props;\n state.settings = useG9Settings().sheets;\n const win = useG9Window();\n const insets = useG9HostInsets();\n const culture = useG9Culture();\n const stack = state.service.stack;\n const entries = useSyncExternalStore(\n (l) => stack.subscribe(l),\n () => stack.getSnapshot(),\n );\n const host = useG9Host();\n // Backdrop card: the page recedes behind a tall primary sheet (not fit, not stacked over) once its visible ratio\n // reaches `backdropCardEffectThreshold` (default 0.75): the opening detent first, then where the sheet came to rest.\n const [rest, setRest] = useState<{ readonly id: number; readonly heightPx: number } | null>(null);\n const primary = entries.find((e) => e.status === 'opening' || e.status === 'open');\n const card =\n state.settings.enableBackdropCardEffect &&\n primary !== undefined &&\n primary.options.enableBackdropCardEffect !== false &&\n primary.options.sizeMode !== 'fitToContent' &&\n backdropCardTransform(\n sheetVisibleRatio(primary.options, win.height, rest?.id === primary.id ? rest.heightPx : null),\n Math.min(0.99, Math.max(0.1, primary.options.backdropCardEffectThreshold ?? 0.75)),\n );\n const effectOn = card && card.scale < 1 ? card : null;\n const effect = effectOn\n ? {\n scale: Math.round(effectOn.scale * 1000) / 1000,\n translateY: Math.round(effectOn.translateY * 10) / 10,\n durationMs: state.settings.openAnimationDurationMs,\n backdropColor: state.settings.backdropCardColor,\n }\n : null;\n const effectKey = effect ? `${effect.scale}|${effect.translateY}|${effect.durationMs}|${effect.backdropColor}` : '';\n useEffect(() => {\n host.setContentEffect(effect);\n }, [effectKey]);\n useEffect(() => () => stack.dispose(), [stack]);\n // Learned heights belong to one look: a theme change re-measures (viewport and culture are part of the key).\n const scheme = useG9Theme().scheme;\n const lastScheme = useRef(scheme);\n useEffect(() => {\n if (lastScheme.current === scheme) return;\n lastScheme.current = scheme;\n state.service.heightMemo.invalidate();\n }, [scheme]);\n const top = [...entries].reverse().find((e) => e.status === 'opening' || e.status === 'open');\n return (\n <view className=\"g9-sheet-stack\">\n {entries.map((entry) => (\n <G9SheetFrame\n key={entry.frameKey}\n entry={entry}\n stack={stack}\n hostHeight={win.height}\n hostWidth={win.width}\n topInset={insets.top}\n bottomInset={insets.bottom}\n settings={state.settings}\n memo={state.service.heightMemo}\n culture={culture.locale}\n isTop={entry === top}\n onRest={(heightPx) => setRest({ id: entry.id, heightPx })}\n />\n ))}\n </view>\n );\n}\n\n/** Creates the sheet service of a host (attached once as a host feature). */\nfunction createSheetService(\n host: G9HostHandle,\n settings?: Required<G9SheetSettings>,\n preferences?: G9SheetMemoPreferences,\n): ServiceState {\n const clock = host.services.clock;\n const state = { settings: settings ?? resolveSheetSettings(undefined) } as ServiceState;\n const stack = new G9SheetStack({\n now: () => clock.monotonicNow(),\n setTimer: (cb, ms) => startTimer(cb, ms),\n clearTimer: (h) => stopTimer(h),\n durations: (o) => ({\n open: o.openAnimationDurationMs ?? state.settings.openAnimationDurationMs,\n close: o.closeAnimationDurationMs ?? state.settings.closeAnimationDurationMs,\n }),\n stageBeforeShow: () => state.settings.stageBeforeShow,\n preOpenMaxHoldMs: () => state.settings.preOpenMaxHoldMs,\n });\n const heightMemo = createSheetHeightMemo({\n ...(preferences ? { preferences } : {}),\n appVersion: state.settings.heightMemoVersion,\n setTimer: (cb, ms) => startTimer(cb, ms),\n clearTimer: (h) => stopTimer(h),\n });\n const service: G9SheetService = {\n stack,\n heightMemo,\n show: (content, options) => stack.show(content, options ?? {}),\n showAsync: (content, options) => Promise.resolve(stack.show(content, options ?? {})),\n replace: (content, options) => stack.replace(content, options ?? fitToContentSheetOptions()),\n showProcessing(build, options, onError, loadingHeight) {\n let handle: G9SheetHandle | null = null;\n const content = () => (\n <G9ProcessingSheetContent\n build={build}\n {...(onError ? { onError } : {})}\n loadingHeight={loadingHeight && loadingHeight > 0 ? loadingHeight : 160}\n handle={() => handle}\n />\n );\n handle = stack.show(content, { ...(options ?? fitToContentSheetOptions()), deferContent: false });\n return handle;\n },\n showFullScreen: (content, options) =>\n stack.show(content, options ?? fullScreenModalSheetOptions(), false) as G9SheetHandle,\n closeTop: () => stack.closeTop(),\n closeAll: () => stack.closeAll(),\n getOpenCount: () => stack.openCount(),\n handleHardwareBack: () => stack.handleHardwareBack(),\n isBeingReplaced: (handle) => {\n if (!handle) return false;\n const entry = stack.getSnapshot().find((e) => e.id === handle.id);\n return entry?.handingOff === true;\n },\n getBackdropCardColor: () => state.settings.backdropCardColor,\n };\n (state as { service: G9SheetService }).service = service;\n host.attachFeature(FEATURE, state);\n host.registerLayerItem('sheets', { key: FEATURE, element: <StackView state={state} />, order: 0 });\n host.back.push(() => (stack.handleHardwareBack() ? 'handled' : 'pass'), { layer: 'sheets' });\n return state;\n}\n\n/** The sheet service of a host, created on first use. */\nexport function sheetServiceOf(\n host: G9HostHandle,\n settings?: Required<G9SheetSettings>,\n preferences?: G9SheetMemoPreferences,\n): G9SheetService {\n const existing = host.getFeature(FEATURE) as ServiceState | undefined;\n if (existing && settings) existing.settings = settings;\n return (existing ?? createSheetService(host, settings, preferences)).service;\n}\n\n/**\n * The sheets of the nearest `G9Host` (MAUI `G9BottomSheetHelper` for that page). Sheets render in the host's\n * `sheets` layer; hardware back closes the top sheet first; the host's unmount settles every open sheet.\n */\nexport function useG9Sheets(): G9SheetService {\n const settings = useG9Settings().sheets;\n // Learned heights persist in the provider's preferences (key `g9controls.sheet-heights`).\n return sheetServiceOf(useG9Host(), settings, useG9Preferences());\n}\n\n/**\n * The sheets of the active host for code outside components (MAUI's static `G9BottomSheetHelper`): view models,\n * services. Throws `host-missing` when no host is mounted.\n */\nexport function g9Sheets(): G9SheetService {\n return sheetServiceOf(g9Hosts.require());\n}\n"],"names":["FEATURE","StackView","props","_primary_options_backdropCardEffectThreshold","state","useG9Settings","win","useG9Window","insets","useG9HostInsets","culture","useG9Culture","stack","entries","useSyncExternalStore","l","host","useG9Host","rest","setRest","useState","primary","e","card","undefined","backdropCardTransform","sheetVisibleRatio","Math","effectOn","effect","effectKey","useEffect","scheme","useG9Theme","lastScheme","useRef","top","view","entry","G9SheetFrame","heightPx","createSheetService","settings","preferences","clock","resolveSheetSettings","G9SheetStack","cb","ms","startTimer","h","stopTimer","o","_o_openAnimationDurationMs","_o_closeAnimationDurationMs","heightMemo","createSheetHeightMemo","service","content","options","Promise","fitToContentSheetOptions","build","onError","loadingHeight","handle","G9ProcessingSheetContent","fullScreenModalSheetOptions","sheetServiceOf","existing","useG9Sheets","useG9Preferences","g9Sheets","g9Hosts"],"mappings":"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"}
1
+ {"version":3,"file":"sheet/service.jsx","sources":["../../src/sheet/service.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState, useSyncExternalStore } from '@lynx-js/react';\nimport { startTimer, stopTimer } from '../base/timers';\nimport { useG9Host, useG9HostInsets } from '../host/hooks';\nimport { type G9HostHandle, g9Hosts } from '../host/registry';\nimport {\n useG9Culture,\n useG9Keyboard,\n useG9Preferences,\n useG9Settings,\n useG9Theme,\n useG9Window,\n} from '../provider/hooks';\nimport { G9SheetFrame } from './frame';\nimport { createSheetHeightMemo, type G9SheetHeightMemo, type G9SheetMemoPreferences } from './height-memo';\nimport {\n fitToContentSheetOptions,\n fullScreenModalSheetOptions,\n type G9SheetOptions,\n type G9SheetSettings,\n resolveSheetSettings,\n} from './options';\nimport { type G9ProcessingBuild, type G9ProcessingErrorHandler, G9ProcessingSheetContent } from './processing';\nimport { backdropCardTransform, sheetVisibleRatio } from './sizing';\nimport { type G9SheetContent, type G9SheetHandle, G9SheetStack } from './stack';\n\n/** The sheet API of one host (MAUI `G9BottomSheetHelper` + `G9BottomSheetExtensions`). */\nexport interface G9SheetService {\n /**\n * Opens a sheet (MAUI `ShowG9BottomSheet`): auto-stacks over an open sheet, hands off with `replaceCurrentSheet`,\n * otherwise opens as primary. `content` may be a factory, built after the open motion (`deferContent`). Returns the\n * sheet-scoped handle, or `null` when throttled (a second show/replace within 369 ms).\n */\n show(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle | null;\n /** `show` as a promise (MAUI `ShowG9BottomSheetAsync`): resolves with the handle (or `null`). */\n showAsync(content: G9SheetContent, options?: G9SheetOptions): Promise<G9SheetHandle | null>;\n /** Replaces the open sheet in place when it can morph, else back-closes it and opens (MAUI `ReplaceG9BottomSheet`). */\n replace(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle | null;\n /**\n * Opens at once with a spinner, then builds the body (MAUI `ShowProcessingG9BottomSheet`): `build(handle, signal)`\n * returns the body (the sheet grows to fit), `null` (closes quietly) or throws (`onError`, else error popup + close).\n * Default options: fit to content, not deferred.\n */\n showProcessing(\n build: G9ProcessingBuild,\n options?: G9SheetOptions,\n onError?: G9ProcessingErrorHandler,\n loadingHeight?: number,\n ): G9SheetHandle | null;\n /** Full-screen modal sheet, not throttled (MAUI `ShowFullScreenAsync`). */\n showFullScreen(content: G9SheetContent, options?: G9SheetOptions): G9SheetHandle;\n /** Back-routes the top sheet (MAUI `CloseTopG9BottomSheet`). */\n closeTop(): void;\n /** Closes every sheet (MAUI `CloseG9BottomSheet`). */\n closeAll(): void;\n /** Open sheets (MAUI `GetOpenSheetCount`). */\n getOpenCount(): number;\n /** Routes hardware back to the top sheet; `false` when none is open (MAUI `HandleHardwareBackPressed`). */\n handleHardwareBack(): boolean;\n /** `true` while a hand-off successor is replacing this sheet (MAUI `IsBeingReplaced`). */\n isBeingReplaced(handle: G9SheetHandle | null | undefined): boolean;\n /** The scrim colour behind receded pages (MAUI `GetBackdropCardColor`). */\n getBackdropCardColor(): string;\n /** The height memory of this host's sheets. */\n readonly heightMemo: G9SheetHeightMemo;\n /** The stack (advanced: rendering, tests). */\n readonly stack: G9SheetStack;\n}\n\nconst FEATURE = 'g9.sheets';\n\ninterface ServiceState {\n readonly service: G9SheetService;\n settings: Required<G9SheetSettings>;\n}\n\nfunction StackView(props: { readonly state: ServiceState }): ReactNode {\n const { state } = props;\n state.settings = useG9Settings().sheets;\n const win = useG9Window();\n const insets = useG9HostInsets();\n const culture = useG9Culture();\n // The keyboard's lift (settings.avoidKeyboard): the window height while the keyboard was hidden is the baseline, so a host\n // that already shrank the window for the IME is not lifted twice.\n const keyboard = useG9Keyboard();\n const baseline = useRef(win.height);\n if (!keyboard.visible) baseline.current = win.height;\n const lift = state.settings.avoidKeyboard ? keyboardLift(keyboard, baseline.current, win.height) : 0;\n const stack = state.service.stack;\n const entries = useSyncExternalStore(\n (l) => stack.subscribe(l),\n () => stack.getSnapshot(),\n );\n const host = useG9Host();\n // Backdrop card: the page recedes behind a tall primary sheet (not fit, not stacked over) once its visible ratio\n // reaches `backdropCardEffectThreshold` (default 0.75): the opening detent first, then where the sheet came to rest.\n const [rest, setRest] = useState<{ readonly id: number; readonly heightPx: number } | null>(null);\n const primary = entries.find((e) => e.status === 'opening' || e.status === 'open');\n const card =\n state.settings.enableBackdropCardEffect &&\n primary !== undefined &&\n primary.options.enableBackdropCardEffect !== false &&\n primary.options.sizeMode !== 'fitToContent' &&\n backdropCardTransform(\n sheetVisibleRatio(primary.options, win.height, rest?.id === primary.id ? rest.heightPx : null),\n Math.min(0.99, Math.max(0.1, primary.options.backdropCardEffectThreshold ?? 0.75)),\n );\n const effectOn = card && card.scale < 1 ? card : null;\n const effect = effectOn\n ? {\n scale: Math.round(effectOn.scale * 1000) / 1000,\n translateY: Math.round(effectOn.translateY * 10) / 10,\n durationMs: state.settings.openAnimationDurationMs,\n backdropColor: state.settings.backdropCardColor,\n }\n : null;\n const effectKey = effect ? `${effect.scale}|${effect.translateY}|${effect.durationMs}|${effect.backdropColor}` : '';\n useEffect(() => {\n host.setContentEffect(effect);\n }, [effectKey]);\n useEffect(() => () => stack.dispose(), [stack]);\n // Learned heights belong to one look: a theme change re-measures (viewport and culture are part of the key).\n const scheme = useG9Theme().scheme;\n const lastScheme = useRef(scheme);\n useEffect(() => {\n if (lastScheme.current === scheme) return;\n lastScheme.current = scheme;\n state.service.heightMemo.invalidate();\n }, [scheme]);\n const top = [...entries].reverse().find((e) => e.status === 'opening' || e.status === 'open');\n return (\n <view className=\"g9-sheet-stack\" style={{ bottom: `${lift}px` }}>\n {entries.map((entry) => (\n <G9SheetFrame\n key={entry.frameKey}\n entry={entry}\n stack={stack}\n hostHeight={win.height - lift}\n hostWidth={win.width}\n topInset={insets.top}\n // The keyboard covers the bottom bar: no inset under a lifted sheet.\n bottomInset={lift > 0 ? 0 : insets.bottom}\n settings={state.settings}\n memo={state.service.heightMemo}\n culture={culture.locale}\n isTop={entry === top}\n onRest={(heightPx) => setRest({ id: entry.id, heightPx })}\n />\n ))}\n </view>\n );\n}\n\n/**\n * How far the sheet layer rises above the soft keyboard: its height, less what the host already took off the window\n * (`baselineHeight` = the window while the keyboard was hidden). 0 while hidden; never negative; never more than the window.\n */\nexport function keyboardLift(\n keyboard: { readonly visible: boolean; readonly height: number },\n baselineHeight: number,\n windowHeight: number,\n): number {\n if (!keyboard.visible || !(keyboard.height > 0)) return 0;\n const resized = Math.max(0, baselineHeight - windowHeight);\n return Math.round(Math.min(Math.max(0, windowHeight - 1), Math.max(0, keyboard.height - resized)));\n}\n\n/** Creates the sheet service of a host (attached once as a host feature). */\nfunction createSheetService(\n host: G9HostHandle,\n settings?: Required<G9SheetSettings>,\n preferences?: G9SheetMemoPreferences,\n): ServiceState {\n const clock = host.services.clock;\n const state = { settings: settings ?? resolveSheetSettings(undefined) } as ServiceState;\n const stack = new G9SheetStack({\n now: () => clock.monotonicNow(),\n setTimer: (cb, ms) => startTimer(cb, ms),\n clearTimer: (h) => stopTimer(h),\n durations: (o) => ({\n open: o.openAnimationDurationMs ?? state.settings.openAnimationDurationMs,\n close: o.closeAnimationDurationMs ?? state.settings.closeAnimationDurationMs,\n }),\n stageBeforeShow: () => state.settings.stageBeforeShow,\n preOpenMaxHoldMs: () => state.settings.preOpenMaxHoldMs,\n });\n const heightMemo = createSheetHeightMemo({\n ...(preferences ? { preferences } : {}),\n appVersion: state.settings.heightMemoVersion,\n setTimer: (cb, ms) => startTimer(cb, ms),\n clearTimer: (h) => stopTimer(h),\n });\n const service: G9SheetService = {\n stack,\n heightMemo,\n show: (content, options) => stack.show(content, options ?? {}),\n showAsync: (content, options) => Promise.resolve(stack.show(content, options ?? {})),\n replace: (content, options) => stack.replace(content, options ?? fitToContentSheetOptions()),\n showProcessing(build, options, onError, loadingHeight) {\n let handle: G9SheetHandle | null = null;\n const content = () => (\n <G9ProcessingSheetContent\n build={build}\n {...(onError ? { onError } : {})}\n loadingHeight={loadingHeight && loadingHeight > 0 ? loadingHeight : 160}\n handle={() => handle}\n />\n );\n handle = stack.show(content, { ...(options ?? fitToContentSheetOptions()), deferContent: false });\n return handle;\n },\n showFullScreen: (content, options) =>\n stack.show(content, options ?? fullScreenModalSheetOptions(), false) as G9SheetHandle,\n closeTop: () => stack.closeTop(),\n closeAll: () => stack.closeAll(),\n getOpenCount: () => stack.openCount(),\n handleHardwareBack: () => stack.handleHardwareBack(),\n isBeingReplaced: (handle) => {\n if (!handle) return false;\n const entry = stack.getSnapshot().find((e) => e.id === handle.id);\n return entry?.handingOff === true;\n },\n getBackdropCardColor: () => state.settings.backdropCardColor,\n };\n (state as { service: G9SheetService }).service = service;\n host.attachFeature(FEATURE, state);\n host.registerLayerItem('sheets', { key: FEATURE, element: <StackView state={state} />, order: 0 });\n host.back.push(() => (stack.handleHardwareBack() ? 'handled' : 'pass'), { layer: 'sheets' });\n return state;\n}\n\n/** The sheet service of a host, created on first use. */\nexport function sheetServiceOf(\n host: G9HostHandle,\n settings?: Required<G9SheetSettings>,\n preferences?: G9SheetMemoPreferences,\n): G9SheetService {\n const existing = host.getFeature(FEATURE) as ServiceState | undefined;\n if (existing && settings) existing.settings = settings;\n return (existing ?? createSheetService(host, settings, preferences)).service;\n}\n\n/**\n * The sheets of the nearest `G9Host` (MAUI `G9BottomSheetHelper` for that page). Sheets render in the host's\n * `sheets` layer; hardware back closes the top sheet first; the host's unmount settles every open sheet.\n */\nexport function useG9Sheets(): G9SheetService {\n const settings = useG9Settings().sheets;\n // Learned heights persist in the provider's preferences (key `g9controls.sheet-heights`).\n return sheetServiceOf(useG9Host(), settings, useG9Preferences());\n}\n\n/**\n * The sheets of the active host for code outside components (MAUI's static `G9BottomSheetHelper`): view models,\n * services. Throws `host-missing` when no host is mounted.\n */\nexport function g9Sheets(): G9SheetService {\n return sheetServiceOf(g9Hosts.require());\n}\n"],"names":["FEATURE","StackView","props","_primary_options_backdropCardEffectThreshold","state","useG9Settings","win","useG9Window","insets","useG9HostInsets","culture","useG9Culture","keyboard","useG9Keyboard","baseline","useRef","lift","keyboardLift","stack","entries","useSyncExternalStore","l","host","useG9Host","rest","setRest","useState","primary","e","card","undefined","backdropCardTransform","sheetVisibleRatio","Math","effectOn","effect","effectKey","useEffect","scheme","useG9Theme","lastScheme","top","view","entry","G9SheetFrame","heightPx","baselineHeight","windowHeight","resized","createSheetService","settings","preferences","clock","resolveSheetSettings","G9SheetStack","cb","ms","startTimer","h","stopTimer","o","_o_openAnimationDurationMs","_o_closeAnimationDurationMs","heightMemo","createSheetHeightMemo","service","content","options","Promise","fitToContentSheetOptions","build","onError","loadingHeight","handle","G9ProcessingSheetContent","fullScreenModalSheetOptions","sheetServiceOf","existing","useG9Sheets","useG9Preferences","g9Sheets","g9Hosts"],"mappings":"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"}
@@ -99,6 +99,20 @@
99
99
  flex: 1;
100
100
  }
101
101
 
102
+ .g9-sheet__body-frame {
103
+ flex-direction: column;
104
+ flex-shrink: 1;
105
+ display: flex;
106
+ position: relative;
107
+ }
108
+
109
+ .g9-sheet__scroll-thumb {
110
+ background-color: var(--g9-on-surface-variant);
111
+ opacity: .45;
112
+ pointer-events: none;
113
+ position: absolute;
114
+ }
115
+
102
116
  .g9-sheet__content {
103
117
  flex-direction: column;
104
118
  display: flex;
@@ -1 +1 @@
1
- {"version":3,"sources":["webpack://./src/sheet/sheet.css"],"names":[],"mappings":"AACA;EAAE,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,SAAS;EACT,OAAO;EACP,QAAQ;AACV;;AAIA;EADE,MAAM;EACN,SAAS;EACT,OAAO;EACP,QAAQ;AACV;;AAKA;EAFE,oBAAoB;AACtB;;AAKA;EAFE,oBAAoB;AACtB;;AAKA;EAFE,oBAAoB;EACpB,sBAAsB;EACtB,aAAa;EACb,gBAAgB;AAClB;;AAMA;EAHE,sBAAsB;EACtB,YAAY;EACZ,cAAc;EACd,aAAa;EACb,kBAAkB;EAClB,iBAAiB;AACnB;;AAMA;EAHE,sBAAsB;EACtB,YAAY;EACZ,cAAc;EACd,aAAa;EACb,gBAAgB;AAClB;;AAOA;EAJE,YAAY;EACZ,kBAAkB;EAClB,SAAS;EACT,OAAO;EACP,QAAQ;AACV;;AAOA;EAJE,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,SAAS;EACT,OAAO;EACP,QAAQ;AACV;;AAOA;EAJE,oBAAoB;AACtB;;AAOA;EAJE,uBAAuB;EACvB,mBAAmB;EACnB,YAAY;EACZ,aAAa;AACf;;AAOA;EAJE,2CAA2C;EAC3C,mBAAmB;EACnB,WAAW;EACX,WAAW;AACb;;AAQA;EALE,sBAAsB;EACtB,cAAc;EACd,aAAa;AACf;;AASA;EANE,wDAAwD;AAC1D;;AASA;EANE,cAAc;AAChB;;AASA;EANE,OAAO;AACT;;AASA;EANE,sBAAsB;EACtB,aAAa;EACb,kBAAkB;AACpB;;AAUA;EAPE,sBAAsB;EACtB,WAAW;EACX,aAAa;EACb,gBAAgB;AAClB;;AAYA;EATE,WAAW;AACb;;AAcA;EAXE,uBAAuB;EACvB,mBAAmB;EACnB,aAAa;EACb,kBAAkB;AACpB;;AAcA;EAXE,6CAA6C;EAC7C,oDAAoD;EACpD,kBAAkB;EAClB,MAAM;EACN,OAAO;EACP,QAAQ;AACV;;AAcA;EAXE;IACE,UAAU;EACZ;;EAEA;IACE,UAAU;EACZ;AACF;;AAaA;EAVE,2CAA2C;AAC7C;;AAaA;EAVE;IACE,UAAU;EACZ;;EAEA;IACE,UAAU;EACZ;AACF;;AAYA;EATE,uBAAuB;EACvB,mBAAmB;EACnB,aAAa;EACb,kBAAkB;AACpB;;AAaA;EAVE,kCAAkC;EAClC,mBAAmB;EACnB,mBAAmB;EACnB,kBAAkB;EAClB,aAAa;AACf;;AAeA;EAZE,mBAAmB;EACnB,OAAO;EACP,mBAAmB;EACnB,aAAa;AACf;;AAeA;EAZE,mBAAmB;EACnB,mBAAmB;EACnB,aAAa;AACf;;AAeA;EAZE,mBAAmB;EACnB,yBAAyB;EACzB,mBAAmB;EACnB,aAAa;AACf;;AAeA;EAZE,yBAAyB;AAC3B;;AAeA;EAZE,mBAAmB;EACnB,OAAO;EACP,mBAAmB;EACnB,aAAa;AACf;;AAeA;EAZE,cAAc;AAChB;;AAeA;EAZE,2BAA2B;EAC3B,mBAAmB;EACnB,aAAa;AACf;;AAeA;EAZE,0BAA0B;EAC1B,uBAAuB;EACvB,iBAAiB;AACnB;;AAeA;EAZE,mBAAmB;EACnB,eAAe;EACf,aAAa;AACf;;AAgBA;EAbE,sBAAsB;EACtB,cAAc;EACd,aAAa;AACf;;AAgBA;EAbE,uBAAuB;EACvB,qBAAqB;EACrB,2CAA2C;EAC3C,sBAAsB;EACtB,YAAY;EACZ,kBAAkB;EAClB,aAAa;AACf;;AAgBA;EAbE,mBAAmB;EACnB,eAAe;EACf,aAAa;AACf;;AAkBA;EAfE,sBAAsB;EACtB,OAAO;EACP,aAAa;AACf","sourcesContent":["/* G9 sheets on lynx-ui Sheet (MAUI G9SheetView / header template). No shadows. */\n.g9-sheet-stack {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n}\n\n/* lynx-ui SheetView (position: fixed): the whole viewport, so the sheet rises from the bottom edge. */\n.g9-sheet__view {\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n/* A non-modal sheet's view lets every touch it does not cover through to the page, native views included. */\n.g9-sheet__view--passthrough {\n pointer-events: none;\n}\n\n.g9-sheet__view--passthrough .g9-sheet {\n pointer-events: auto;\n}\n\n.g9-sheet {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n pointer-events: auto;\n}\n\n/* G9's own views inside lynx-ui's SheetContent (whose style a worklet owns): the frame recedes, the surface paints. */\n.g9-sheet__frame {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 0;\n position: relative;\n overflow: visible;\n}\n\n.g9-sheet__surface {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 0;\n overflow: hidden;\n}\n\n/* Paints below the surface for a drag past the top detent; outside the layout, so fit heights ignore it. */\n.g9-sheet__skirt {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n height: 50vh;\n}\n\n.g9-sheet__scrim {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: auto;\n}\n\n.g9-sheet__scrim--covered {\n pointer-events: none;\n}\n\n.g9-sheet__grabber-area {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 30px;\n}\n\n.g9-sheet__grabber {\n width: 32px;\n height: 4px;\n border-radius: 12px;\n background-color: var(--g9-outline-variant);\n}\n\n/* The grabber, header and body gap, measured as one: a fit sheet's cap includes them (MAUI). */\n.g9-sheet__chrome-top {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n/* MAUI UseStandardBodyTopGap: SheetHeaderVerticalGap under the header (10, or the app's scaled value). */\n.g9-sheet__body-gap {\n height: var(--g9-layout-sheet-header-vertical-gap, 10px);\n}\n\n.g9-sheet__body {\n flex-shrink: 1;\n}\n\n.g9-sheet__body--fill {\n flex: 1;\n}\n\n.g9-sheet__content {\n display: flex;\n flex-direction: column;\n position: relative;\n}\n\n/* scrollBody: false — the content scrolls itself and fills the body (longhands: a definite basis for its children). */\n.g9-sheet__body--static {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 1;\n flex-basis: 0px;\n overflow: hidden;\n}\n\n.g9-sheet__content--fill {\n flex-grow: 1;\n flex-shrink: 1;\n flex-basis: 0px;\n}\n\n.g9-sheet__placeholder {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.g9-sheet__cover {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background-color: var(--g9-surface-container);\n animation: g9-sheet-cover-out 220ms ease-out forwards;\n}\n\n@keyframes g9-sheet-cover-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n.g9-sheet-reveal {\n animation: g9-sheet-reveal-in 140ms ease-out;\n}\n\n@keyframes g9-sheet-reveal-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.g9-sheet-loading,\n.g9-processing-sheet__loading {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.g9-sheet-header {\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 10px 16px;\n border-bottom-width: 1px;\n border-bottom-style: solid;\n border-bottom-color: rgba(121, 116, 126, 0.35);\n}\n\n.g9-sheet-header__side {\n display: flex;\n flex-direction: row;\n flex: 1;\n align-items: center;\n}\n\n.g9-sheet-header__start {\n display: flex;\n flex-direction: row;\n align-items: center;\n}\n\n.g9-sheet-header__end {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n}\n\n.g9-sheet-header__side.g9-sheet-header__end {\n justify-content: flex-end;\n}\n\n.g9-sheet-header__grow {\n display: flex;\n flex-direction: row;\n flex: 1;\n align-items: center;\n}\n\n.g9-sheet-header__title-near {\n padding: 0px 8px;\n}\n\n.g9-sheet-header__back {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n}\n\n.g9-sheet-header__title {\n font-weight: bold;\n color: var(--g9-secondary);\n text-overflow: ellipsis;\n}\n\n.g9-sheet-header__items {\n display: flex;\n flex-direction: row;\n column-gap: 8px;\n}\n\n/* Holds the footer (or nothing) so its height is measured with the body's for a fit sheet. */\n.g9-sheet__footer-slot {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n.g9-sheet-footer {\n display: flex;\n flex-direction: column;\n row-gap: 8px;\n padding: 12px 16px;\n border-top-width: 1px;\n border-top-style: solid;\n border-top-color: var(--g9-outline-variant);\n}\n\n.g9-sheet-footer__row {\n display: flex;\n flex-direction: row;\n column-gap: 8px;\n}\n\n/* A column: whatever a cell holds (a button, a wrapper around one) stretches to the cell's width, as MAUI's footer\n buttons fill their cell. */\n.g9-sheet-footer__cell {\n display: flex;\n flex-direction: column;\n flex: 1;\n}\n"],"sourceRoot":""}
1
+ {"version":3,"sources":["webpack://./src/sheet/sheet.css"],"names":[],"mappings":"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","sourcesContent":["/* G9 sheets on lynx-ui Sheet (MAUI G9SheetView / header template). No shadows. */\n.g9-sheet-stack {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n}\n\n/* lynx-ui SheetView (position: fixed): the whole viewport, so the sheet rises from the bottom edge. */\n.g9-sheet__view {\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n/* A non-modal sheet's view lets every touch it does not cover through to the page, native views included. */\n.g9-sheet__view--passthrough {\n pointer-events: none;\n}\n\n.g9-sheet__view--passthrough .g9-sheet {\n pointer-events: auto;\n}\n\n.g9-sheet {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n pointer-events: auto;\n}\n\n/* G9's own views inside lynx-ui's SheetContent (whose style a worklet owns): the frame recedes, the surface paints. */\n.g9-sheet__frame {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 0;\n position: relative;\n overflow: visible;\n}\n\n.g9-sheet__surface {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 0;\n overflow: hidden;\n}\n\n/* Paints below the surface for a drag past the top detent; outside the layout, so fit heights ignore it. */\n.g9-sheet__skirt {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n height: 50vh;\n}\n\n.g9-sheet__scrim {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: auto;\n}\n\n.g9-sheet__scrim--covered {\n pointer-events: none;\n}\n\n.g9-sheet__grabber-area {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 30px;\n}\n\n.g9-sheet__grabber {\n width: 32px;\n height: 4px;\n border-radius: 12px;\n background-color: var(--g9-outline-variant);\n}\n\n/* The grabber, header and body gap, measured as one: a fit sheet's cap includes them (MAUI). */\n.g9-sheet__chrome-top {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n/* MAUI UseStandardBodyTopGap: SheetHeaderVerticalGap under the header (10, or the app's scaled value). */\n.g9-sheet__body-gap {\n height: var(--g9-layout-sheet-header-vertical-gap, 10px);\n}\n\n.g9-sheet__body {\n flex-shrink: 1;\n}\n\n.g9-sheet__body--fill {\n flex: 1;\n}\n\n/* scrollIndicator: 'always' — the scroller and its thumb (scroll-indicator.tsx). The frame takes the body's place. */\n.g9-sheet__body-frame {\n display: flex;\n flex-direction: column;\n flex-shrink: 1;\n position: relative;\n}\n\n.g9-sheet__scroll-thumb {\n position: absolute;\n background-color: var(--g9-on-surface-variant);\n opacity: 0.45;\n pointer-events: none;\n}\n\n.g9-sheet__content {\n display: flex;\n flex-direction: column;\n position: relative;\n}\n\n/* scrollBody: false — the content scrolls itself and fills the body (longhands: a definite basis for its children). */\n.g9-sheet__body--static {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n flex-shrink: 1;\n flex-basis: 0px;\n overflow: hidden;\n}\n\n.g9-sheet__content--fill {\n flex-grow: 1;\n flex-shrink: 1;\n flex-basis: 0px;\n}\n\n.g9-sheet__placeholder {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.g9-sheet__cover {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n background-color: var(--g9-surface-container);\n animation: g9-sheet-cover-out 220ms ease-out forwards;\n}\n\n@keyframes g9-sheet-cover-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n.g9-sheet-reveal {\n animation: g9-sheet-reveal-in 140ms ease-out;\n}\n\n@keyframes g9-sheet-reveal-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.g9-sheet-loading,\n.g9-processing-sheet__loading {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.g9-sheet-header {\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 10px 16px;\n border-bottom-width: 1px;\n border-bottom-style: solid;\n border-bottom-color: rgba(121, 116, 126, 0.35);\n}\n\n.g9-sheet-header__side {\n display: flex;\n flex-direction: row;\n flex: 1;\n align-items: center;\n}\n\n.g9-sheet-header__start {\n display: flex;\n flex-direction: row;\n align-items: center;\n}\n\n.g9-sheet-header__end {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n}\n\n.g9-sheet-header__side.g9-sheet-header__end {\n justify-content: flex-end;\n}\n\n.g9-sheet-header__grow {\n display: flex;\n flex-direction: row;\n flex: 1;\n align-items: center;\n}\n\n.g9-sheet-header__title-near {\n padding: 0px 8px;\n}\n\n.g9-sheet-header__back {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n}\n\n.g9-sheet-header__title {\n font-weight: bold;\n color: var(--g9-secondary);\n text-overflow: ellipsis;\n}\n\n.g9-sheet-header__items {\n display: flex;\n flex-direction: row;\n column-gap: 8px;\n}\n\n/* Holds the footer (or nothing) so its height is measured with the body's for a fit sheet. */\n.g9-sheet__footer-slot {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n}\n\n.g9-sheet-footer {\n display: flex;\n flex-direction: column;\n row-gap: 8px;\n padding: 12px 16px;\n border-top-width: 1px;\n border-top-style: solid;\n border-top-color: var(--g9-outline-variant);\n}\n\n.g9-sheet-footer__row {\n display: flex;\n flex-direction: row;\n column-gap: 8px;\n}\n\n/* A column: whatever a cell holds (a button, a wrapper around one) stretches to the cell's width, as MAUI's footer\n buttons fill their cell. */\n.g9-sheet-footer__cell {\n display: flex;\n flex-direction: column;\n flex: 1;\n}\n"],"sourceRoot":""}
@@ -3,6 +3,8 @@ import type { G9SheetDetent, G9SheetOptions } from './options.js';
3
3
  export declare const g9SheetDefaultPeekHeight = 100;
4
4
  /** Absolute minimum of an authoritative fit height (MAUI helper :81). */
5
5
  export declare const g9SheetFitMinHeight = 80;
6
+ /** Default `scrollToEndThreshold`: four 52 px rows from the end (MAUI 1.4.8 selection sheet, `OnItemsScrolled`). */
7
+ export declare const g9SheetScrollToEndThreshold = 208;
6
8
  /** Floor while the height is unknown (loading window). */
7
9
  export declare const g9SheetFitLoadingMinHeight = 180;
8
10
  /** Finger travel at release that requests a close (MAUI `DragCloseThreshold`). */
@@ -1 +1 @@
1
- {"version":3,"file":"sizing.d.ts","sourceRoot":"","sources":["../../src/sheet/sizing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sizing.d.ts","sourceRoot":"","sources":["../../src/sheet/sizing.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  const g9SheetDefaultPeekHeight = 100;
2
2
  const g9SheetFitMinHeight = 80;
3
+ const g9SheetScrollToEndThreshold = 208;
3
4
  const g9SheetFitLoadingMinHeight = 180;
4
5
  const g9SheetDragCloseThreshold = 72;
5
6
  const g9SheetTopSafeAreaBaseGap = 3;
@@ -156,6 +157,6 @@ function platformSheetConstraints(options, platform = currentPlatform()) {
156
157
  }
157
158
  return style;
158
159
  }
159
- export { backdropCardTransform, clampFitHeight, currentPlatform, g9SheetDefaultPeekHeight, g9SheetDragCloseThreshold, g9SheetFitLoadingMinHeight, g9SheetFitMinHeight, g9SheetTopSafeAreaBaseGap, parentRecedeOffset, platformSheetConstraints, resolveSheetLayout, scaledSheetDuration, sheetOverlayOpacity, sheetSurfaceBottomPadding, sheetSurfaceTopPadding, sheetTopPadding, sheetVisibleRatio };
160
+ export { backdropCardTransform, clampFitHeight, currentPlatform, g9SheetDefaultPeekHeight, g9SheetDragCloseThreshold, g9SheetFitLoadingMinHeight, g9SheetFitMinHeight, g9SheetScrollToEndThreshold, g9SheetTopSafeAreaBaseGap, parentRecedeOffset, platformSheetConstraints, resolveSheetLayout, scaledSheetDuration, sheetOverlayOpacity, sheetSurfaceBottomPadding, sheetSurfaceTopPadding, sheetTopPadding, sheetVisibleRatio };
160
161
 
161
162
  //# sourceMappingURL=sizing.jsx.map