@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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/base/index.d.ts +1 -1
- package/dist/base/index.d.ts.map +1 -1
- package/dist/base/index.jsx +1 -1
- package/dist/base/pressable.d.ts.map +1 -1
- package/dist/base/pressable.jsx +2 -1
- package/dist/base/pressable.jsx.map +1 -1
- package/dist/base/selection-item.d.ts +9 -1
- package/dist/base/selection-item.d.ts.map +1 -1
- package/dist/base/selection-item.jsx +10 -1
- package/dist/base/selection-item.jsx.map +1 -1
- package/dist/button/button.css +20 -0
- package/dist/button/button.css.map +1 -1
- package/dist/button/header-action-button.d.ts +5 -0
- package/dist/button/header-action-button.d.ts.map +1 -1
- package/dist/button/header-action-button.jsx +6 -1
- package/dist/button/header-action-button.jsx.map +1 -1
- package/dist/button/visuals.d.ts.map +1 -1
- package/dist/button/visuals.jsx +1 -1
- package/dist/button/visuals.jsx.map +1 -1
- package/dist/cascade/cascade-panel.d.ts.map +1 -1
- package/dist/cascade/cascade-panel.jsx +2 -2
- package/dist/cascade/cascade-panel.jsx.map +1 -1
- package/dist/edge-panel/edge-panel.jsx +5 -5
- package/dist/edge-panel/edge-panel.jsx.map +1 -1
- package/dist/expander/expander.d.ts.map +1 -1
- package/dist/expander/expander.jsx +2 -1
- package/dist/expander/expander.jsx.map +1 -1
- package/dist/fields/editor.d.ts.map +1 -1
- package/dist/fields/editor.jsx +2 -2
- package/dist/fields/editor.jsx.map +1 -1
- package/dist/fields/fields.css +21 -0
- package/dist/fields/fields.css.map +1 -1
- package/dist/fields/index.d.ts +1 -1
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.jsx +1 -1
- package/dist/fields/outlined-field.d.ts +27 -1
- package/dist/fields/outlined-field.d.ts.map +1 -1
- package/dist/fields/outlined-field.jsx +29 -2
- package/dist/fields/outlined-field.jsx.map +1 -1
- package/dist/fields/text-entry.d.ts.map +1 -1
- package/dist/fields/text-entry.jsx +2 -2
- package/dist/fields/text-entry.jsx.map +1 -1
- package/dist/host/host.css.map +1 -1
- package/dist/host/host.d.ts +3 -2
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.jsx +2 -2
- package/dist/host/host.jsx.map +1 -1
- package/dist/pickers/combo-box.d.ts +8 -0
- package/dist/pickers/combo-box.d.ts.map +1 -1
- package/dist/pickers/combo-box.jsx +51 -9
- package/dist/pickers/combo-box.jsx.map +1 -1
- package/dist/pickers/date-time-picker.d.ts +2 -2
- package/dist/pickers/date-time-picker.d.ts.map +1 -1
- package/dist/pickers/date-time-picker.jsx +4 -3
- package/dist/pickers/date-time-picker.jsx.map +1 -1
- package/dist/pickers/date-time.d.ts +5 -2
- package/dist/pickers/date-time.d.ts.map +1 -1
- package/dist/pickers/date-time.jsx +1 -1
- package/dist/pickers/date-time.jsx.map +1 -1
- package/dist/pickers/picker-sheet.d.ts +6 -2
- package/dist/pickers/picker-sheet.d.ts.map +1 -1
- package/dist/pickers/picker-sheet.jsx +2 -3
- package/dist/pickers/picker-sheet.jsx.map +1 -1
- package/dist/pickers/picker.d.ts.map +1 -1
- package/dist/pickers/picker.jsx +3 -2
- package/dist/pickers/picker.jsx.map +1 -1
- package/dist/pickers/pickers.css +27 -0
- package/dist/pickers/pickers.css.map +1 -1
- package/dist/pickers/timespan-picker.d.ts.map +1 -1
- package/dist/pickers/timespan-picker.jsx +3 -2
- package/dist/pickers/timespan-picker.jsx.map +1 -1
- package/dist/pickers/trigger.d.ts +3 -1
- package/dist/pickers/trigger.d.ts.map +1 -1
- package/dist/pickers/trigger.jsx +6 -1
- package/dist/pickers/trigger.jsx.map +1 -1
- package/dist/plus-button/model.d.ts.map +1 -1
- package/dist/plus-button/model.jsx +5 -1
- package/dist/plus-button/model.jsx.map +1 -1
- package/dist/popup/frame.jsx +2 -2
- package/dist/popup/frame.jsx.map +1 -1
- package/dist/popup/service.d.ts.map +1 -1
- package/dist/popup/service.jsx +2 -2
- package/dist/popup/service.jsx.map +1 -1
- package/dist/provider/provider.css +4 -0
- package/dist/provider/provider.css.map +1 -1
- package/dist/provider/provider.d.ts.map +1 -1
- package/dist/provider/provider.jsx +4 -2
- package/dist/provider/provider.jsx.map +1 -1
- package/dist/provider/settings.d.ts +12 -0
- package/dist/provider/settings.d.ts.map +1 -1
- package/dist/provider/settings.jsx +6 -3
- package/dist/provider/settings.jsx.map +1 -1
- package/dist/provider/theme.css +4 -0
- package/dist/provider/theme.css.map +1 -1
- package/dist/range-slider/math.d.ts +14 -4
- package/dist/range-slider/math.d.ts.map +1 -1
- package/dist/range-slider/math.jsx +16 -4
- package/dist/range-slider/math.jsx.map +1 -1
- package/dist/range-slider/range-slider.css +17 -0
- package/dist/range-slider/range-slider.css.map +1 -1
- package/dist/range-slider/range-slider.d.ts +11 -0
- package/dist/range-slider/range-slider.d.ts.map +1 -1
- package/dist/range-slider/range-slider.jsx +35 -13
- package/dist/range-slider/range-slider.jsx.map +1 -1
- package/dist/selection/index.d.ts +2 -1
- package/dist/selection/index.d.ts.map +1 -1
- package/dist/selection/index.jsx +2 -1
- package/dist/selection/selection-sheet.d.ts +8 -1
- package/dist/selection/selection-sheet.d.ts.map +1 -1
- package/dist/selection/selection-sheet.jsx +64 -11
- package/dist/selection/selection-sheet.jsx.map +1 -1
- package/dist/selection/selection.css +7 -0
- package/dist/selection/selection.css.map +1 -1
- package/dist/selection/window.d.ts +29 -0
- package/dist/selection/window.d.ts.map +1 -0
- package/dist/selection/window.jsx +24 -0
- package/dist/selection/window.jsx.map +1 -0
- package/dist/sheet/frame.d.ts.map +1 -1
- package/dist/sheet/frame.jsx +35 -9
- package/dist/sheet/frame.jsx.map +1 -1
- package/dist/sheet/header.d.ts.map +1 -1
- package/dist/sheet/header.jsx +3 -1
- package/dist/sheet/header.jsx.map +1 -1
- package/dist/sheet/index.d.ts +2 -1
- package/dist/sheet/index.d.ts.map +1 -1
- package/dist/sheet/index.jsx +2 -1
- package/dist/sheet/motion.d.ts.map +1 -1
- package/dist/sheet/motion.jsx +14 -0
- package/dist/sheet/motion.jsx.map +1 -1
- package/dist/sheet/options.d.ts +26 -0
- package/dist/sheet/options.d.ts.map +1 -1
- package/dist/sheet/options.jsx +2 -1
- package/dist/sheet/options.jsx.map +1 -1
- package/dist/sheet/scroll-indicator.d.ts +33 -0
- package/dist/sheet/scroll-indicator.d.ts.map +1 -0
- package/dist/sheet/scroll-indicator.jsx +84 -0
- package/dist/sheet/scroll-indicator.jsx.map +1 -0
- package/dist/sheet/service.d.ts +8 -0
- package/dist/sheet/service.d.ts.map +1 -1
- package/dist/sheet/service.jsx +15 -4
- package/dist/sheet/service.jsx.map +1 -1
- package/dist/sheet/sheet.css +14 -0
- package/dist/sheet/sheet.css.map +1 -1
- package/dist/sheet/sizing.d.ts +2 -0
- package/dist/sheet/sizing.d.ts.map +1 -1
- package/dist/sheet/sizing.jsx +2 -1
- package/dist/sheet/sizing.jsx.map +1 -1
- package/dist/tab-bar/tab-bar.d.ts.map +1 -1
- package/dist/tab-bar/tab-bar.jsx +11 -6
- package/dist/tab-bar/tab-bar.jsx.map +1 -1
- package/dist/toast/service.jsx +3 -3
- package/dist/toast/service.jsx.map +1 -1
- package/dist/toast/store.d.ts.map +1 -1
- package/dist/toast/store.jsx +3 -2
- package/dist/toast/store.jsx.map +1 -1
- package/dist/toggle/chip-group.d.ts +9 -1
- package/dist/toggle/chip-group.d.ts.map +1 -1
- package/dist/toggle/chip-group.jsx +51 -12
- package/dist/toggle/chip-group.jsx.map +1 -1
- package/dist/toggle/switch.d.ts +1 -1
- package/dist/toggle/switch.d.ts.map +1 -1
- package/dist/toggle/switch.jsx +3 -2
- package/dist/toggle/switch.jsx.map +1 -1
- package/dist/toggle/toggle.css +20 -0
- package/dist/toggle/toggle.css.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection/selection-sheet.jsx","sources":["../../src/selection/selection-sheet.tsx"],"sourcesContent":["import './selection.css';\nimport { formatColor, G9StringKey, type G9TextInputDirection, withAlpha } from '@g9tm/lynxcontrols-foundation';\nimport { type ReactNode, useEffect, useRef, useState, useSyncExternalStore } from '@lynx-js/react';\nimport { g9ChildId, g9RowStyle, g9TextStart } from '../base/control';\nimport { useG9Press } from '../base/press';\nimport type { G9SelectionItem } from '../base/selection-item';\nimport { type G9TimerHandle, startTimer, stopTimer } from '../base/timers';\nimport { G9Button } from '../button/button';\nimport { G9SearchEntry } from '../fields/search-entry';\nimport { G9TextEntry } from '../fields/text-entry';\nimport { G9IconSlot, hasIconSlot } from '../icon/slot';\nimport { G9Swatch } from '../icon/swatch';\nimport { useG9Direction, useG9Settings, useG9Strings, useG9Theme } from '../provider/hooks';\nimport { fitToContentSheetOptions, fullScreenWithoutHandleSheetOptions, type G9SheetOptions } from '../sheet/options';\nimport type { G9SheetService } from '../sheet/service';\nimport type { G9SheetHandle } from '../sheet/stack';\nimport { createSelectionModel, type G9SelectionModel } from './model';\n\n/** MAUI `G9SelectionSheet.EagerBuildItemLimit`: lists up to 40 items are built at once; longer lists defer. */\nexport const g9SelectionEagerBuildItemLimit = 40;\n/** Row height of the selection sheet (MAUI 52). */\nexport const g9SelectionRowHeight = 52;\n/** Search debounce of the selection sheet (MAUI 150 ms). */\nexport const g9SelectionSearchDebounceMs = 150;\n/** Wait after a close-on-select pick before closing (MAUI 120 ms). */\nexport const g9SelectionCloseDelayMs = 120;\n\n/** The outcome of a selection sheet (MAUI `G9SelectionSheetResult`). */\nexport interface G9SelectionSheetResult<T extends G9SelectionItem = G9SelectionItem> {\n /** A pick on a close-on-select sheet, Done, or Reset; `false` for every dismissal. */\n readonly wasAccepted: boolean;\n /** The selection differs from the opening one. */\n readonly selectionChanged: boolean;\n /** The final selection (opening items that are not listed or disabled stay unless deselected). */\n readonly items: ReadonlyArray<T>;\n}\n\n/**\n * The selection identity of an item inside one list (MAUI `G9SelectionSheet.KeyOf`): `k:<key>` when the key is set,\n * else `t:<text>` when the text is unique among key-less items, else the position (`i:<n>`). Keys and texts never\n * match each other.\n */\nexport function selectionIdentities(items: ReadonlyArray<G9SelectionItem>): string[] {\n const counts = new Map<string, number>();\n for (const item of items) {\n if (item.key == null || item.key.trim() === '') counts.set(item.text, (counts.get(item.text) ?? 0) + 1);\n }\n return items.map((item, i) =>\n item.key != null && item.key.trim() !== ''\n ? `k:${item.key}`\n : (counts.get(item.text) ?? 0) > 1\n ? `i:${i}`\n : `t:${item.text}`,\n );\n}\n\n/** Estimated body height (MAUI `EstimateContentHeight`): rows × 52 + chrome, clamped to [2 rows + chrome, 520]. */\nexport function estimateSelectionHeight(count: number, showSearch: boolean): number {\n const chrome = (showSearch ? 64 : 0) + 18;\n return Math.min(520, Math.max(2 * g9SelectionRowHeight + chrome, count * g9SelectionRowHeight + chrome));\n}\n\n/** Arguments of {@link showSelectionSheet} (MAUI `ShowForResultAsync`). */\nexport interface G9SelectionSheetRequest<T extends G9SelectionItem> {\n readonly title: string;\n readonly items: ReadonlyArray<T>;\n readonly selectedItems?: ReadonlyArray<T>;\n readonly allowMultiple?: boolean;\n /** Single mode: a pick completes and closes after 120 ms. Default true. */\n readonly closeOnSingleSelection?: boolean;\n readonly showSearch?: boolean;\n /** No-results text. Default the `noResults` string. */\n readonly emptyText?: string | null;\n /** Row text direction. Default `'matchParent'`. */\n readonly itemTextDirection?: G9TextInputDirection;\n /** A non-empty reset selection adds a Reset toolbar item that completes with it. */\n readonly resetSelection?: ReadonlyArray<T> | null;\n /** Count pill label (multi). Default `\"{n} {selected}\"`. */\n readonly countLabel?: (count: number) => string;\n /** Extra sheet options (merged over the defaults). */\n readonly options?: G9SheetOptions;\n}\n\ninterface BodyProps<T extends G9SelectionItem> {\n readonly request: G9SelectionSheetRequest<T>;\n readonly ids: ReadonlyArray<string>;\n readonly initial: G9SelectionModel<T>;\n readonly onComplete: (keys: ReadonlyArray<string>, accepted: boolean) => void;\n readonly onDraft: (model: G9SelectionModel<T>) => void;\n readonly done: { current: boolean };\n}\n\nfunction SelectionRow(props: {\n readonly item: G9SelectionItem;\n /** Element id (`${sheet automationId}_Item_${key}`), so automation finds the row like a person sees it. */\n readonly elementId?: string | undefined;\n readonly selected: boolean;\n readonly direction: 'ltr' | 'rtl';\n readonly onTap: () => void;\n}): ReactNode {\n const palette = useG9Theme().palette;\n const glyphs = useG9Settings().glyphs;\n const { item, selected } = props;\n const press = useG9Press(props.onTap, { blocked: item.isEnabled === false, source: 'G9SelectionSheet', guardMs: 0 });\n const icon = { emoji: item.emoji, icon: item.icon, imagePath: item.iconPath, image: item.iconImage };\n const iconColor = item.iconTintColor ?? (selected ? palette.Primary : palette.TextSecondary);\n return (\n <view\n {...(props.elementId ? { id: props.elementId } : {})}\n className={`g9-selection-row${selected ? ' g9-selection-row--selected' : ''}`}\n style={selected ? { backgroundColor: formatColor(withAlpha(palette.Primary, 0.1)) } : {}}\n accessibility-element={true}\n accessibility-traits=\"button\"\n accessibility-label={item.text}\n {...(selected ? { 'accessibility-value': 'selected' } : {})}\n bindtap={press}\n >\n <view\n className={`g9-selection-row__inner g9-dir-${props.direction}`}\n style={{ ...g9RowStyle(props.direction), ...(item.isEnabled === false ? { opacity: 0.45 } : {}) }}\n >\n {hasIconSlot(icon) ? (\n <G9IconSlot {...icon} size={18} color={iconColor} />\n ) : item.swatchFirstColor?.trim() || item.swatchSecondColor?.trim() ? (\n <G9Swatch first={item.swatchFirstColor} second={item.swatchSecondColor} direction={props.direction} />\n ) : (\n // MAUI's row is a Grid of ColumnSpacing 12 whose icon column stays when empty: its spacing still sits before\n // the text, so an icon-less row's text starts 16 + 12 dp in, level with nothing but the same in every picker.\n <view className=\"g9-selection-row__icon-gap\" />\n )}\n <text\n className=\"g9-selection-row__text\"\n text-maxline=\"1\"\n style={{\n color: selected ? palette.Primary : palette.TextPrimary,\n fontWeight: selected ? 'bold' : 'normal',\n ...g9TextStart(props.direction),\n }}\n >\n {item.text}\n </text>\n <view style={{ opacity: selected ? 1 : 0 }}>\n <G9IconSlot icon={glyphs.check} size={18} color={palette.Primary} />\n </view>\n </view>\n </view>\n );\n}\n\nfunction SelectionBody<T extends G9SelectionItem>(props: BodyProps<T>): ReactNode {\n const strings = useG9Strings();\n const parentDir = useG9Direction();\n const { request, ids } = props;\n const [model, setModel] = useState(props.initial);\n const [query, setQuery] = useState('');\n const [applied, setApplied] = useState('');\n const timer = useRef<G9TimerHandle | null>(null);\n const picking = useRef(false);\n useEffect(\n () => () => {\n if (timer.current !== null) stopTimer(timer.current);\n },\n [],\n );\n const visible = request.showSearch ? model.withItems(request.items).filter(applied) : request.items;\n const visibleIds = new Set(visible.map((item) => ids[request.items.indexOf(item)]));\n const dir =\n request.itemTextDirection === 'leftToRight'\n ? 'ltr'\n : request.itemTextDirection === 'rightToLeft'\n ? 'rtl'\n : parentDir;\n const multiple = request.allowMultiple === true;\n const onQuery = (value: string) => {\n setQuery(value);\n if (timer.current !== null) stopTimer(timer.current);\n if (value.trim() === '') {\n setApplied(value);\n return;\n }\n timer.current = startTimer(() => setApplied(value), g9SelectionSearchDebounceMs);\n };\n const tap = (id: string) => {\n if (props.done.current || picking.current) return;\n const next = model.toggle(id);\n if (next === model) return;\n setModel(next);\n props.onDraft(next);\n if (!multiple && request.closeOnSingleSelection !== false) {\n picking.current = true;\n startTimer(() => props.onComplete(next.selectedKeys, true), g9SelectionCloseDelayMs);\n }\n };\n return (\n <view className=\"g9-selection\">\n {request.showSearch ? (\n <view className=\"g9-selection__search\">\n <G9TextEntry\n placeholder={strings.get(G9StringKey.Search)}\n leadingIcon=\"search\"\n value={query}\n onValueChange={onQuery}\n />\n </view>\n ) : null}\n {visible.length > 0 ? (\n <view className=\"g9-selection__items\">\n {request.items.map((item, i) => {\n const id = ids[i] as string;\n if (!visibleIds.has(id)) return null;\n return (\n <SelectionRow\n key={id}\n item={item}\n elementId={g9ChildId(request.options?.automationId, `Item_${item.key ?? i}`)}\n selected={model.isSelected(id)}\n direction={dir}\n onTap={() => tap(id)}\n />\n );\n })}\n </view>\n ) : null}\n {visible.length === 0 ? (\n <text className=\"g9-selection__empty\">{request.emptyText ?? strings.get(G9StringKey.NoResults)}</text>\n ) : null}\n </view>\n );\n}\n\n/**\n * Shows the selection sheet (MAUI `G9SelectionSheet.ShowForResultAsync`): a fit sheet with a header (title near the\n * close button), optional search (150 ms debounce, text match, hidden selected rows stay selected), rows with icon or\n * swatch, check mark and selection tint. Single mode with `closeOnSingleSelection` completes on a pick; multi mode\n * shows a count pill and Done; a reset selection adds Reset. Any dismissal resolves `wasAccepted: false` with the\n * current draft (or the opening selection when the sheet never built).\n */\nexport function showSelectionSheet<T extends G9SelectionItem>(\n sheets: G9SheetService,\n request: G9SelectionSheetRequest<T>,\n): Promise<G9SelectionSheetResult<T>> {\n const items = [...request.items];\n const ids = selectionIdentities(items);\n const opening = request.selectedItems ?? [];\n // Opening items match listed items by identity; the rest are kept as \"not listed\".\n const openingIds = selectionIdentities([...items, ...opening]).slice(items.length);\n const listedIds = new Set(ids);\n const initialKeys = openingIds.filter((id) => listedIds.has(id));\n const unlisted = opening.filter((_, i) => !listedIds.has(openingIds[i] as string));\n const multiple = request.allowMultiple === true;\n const initial = createSelectionModel<T>({\n items,\n getKey: (item) => ids[items.indexOf(item)] as string,\n getText: (item) => item.text,\n mode: multiple ? 'multiple' : 'single',\n selectedKeys: initialKeys,\n isEnabled: (item) => item.isEnabled !== false,\n });\n return new Promise((resolve) => {\n let draft = initial;\n const draftListeners = new Set<() => void>();\n const draftStore = {\n subscribe: (l: () => void) => {\n draftListeners.add(l);\n return () => {\n draftListeners.delete(l);\n };\n },\n count: () => draft.selectedKeys.length,\n };\n let settled = false;\n const done = { current: false };\n const startKeys = new Set(initialKeys);\n const collect = (keys: ReadonlyArray<string>): T[] => {\n const set = new Set(keys);\n return [...items.filter((_, i) => set.has(ids[i] as string)), ...unlisted];\n };\n const settle = (keys: ReadonlyArray<string>, accepted: boolean, explicit?: ReadonlyArray<T>) => {\n if (settled) return;\n settled = true;\n done.current = true;\n const result = explicit ?? collect(keys);\n const changed = explicit !== undefined || keys.length !== startKeys.size || keys.some((k) => !startKeys.has(k));\n resolve({ wasAccepted: accepted, selectionChanged: changed, items: result });\n };\n let handle: G9SheetHandle | null = null;\n const complete = (keys: ReadonlyArray<string>, accepted: boolean) => {\n settle(keys, accepted);\n handle?.close();\n };\n const reset = request.resetSelection && request.resetSelection.length > 0 ? request.resetSelection : null;\n const body = () => (\n <SelectionBody\n request={request}\n ids={ids}\n initial={initial}\n done={done}\n onDraft={(m) => {\n draft = m;\n for (const l of [...draftListeners]) l();\n }}\n onComplete={complete}\n />\n );\n const options: G9SheetOptions = {\n ...fitToContentSheetOptions(),\n deferContent: items.length > g9SelectionEagerBuildItemLimit,\n deferredLoadingPlaceholderHeight: estimateSelectionHeight(items.length, request.showSearch === true),\n loadingSkeleton: 'listRows',\n loadingSkeletonRowCount: items.length,\n backgroundColor: 'var(--g9-surface)',\n showToolbar: true,\n showCloseButton: true,\n title: request.title,\n headerTitlePlacement: 'nearBack',\n ...(multiple || reset\n ? {\n headerTrailingView: (\n <SelectionHeaderActions\n multiple={multiple}\n draft={draftStore}\n {...(request.countLabel ? { countLabel: request.countLabel } : {})}\n onDone={() => complete(draft.selectedKeys, true)}\n {...(reset\n ? {\n onReset: () => {\n settle([], true, reset);\n handle?.close();\n },\n }\n : {})}\n />\n ),\n }\n : {}),\n ...request.options,\n onClosed: () => {\n request.options?.onClosed?.();\n settle(draft.selectedKeys, false);\n },\n };\n handle = sheets.show(items.length > g9SelectionEagerBuildItemLimit ? body : body(), options);\n if (!handle) settle(initialKeys, false);\n });\n}\n\nfunction SelectionHeaderActions(props: {\n readonly multiple: boolean;\n readonly draft: { subscribe(listener: () => void): () => void; count(): number };\n readonly countLabel?: (n: number) => string;\n readonly onDone: () => void;\n readonly onReset?: () => void;\n}): ReactNode {\n const strings = useG9Strings();\n const direction = useG9Direction();\n const n = useSyncExternalStore(props.draft.subscribe, props.draft.count);\n return (\n <view className=\"g9-selection__actions\" style={g9RowStyle(direction)}>\n {props.onReset ? (\n <G9Button text={strings.get(G9StringKey.Reset)} variant=\"text\" size=\"small\" onPress={props.onReset} />\n ) : null}\n {props.multiple && n > 0 ? (\n <view className=\"g9-selection__count\">\n <text className=\"g9-selection__count-text\">\n {props.countLabel ? props.countLabel(n) : `${n} ${strings.get(G9StringKey.Selected)}`}\n </text>\n </view>\n ) : null}\n {props.multiple ? (\n <G9Button text={strings.get(G9StringKey.Done)} variant=\"text\" size=\"small\" onPress={props.onDone} />\n ) : null}\n </view>\n );\n}\n\n/** Arguments of {@link showListSheet} (MAUI `ShowListG9BottomSheetAsync`). */\nexport interface G9ListSheetRequest<T extends G9SelectionItem> {\n readonly title: string;\n readonly items: ReadonlyArray<T>;\n readonly selected?: ReadonlyArray<T>;\n readonly multiple?: boolean;\n /** Default true. */\n readonly closeOnSingleSelection?: boolean;\n /** Shows the search field (250 ms debounce, trimmed) with this placeholder. */\n readonly searchPlaceholder?: string | null;\n /** Default full screen without a handle (MAUI). A fit-to-content `sizeMode` keeps the sheet compact. */\n readonly options?: G9SheetOptions;\n /** Apply button text (multi). Default the `save` string. */\n readonly applyButtonText?: string;\n}\n\n/**\n * The shared list picker (MAUI `ShowListG9BottomSheetAsync` / `G9BottomSheetListPickerModal`): search field with\n * placeholder, rows with a selection tint (no check mark), Apply in multi mode, close-on-select after 120 ms. Resolves\n * with the selection when it completes or closes (no accepted/dismissed distinction, as MAUI); `[]` when throttled.\n */\nexport function showListSheet<T extends G9SelectionItem>(\n sheets: G9SheetService,\n request: G9ListSheetRequest<T>,\n): Promise<T[]> {\n const items = [...request.items];\n const keyOf = (item: G9SelectionItem) => (item.key != null && item.key.trim() !== '' ? item.key : item.text);\n const multiple = request.multiple === true;\n const initial = createSelectionModel<T>({\n items,\n getKey: keyOf,\n getText: (item) => item.text,\n mode: multiple ? 'multiple' : 'single',\n selectedKeys: (request.selected ?? []).map(keyOf),\n isEnabled: (item) => item.isEnabled !== false,\n });\n return new Promise((resolve) => {\n let draft = initial;\n let settled = false;\n let handle: G9SheetHandle | null = null;\n const settle = () => {\n if (settled) return;\n settled = true;\n resolve(draft.selectedItems());\n };\n const complete = () => {\n settle();\n handle?.close();\n };\n const body = () => (\n <ListPickerBody\n request={request}\n initial={initial}\n keyOf={keyOf}\n onDraft={(m) => {\n draft = m;\n }}\n onComplete={complete}\n />\n );\n const base = request.options ?? fullScreenWithoutHandleSheetOptions();\n const fit = base.sizeMode === 'fitToContent';\n const options: G9SheetOptions = {\n ...base,\n ...(fit\n ? {}\n : {\n states: ['large'],\n currentState: 'large',\n hasHandle: false,\n isDraggable: true,\n useFullScreenLoadingPlaceholder: true,\n }),\n showToolbar: true,\n showCloseButton: true,\n title: request.title,\n headerTitlePlacement: 'nearBack',\n deferContent: true,\n onClosed: () => {\n base.onClosed?.();\n settle();\n },\n };\n handle = sheets.show(body, options);\n if (!handle) {\n settled = true;\n resolve([]);\n }\n });\n}\n\nfunction ListPickerBody<T extends G9SelectionItem>(props: {\n readonly request: G9ListSheetRequest<T>;\n readonly initial: G9SelectionModel<T>;\n readonly keyOf: (item: G9SelectionItem) => string;\n readonly onDraft: (model: G9SelectionModel<T>) => void;\n readonly onComplete: () => void;\n}): ReactNode {\n const strings = useG9Strings();\n const palette = useG9Theme().palette;\n const [model, setModel] = useState(props.initial);\n const [query, setQuery] = useState('');\n const picking = useRef(false);\n const { request } = props;\n const visible = model.filter(query, { trim: true });\n const tap = (item: T) => {\n if (picking.current || item.isEnabled === false) return;\n const next = model.toggle(props.keyOf(item));\n setModel(next);\n props.onDraft(next);\n if (!request.multiple && request.closeOnSingleSelection !== false) {\n picking.current = true;\n startTimer(props.onComplete, g9SelectionCloseDelayMs);\n }\n };\n return (\n <view className=\"g9-list-picker\">\n {request.searchPlaceholder ? (\n <view className=\"g9-selection__search\">\n <G9SearchEntry\n placeholder={request.searchPlaceholder}\n voiceEnabled={false}\n onDebouncedValueChange={setQuery}\n />\n </view>\n ) : null}\n {visible.map((item) => (\n <ListPickerRow\n key={props.keyOf(item)}\n item={item}\n selected={model.isSelected(props.keyOf(item))}\n tint={palette.PrimaryContainer}\n onTap={() => tap(item)}\n />\n ))}\n {request.multiple ? (\n <view className=\"g9-list-picker__apply\">\n <G9Button\n text={request.applyButtonText ?? strings.get(G9StringKey.Save)}\n size=\"hero\"\n onPress={props.onComplete}\n />\n </view>\n ) : null}\n </view>\n );\n}\n\nfunction ListPickerRow(props: {\n readonly item: G9SelectionItem;\n readonly selected: boolean;\n readonly tint: string;\n readonly onTap: () => void;\n}): ReactNode {\n const press = useG9Press(props.onTap, {\n source: 'G9ListPicker',\n guardMs: 0,\n blocked: props.item.isEnabled === false,\n });\n const icon = { icon: props.item.icon, imagePath: props.item.iconPath, image: props.item.iconImage };\n const direction = useG9Direction();\n return (\n <view\n className={`g9-list-picker__row${props.selected ? ' g9-list-picker__row--selected' : ''}`}\n style={{ ...g9RowStyle(direction), ...(props.selected ? { backgroundColor: props.tint } : {}) }}\n accessibility-element={true}\n accessibility-traits=\"button\"\n accessibility-label={props.item.text}\n bindtap={press}\n >\n {hasIconSlot(icon) ? <G9IconSlot {...icon} size={20} color=\"var(--g9-on-surface-variant)\" /> : null}\n <text className=\"g9-list-picker__text\" text-maxline=\"1\" style={g9TextStart(direction)}>\n {props.item.text}\n </text>\n </view>\n );\n}\n"],"names":["g9SelectionEagerBuildItemLimit","g9SelectionRowHeight","g9SelectionSearchDebounceMs","g9SelectionCloseDelayMs","selectionIdentities","items","counts","Map","item","_counts_get","i","estimateSelectionHeight","count","showSearch","chrome","Math","SelectionRow","props","_item_iconTintColor","_item_swatchFirstColor","_item_swatchSecondColor","palette","useG9Theme","glyphs","useG9Settings","selected","press","useG9Press","icon","iconColor","view","formatColor","withAlpha","g9RowStyle","hasIconSlot","G9IconSlot","G9Swatch","text","g9TextStart","SelectionBody","_request_emptyText","strings","useG9Strings","parentDir","useG9Direction","request","ids","model","setModel","useState","query","setQuery","applied","setApplied","timer","useRef","picking","useEffect","stopTimer","visible","visibleIds","Set","dir","multiple","onQuery","value","startTimer","tap","id","next","G9TextEntry","G9StringKey","_item_key","_request_options","g9ChildId","showSelectionSheet","sheets","_request_selectedItems","opening","openingIds","listedIds","initialKeys","unlisted","_","initial","createSelectionModel","Promise","resolve","draft","draftListeners","draftStore","l","settled","done","startKeys","collect","keys","set","settle","accepted","explicit","result","changed","undefined","k","handle","complete","reset","body","m","options","fitToContentSheetOptions","SelectionHeaderActions","direction","n","useSyncExternalStore","G9Button","showListSheet","_request_selected","keyOf","ListPickerBody","base","fullScreenWithoutHandleSheetOptions","fit","_request_applyButtonText","G9SearchEntry","ListPickerRow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"selection/selection-sheet.jsx","sources":["../../src/selection/selection-sheet.tsx"],"sourcesContent":["import './selection.css';\nimport {\n formatColor,\n G9Metrics,\n G9StringKey,\n type G9TextInputDirection,\n withAlpha,\n} from '@g9tm/lynxcontrols-foundation';\nimport { type ReactNode, useEffect, useRef, useState, useSyncExternalStore } from '@lynx-js/react';\nimport { g9ChildId, g9RowStyle, g9TextStart } from '../base/control';\nimport { useG9Press } from '../base/press';\nimport { type G9SelectionItem, isAvatarImage } from '../base/selection-item';\nimport { type G9TimerHandle, startTimer, stopTimer } from '../base/timers';\nimport { G9Button } from '../button/button';\nimport { G9SearchEntry } from '../fields/search-entry';\nimport { G9TextEntry } from '../fields/text-entry';\nimport { G9IconSlot, hasIconSlot } from '../icon/slot';\nimport { G9Swatch } from '../icon/swatch';\nimport { useG9Direction, useG9Settings, useG9Strings, useG9Theme } from '../provider/hooks';\nimport { fitToContentSheetOptions, fullScreenWithoutHandleSheetOptions, type G9SheetOptions } from '../sheet/options';\nimport type { G9SheetService } from '../sheet/service';\nimport type { G9SheetHandle } from '../sheet/stack';\nimport { createSelectionModel, type G9SelectionModel } from './model';\nimport { computeSelectionWindow, g9SelectionGrowThreshold, g9SelectionRowPageSize, nextSelectionLimit } from './window';\n\n/** MAUI `G9SelectionSheet.EagerBuildItemLimit`: lists up to 40 items are built at once; longer lists defer. */\nexport const g9SelectionEagerBuildItemLimit = 40;\n/** Row height of the selection sheet (MAUI 52). */\nexport const g9SelectionRowHeight = 52;\n/** Search debounce of the selection sheet (MAUI 150 ms). */\nexport const g9SelectionSearchDebounceMs = 150;\n/** Wait after a close-on-select pick before closing (MAUI 120 ms). */\nexport const g9SelectionCloseDelayMs = 120;\n\n/** The outcome of a selection sheet (MAUI `G9SelectionSheetResult`). */\nexport interface G9SelectionSheetResult<T extends G9SelectionItem = G9SelectionItem> {\n /** A pick on a close-on-select sheet, Done, or Reset; `false` for every dismissal. */\n readonly wasAccepted: boolean;\n /** The selection differs from the opening one. */\n readonly selectionChanged: boolean;\n /** The final selection (opening items that are not listed or disabled stay unless deselected). */\n readonly items: ReadonlyArray<T>;\n}\n\n/**\n * The selection identity of an item inside one list (MAUI `G9SelectionSheet.KeyOf`): `k:<key>` when the key is set,\n * else `t:<text>` when the text is unique among key-less items, else the position (`i:<n>`). Keys and texts never\n * match each other.\n */\nexport function selectionIdentities(items: ReadonlyArray<G9SelectionItem>): string[] {\n const counts = new Map<string, number>();\n for (const item of items) {\n if (item.key == null || item.key.trim() === '') counts.set(item.text, (counts.get(item.text) ?? 0) + 1);\n }\n return items.map((item, i) =>\n item.key != null && item.key.trim() !== ''\n ? `k:${item.key}`\n : (counts.get(item.text) ?? 0) > 1\n ? `i:${i}`\n : `t:${item.text}`,\n );\n}\n\n/** Estimated body height (MAUI `EstimateContentHeight`): rows × 52 + chrome, clamped to [2 rows + chrome, 520]. */\nexport function estimateSelectionHeight(count: number, showSearch: boolean): number {\n const chrome = (showSearch ? 64 : 0) + 18;\n return Math.min(520, Math.max(2 * g9SelectionRowHeight + chrome, count * g9SelectionRowHeight + chrome));\n}\n\n/** Arguments of {@link showSelectionSheet} (MAUI `ShowForResultAsync`). */\nexport interface G9SelectionSheetRequest<T extends G9SelectionItem> {\n readonly title: string;\n readonly items: ReadonlyArray<T>;\n readonly selectedItems?: ReadonlyArray<T>;\n readonly allowMultiple?: boolean;\n /** Single mode: a pick completes and closes after 120 ms. Default true. */\n readonly closeOnSingleSelection?: boolean;\n readonly showSearch?: boolean;\n /** No-results text. Default the `noResults` string. */\n readonly emptyText?: string | null;\n /** Row text direction. Default `'matchParent'`. */\n readonly itemTextDirection?: G9TextInputDirection;\n /** A non-empty reset selection adds a Reset toolbar item that completes with it. */\n readonly resetSelection?: ReadonlyArray<T> | null;\n /** Count pill label (multi). Default `\"{n} {selected}\"`. */\n readonly countLabel?: (count: number) => string;\n /**\n * Multi: Done stays disabled until at least this many items are ticked (MAUI `minimumSelected`, G9MAUIControls 1.4.7) —\n * the sheet never closes on an answer the caller would refuse and reopen. Default 0.\n */\n readonly minimumSelected?: number;\n /** Extra sheet options (merged over the defaults). */\n readonly options?: G9SheetOptions;\n}\n\ninterface BodyProps<T extends G9SelectionItem> {\n readonly request: G9SelectionSheetRequest<T>;\n readonly ids: ReadonlyArray<string>;\n readonly initial: G9SelectionModel<T>;\n readonly onComplete: (keys: ReadonlyArray<string>, accepted: boolean) => void;\n readonly onDraft: (model: G9SelectionModel<T>) => void;\n readonly done: { current: boolean };\n /** The sheet body was scrolled to its end (options.onScrollToEnd): the window grows by a page. */\n readonly scrolledToEnd: { subscribe(listener: () => void): () => void };\n}\n\n/** Placeholder rows: no more than the tallest selection sheet can show (MAUI 1.4.8 `SkeletonRowCap`). */\nexport const g9SelectionSkeletonRowCap = Math.ceil(G9Metrics.SelectionMaxHeight / G9Metrics.SelectionRowHeight) + 1;\n\nfunction SelectionRow(props: {\n readonly item: G9SelectionItem;\n /** Element id (`${sheet automationId}_Item_${key}`), so automation finds the row like a person sees it. */\n readonly elementId?: string | undefined;\n readonly selected: boolean;\n readonly direction: 'ltr' | 'rtl';\n readonly onTap: () => void;\n}): ReactNode {\n const palette = useG9Theme().palette;\n const glyphs = useG9Settings().glyphs;\n const { item, selected } = props;\n const press = useG9Press(props.onTap, { blocked: item.isEnabled === false, source: 'G9SelectionSheet', guardMs: 0 });\n const icon = { emoji: item.emoji, icon: item.icon, imagePath: item.iconPath, image: item.iconImage };\n const iconColor = item.iconTintColor ?? (selected ? palette.Primary : palette.TextSecondary);\n // A person's picture is round and larger (MAUI 1.4.10 IsAvatar); an emoji or a glyph never is.\n const avatar = isAvatarImage(item);\n const iconSize = avatar ? G9Metrics.SelectionAvatarSize : G9Metrics.SelectionIconSize;\n return (\n <view\n {...(props.elementId ? { id: props.elementId } : {})}\n className={`g9-selection-row${selected ? ' g9-selection-row--selected' : ''}`}\n style={selected ? { backgroundColor: formatColor(withAlpha(palette.Primary, 0.1)) } : {}}\n accessibility-element={true}\n accessibility-traits=\"button\"\n accessibility-label={item.text}\n {...(selected ? { 'accessibility-value': 'selected' } : {})}\n bindtap={press}\n >\n <view\n className={`g9-selection-row__inner g9-dir-${props.direction}`}\n style={{ ...g9RowStyle(props.direction), ...(item.isEnabled === false ? { opacity: 0.45 } : {}) }}\n >\n {hasIconSlot(icon) ? (\n <G9IconSlot\n {...icon}\n size={iconSize}\n color={iconColor}\n {...(avatar ? { imageCornerRadius: iconSize / 2 } : {})}\n />\n ) : item.swatchFirstColor?.trim() || item.swatchSecondColor?.trim() ? (\n <G9Swatch first={item.swatchFirstColor} second={item.swatchSecondColor} direction={props.direction} />\n ) : (\n // MAUI's row is a Grid of ColumnSpacing 12 whose icon column stays when empty: its spacing still sits before\n // the text, so an icon-less row's text starts 16 + 12 dp in, level with nothing but the same in every picker.\n <view className=\"g9-selection-row__icon-gap\" />\n )}\n <text\n className=\"g9-selection-row__text\"\n text-maxline=\"1\"\n style={{\n color: selected ? palette.Primary : palette.TextPrimary,\n fontWeight: selected ? 'bold' : 'normal',\n ...g9TextStart(props.direction),\n }}\n >\n {item.text}\n </text>\n <view style={{ opacity: selected ? 1 : 0 }}>\n <G9IconSlot icon={glyphs.check} size={18} color={palette.Primary} />\n </view>\n </view>\n </view>\n );\n}\n\nfunction SelectionBody<T extends G9SelectionItem>(props: BodyProps<T>): ReactNode {\n const strings = useG9Strings();\n const parentDir = useG9Direction();\n const { request, ids } = props;\n const [model, setModel] = useState(props.initial);\n const [query, setQuery] = useState('');\n const [applied, setApplied] = useState('');\n const timer = useRef<G9TimerHandle | null>(null);\n const picking = useRef(false);\n useEffect(\n () => () => {\n if (timer.current !== null) stopTimer(timer.current);\n },\n [],\n );\n const visible = request.showSearch ? model.withItems(request.items).filter(applied) : request.items;\n const visibleIds = new Set(visible.map((item) => ids[request.items.indexOf(item)]));\n // The row window (MAUI 1.4.8, LES-0056): the first page of matches, one more page per scroll to the end, never more\n // than g9SelectionMaxRenderedRows; a new query starts from the first page again (the window is the top of ITS matches).\n const [grown, setGrown] = useState({ query: applied, limit: g9SelectionRowPageSize });\n const limit = grown.query === applied ? grown.limit : g9SelectionRowPageSize;\n const shown = computeSelectionWindow(\n request.items.length,\n (i) => visibleIds.has(ids[i] as string),\n (i) => model.isSelected(ids[i] as string),\n limit,\n );\n const latest = useRef({ applied, limit, hidden: shown.hidden });\n latest.current = { applied, limit, hidden: shown.hidden };\n useEffect(\n () =>\n props.scrolledToEnd.subscribe(() => {\n const now = latest.current;\n const next = nextSelectionLimit(now.limit, now.hidden);\n if (next !== now.limit) setGrown({ query: now.applied, limit: next });\n }),\n [props.scrolledToEnd],\n );\n const dir =\n request.itemTextDirection === 'leftToRight'\n ? 'ltr'\n : request.itemTextDirection === 'rightToLeft'\n ? 'rtl'\n : parentDir;\n const multiple = request.allowMultiple === true;\n const onQuery = (value: string) => {\n setQuery(value);\n if (timer.current !== null) stopTimer(timer.current);\n if (value.trim() === '') {\n setApplied(value);\n return;\n }\n timer.current = startTimer(() => setApplied(value), g9SelectionSearchDebounceMs);\n };\n const tap = (id: string) => {\n if (props.done.current || picking.current) return;\n const next = model.toggle(id);\n if (next === model) return;\n setModel(next);\n props.onDraft(next);\n if (!multiple && request.closeOnSingleSelection !== false) {\n picking.current = true;\n startTimer(() => props.onComplete(next.selectedKeys, true), g9SelectionCloseDelayMs);\n }\n };\n return (\n <view className=\"g9-selection\">\n {request.showSearch ? (\n <view className=\"g9-selection__search\">\n <G9TextEntry\n placeholder={strings.get(G9StringKey.Search)}\n leadingIcon=\"search\"\n value={query}\n onValueChange={onQuery}\n />\n </view>\n ) : null}\n {shown.indices.length > 0 ? (\n <view className=\"g9-selection__items\">\n {shown.indices.map((i) => {\n const id = ids[i] as string;\n const item = request.items[i] as T;\n return (\n <SelectionRow\n key={id}\n item={item}\n elementId={g9ChildId(request.options?.automationId, `Item_${item.key ?? i}`)}\n selected={model.isSelected(id)}\n direction={dir}\n onTap={() => tap(id)}\n />\n );\n })}\n </view>\n ) : null}\n {shown.hidden > 0 ? (\n <text className=\"g9-selection__more\">{strings.format(G9StringKey.MoreResultsFormat, shown.hidden)}</text>\n ) : null}\n {visible.length === 0 ? (\n <text className=\"g9-selection__empty\">{request.emptyText ?? strings.get(G9StringKey.NoResults)}</text>\n ) : null}\n </view>\n );\n}\n\n/**\n * Shows the selection sheet (MAUI `G9SelectionSheet.ShowForResultAsync`): a fit sheet with a header (title near the\n * close button), optional search (150 ms debounce, text match, hidden selected rows stay selected), rows with icon or\n * swatch, check mark and selection tint. Single mode with `closeOnSingleSelection` completes on a pick; multi mode\n * shows a count pill and Done; a reset selection adds Reset. Any dismissal resolves `wasAccepted: false` with the\n * current draft (or the opening selection when the sheet never built).\n */\nexport function showSelectionSheet<T extends G9SelectionItem>(\n sheets: G9SheetService,\n request: G9SelectionSheetRequest<T>,\n): Promise<G9SelectionSheetResult<T>> {\n const items = [...request.items];\n const ids = selectionIdentities(items);\n const opening = request.selectedItems ?? [];\n // Opening items match listed items by identity; the rest are kept as \"not listed\".\n const openingIds = selectionIdentities([...items, ...opening]).slice(items.length);\n const listedIds = new Set(ids);\n const initialKeys = openingIds.filter((id) => listedIds.has(id));\n const unlisted = opening.filter((_, i) => !listedIds.has(openingIds[i] as string));\n const multiple = request.allowMultiple === true;\n const initial = createSelectionModel<T>({\n items,\n getKey: (item) => ids[items.indexOf(item)] as string,\n getText: (item) => item.text,\n mode: multiple ? 'multiple' : 'single',\n selectedKeys: initialKeys,\n isEnabled: (item) => item.isEnabled !== false,\n });\n return new Promise((resolve) => {\n let draft = initial;\n const draftListeners = new Set<() => void>();\n const draftStore = {\n subscribe: (l: () => void) => {\n draftListeners.add(l);\n return () => {\n draftListeners.delete(l);\n };\n },\n count: () => draft.selectedKeys.length,\n };\n let settled = false;\n const done = { current: false };\n const startKeys = new Set(initialKeys);\n const collect = (keys: ReadonlyArray<string>): T[] => {\n const set = new Set(keys);\n return [...items.filter((_, i) => set.has(ids[i] as string)), ...unlisted];\n };\n const settle = (keys: ReadonlyArray<string>, accepted: boolean, explicit?: ReadonlyArray<T>) => {\n if (settled) return;\n settled = true;\n done.current = true;\n const result = explicit ?? collect(keys);\n const changed = explicit !== undefined || keys.length !== startKeys.size || keys.some((k) => !startKeys.has(k));\n resolve({ wasAccepted: accepted, selectionChanged: changed, items: result });\n };\n let handle: G9SheetHandle | null = null;\n const complete = (keys: ReadonlyArray<string>, accepted: boolean) => {\n settle(keys, accepted);\n handle?.close();\n };\n const reset = request.resetSelection && request.resetSelection.length > 0 ? request.resetSelection : null;\n const endListeners = new Set<() => void>();\n const scrolledToEnd = {\n subscribe: (l: () => void) => {\n endListeners.add(l);\n return () => {\n endListeners.delete(l);\n };\n },\n };\n const body = () => (\n <SelectionBody\n request={request}\n ids={ids}\n initial={initial}\n done={done}\n scrolledToEnd={scrolledToEnd}\n onDraft={(m) => {\n draft = m;\n for (const l of [...draftListeners]) l();\n }}\n onComplete={complete}\n />\n );\n const options: G9SheetOptions = {\n ...fitToContentSheetOptions(),\n deferContent: items.length > g9SelectionEagerBuildItemLimit,\n deferredLoadingPlaceholderHeight: estimateSelectionHeight(items.length, request.showSearch === true),\n loadingSkeleton: 'listRows',\n // ⛔ Capped at what the sheet can show. It was the item count: 3,416 people built 3,416 placeholder rows before\n // the real ones (MAUI's ANR of 2026-11-08, LES-0056).\n loadingSkeletonRowCount: Math.min(items.length, g9SelectionSkeletonRowCap),\n onScrollToEnd: () => {\n for (const l of [...endListeners]) l();\n },\n scrollToEndThreshold: g9SelectionGrowThreshold,\n backgroundColor: 'var(--g9-surface)',\n showToolbar: true,\n showCloseButton: true,\n title: request.title,\n headerTitlePlacement: 'nearBack',\n ...(multiple || reset\n ? {\n headerTrailingView: (\n <SelectionHeaderActions\n multiple={multiple}\n draft={draftStore}\n minimum={Math.max(0, request.minimumSelected ?? 0)}\n {...(request.countLabel ? { countLabel: request.countLabel } : {})}\n onDone={() => {\n if (draft.selectedKeys.length >= Math.max(0, request.minimumSelected ?? 0))\n complete(draft.selectedKeys, true);\n }}\n {...(reset\n ? {\n onReset: () => {\n settle([], true, reset);\n handle?.close();\n },\n }\n : {})}\n />\n ),\n }\n : {}),\n ...request.options,\n onClosed: () => {\n request.options?.onClosed?.();\n settle(draft.selectedKeys, false);\n },\n };\n handle = sheets.show(items.length > g9SelectionEagerBuildItemLimit ? body : body(), options);\n if (!handle) settle(initialKeys, false);\n });\n}\n\nfunction SelectionHeaderActions(props: {\n readonly multiple: boolean;\n readonly draft: { subscribe(listener: () => void): () => void; count(): number };\n readonly minimum: number;\n readonly countLabel?: (n: number) => string;\n readonly onDone: () => void;\n readonly onReset?: () => void;\n}): ReactNode {\n const strings = useG9Strings();\n const direction = useG9Direction();\n const n = useSyncExternalStore(props.draft.subscribe, props.draft.count);\n return (\n <view className=\"g9-selection__actions\" style={g9RowStyle(direction)}>\n {props.onReset ? (\n <G9Button text={strings.get(G9StringKey.Reset)} variant=\"text\" size=\"small\" onPress={props.onReset} />\n ) : null}\n {props.multiple && n > 0 ? (\n <view className=\"g9-selection__count\">\n <text className=\"g9-selection__count-text\">\n {props.countLabel ? props.countLabel(n) : `${n} ${strings.get(G9StringKey.Selected)}`}\n </text>\n </view>\n ) : null}\n {props.multiple ? (\n <G9Button\n text={strings.get(G9StringKey.Done)}\n variant=\"text\"\n size=\"small\"\n disabled={n < props.minimum}\n onPress={props.onDone}\n />\n ) : null}\n </view>\n );\n}\n\n/** Arguments of {@link showListSheet} (MAUI `ShowListG9BottomSheetAsync`). */\nexport interface G9ListSheetRequest<T extends G9SelectionItem> {\n readonly title: string;\n readonly items: ReadonlyArray<T>;\n readonly selected?: ReadonlyArray<T>;\n readonly multiple?: boolean;\n /** Default true. */\n readonly closeOnSingleSelection?: boolean;\n /** Shows the search field (250 ms debounce, trimmed) with this placeholder. */\n readonly searchPlaceholder?: string | null;\n /** Default full screen without a handle (MAUI). A fit-to-content `sizeMode` keeps the sheet compact. */\n readonly options?: G9SheetOptions;\n /** Apply button text (multi). Default the `save` string. */\n readonly applyButtonText?: string;\n}\n\n/**\n * The shared list picker (MAUI `ShowListG9BottomSheetAsync` / `G9BottomSheetListPickerModal`): search field with\n * placeholder, rows with a selection tint (no check mark), Apply in multi mode, close-on-select after 120 ms. Resolves\n * with the selection when it completes or closes (no accepted/dismissed distinction, as MAUI); `[]` when throttled.\n */\nexport function showListSheet<T extends G9SelectionItem>(\n sheets: G9SheetService,\n request: G9ListSheetRequest<T>,\n): Promise<T[]> {\n const items = [...request.items];\n const keyOf = (item: G9SelectionItem) => (item.key != null && item.key.trim() !== '' ? item.key : item.text);\n const multiple = request.multiple === true;\n const initial = createSelectionModel<T>({\n items,\n getKey: keyOf,\n getText: (item) => item.text,\n mode: multiple ? 'multiple' : 'single',\n selectedKeys: (request.selected ?? []).map(keyOf),\n isEnabled: (item) => item.isEnabled !== false,\n });\n return new Promise((resolve) => {\n let draft = initial;\n let settled = false;\n let handle: G9SheetHandle | null = null;\n const settle = () => {\n if (settled) return;\n settled = true;\n resolve(draft.selectedItems());\n };\n const complete = () => {\n settle();\n handle?.close();\n };\n const body = () => (\n <ListPickerBody\n request={request}\n initial={initial}\n keyOf={keyOf}\n onDraft={(m) => {\n draft = m;\n }}\n onComplete={complete}\n />\n );\n const base = request.options ?? fullScreenWithoutHandleSheetOptions();\n const fit = base.sizeMode === 'fitToContent';\n const options: G9SheetOptions = {\n ...base,\n ...(fit\n ? {}\n : {\n states: ['large'],\n currentState: 'large',\n hasHandle: false,\n isDraggable: true,\n useFullScreenLoadingPlaceholder: true,\n }),\n showToolbar: true,\n showCloseButton: true,\n title: request.title,\n headerTitlePlacement: 'nearBack',\n deferContent: true,\n onClosed: () => {\n base.onClosed?.();\n settle();\n },\n };\n handle = sheets.show(body, options);\n if (!handle) {\n settled = true;\n resolve([]);\n }\n });\n}\n\nfunction ListPickerBody<T extends G9SelectionItem>(props: {\n readonly request: G9ListSheetRequest<T>;\n readonly initial: G9SelectionModel<T>;\n readonly keyOf: (item: G9SelectionItem) => string;\n readonly onDraft: (model: G9SelectionModel<T>) => void;\n readonly onComplete: () => void;\n}): ReactNode {\n const strings = useG9Strings();\n const palette = useG9Theme().palette;\n const [model, setModel] = useState(props.initial);\n const [query, setQuery] = useState('');\n const picking = useRef(false);\n const { request } = props;\n const visible = model.filter(query, { trim: true });\n const tap = (item: T) => {\n if (picking.current || item.isEnabled === false) return;\n const next = model.toggle(props.keyOf(item));\n setModel(next);\n props.onDraft(next);\n if (!request.multiple && request.closeOnSingleSelection !== false) {\n picking.current = true;\n startTimer(props.onComplete, g9SelectionCloseDelayMs);\n }\n };\n return (\n <view className=\"g9-list-picker\">\n {request.searchPlaceholder ? (\n <view className=\"g9-selection__search\">\n <G9SearchEntry\n placeholder={request.searchPlaceholder}\n voiceEnabled={false}\n onDebouncedValueChange={setQuery}\n />\n </view>\n ) : null}\n {visible.map((item) => (\n <ListPickerRow\n key={props.keyOf(item)}\n item={item}\n selected={model.isSelected(props.keyOf(item))}\n tint={palette.PrimaryContainer}\n onTap={() => tap(item)}\n />\n ))}\n {request.multiple ? (\n <view className=\"g9-list-picker__apply\">\n <G9Button\n text={request.applyButtonText ?? strings.get(G9StringKey.Save)}\n size=\"hero\"\n onPress={props.onComplete}\n />\n </view>\n ) : null}\n </view>\n );\n}\n\nfunction ListPickerRow(props: {\n readonly item: G9SelectionItem;\n readonly selected: boolean;\n readonly tint: string;\n readonly onTap: () => void;\n}): ReactNode {\n const press = useG9Press(props.onTap, {\n source: 'G9ListPicker',\n guardMs: 0,\n blocked: props.item.isEnabled === false,\n });\n const icon = { icon: props.item.icon, imagePath: props.item.iconPath, image: props.item.iconImage };\n const direction = useG9Direction();\n return (\n <view\n className={`g9-list-picker__row${props.selected ? ' g9-list-picker__row--selected' : ''}`}\n style={{ ...g9RowStyle(direction), ...(props.selected ? { backgroundColor: props.tint } : {}) }}\n accessibility-element={true}\n accessibility-traits=\"button\"\n accessibility-label={props.item.text}\n bindtap={press}\n >\n {hasIconSlot(icon) ? <G9IconSlot {...icon} size={20} color=\"var(--g9-on-surface-variant)\" /> : null}\n <text className=\"g9-list-picker__text\" text-maxline=\"1\" style={g9TextStart(direction)}>\n {props.item.text}\n </text>\n </view>\n );\n}\n"],"names":["g9SelectionEagerBuildItemLimit","g9SelectionRowHeight","g9SelectionSearchDebounceMs","g9SelectionCloseDelayMs","selectionIdentities","items","counts","Map","item","_counts_get","i","estimateSelectionHeight","count","showSearch","chrome","Math","g9SelectionSkeletonRowCap","G9Metrics","SelectionRow","props","_item_iconTintColor","_item_swatchFirstColor","_item_swatchSecondColor","palette","useG9Theme","glyphs","useG9Settings","selected","press","useG9Press","icon","iconColor","avatar","isAvatarImage","iconSize","view","formatColor","withAlpha","g9RowStyle","hasIconSlot","G9IconSlot","G9Swatch","text","g9TextStart","SelectionBody","_request_emptyText","strings","useG9Strings","parentDir","useG9Direction","request","ids","model","setModel","useState","query","setQuery","applied","setApplied","timer","useRef","picking","useEffect","stopTimer","visible","visibleIds","Set","grown","setGrown","g9SelectionRowPageSize","limit","shown","computeSelectionWindow","latest","now","next","nextSelectionLimit","dir","multiple","onQuery","value","startTimer","tap","id","G9TextEntry","G9StringKey","_item_key","_request_options","g9ChildId","showSelectionSheet","sheets","_request_selectedItems","opening","openingIds","listedIds","initialKeys","unlisted","_","initial","createSelectionModel","Promise","resolve","_request_minimumSelected","draft","draftListeners","draftStore","l","settled","done","startKeys","collect","keys","set","settle","accepted","explicit","result","changed","undefined","k","handle","complete","reset","endListeners","scrolledToEnd","body","m","options","fitToContentSheetOptions","g9SelectionGrowThreshold","SelectionHeaderActions","direction","n","useSyncExternalStore","G9Button","showListSheet","_request_selected","keyOf","ListPickerBody","base","fullScreenWithoutHandleSheetOptions","fit","_request_applyButtonText","G9SearchEntry","ListPickerRow"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["webpack://./src/selection/selection.css"],"names":[],"mappings":"AACA;EAAE,sBAAsB;EACtB,aAAa;AACf;;AAMA;EAHE,mBAAmB;AACrB;;AAMA;EAHE,sBAAsB;EACtB,cAAc;EACd,aAAa;AACf;;AAMA;EAHE,iBAAiB;AACnB;;AAQA;EALE,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,aAAa;AACf;;AAQA;EALE,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB;EAChB,eAAe;EACf,aAAa;AACf;;AAQA;EALE,QAAQ;EACR,WAAW;AACb;;AAQA;EALE,uBAAuB;EACvB,OAAO;EACP,eAAe;AACjB;;AAQA;EALE,kBAAkB;EAClB,8BAA8B;EAC9B,kBAAkB;EAClB,eAAe;AACjB;;
|
|
1
|
+
{"version":3,"sources":["webpack://./src/selection/selection.css"],"names":[],"mappings":"AACA;EAAE,sBAAsB;EACtB,aAAa;AACf;;AAMA;EAHE,mBAAmB;AACrB;;AAMA;EAHE,sBAAsB;EACtB,cAAc;EACd,aAAa;AACf;;AAMA;EAHE,iBAAiB;AACnB;;AAQA;EALE,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,aAAa;AACf;;AAQA;EALE,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB;EAChB,eAAe;EACf,aAAa;AACf;;AAQA;EALE,QAAQ;EACR,WAAW;AACb;;AAQA;EALE,uBAAuB;EACvB,OAAO;EACP,eAAe;AACjB;;AAQA;EALE,kBAAkB;EAClB,8BAA8B;EAC9B,kBAAkB;EAClB,eAAe;AACjB;;AASA;EANE,kBAAkB;EAClB,8BAA8B;EAC9B,kBAAkB;EAClB,eAAe;AACjB;;AASA;EANE,mBAAmB;EACnB,mBAAmB;EACnB,eAAe;EACf,aAAa;AACf;;AASA;EANE,6CAA6C;EAC7C,mBAAmB;EACnB,gBAAgB;AAClB;;AASA;EANE,qCAAqC;EACrC,eAAe;AACjB;;AASA;EANE,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB;EAChB,gBAAgB;EAChB,eAAe;EACf,aAAa;AACf;;AASA;EANE,6BAA6B;EAC7B,OAAO;EACP,eAAe;AACjB;;AASA;EANE,kBAAkB;AACpB","sourcesContent":["/* Selection sheet and list picker (MAUI G9SelectionSheet, G9BottomSheetListPickerModal). */\n.g9-selection,\n.g9-list-picker {\n display: flex;\n flex-direction: column;\n}\n\n/* MAUI G9SelectionSheet: the sheet's Padding (0, 0, 0, 4) and the rows host's Padding (0, 4, 0, 4) — 4 dp between the\n header and the first row, 8 dp under the last. */\n.g9-selection {\n padding-bottom: 4px;\n}\n\n.g9-selection__items {\n display: flex;\n flex-direction: column;\n padding: 4px 0px;\n}\n\n.g9-selection__search {\n padding: 8px 12px;\n}\n\n/* A column: the inner row stretches to the full width and is centred VERTICALLY (as a row container, the inner row\n was centred horizontally — icon, text and check bunched in the middle of the sheet). */\n.g9-selection-row {\n min-height: 52px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.g9-selection-row__inner {\n display: flex;\n flex-direction: row;\n align-items: center;\n column-gap: 12px;\n padding: 0px 16px;\n}\n\n.g9-selection-row__icon-gap {\n width: 0px;\n height: 1px;\n}\n\n.g9-selection-row__text {\n flex: 1;\n font-size: 14px;\n text-overflow: ellipsis;\n}\n\n.g9-selection__empty {\n padding: 28px 16px;\n font-size: 13px;\n text-align: center;\n color: var(--g9-text-tertiary);\n}\n\n/* The «N more — search» footer of a long list (MAUI 1.4.8): TextTertiary 12, centred, 16 / 14 padding. */\n.g9-selection__more {\n padding: 14px 16px;\n font-size: 12px;\n text-align: center;\n color: var(--g9-text-tertiary);\n}\n\n.g9-selection__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n column-gap: 8px;\n}\n\n.g9-selection__count {\n padding: 2px 8px;\n border-radius: 10px;\n background-color: var(--g9-primary-container);\n}\n\n.g9-selection__count-text {\n font-size: 12px;\n color: var(--g9-on-primary-container);\n}\n\n.g9-list-picker__row {\n display: flex;\n flex-direction: row;\n align-items: center;\n column-gap: 10px;\n min-height: 52px;\n padding: 0px 16px;\n}\n\n.g9-list-picker__text {\n flex: 1;\n font-size: 14px;\n color: var(--g9-text-primary);\n}\n\n.g9-list-picker__apply {\n padding: 12px 16px;\n}\n"],"sourceRoot":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The selection sheet's row window (MAUI 1.4.8 `G9SelectionWindow`, LES-0056). A 3,416-person assignee list built a row
|
|
3
|
+
* per item and was killed as an ANR in the MAUI app; the Lynx sheet built a row per item too. The sheet now renders only
|
|
4
|
+
* the window this computes: the first `limit` matches in list order, plus every selected match beyond them (a chosen
|
|
5
|
+
* value must stay on screen to be un-chosen), and counts the matches it left out for the «N more» footer.
|
|
6
|
+
*/
|
|
7
|
+
export interface G9SelectionWindow {
|
|
8
|
+
/** The item indices to render, in list order. */
|
|
9
|
+
readonly indices: ReadonlyArray<number>;
|
|
10
|
+
/** Matches left out of the window by the limit (selected ones are never left out). */
|
|
11
|
+
readonly hidden: number;
|
|
12
|
+
}
|
|
13
|
+
/** Rows rendered per page; the next page joins when the list is scrolled to its end (MAUI `RowPageSize`, 60). */
|
|
14
|
+
export declare const g9SelectionRowPageSize = 60;
|
|
15
|
+
/** The most matching rows one query renders, whatever the scrolling (MAUI `MaxRenderedRows`, 200). */
|
|
16
|
+
export declare const g9SelectionMaxRenderedRows = 200;
|
|
17
|
+
/** How close to the end of the list (px) the next page is asked for: four rows (MAUI `SelectionRowHeight * 4`). */
|
|
18
|
+
export declare const g9SelectionGrowThreshold: number;
|
|
19
|
+
/**
|
|
20
|
+
* The window of a query (MAUI `G9SelectionWindow.Compute`).
|
|
21
|
+
* @param count how many items the sheet holds
|
|
22
|
+
* @param matches whether item `i` matches the query
|
|
23
|
+
* @param isSelected whether item `i` is selected now
|
|
24
|
+
* @param limit how many matching rows the window may hold (selected ones beyond it do not count)
|
|
25
|
+
*/
|
|
26
|
+
export declare function computeSelectionWindow(count: number, matches: (index: number) => boolean, isSelected: (index: number) => boolean, limit: number): G9SelectionWindow;
|
|
27
|
+
/** The next render limit after a scroll to the end: one more page, never past {@link g9SelectionMaxRenderedRows}. */
|
|
28
|
+
export declare function nextSelectionLimit(current: number, hidden: number): number;
|
|
29
|
+
//# sourceMappingURL=window.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../src/selection/window.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,iHAAiH;AACjH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,sGAAsG;AACtG,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,mHAAmH;AACnH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACnC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EACtC,KAAK,EAAE,MAAM,GACZ,iBAAiB,CAgBnB;AAED,qHAAqH;AACrH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG1E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const g9SelectionRowPageSize = 60;
|
|
2
|
+
const g9SelectionMaxRenderedRows = 200;
|
|
3
|
+
const g9SelectionGrowThreshold = 208;
|
|
4
|
+
function computeSelectionWindow(count, matches, isSelected, limit) {
|
|
5
|
+
const indices = [];
|
|
6
|
+
let hidden = 0;
|
|
7
|
+
let shown = 0;
|
|
8
|
+
for(let i = 0; i < count; i++)if (matches(i)) if (shown < limit) {
|
|
9
|
+
indices.push(i);
|
|
10
|
+
shown++;
|
|
11
|
+
} else if (isSelected(i)) indices.push(i);
|
|
12
|
+
else hidden++;
|
|
13
|
+
return {
|
|
14
|
+
indices,
|
|
15
|
+
hidden
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function nextSelectionLimit(current, hidden) {
|
|
19
|
+
if (hidden <= 0) return current;
|
|
20
|
+
return Math.min(current + g9SelectionRowPageSize, g9SelectionMaxRenderedRows);
|
|
21
|
+
}
|
|
22
|
+
export { computeSelectionWindow, g9SelectionGrowThreshold, g9SelectionMaxRenderedRows, g9SelectionRowPageSize, nextSelectionLimit };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=window.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection/window.jsx","sources":["../../src/selection/window.ts"],"sourcesContent":["/**\n * The selection sheet's row window (MAUI 1.4.8 `G9SelectionWindow`, LES-0056). A 3,416-person assignee list built a row\n * per item and was killed as an ANR in the MAUI app; the Lynx sheet built a row per item too. The sheet now renders only\n * the window this computes: the first `limit` matches in list order, plus every selected match beyond them (a chosen\n * value must stay on screen to be un-chosen), and counts the matches it left out for the «N more» footer.\n */\nexport interface G9SelectionWindow {\n /** The item indices to render, in list order. */\n readonly indices: ReadonlyArray<number>;\n /** Matches left out of the window by the limit (selected ones are never left out). */\n readonly hidden: number;\n}\n\n/** Rows rendered per page; the next page joins when the list is scrolled to its end (MAUI `RowPageSize`, 60). */\nexport const g9SelectionRowPageSize = 60;\n/** The most matching rows one query renders, whatever the scrolling (MAUI `MaxRenderedRows`, 200). */\nexport const g9SelectionMaxRenderedRows = 200;\n/** How close to the end of the list (px) the next page is asked for: four rows (MAUI `SelectionRowHeight * 4`). */\nexport const g9SelectionGrowThreshold = 4 * 52;\n\n/**\n * The window of a query (MAUI `G9SelectionWindow.Compute`).\n * @param count how many items the sheet holds\n * @param matches whether item `i` matches the query\n * @param isSelected whether item `i` is selected now\n * @param limit how many matching rows the window may hold (selected ones beyond it do not count)\n */\nexport function computeSelectionWindow(\n count: number,\n matches: (index: number) => boolean,\n isSelected: (index: number) => boolean,\n limit: number,\n): G9SelectionWindow {\n const indices: number[] = [];\n let hidden = 0;\n let shown = 0;\n for (let i = 0; i < count; i++) {\n if (!matches(i)) continue;\n if (shown < limit) {\n indices.push(i);\n shown++;\n } else if (isSelected(i)) {\n indices.push(i);\n } else {\n hidden++;\n }\n }\n return { indices, hidden };\n}\n\n/** The next render limit after a scroll to the end: one more page, never past {@link g9SelectionMaxRenderedRows}. */\nexport function nextSelectionLimit(current: number, hidden: number): number {\n if (hidden <= 0) return current;\n return Math.min(current + g9SelectionRowPageSize, g9SelectionMaxRenderedRows);\n}\n"],"names":["g9SelectionRowPageSize","g9SelectionMaxRenderedRows","g9SelectionGrowThreshold","computeSelectionWindow","count","matches","isSelected","limit","indices","hidden","shown","i","nextSelectionLimit","current","Math"],"mappings":"AAcO,MAAMA,yBAAyB;AAE/B,MAAMC,6BAA6B;AAEnC,MAAMC,2BAA2B;AASjC,SAASC,uBACdC,KAAa,EACbC,OAAmC,EACnCC,UAAsC,EACtCC,KAAa;IAEb,MAAMC,UAAoB,EAAE;IAC5B,IAAIC,SAAS;IACb,IAAIC,QAAQ;IACZ,IAAK,IAAIC,IAAI,GAAGA,IAAIP,OAAOO,IACzB,IAAKN,QAAQM,IACb,IAAID,QAAQH,OAAO;QACjBC,QAAQ,IAAI,CAACG;QACbD;IACF,OAAO,IAAIJ,WAAWK,IACpBH,QAAQ,IAAI,CAACG;SAEbF;IAGJ,OAAO;QAAED;QAASC;IAAO;AAC3B;AAGO,SAASG,mBAAmBC,OAAe,EAAEJ,MAAc;IAChE,IAAIA,UAAU,GAAG,OAAOI;IACxB,OAAOC,KAAK,GAAG,CAACD,UAAUb,wBAAwBC;AACpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/sheet/frame.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/sheet/frame.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,aAAa,EAKnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAiB,KAAK,SAAS,EAA2C,MAAM,gBAAgB,CAAC;AASxG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,WAAW,CAAC;AAgBhE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEzE,qGAAqG;AACrG,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAID,kDAAkD;AAClD,wBAAgB,iBAAiB,IAAI,mBAAmB,GAAG,IAAI,CAE9D;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACxC,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AA4BD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAmXhE"}
|
package/dist/sheet/frame.jsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./sheet.css";
|
|
2
|
-
import { createAbortController, formatColor, resolveThemeColor, tryParseColor, withAlpha } from "@g9tm/lynxcontrols-foundation";
|
|
2
|
+
import { createAbortController, formatColor, g9Ms, resolveThemeColor, tryParseColor, withAlpha } from "@g9tm/lynxcontrols-foundation";
|
|
3
3
|
import { SheetContent, SheetRoot, SheetView } from "@lynx-js/lynx-ui-sheet";
|
|
4
4
|
import { createContext, useContext, useEffect, useRef, useState } from "@lynx-js/react";
|
|
5
5
|
import { g9IdProps } from "../base/control.jsx";
|
|
@@ -11,7 +11,8 @@ import { useG9Theme } from "../provider/hooks.jsx";
|
|
|
11
11
|
import { G9SheetGestureFrame, useSheetBodyGesture, useSheetGestureRefs } from "./gesture.jsx";
|
|
12
12
|
import { G9SheetFooter, G9SheetHeader } from "./header.jsx";
|
|
13
13
|
import { resolveSheetMotion } from "./motion.jsx";
|
|
14
|
-
import {
|
|
14
|
+
import { G9SheetScrollIndicator, G9SheetScrollModel } from "./scroll-indicator.jsx";
|
|
15
|
+
import { clampFitHeight, currentPlatform, g9SheetDragCloseThreshold, g9SheetFitLoadingMinHeight, g9SheetFitMinHeight, g9SheetScrollToEndThreshold, parentRecedeOffset, platformSheetConstraints, resolveSheetLayout, sheetOverlayOpacity, sheetSurfaceBottomPadding, sheetSurfaceTopPadding } from "./sizing.jsx";
|
|
15
16
|
const SheetContext = createContext(null);
|
|
16
17
|
function useG9SheetContext() {
|
|
17
18
|
return useContext(SheetContext);
|
|
@@ -26,7 +27,7 @@ const sheetInnerStyle = {
|
|
|
26
27
|
display: 'flex',
|
|
27
28
|
flexDirection: 'column'
|
|
28
29
|
};
|
|
29
|
-
const g9SheetRecedeTransition =
|
|
30
|
+
const g9SheetRecedeTransition = ()=>`transform ${g9Ms(220)}ms ease-out, opacity ${g9Ms(220)}ms ease-out`;
|
|
30
31
|
function orderedDetents(o) {
|
|
31
32
|
const requested = o.states && o.states.length > 0 ? o.states : [
|
|
32
33
|
'medium',
|
|
@@ -46,7 +47,7 @@ function initialDetent(o, fit) {
|
|
|
46
47
|
return ordered.includes(current) ? current : null != (_ordered_ = ordered[0]) ? _ordered_ : 'medium';
|
|
47
48
|
}
|
|
48
49
|
function G9SheetFrame(props) {
|
|
49
|
-
var _ref, _o_deferredLoadingPlaceholderHeight, _o_loadingSkeletonRowCount, _ratios_layout_initialSnap, _props_bottomInset, _o_openAnimationDurationMs, _o_closeAnimationDurationMs, _o_cornerRadius, _o_backgroundColor, _ratios_restIndex, _o_padding, _o_padding1;
|
|
50
|
+
var _ref, _o_deferredLoadingPlaceholderHeight, _o_loadingSkeletonRowCount, _ratios_layout_initialSnap, _props_bottomInset, _o_scrollToEndThreshold, _o_openAnimationDurationMs, _o_closeAnimationDurationMs, _o_cornerRadius, _o_backgroundColor, _ratios_restIndex, _o_padding, _o_padding1, _o_padding2;
|
|
50
51
|
var _props_memo;
|
|
51
52
|
const { entry, stack, settings } = props;
|
|
52
53
|
const palette = useG9Theme().palette;
|
|
@@ -87,7 +88,7 @@ function G9SheetFrame(props) {
|
|
|
87
88
|
setRevealed(true);
|
|
88
89
|
if (false !== o.fadeDeferredContentIn) {
|
|
89
90
|
setCovering(true);
|
|
90
|
-
coverTimer.current = startTimer(()=>setCovering(false), 220);
|
|
91
|
+
coverTimer.current = startTimer(()=>setCovering(false), g9Ms(220));
|
|
91
92
|
}
|
|
92
93
|
}, delay);
|
|
93
94
|
return ()=>{
|
|
@@ -113,10 +114,13 @@ function G9SheetFrame(props) {
|
|
|
113
114
|
var _e_detail;
|
|
114
115
|
return setFooterHeight(Math.max(0, null != (_ref = null == (_e_detail = e.detail) ? void 0 : _e_detail.height) ? _ref : 0));
|
|
115
116
|
};
|
|
117
|
+
const indicator = useRef(null);
|
|
118
|
+
if ('always' === o.scrollIndicator && false !== o.scrollBody && !indicator.current) indicator.current = new G9SheetScrollModel();
|
|
116
119
|
const onBodyLayout = (e)=>{
|
|
117
|
-
var _ref;
|
|
118
|
-
var _e_detail, _props_memo;
|
|
120
|
+
var _ref, _o_padding;
|
|
121
|
+
var _e_detail, _indicator_current, _props_memo;
|
|
119
122
|
const h = null != (_ref = null == (_e_detail = e.detail) ? void 0 : _e_detail.height) ? _ref : 0;
|
|
123
|
+
null == (_indicator_current = indicator.current) || _indicator_current.setContent(h > 0 ? h + 2 * (null != (_o_padding = o.padding) ? _o_padding : 0) : 0);
|
|
120
124
|
if (h <= 0) return;
|
|
121
125
|
setBodyHeight(h);
|
|
122
126
|
if (memoKey && revealed && !covering) null == (_props_memo = props.memo) || _props_memo.record(memoKey, h);
|
|
@@ -175,6 +179,10 @@ function G9SheetFrame(props) {
|
|
|
175
179
|
};
|
|
176
180
|
const platform = currentPlatform();
|
|
177
181
|
const phone = 'android' === platform || 'ios' === platform;
|
|
182
|
+
const endProps = o.onScrollToEnd ? {
|
|
183
|
+
'lower-threshold': null != (_o_scrollToEndThreshold = o.scrollToEndThreshold) ? _o_scrollToEndThreshold : g9SheetScrollToEndThreshold,
|
|
184
|
+
bindscrolltolower: o.onScrollToEnd
|
|
185
|
+
} : {};
|
|
178
186
|
const openMs = null != (_o_openAnimationDurationMs = o.openAnimationDurationMs) ? _o_openAnimationDurationMs : settings.openAnimationDurationMs;
|
|
179
187
|
const closeMs = null != (_o_closeAnimationDurationMs = o.closeAnimationDurationMs) ? _o_closeAnimationDurationMs : settings.closeAnimationDurationMs;
|
|
180
188
|
const corner = 'android' === platform && true === o.androidShouldRemoveExpandedCorners && layout.fullScreen ? 0 : null != (_o_cornerRadius = o.cornerRadius) ? _o_cornerRadius : 12;
|
|
@@ -228,7 +236,7 @@ function G9SheetFrame(props) {
|
|
|
228
236
|
<SheetContent className={`g9-sheet g9-sheet--${entry.status}${layout.fit ? ' g9-sheet--fit' : ''}`} style={platformSheetConstraints(o)} innerStyle={sheetInnerStyle} {...motion}>
|
|
229
237
|
<G9SheetGestureFrame refs={gesture} canDrag={!layout.dragDisabled} bodyDrags={false !== o.scrollingExpandsSheet} className="g9-sheet__frame" style={{
|
|
230
238
|
...recede,
|
|
231
|
-
transition: g9SheetRecedeTransition
|
|
239
|
+
transition: g9SheetRecedeTransition()
|
|
232
240
|
}}>
|
|
233
241
|
<view className="g9-sheet__surface" {...g9IdProps(o.automationId)} style={{
|
|
234
242
|
backgroundColor: surface,
|
|
@@ -250,11 +258,29 @@ function G9SheetFrame(props) {
|
|
|
250
258
|
padding: `${null != (_o_padding = o.padding) ? _o_padding : 0}px`
|
|
251
259
|
}}>
|
|
252
260
|
{content}
|
|
253
|
-
</view> : <
|
|
261
|
+
</view> : indicator.current ? <view className={`g9-sheet__body-frame${layout.fillBody ? ' g9-sheet__body--fill' : ''}`}>
|
|
262
|
+
<scroll-view className={`g9-sheet__body${layout.fillBody ? ' g9-sheet__body--fill' : ''}`} scroll-orientation="vertical" main-thread:ref={gesture.body} main-thread:bindscroll={phone ? bodyGesture.onScrollMT : void 0} main-thread:bindtouchstart={bodyGesture.onTouchStartMT} scroll-event-throttle={16} {...endProps} bindscroll={(e)=>{
|
|
263
|
+
var _ref;
|
|
264
|
+
var _e_detail, _indicator_current;
|
|
265
|
+
return null == (_indicator_current = indicator.current) ? void 0 : _indicator_current.setTop(null != (_ref = null == (_e_detail = e.detail) ? void 0 : _e_detail.scrollTop) ? _ref : 0);
|
|
266
|
+
}} bindlayoutchange={(e)=>{
|
|
267
|
+
var _ref;
|
|
268
|
+
var _e_detail, _indicator_current;
|
|
269
|
+
return null == (_indicator_current = indicator.current) ? void 0 : _indicator_current.setViewport(null != (_ref = null == (_e_detail = e.detail) ? void 0 : _e_detail.height) ? _ref : 0);
|
|
270
|
+
}} style={{
|
|
254
271
|
padding: `${null != (_o_padding1 = o.padding) ? _o_padding1 : 0}px`,
|
|
255
272
|
...null !== maxBody ? {
|
|
256
273
|
maxHeight: `${maxBody}px`
|
|
257
274
|
} : {}
|
|
275
|
+
}}>
|
|
276
|
+
{content}
|
|
277
|
+
</scroll-view>
|
|
278
|
+
<G9SheetScrollIndicator model={indicator.current}/>
|
|
279
|
+
</view> : <scroll-view className={`g9-sheet__body${layout.fillBody ? ' g9-sheet__body--fill' : ''}`} scroll-orientation="vertical" main-thread:ref={gesture.body} main-thread:bindscroll={phone ? bodyGesture.onScrollMT : void 0} main-thread:bindtouchstart={bodyGesture.onTouchStartMT} {...endProps} style={{
|
|
280
|
+
padding: `${null != (_o_padding2 = o.padding) ? _o_padding2 : 0}px`,
|
|
281
|
+
...null !== maxBody ? {
|
|
282
|
+
maxHeight: `${maxBody}px`
|
|
283
|
+
} : {}
|
|
258
284
|
}}>
|
|
259
285
|
{content}
|
|
260
286
|
</scroll-view>}
|