@multiplatform.one/forms 7.65.2 → 7.67.0
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/cjs/FloatingPanel/RegularPanel.cjs +164 -0
- package/dist/cjs/FloatingPanel/RegularPanel.native.js +169 -0
- package/dist/cjs/FloatingPanel/RegularPanel.native.js.map +1 -0
- package/dist/cjs/FloatingPanel/compactFace.cjs +6 -0
- package/dist/cjs/FloatingPanel/compactFace.native.js +6 -0
- package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/containingBlock.cjs +46 -0
- package/dist/cjs/FloatingPanel/containingBlock.native.js +51 -0
- package/dist/cjs/FloatingPanel/containingBlock.native.js.map +1 -0
- package/dist/cjs/FloatingPanel/index.cjs +2 -20
- package/dist/cjs/FloatingPanel/index.native.js +79 -45
- package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/pointAnchor.cjs +25 -0
- package/dist/cjs/FloatingPanel/pointAnchor.native.js +26 -0
- package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/regularPlacement.cjs +61 -0
- package/dist/cjs/FloatingPanel/regularPlacement.native.js +65 -0
- package/dist/cjs/FloatingPanel/regularPlacement.native.js.map +1 -0
- package/dist/cjs/fields/Combobox/index.cjs +8 -10
- package/dist/cjs/fields/Combobox/index.native.js +10 -10
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/DatePicker/parts.cjs +1 -0
- package/dist/cjs/fields/DatePicker/parts.native.js +3 -0
- package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/Input/index.cjs +5 -0
- package/dist/cjs/fields/Input/index.native.js +5 -0
- package/dist/cjs/fields/Input/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/InlineChoices.cjs +3 -2
- package/dist/cjs/fields/Select/InlineChoices.native.js +5 -2
- package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Select/SheetPickerRow.cjs +154 -0
- package/dist/cjs/fields/Select/SheetPickerRow.native.js +165 -0
- package/dist/cjs/fields/Select/SheetPickerRow.native.js.map +1 -0
- package/dist/cjs/fields/Select/index.cjs +64 -5
- package/dist/cjs/fields/Select/index.native.js +86 -27
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.cjs +14 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js +15 -1
- package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/cjs/fields/Slider/index.cjs +96 -4
- package/dist/cjs/fields/Slider/index.native.js +103 -5
- package/dist/cjs/fields/Slider/index.native.js.map +1 -1
- package/dist/cjs/fields/Switch/index.cjs +71 -1
- package/dist/cjs/fields/Switch/index.native.js +72 -1
- package/dist/cjs/fields/Switch/index.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/parts.cjs +1 -0
- package/dist/cjs/fields/TimePicker/parts.native.js +1 -0
- package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/cjs/fields/ToggleGroup/index.cjs +67 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js +75 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +34 -19
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +44 -21
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/cjs/fields/nativeDateTime/sheetKeyboard.cjs +54 -0
- package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js +57 -0
- package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
- package/dist/cjs/index.cjs +11 -0
- package/dist/cjs/index.native.js +11 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/shared/overlaySizeClass.cjs +42 -0
- package/dist/cjs/shared/overlaySizeClass.native.js +45 -0
- package/dist/cjs/shared/overlaySizeClass.native.js.map +1 -0
- package/dist/cjs/shared/sheetNavigation.cjs +76 -0
- package/dist/cjs/shared/sheetNavigation.native.js +129 -0
- package/dist/cjs/shared/sheetNavigation.native.js.map +1 -0
- package/dist/cjs/shared/systemControlModules.cjs +34 -0
- package/dist/cjs/shared/systemControlModules.gnome.cjs +34 -0
- package/dist/cjs/shared/systemControlModules.gnome.native.js +37 -0
- package/dist/cjs/shared/systemControlModules.gnome.native.js.map +1 -0
- package/dist/cjs/shared/systemControlModules.native.js +77 -0
- package/dist/cjs/shared/systemControlModules.native.js.map +1 -0
- package/dist/cjs/shared/systemControls.cjs +47 -0
- package/dist/cjs/shared/systemControls.native.js +51 -0
- package/dist/cjs/shared/systemControls.native.js.map +1 -0
- package/dist/esm/FloatingPanel/RegularPanel.mjs +139 -0
- package/dist/esm/FloatingPanel/RegularPanel.mjs.map +1 -0
- package/dist/esm/FloatingPanel/RegularPanel.native.js +141 -0
- package/dist/esm/FloatingPanel/RegularPanel.native.js.map +1 -0
- package/dist/esm/FloatingPanel/compactFace.mjs +5 -1
- package/dist/esm/FloatingPanel/compactFace.mjs.map +1 -1
- package/dist/esm/FloatingPanel/compactFace.native.js +5 -1
- package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -1
- package/dist/esm/FloatingPanel/containingBlock.mjs +21 -0
- package/dist/esm/FloatingPanel/containingBlock.mjs.map +1 -0
- package/dist/esm/FloatingPanel/containingBlock.native.js +23 -0
- package/dist/esm/FloatingPanel/containingBlock.native.js.map +1 -0
- package/dist/esm/FloatingPanel/index.mjs +1 -19
- package/dist/esm/FloatingPanel/index.mjs.map +1 -1
- package/dist/esm/FloatingPanel/index.native.js +83 -49
- package/dist/esm/FloatingPanel/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/pointAnchor.mjs +25 -1
- package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/esm/FloatingPanel/pointAnchor.native.js +26 -1
- package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/esm/FloatingPanel/regularPlacement.mjs +35 -0
- package/dist/esm/FloatingPanel/regularPlacement.mjs.map +1 -0
- package/dist/esm/FloatingPanel/regularPlacement.native.js +36 -0
- package/dist/esm/FloatingPanel/regularPlacement.native.js.map +1 -0
- package/dist/esm/fields/Combobox/index.mjs +9 -11
- package/dist/esm/fields/Combobox/index.mjs.map +1 -1
- package/dist/esm/fields/Combobox/index.native.js +11 -11
- package/dist/esm/fields/Combobox/index.native.js.map +1 -1
- package/dist/esm/fields/DatePicker/parts.mjs +1 -0
- package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
- package/dist/esm/fields/DatePicker/parts.native.js +3 -0
- package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/esm/fields/Input/index.mjs +6 -1
- package/dist/esm/fields/Input/index.mjs.map +1 -1
- package/dist/esm/fields/Input/index.native.js +6 -1
- package/dist/esm/fields/Input/index.native.js.map +1 -1
- package/dist/esm/fields/Select/InlineChoices.mjs +3 -2
- package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -1
- package/dist/esm/fields/Select/InlineChoices.native.js +5 -2
- package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/esm/fields/Select/SheetPickerRow.mjs +129 -0
- package/dist/esm/fields/Select/SheetPickerRow.mjs.map +1 -0
- package/dist/esm/fields/Select/SheetPickerRow.native.js +137 -0
- package/dist/esm/fields/Select/SheetPickerRow.native.js.map +1 -0
- package/dist/esm/fields/Select/index.mjs +66 -7
- package/dist/esm/fields/Select/index.mjs.map +1 -1
- package/dist/esm/fields/Select/index.native.js +88 -29
- package/dist/esm/fields/Select/index.native.js.map +1 -1
- package/dist/esm/fields/Select/shouldInlineChoices.mjs +12 -1
- package/dist/esm/fields/Select/shouldInlineChoices.mjs.map +1 -1
- package/dist/esm/fields/Select/shouldInlineChoices.native.js +13 -1
- package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/esm/fields/Slider/index.mjs +96 -4
- package/dist/esm/fields/Slider/index.mjs.map +1 -1
- package/dist/esm/fields/Slider/index.native.js +103 -5
- package/dist/esm/fields/Slider/index.native.js.map +1 -1
- package/dist/esm/fields/Switch/index.mjs +71 -1
- package/dist/esm/fields/Switch/index.mjs.map +1 -1
- package/dist/esm/fields/Switch/index.native.js +72 -1
- package/dist/esm/fields/Switch/index.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/parts.mjs +1 -0
- package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
- package/dist/esm/fields/TimePicker/parts.native.js +1 -0
- package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/esm/fields/ToggleGroup/index.mjs +67 -1
- package/dist/esm/fields/ToggleGroup/index.mjs.map +1 -1
- package/dist/esm/fields/ToggleGroup/index.native.js +75 -1
- package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +36 -21
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +46 -23
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs +21 -0
- package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -0
- package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js +21 -0
- package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
- package/dist/esm/index.mjs +3 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/shared/overlaySizeClass.mjs +14 -0
- package/dist/esm/shared/overlaySizeClass.mjs.map +1 -0
- package/dist/esm/shared/overlaySizeClass.native.js +14 -0
- package/dist/esm/shared/overlaySizeClass.native.js.map +1 -0
- package/dist/esm/shared/sheetNavigation.mjs +47 -0
- package/dist/esm/shared/sheetNavigation.mjs.map +1 -0
- package/dist/esm/shared/sheetNavigation.native.js +97 -0
- package/dist/esm/shared/sheetNavigation.native.js.map +1 -0
- package/dist/esm/shared/systemControlModules.gnome.mjs +8 -0
- package/dist/esm/shared/systemControlModules.gnome.mjs.map +1 -0
- package/dist/esm/shared/systemControlModules.gnome.native.js +8 -0
- package/dist/esm/shared/systemControlModules.gnome.native.js.map +1 -0
- package/dist/esm/shared/systemControlModules.mjs +8 -0
- package/dist/esm/shared/systemControlModules.mjs.map +1 -0
- package/dist/esm/shared/systemControlModules.native.js +47 -0
- package/dist/esm/shared/systemControlModules.native.js.map +1 -0
- package/dist/esm/shared/systemControls.mjs +19 -0
- package/dist/esm/shared/systemControls.mjs.map +1 -0
- package/dist/esm/shared/systemControls.native.js +20 -0
- package/dist/esm/shared/systemControls.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/RegularPanel.mjs +139 -0
- package/dist/jsx/FloatingPanel/RegularPanel.mjs.map +1 -0
- package/dist/jsx/FloatingPanel/RegularPanel.native.js +169 -0
- package/dist/jsx/FloatingPanel/RegularPanel.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/compactFace.mjs +5 -1
- package/dist/jsx/FloatingPanel/compactFace.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/compactFace.native.js +6 -0
- package/dist/jsx/FloatingPanel/compactFace.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/containingBlock.mjs +21 -0
- package/dist/jsx/FloatingPanel/containingBlock.mjs.map +1 -0
- package/dist/jsx/FloatingPanel/containingBlock.native.js +51 -0
- package/dist/jsx/FloatingPanel/containingBlock.native.js.map +1 -0
- package/dist/jsx/FloatingPanel/index.mjs +1 -19
- package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/index.native.js +79 -45
- package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/pointAnchor.mjs +25 -1
- package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/pointAnchor.native.js +26 -0
- package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/regularPlacement.mjs +35 -0
- package/dist/jsx/FloatingPanel/regularPlacement.mjs.map +1 -0
- package/dist/jsx/FloatingPanel/regularPlacement.native.js +65 -0
- package/dist/jsx/FloatingPanel/regularPlacement.native.js.map +1 -0
- package/dist/jsx/fields/Combobox/index.mjs +9 -11
- package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
- package/dist/jsx/fields/Combobox/index.native.js +10 -10
- package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
- package/dist/jsx/fields/DatePicker/parts.mjs +1 -0
- package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
- package/dist/jsx/fields/DatePicker/parts.native.js +3 -0
- package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
- package/dist/jsx/fields/Input/index.mjs +6 -1
- package/dist/jsx/fields/Input/index.mjs.map +1 -1
- package/dist/jsx/fields/Input/index.native.js +5 -0
- package/dist/jsx/fields/Input/index.native.js.map +1 -1
- package/dist/jsx/fields/Select/InlineChoices.mjs +3 -2
- package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -1
- package/dist/jsx/fields/Select/InlineChoices.native.js +5 -2
- package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -1
- package/dist/jsx/fields/Select/SheetPickerRow.mjs +129 -0
- package/dist/jsx/fields/Select/SheetPickerRow.mjs.map +1 -0
- package/dist/jsx/fields/Select/SheetPickerRow.native.js +165 -0
- package/dist/jsx/fields/Select/SheetPickerRow.native.js.map +1 -0
- package/dist/jsx/fields/Select/index.mjs +66 -7
- package/dist/jsx/fields/Select/index.mjs.map +1 -1
- package/dist/jsx/fields/Select/index.native.js +86 -27
- package/dist/jsx/fields/Select/index.native.js.map +1 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.mjs +12 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.mjs.map +1 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.native.js +15 -1
- package/dist/jsx/fields/Select/shouldInlineChoices.native.js.map +1 -1
- package/dist/jsx/fields/Slider/index.mjs +96 -4
- package/dist/jsx/fields/Slider/index.mjs.map +1 -1
- package/dist/jsx/fields/Slider/index.native.js +103 -5
- package/dist/jsx/fields/Slider/index.native.js.map +1 -1
- package/dist/jsx/fields/Switch/index.mjs +71 -1
- package/dist/jsx/fields/Switch/index.mjs.map +1 -1
- package/dist/jsx/fields/Switch/index.native.js +72 -1
- package/dist/jsx/fields/Switch/index.native.js.map +1 -1
- package/dist/jsx/fields/TimePicker/parts.mjs +1 -0
- package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
- package/dist/jsx/fields/TimePicker/parts.native.js +1 -0
- package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
- package/dist/jsx/fields/ToggleGroup/index.mjs +67 -1
- package/dist/jsx/fields/ToggleGroup/index.mjs.map +1 -1
- package/dist/jsx/fields/ToggleGroup/index.native.js +75 -1
- package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +36 -21
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +44 -21
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
- package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs +21 -0
- package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -0
- package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js +57 -0
- package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
- package/dist/jsx/index.js +3 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +3 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +11 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/shared/overlaySizeClass.mjs +14 -0
- package/dist/jsx/shared/overlaySizeClass.mjs.map +1 -0
- package/dist/jsx/shared/overlaySizeClass.native.js +45 -0
- package/dist/jsx/shared/overlaySizeClass.native.js.map +1 -0
- package/dist/jsx/shared/sheetNavigation.mjs +47 -0
- package/dist/jsx/shared/sheetNavigation.mjs.map +1 -0
- package/dist/jsx/shared/sheetNavigation.native.js +129 -0
- package/dist/jsx/shared/sheetNavigation.native.js.map +1 -0
- package/dist/jsx/shared/systemControlModules.gnome.mjs +8 -0
- package/dist/jsx/shared/systemControlModules.gnome.mjs.map +1 -0
- package/dist/jsx/shared/systemControlModules.gnome.native.js +37 -0
- package/dist/jsx/shared/systemControlModules.gnome.native.js.map +1 -0
- package/dist/jsx/shared/systemControlModules.mjs +8 -0
- package/dist/jsx/shared/systemControlModules.mjs.map +1 -0
- package/dist/jsx/shared/systemControlModules.native.js +77 -0
- package/dist/jsx/shared/systemControlModules.native.js.map +1 -0
- package/dist/jsx/shared/systemControls.mjs +19 -0
- package/dist/jsx/shared/systemControls.mjs.map +1 -0
- package/dist/jsx/shared/systemControls.native.js +51 -0
- package/dist/jsx/shared/systemControls.native.js.map +1 -0
- package/package.json +16 -8
- package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +73 -3
- package/src/FloatingPanel/FloatingPanel.regularWidth.native.spec.tsx +193 -0
- package/src/FloatingPanel/RegularPanel.tsx +159 -0
- package/src/FloatingPanel/compactFace.spec.ts +24 -1
- package/src/FloatingPanel/compactFace.ts +16 -0
- package/src/FloatingPanel/containingBlock.ts +32 -0
- package/src/FloatingPanel/index.native.tsx +80 -35
- package/src/FloatingPanel/index.tsx +1 -33
- package/src/FloatingPanel/pointAnchor.spec.ts +29 -0
- package/src/FloatingPanel/pointAnchor.ts +30 -0
- package/src/FloatingPanel/regularPlacement.spec.ts +65 -0
- package/src/FloatingPanel/regularPlacement.ts +40 -0
- package/src/fields/Combobox/Combobox.regularWidth.native.spec.tsx +94 -0
- package/src/fields/Combobox/index.tsx +11 -34
- package/src/fields/DatePicker/parts.tsx +3 -0
- package/src/fields/DatePicker/touchWeb.spec.tsx +13 -0
- package/src/fields/Input/Input.formName.spec.tsx +53 -0
- package/src/fields/Input/index.tsx +6 -1
- package/src/fields/Select/InlineChoices.tsx +6 -3
- package/src/fields/Select/SheetPickerRow.tsx +160 -0
- package/src/fields/Select/index.tsx +67 -5
- package/src/fields/Select/shouldInlineChoices.spec.ts +21 -1
- package/src/fields/Select/shouldInlineChoices.ts +26 -0
- package/src/fields/Slider/Slider.system.native.spec.tsx +168 -0
- package/src/fields/Slider/index.tsx +166 -30
- package/src/fields/Switch/Switch.system.native.spec.tsx +162 -0
- package/src/fields/Switch/index.tsx +98 -0
- package/src/fields/TimePicker/parts.tsx +1 -0
- package/src/fields/ToggleGroup/ToggleGroup.system.native.spec.tsx +192 -0
- package/src/fields/ToggleGroup/index.tsx +111 -0
- package/src/fields/nativeDateTime/OsDateTimeSheet.presentation.spec.tsx +167 -0
- package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +36 -18
- package/src/fields/nativeDateTime/sheetKeyboard.spec.ts +60 -0
- package/src/fields/nativeDateTime/sheetKeyboard.ts +45 -0
- package/src/index.ts +15 -0
- package/src/shared/overlaySizeClass.spec.ts +27 -0
- package/src/shared/overlaySizeClass.ts +36 -0
- package/src/shared/sheetNavigation.ts +82 -0
- package/src/shared/systemControlModules.gnome.ts +10 -0
- package/src/shared/systemControlModules.native.spec.ts +52 -0
- package/src/shared/systemControlModules.native.ts +66 -0
- package/src/shared/systemControlModules.ts +10 -0
- package/src/shared/systemControls.ts +70 -0
- package/types/FloatingPanel/RegularPanel.d.ts +29 -0
- package/types/FloatingPanel/RegularPanel.d.ts.map +1 -0
- package/types/FloatingPanel/compactFace.d.ts +12 -0
- package/types/FloatingPanel/compactFace.d.ts.map +1 -1
- package/types/FloatingPanel/containingBlock.d.ts +14 -0
- package/types/FloatingPanel/containingBlock.d.ts.map +1 -0
- package/types/FloatingPanel/index.d.ts.map +1 -1
- package/types/FloatingPanel/index.native.d.ts +6 -1
- package/types/FloatingPanel/index.native.d.ts.map +1 -1
- package/types/FloatingPanel/pointAnchor.d.ts +12 -0
- package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
- package/types/FloatingPanel/regularPlacement.d.ts +20 -0
- package/types/FloatingPanel/regularPlacement.d.ts.map +1 -0
- package/types/fields/Combobox/index.d.ts.map +1 -1
- package/types/fields/DatePicker/parts.d.ts.map +1 -1
- package/types/fields/Input/index.d.ts.map +1 -1
- package/types/fields/Select/InlineChoices.d.ts.map +1 -1
- package/types/fields/Select/SheetPickerRow.d.ts +23 -0
- package/types/fields/Select/SheetPickerRow.d.ts.map +1 -0
- package/types/fields/Select/index.d.ts.map +1 -1
- package/types/fields/Select/shouldInlineChoices.d.ts +15 -0
- package/types/fields/Select/shouldInlineChoices.d.ts.map +1 -1
- package/types/fields/Slider/index.d.ts +7 -1
- package/types/fields/Slider/index.d.ts.map +1 -1
- package/types/fields/Switch/index.d.ts +7 -1
- package/types/fields/Switch/index.d.ts.map +1 -1
- package/types/fields/TimePicker/parts.d.ts.map +1 -1
- package/types/fields/ToggleGroup/index.d.ts +8 -1
- package/types/fields/ToggleGroup/index.d.ts.map +1 -1
- package/types/fields/nativeDateTime/OsDateTimeSheet.d.ts.map +1 -1
- package/types/fields/nativeDateTime/sheetKeyboard.d.ts +20 -0
- package/types/fields/nativeDateTime/sheetKeyboard.d.ts.map +1 -0
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -1
- package/types/shared/overlaySizeClass.d.ts +24 -0
- package/types/shared/overlaySizeClass.d.ts.map +1 -0
- package/types/shared/sheetNavigation.d.ts +31 -0
- package/types/shared/sheetNavigation.d.ts.map +1 -0
- package/types/shared/systemControlModules.d.ts +5 -0
- package/types/shared/systemControlModules.d.ts.map +1 -0
- package/types/shared/systemControlModules.gnome.d.ts +5 -0
- package/types/shared/systemControlModules.gnome.d.ts.map +1 -0
- package/types/shared/systemControlModules.native.d.ts +20 -0
- package/types/shared/systemControlModules.native.d.ts.map +1 -0
- package/types/shared/systemControls.d.ts +53 -0
- package/types/shared/systemControls.d.ts.map +1 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FZ-8116 (LC-266): the window's size class picks the native FloatingPanel's
|
|
3
|
+
* form. At regular width (an iPad, a wide Android window) a picker opens over
|
|
4
|
+
* its field the way the web float does; at compact width (iPhone, Slide Over)
|
|
5
|
+
* it keeps the bottom sheet.
|
|
6
|
+
*/
|
|
7
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
8
|
+
import { act } from "@testing-library/react";
|
|
9
|
+
import { useState, type ReactNode } from "react";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { Text } from "tamagui";
|
|
12
|
+
import { FloatingPanel } from "./index.native";
|
|
13
|
+
import type { FloatingPanelProps } from "./index";
|
|
14
|
+
import { regularFillHeight } from "./regularPlacement";
|
|
15
|
+
import { panelViewportPadding } from "./useFloatingPanel";
|
|
16
|
+
|
|
17
|
+
const screen = vi.hoisted(() => ({ width: 820, height: 1180 }));
|
|
18
|
+
vi.mock("react-native-web", async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal<typeof import("react-native")>();
|
|
20
|
+
return {
|
|
21
|
+
...actual,
|
|
22
|
+
ActionSheetIOS: undefined,
|
|
23
|
+
Modal: ({ children, visible }: { children: ReactNode; visible: boolean }) =>
|
|
24
|
+
visible ? children : null,
|
|
25
|
+
useWindowDimensions: () => ({ ...screen, scale: 2, fontScale: 1 }),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
let field = { x: 40, y: 300, width: 360, height: 44 };
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
vi.useFakeTimers();
|
|
32
|
+
field = { x: 40, y: 300, width: 360, height: 44 };
|
|
33
|
+
vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(() => ({
|
|
34
|
+
x: field.x,
|
|
35
|
+
y: field.y,
|
|
36
|
+
left: field.x,
|
|
37
|
+
top: field.y,
|
|
38
|
+
width: field.width,
|
|
39
|
+
height: field.height,
|
|
40
|
+
right: field.x + field.width,
|
|
41
|
+
bottom: field.y + field.height,
|
|
42
|
+
toJSON: () => ({}),
|
|
43
|
+
}));
|
|
44
|
+
});
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
vi.useRealTimers();
|
|
48
|
+
screen.width = 820;
|
|
49
|
+
screen.height = 1180;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function Picker(props: Partial<FloatingPanelProps>) {
|
|
53
|
+
const [open, setOpen] = useState(false);
|
|
54
|
+
return (
|
|
55
|
+
<FloatingPanel
|
|
56
|
+
open={open}
|
|
57
|
+
onOpenChange={setOpen}
|
|
58
|
+
trigger={<Text>Colour</Text>}
|
|
59
|
+
triggerA11y={{ label: "Colour" }}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
<Text>Red</Text>
|
|
63
|
+
<Text>Green</Text>
|
|
64
|
+
</FloatingPanel>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function tap(target: Element) {
|
|
69
|
+
act(() => {
|
|
70
|
+
target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, button: 0 }));
|
|
71
|
+
target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, button: 0 }));
|
|
72
|
+
target.dispatchEvent(new MouseEvent("click", { bubbles: true, button: 0 }));
|
|
73
|
+
});
|
|
74
|
+
act(() => {
|
|
75
|
+
vi.advanceTimersByTime(1);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function layout(node: Element, width: number, height: number) {
|
|
80
|
+
const onLayout = (node as unknown as { __reactLayoutHandler?: (event: unknown) => void })
|
|
81
|
+
.__reactLayoutHandler;
|
|
82
|
+
expect(onLayout).toBeTypeOf("function");
|
|
83
|
+
act(() => {
|
|
84
|
+
onLayout?.({ nativeEvent: { layout: { x: 0, y: 0, width, height } } });
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const regular = () => document.querySelector<HTMLElement>('[data-testid="floating-panel-regular"]');
|
|
89
|
+
const sheet = () => document.querySelector('[data-testid="floating-panel-sheet"]');
|
|
90
|
+
const echo = () =>
|
|
91
|
+
document.querySelector<HTMLElement>('[data-testid="floating-panel-regular-echo"]');
|
|
92
|
+
const scroll = () => document.querySelector('[data-testid="floating-panel-regular-scroll"]');
|
|
93
|
+
|
|
94
|
+
function open(props: Partial<FloatingPanelProps> = {}) {
|
|
95
|
+
const result = renderWithProviders(<Picker {...props} />);
|
|
96
|
+
tap(result.getByRole("button", { name: "Colour" }));
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
describe("FloatingPanel native at regular width (FZ-8116)", () => {
|
|
101
|
+
it("opens over its field on an iPad-wide window, not as a bottom sheet", () => {
|
|
102
|
+
open();
|
|
103
|
+
const panel = regular();
|
|
104
|
+
expect(panel).not.toBeNull();
|
|
105
|
+
expect(sheet()).toBeNull();
|
|
106
|
+
expect(panel?.style.opacity).toBe("0");
|
|
107
|
+
layout(panel as HTMLElement, 240, 200);
|
|
108
|
+
expect(panel?.style.left).toBe("40px");
|
|
109
|
+
expect(panel?.style.top).toBe("300px");
|
|
110
|
+
expect(panel?.style.opacity).toBe("1");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("keeps its shadow: an inner view clips, not the elevated surface", () => {
|
|
114
|
+
open();
|
|
115
|
+
const surface = document.querySelector('[data-testid="floating-panel-regular-surface"]');
|
|
116
|
+
const clip = document.querySelector('[data-testid="floating-panel-regular-clip"]');
|
|
117
|
+
expect(surface?.contains(clip)).toBe(true);
|
|
118
|
+
expect(surface?.className).not.toContain("_ox-hidden");
|
|
119
|
+
expect(clip?.className).toContain("_ox-hidden");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("is at least the field's width by default", () => {
|
|
123
|
+
open();
|
|
124
|
+
expect(regular()?.style.minWidth).toBe("360px");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("is the field's width exactly for match-trigger", () => {
|
|
128
|
+
open({ widthMode: "match-trigger" });
|
|
129
|
+
expect(regular()?.style.width).toBe("360px");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("hugs its content for fit-content, from the field's start edge", () => {
|
|
133
|
+
open({ widthMode: "fit-content" });
|
|
134
|
+
const panel = regular() as HTMLElement;
|
|
135
|
+
expect(panel.style.minWidth).toBe("");
|
|
136
|
+
expect(panel.style.width).toBe("");
|
|
137
|
+
layout(panel, 300, 320);
|
|
138
|
+
expect(panel.style.left).toBe("40px");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("echoes the field as its first row, and pressing it closes the panel", () => {
|
|
142
|
+
open();
|
|
143
|
+
const row = echo() as HTMLElement;
|
|
144
|
+
expect(row.textContent).toBe("Colour");
|
|
145
|
+
expect(row.style.height).toBe("44px");
|
|
146
|
+
act(() => {
|
|
147
|
+
vi.advanceTimersByTime(1000);
|
|
148
|
+
});
|
|
149
|
+
tap(row);
|
|
150
|
+
expect(regular()).toBeNull();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("slides up inside the padded window when the field sits near the bottom", () => {
|
|
154
|
+
field = { x: 40, y: 1080, width: 360, height: 44 };
|
|
155
|
+
open();
|
|
156
|
+
const panel = regular() as HTMLElement;
|
|
157
|
+
layout(panel, 360, 300);
|
|
158
|
+
const top = parseFloat(panel.style.top);
|
|
159
|
+
expect(top + 300).toBeLessThanOrEqual(1180 - panelViewportPadding);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("gives a gesture editor no scrollport (LC-83)", () => {
|
|
163
|
+
open();
|
|
164
|
+
expect(scroll()).toBeNull();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("scrolls a scrollable list", () => {
|
|
168
|
+
open({ scrollable: true });
|
|
169
|
+
expect(scroll()).not.toBeNull();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("opens a search list (sheetFill) at a definite height", () => {
|
|
173
|
+
open({ scrollable: true, sheetFill: true });
|
|
174
|
+
expect(regular()?.style.height).toBe(`${regularFillHeight}px`);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("keeps the bottom sheet when the caller forces it", () => {
|
|
178
|
+
open({ sheet: true });
|
|
179
|
+
expect(regular()).toBeNull();
|
|
180
|
+
expect(sheet()).not.toBeNull();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it.each([
|
|
184
|
+
["an iPhone", 390, 844],
|
|
185
|
+
["iPad Slide Over", 320, 1180],
|
|
186
|
+
])("keeps the bottom sheet on %s", (_name, width, height) => {
|
|
187
|
+
screen.width = width;
|
|
188
|
+
screen.height = height;
|
|
189
|
+
open();
|
|
190
|
+
expect(regular()).toBeNull();
|
|
191
|
+
expect(sheet()).not.toBeNull();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
2
|
+
import { type ReactNode, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
I18nManager,
|
|
5
|
+
Pressable,
|
|
6
|
+
ScrollView as RNScrollView,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
View as RNView,
|
|
9
|
+
} from "react-native";
|
|
10
|
+
import { YStack } from "tamagui";
|
|
11
|
+
import { t } from "../shared/t";
|
|
12
|
+
import type { PanelBounds, TriggerRect } from "./pointAnchor";
|
|
13
|
+
import { placeRegularPanel, regularFillHeight } from "./regularPlacement";
|
|
14
|
+
import type { PanelWidthMode } from "./useFloatingPanel";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A FloatingPanel at regular width (FZ-8116): over its field instead of a
|
|
18
|
+
* bottom sheet. Measured once per open at its natural size, then placed on
|
|
19
|
+
* the field's window rect. The field is echoed as the first row, as the web
|
|
20
|
+
* float's named close row is, and pressing it closes the panel.
|
|
21
|
+
*
|
|
22
|
+
* Only a `scrollable` panel gets a scrollport: a gesture editor (ColorPicker,
|
|
23
|
+
* DatePicker) must take its own drags (LC-83).
|
|
24
|
+
*/
|
|
25
|
+
export function RegularPanel({
|
|
26
|
+
anchor,
|
|
27
|
+
bounds,
|
|
28
|
+
widthMode,
|
|
29
|
+
echo,
|
|
30
|
+
echoLabel,
|
|
31
|
+
header,
|
|
32
|
+
scrollable,
|
|
33
|
+
fill,
|
|
34
|
+
scrollViewProps,
|
|
35
|
+
framePadding,
|
|
36
|
+
frameGap,
|
|
37
|
+
onBackdropPress,
|
|
38
|
+
onClose,
|
|
39
|
+
children,
|
|
40
|
+
}: {
|
|
41
|
+
anchor: TriggerRect | null;
|
|
42
|
+
bounds: PanelBounds;
|
|
43
|
+
widthMode: PanelWidthMode;
|
|
44
|
+
echo: ReactNode;
|
|
45
|
+
echoLabel?: string;
|
|
46
|
+
header?: ReactNode;
|
|
47
|
+
scrollable: boolean;
|
|
48
|
+
fill: boolean;
|
|
49
|
+
scrollViewProps?: Record<string, unknown>;
|
|
50
|
+
framePadding: string;
|
|
51
|
+
frameGap: string | undefined;
|
|
52
|
+
onBackdropPress: () => void;
|
|
53
|
+
onClose: () => void;
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
}) {
|
|
56
|
+
const { knobProps } = useResolvedKnobs({ painted: false });
|
|
57
|
+
const [size, setSize] = useState<{ width: number; height: number } | null>(null);
|
|
58
|
+
const room = Math.max(0, bounds.bottom - bounds.top);
|
|
59
|
+
const fillHeight = fill ? Math.min(regularFillHeight, room) : undefined;
|
|
60
|
+
const placement =
|
|
61
|
+
anchor && size
|
|
62
|
+
? placeRegularPanel({
|
|
63
|
+
trigger: anchor,
|
|
64
|
+
width: size.width,
|
|
65
|
+
height: fillHeight ?? size.height,
|
|
66
|
+
bounds,
|
|
67
|
+
widthMode,
|
|
68
|
+
rtl: I18nManager.isRTL,
|
|
69
|
+
})
|
|
70
|
+
: null;
|
|
71
|
+
const widthStyle =
|
|
72
|
+
widthMode === "match-trigger"
|
|
73
|
+
? { width: anchor?.width }
|
|
74
|
+
: widthMode === "at-least-trigger"
|
|
75
|
+
? { minWidth: anchor?.width ?? 0 }
|
|
76
|
+
: undefined;
|
|
77
|
+
const echoRow =
|
|
78
|
+
echo != null && anchor && anchor.height > 0 ? (
|
|
79
|
+
<Pressable
|
|
80
|
+
testID="floating-panel-regular-echo"
|
|
81
|
+
onPress={onClose}
|
|
82
|
+
accessibilityRole="button"
|
|
83
|
+
{...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
|
|
84
|
+
aria-expanded
|
|
85
|
+
style={{ height: anchor.height, justifyContent: "center" }}
|
|
86
|
+
>
|
|
87
|
+
<RNView pointerEvents="none">{echo}</RNView>
|
|
88
|
+
</Pressable>
|
|
89
|
+
) : null;
|
|
90
|
+
return (
|
|
91
|
+
<RNView style={StyleSheet.absoluteFill}>
|
|
92
|
+
<Pressable
|
|
93
|
+
style={StyleSheet.absoluteFill}
|
|
94
|
+
onPress={onBackdropPress}
|
|
95
|
+
accessibilityRole="button"
|
|
96
|
+
accessibilityLabel={t("Close")}
|
|
97
|
+
/>
|
|
98
|
+
<RNView
|
|
99
|
+
testID="floating-panel-regular"
|
|
100
|
+
onLayout={(e) => {
|
|
101
|
+
if (size) return;
|
|
102
|
+
const { width, height } = e.nativeEvent.layout;
|
|
103
|
+
if (width > 0 && height > 0) setSize({ width, height });
|
|
104
|
+
}}
|
|
105
|
+
style={{
|
|
106
|
+
position: "absolute",
|
|
107
|
+
left: placement?.left ?? bounds.left,
|
|
108
|
+
top: placement?.top ?? bounds.top,
|
|
109
|
+
...widthStyle,
|
|
110
|
+
maxWidth: bounds.right - bounds.left,
|
|
111
|
+
maxHeight: placement?.maxHeight ?? room,
|
|
112
|
+
...(fillHeight ? { height: Math.min(fillHeight, placement?.maxHeight ?? room) } : null),
|
|
113
|
+
opacity: placement ? 1 : 0,
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<YStack
|
|
117
|
+
testID="floating-panel-regular-surface"
|
|
118
|
+
{...knobProps.elevatedSurface}
|
|
119
|
+
flexShrink={1}
|
|
120
|
+
minHeight={0}
|
|
121
|
+
{...(fill ? { flex: 1 } : undefined)}
|
|
122
|
+
onAccessibilityEscape={onClose}
|
|
123
|
+
>
|
|
124
|
+
<YStack
|
|
125
|
+
testID="floating-panel-regular-clip"
|
|
126
|
+
borderRadius={knobProps.elevatedSurface.borderRadius}
|
|
127
|
+
overflow="hidden"
|
|
128
|
+
flexShrink={1}
|
|
129
|
+
minHeight={0}
|
|
130
|
+
{...(fill ? { flex: 1 } : undefined)}
|
|
131
|
+
>
|
|
132
|
+
{echoRow}
|
|
133
|
+
<YStack
|
|
134
|
+
padding={framePadding}
|
|
135
|
+
gap={frameGap}
|
|
136
|
+
flexShrink={1}
|
|
137
|
+
minHeight={0}
|
|
138
|
+
{...(fill ? { flex: 1 } : undefined)}
|
|
139
|
+
>
|
|
140
|
+
{header}
|
|
141
|
+
{scrollable ? (
|
|
142
|
+
<RNScrollView
|
|
143
|
+
testID="floating-panel-regular-scroll"
|
|
144
|
+
style={fill ? { flex: 1 } : { flexGrow: 0, flexShrink: 1 }}
|
|
145
|
+
keyboardShouldPersistTaps="handled"
|
|
146
|
+
{...(scrollViewProps as object)}
|
|
147
|
+
>
|
|
148
|
+
{children}
|
|
149
|
+
</RNScrollView>
|
|
150
|
+
) : (
|
|
151
|
+
children
|
|
152
|
+
)}
|
|
153
|
+
</YStack>
|
|
154
|
+
</YStack>
|
|
155
|
+
</YStack>
|
|
156
|
+
</RNView>
|
|
157
|
+
</RNView>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
MENU_MIN_WIDTH,
|
|
4
|
+
menuMinWidth,
|
|
5
|
+
pickerCompactFace,
|
|
6
|
+
resolveCompactFace,
|
|
7
|
+
SHORT_LIST_MAX,
|
|
8
|
+
} from "./compactFace";
|
|
3
9
|
|
|
4
10
|
describe("resolveCompactFace (FZ-7830)", () => {
|
|
5
11
|
it("keeps the sheet by default, at page level and inside an overlay", () => {
|
|
@@ -38,3 +44,20 @@ describe("pickerCompactFace (FZ-7830)", () => {
|
|
|
38
44
|
expect(resolveCompactFace(pickerCompactFace(3, true), false)).toBe("sheet");
|
|
39
45
|
});
|
|
40
46
|
});
|
|
47
|
+
|
|
48
|
+
describe("menuMinWidth (FZ-8220)", () => {
|
|
49
|
+
it("never opens a menu narrower than the platform floor", () => {
|
|
50
|
+
expect(menuMinWidth(44, 370)).toBe(MENU_MIN_WIDTH);
|
|
51
|
+
expect(menuMinWidth(0, 370)).toBe(MENU_MIN_WIDTH);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("keeps a wider trigger's width", () => {
|
|
55
|
+
expect(menuMinWidth(320, 370)).toBe(320);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("clamps to the room between the screen's margins", () => {
|
|
59
|
+
expect(menuMinWidth(44, 220)).toBe(220);
|
|
60
|
+
expect(menuMinWidth(400, 370)).toBe(370);
|
|
61
|
+
expect(menuMinWidth(44, -5)).toBe(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -30,3 +30,19 @@ export const SHORT_LIST_MAX = 7;
|
|
|
30
30
|
export function pickerCompactFace(optionCount: number, searchable = false): CompactFace {
|
|
31
31
|
return !searchable && optionCount <= SHORT_LIST_MAX ? "menu" : "auto";
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The narrowest a menu-faced panel opens on native (FZ-8220): the iOS
|
|
36
|
+
* pull-down's floor, inside Material's 112–280 menu range. A menu's rows
|
|
37
|
+
* fill their width and have none of their own, so without a floor the panel
|
|
38
|
+
* took its trigger's width and an avatar's 44pt squeezed the text away.
|
|
39
|
+
*/
|
|
40
|
+
export const MENU_MIN_WIDTH = 250;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A menu face's minimum width: at least its trigger and the platform floor,
|
|
44
|
+
* never wider than the room between the screen's margins.
|
|
45
|
+
*/
|
|
46
|
+
export function menuMinWidth(triggerWidth: number, availableWidth: number): number {
|
|
47
|
+
return Math.max(0, Math.min(Math.max(triggerWidth, MENU_MIN_WIDTH), availableWidth));
|
|
48
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewport origin of the box a `position: fixed` panel is laid out against.
|
|
3
|
+
* The top/left math is in viewport coordinates, which is only right while that
|
|
4
|
+
* box is the viewport. An ancestor with a transform, filter, perspective,
|
|
5
|
+
* paint containment or container query becomes the containing block instead.
|
|
6
|
+
* PanelPortal lifts the panel out of scroll views, but a panel hosted in a
|
|
7
|
+
* transformed dialog still lays out against that dialog. A `display: contents`
|
|
8
|
+
* node has no box, so its computed `contain` (Tamagui's theme span) is ignored.
|
|
9
|
+
*/
|
|
10
|
+
export function fixedContainingBlockOrigin(element: HTMLElement): { top: number; left: number } {
|
|
11
|
+
for (let node = element.parentElement; node; node = node.parentElement) {
|
|
12
|
+
const cs = getComputedStyle(node);
|
|
13
|
+
if (cs.display === "contents") continue;
|
|
14
|
+
const set = (value: string | undefined, initial: string) => !!value && value !== initial;
|
|
15
|
+
const captures =
|
|
16
|
+
set(cs.transform, "none") ||
|
|
17
|
+
set(cs.perspective, "none") ||
|
|
18
|
+
set(cs.filter, "none") ||
|
|
19
|
+
set(cs.backdropFilter, "none") ||
|
|
20
|
+
set(cs.containerType, "normal") ||
|
|
21
|
+
/transform|perspective|filter/.test(cs.willChange) ||
|
|
22
|
+
/paint|layout|strict|content/.test(cs.contain);
|
|
23
|
+
if (captures) {
|
|
24
|
+
const rect = node.getBoundingClientRect();
|
|
25
|
+
return {
|
|
26
|
+
top: rect.top + node.clientTop - node.scrollTop,
|
|
27
|
+
left: rect.left + node.clientLeft - node.scrollLeft,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { top: 0, left: 0 };
|
|
32
|
+
}
|
|
@@ -55,6 +55,11 @@
|
|
|
55
55
|
* than OVERLAY_BREAKPOINT (a tablet) it opens at the long-press point, the
|
|
56
56
|
* same free overlay the web draws at the pointer; a phone keeps the sheet,
|
|
57
57
|
* as web does at ≤640.
|
|
58
|
+
*
|
|
59
|
+
* Regular width (FZ-8116, LC-266): on an iPad or any window wider than
|
|
60
|
+
* OVERLAY_BREAKPOINT the sheet is the wrong form. The panel opens over its
|
|
61
|
+
* field the way the web float does (LC-105, LC-112), sized by `widthMode`;
|
|
62
|
+
* compact windows (iPhone, Slide Over) keep the sheet. `sheet` forces it.
|
|
58
63
|
*/
|
|
59
64
|
|
|
60
65
|
import { nativeAnimationConfig, type MotionStop } from "@multiplatform.one/theme";
|
|
@@ -83,27 +88,25 @@ import {
|
|
|
83
88
|
type GestureResponderEvent,
|
|
84
89
|
} from "react-native";
|
|
85
90
|
import { SafeAreaInsetsContext, initialWindowMetrics } from "react-native-safe-area-context";
|
|
86
|
-
import {
|
|
87
|
-
OVERLAY_BREAKPOINT,
|
|
88
|
-
Surface,
|
|
89
|
-
useResolvedKnobs,
|
|
90
|
-
motionDurationMs,
|
|
91
|
-
} from "@multiplatform.one/theme";
|
|
91
|
+
import { Surface, useResolvedKnobs, motionDurationMs } from "@multiplatform.one/theme";
|
|
92
92
|
import { View, YStack } from "tamagui";
|
|
93
93
|
import { useInsideOverlay, useOverlayZIndex } from "../shared/overlayStack";
|
|
94
94
|
import { OverlayWindow } from "../shared/OverlayWindow";
|
|
95
95
|
import { t } from "../shared/t";
|
|
96
|
+
import { overlaySizeClass } from "../shared/overlaySizeClass";
|
|
96
97
|
import { useKeyboardInset } from "../shared/useKeyboardInset";
|
|
97
98
|
import type { FloatingPanelProps } from "./index";
|
|
98
|
-
import { resolveCompactFace } from "./compactFace";
|
|
99
|
+
import { menuMinWidth, resolveCompactFace } from "./compactFace";
|
|
99
100
|
import {
|
|
100
101
|
placeAtPoint,
|
|
102
|
+
placeBesideTrigger,
|
|
101
103
|
placeOverTrigger,
|
|
102
104
|
type PanelBounds,
|
|
103
105
|
type PanelPoint,
|
|
104
106
|
type TriggerRect,
|
|
105
107
|
} from "./pointAnchor";
|
|
106
|
-
import {
|
|
108
|
+
import { RegularPanel } from "./RegularPanel";
|
|
109
|
+
import { panelViewportPadding, resolvePanelWidthMode } from "./useFloatingPanel";
|
|
107
110
|
import { TrailingActionOverlay, TriggerWithTrailingAction } from "./trailingAction";
|
|
108
111
|
|
|
109
112
|
// Re-export the hook + constants so Select / Combobox / external consumers
|
|
@@ -160,6 +163,9 @@ export function FloatingPanel({
|
|
|
160
163
|
triggerRow,
|
|
161
164
|
triggerEcho = true,
|
|
162
165
|
anchorMode,
|
|
166
|
+
sheet,
|
|
167
|
+
widthMode,
|
|
168
|
+
fitContent,
|
|
163
169
|
}: FloatingPanelProps) {
|
|
164
170
|
// The panel floats over the page: it never inherits a painted ancestor.
|
|
165
171
|
const { knobProps } = useResolvedKnobs({ painted: false });
|
|
@@ -202,15 +208,18 @@ export function FloatingPanel({
|
|
|
202
208
|
[disabled, onOpenChange],
|
|
203
209
|
);
|
|
204
210
|
const isContextMenu = openOn === "contextmenu";
|
|
205
|
-
const
|
|
211
|
+
const regular = overlaySizeClass(windowWidth) === "regular";
|
|
212
|
+
const atPoint = isContextMenu && pressPoint !== null && regular;
|
|
206
213
|
const insideOverlay = useInsideOverlay();
|
|
207
214
|
const asMenu = !isContextMenu && resolveCompactFace(compactFace, insideOverlay) === "menu";
|
|
215
|
+
const asRegular = regular && !asMenu && !isContextMenu && sheet !== true;
|
|
216
|
+
const anchored = asMenu || asRegular;
|
|
208
217
|
const triggerRef = useRef<RNView | null>(null);
|
|
209
218
|
const [anchor, setAnchor] = useState<TriggerRect | null>(null);
|
|
210
219
|
// The trigger's window rect, read each time the menu opens: it may have
|
|
211
220
|
// moved (a scrolled sheet) since the last open.
|
|
212
221
|
useLayoutEffect(() => {
|
|
213
|
-
if (!
|
|
222
|
+
if (!anchored || !open) {
|
|
214
223
|
setAnchor(null);
|
|
215
224
|
return;
|
|
216
225
|
}
|
|
@@ -230,7 +239,7 @@ export function FloatingPanel({
|
|
|
230
239
|
return () => {
|
|
231
240
|
live = false;
|
|
232
241
|
};
|
|
233
|
-
}, [
|
|
242
|
+
}, [anchored, open]);
|
|
234
243
|
|
|
235
244
|
const handleBackdropPress = useCallback(() => {
|
|
236
245
|
if (backdropArmed) close();
|
|
@@ -582,11 +591,8 @@ export function FloatingPanel({
|
|
|
582
591
|
<TriggerMenuPanel
|
|
583
592
|
// An attached menu (an icon trigger, no echo row) opens under its
|
|
584
593
|
// trigger instead of over it, the UIMenu pull-down (LC-262).
|
|
585
|
-
anchor={
|
|
586
|
-
|
|
587
|
-
? { ...anchor, y: anchor.y + anchor.height }
|
|
588
|
-
: anchor
|
|
589
|
-
}
|
|
594
|
+
anchor={anchor}
|
|
595
|
+
attach={anchorMode === "attach"}
|
|
590
596
|
bounds={{
|
|
591
597
|
top: topInset + panelViewportPadding,
|
|
592
598
|
left: (safeArea?.left ?? 0) + panelViewportPadding,
|
|
@@ -627,6 +633,32 @@ export function FloatingPanel({
|
|
|
627
633
|
{header}
|
|
628
634
|
{children}
|
|
629
635
|
</PointPanel>
|
|
636
|
+
) : asRegular ? (
|
|
637
|
+
<RegularPanel
|
|
638
|
+
anchor={anchor}
|
|
639
|
+
bounds={{
|
|
640
|
+
top: topInset + panelViewportPadding,
|
|
641
|
+
left: (safeArea?.left ?? 0) + panelViewportPadding,
|
|
642
|
+
right: windowWidth - (safeArea?.right ?? 0) - panelViewportPadding,
|
|
643
|
+
bottom:
|
|
644
|
+
windowHeight -
|
|
645
|
+
Math.max(safeArea?.bottom ?? 0, keyboardInset) -
|
|
646
|
+
panelViewportPadding,
|
|
647
|
+
}}
|
|
648
|
+
widthMode={resolvePanelWidthMode(widthMode, fitContent)}
|
|
649
|
+
echo={triggerEcho ? (triggerRow ?? trigger) : null}
|
|
650
|
+
echoLabel={triggerA11y?.label}
|
|
651
|
+
header={header}
|
|
652
|
+
scrollable={!!scrollable}
|
|
653
|
+
fill={!!sheetFill}
|
|
654
|
+
scrollViewProps={scrollViewProps}
|
|
655
|
+
framePadding={framePadding}
|
|
656
|
+
frameGap={frameGap}
|
|
657
|
+
onBackdropPress={handleBackdropPress}
|
|
658
|
+
onClose={close}
|
|
659
|
+
>
|
|
660
|
+
{children}
|
|
661
|
+
</RegularPanel>
|
|
630
662
|
) : (
|
|
631
663
|
/*
|
|
632
664
|
A plain padded column, not KeyboardAvoidingView: inside a Modal the
|
|
@@ -732,6 +764,7 @@ export function FloatingPanel({
|
|
|
732
764
|
*/
|
|
733
765
|
function TriggerMenuPanel({
|
|
734
766
|
anchor,
|
|
767
|
+
attach = false,
|
|
735
768
|
bounds,
|
|
736
769
|
echo,
|
|
737
770
|
echoLabel,
|
|
@@ -742,6 +775,7 @@ function TriggerMenuPanel({
|
|
|
742
775
|
children,
|
|
743
776
|
}: {
|
|
744
777
|
anchor: TriggerRect | null;
|
|
778
|
+
attach?: boolean;
|
|
745
779
|
bounds: PanelBounds;
|
|
746
780
|
echo: ReactNode;
|
|
747
781
|
echoLabel?: string;
|
|
@@ -755,7 +789,7 @@ function TriggerMenuPanel({
|
|
|
755
789
|
const [size, setSize] = useState<{ width: number; height: number } | null>(null);
|
|
756
790
|
const placement =
|
|
757
791
|
anchor && size
|
|
758
|
-
? placeOverTrigger({
|
|
792
|
+
? (attach ? placeBesideTrigger : placeOverTrigger)({
|
|
759
793
|
trigger: anchor,
|
|
760
794
|
width: size.width,
|
|
761
795
|
height: size.height,
|
|
@@ -782,36 +816,47 @@ function TriggerMenuPanel({
|
|
|
782
816
|
position: "absolute",
|
|
783
817
|
left: placement?.left ?? bounds.left,
|
|
784
818
|
top: placement?.top ?? bounds.top,
|
|
785
|
-
minWidth: anchor?.width ?? 0,
|
|
819
|
+
minWidth: menuMinWidth(anchor?.width ?? 0, bounds.right - bounds.left),
|
|
786
820
|
maxWidth: bounds.right - bounds.left,
|
|
787
821
|
maxHeight: placement?.maxHeight ?? bounds.bottom - bounds.top,
|
|
788
822
|
opacity: placement ? 1 : 0,
|
|
789
823
|
}}
|
|
790
824
|
>
|
|
791
825
|
<YStack
|
|
826
|
+
testID="floating-panel-menu-surface"
|
|
792
827
|
{...knobProps.elevatedSurface}
|
|
793
828
|
flexShrink={1}
|
|
794
829
|
minHeight={0}
|
|
795
|
-
overflow="hidden"
|
|
796
830
|
onAccessibilityEscape={onClose}
|
|
797
831
|
>
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
832
|
+
<YStack
|
|
833
|
+
testID="floating-panel-menu-clip"
|
|
834
|
+
borderRadius={knobProps.elevatedSurface.borderRadius}
|
|
835
|
+
overflow="hidden"
|
|
836
|
+
flexShrink={1}
|
|
837
|
+
minHeight={0}
|
|
838
|
+
>
|
|
839
|
+
{echo != null && anchor && anchor.height > 0 ? (
|
|
840
|
+
<Pressable
|
|
841
|
+
testID="floating-panel-menu-echo"
|
|
842
|
+
onPress={onClose}
|
|
843
|
+
accessibilityRole="button"
|
|
844
|
+
{...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
|
|
845
|
+
aria-expanded
|
|
846
|
+
style={{ height: anchor.height, minWidth: anchor.width, justifyContent: "center" }}
|
|
847
|
+
>
|
|
848
|
+
<RNView pointerEvents="none">{echo}</RNView>
|
|
849
|
+
</Pressable>
|
|
850
|
+
) : null}
|
|
851
|
+
<RNScrollView
|
|
852
|
+
style={{ flexGrow: 0, flexShrink: 1 }}
|
|
853
|
+
keyboardShouldPersistTaps="handled"
|
|
806
854
|
>
|
|
807
|
-
<
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
{children}
|
|
813
|
-
</YStack>
|
|
814
|
-
</RNScrollView>
|
|
855
|
+
<YStack padding={framePadding} gap={frameGap}>
|
|
856
|
+
{children}
|
|
857
|
+
</YStack>
|
|
858
|
+
</RNScrollView>
|
|
859
|
+
</YStack>
|
|
815
860
|
</YStack>
|
|
816
861
|
</RNView>
|
|
817
862
|
</RNView>
|