@multiplatform.one/forms 7.66.0 → 7.68.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/AdaptivePopup/index.cjs +45 -5
- package/dist/cjs/AdaptivePopup/index.native.js +47 -5
- package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
- package/dist/cjs/Button/glass.cjs +30 -0
- package/dist/cjs/Button/glass.native.js +47 -0
- package/dist/cjs/Button/glass.native.js.map +1 -0
- package/dist/cjs/Button/index.cjs +157 -28
- package/dist/cjs/Button/index.native.js +156 -27
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/ContextualSaveBar/index.cjs +6 -8
- package/dist/cjs/ContextualSaveBar/index.native.js +6 -8
- package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/cjs/DescriptionList/index.cjs +0 -1
- package/dist/cjs/DescriptionList/index.native.js +0 -1
- package/dist/cjs/DescriptionList/index.native.js.map +1 -1
- 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/Barcode/BarcodeScanner.cjs +7 -8
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +7 -8
- package/dist/cjs/fields/Barcode/BarcodeScanner.native.js.map +1 -1
- package/dist/cjs/fields/Combobox/index.cjs +1 -1
- package/dist/cjs/fields/Combobox/index.native.js +3 -1
- package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload/index.cjs +83 -60
- package/dist/cjs/fields/FileUpload/index.native.js +96 -73
- package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/index.cjs +7 -8
- package/dist/cjs/fields/Geolocation/index.native.js +7 -8
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/ImageField/index.cjs +4 -6
- package/dist/cjs/fields/ImageField/index.native.js +4 -6
- package/dist/cjs/fields/ImageField/index.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 +63 -4
- package/dist/cjs/fields/Select/index.native.js +85 -26
- 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/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 +54 -47
- package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +64 -49
- 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 +19 -1
- package/dist/cjs/index.native.js +18 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/shared/colorRamps.cjs +0 -8
- package/dist/cjs/shared/colorRamps.native.js +0 -8
- package/dist/cjs/shared/colorRamps.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/cjs/standardActions.cjs +117 -0
- package/dist/cjs/standardActions.native.js +120 -0
- package/dist/cjs/standardActions.native.js.map +1 -0
- package/dist/esm/AdaptivePopup/index.mjs +45 -5
- package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
- package/dist/esm/AdaptivePopup/index.native.js +47 -5
- package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
- package/dist/esm/Button/glass.mjs +5 -0
- package/dist/esm/Button/glass.mjs.map +1 -0
- package/dist/esm/Button/glass.native.js +19 -0
- package/dist/esm/Button/glass.native.js.map +1 -0
- package/dist/esm/Button/index.mjs +153 -28
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +153 -28
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/ContextualSaveBar/index.mjs +7 -9
- package/dist/esm/ContextualSaveBar/index.mjs.map +1 -1
- package/dist/esm/ContextualSaveBar/index.native.js +7 -9
- package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/esm/DescriptionList/index.mjs +0 -1
- package/dist/esm/DescriptionList/index.mjs.map +1 -1
- package/dist/esm/DescriptionList/index.native.js +0 -1
- package/dist/esm/DescriptionList/index.native.js.map +1 -1
- 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/Barcode/BarcodeScanner.mjs +8 -9
- package/dist/esm/fields/Barcode/BarcodeScanner.mjs.map +1 -1
- package/dist/esm/fields/Barcode/BarcodeScanner.native.js +8 -9
- package/dist/esm/fields/Barcode/BarcodeScanner.native.js.map +1 -1
- package/dist/esm/fields/Combobox/index.mjs +1 -1
- package/dist/esm/fields/Combobox/index.mjs.map +1 -1
- package/dist/esm/fields/Combobox/index.native.js +3 -1
- package/dist/esm/fields/Combobox/index.native.js.map +1 -1
- package/dist/esm/fields/FileUpload/index.mjs +84 -61
- package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
- package/dist/esm/fields/FileUpload/index.native.js +97 -74
- package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
- package/dist/esm/fields/Geolocation/index.mjs +8 -9
- package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
- package/dist/esm/fields/Geolocation/index.native.js +8 -9
- package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
- package/dist/esm/fields/ImageField/index.mjs +6 -8
- package/dist/esm/fields/ImageField/index.mjs.map +1 -1
- package/dist/esm/fields/ImageField/index.native.js +6 -8
- package/dist/esm/fields/ImageField/index.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 +64 -5
- package/dist/esm/fields/Select/index.mjs.map +1 -1
- package/dist/esm/fields/Select/index.native.js +86 -27
- 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/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 +56 -49
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +66 -51
- 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 +5 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +5 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/shared/colorRamps.mjs +0 -8
- package/dist/esm/shared/colorRamps.mjs.map +1 -1
- package/dist/esm/shared/colorRamps.native.js +0 -8
- package/dist/esm/shared/colorRamps.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/esm/standardActions.mjs +91 -0
- package/dist/esm/standardActions.mjs.map +1 -0
- package/dist/esm/standardActions.native.js +91 -0
- package/dist/esm/standardActions.native.js.map +1 -0
- package/dist/jsx/AdaptivePopup/index.mjs +45 -5
- package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
- package/dist/jsx/AdaptivePopup/index.native.js +47 -5
- package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
- package/dist/jsx/Button/glass.mjs +5 -0
- package/dist/jsx/Button/glass.mjs.map +1 -0
- package/dist/jsx/Button/glass.native.js +47 -0
- package/dist/jsx/Button/glass.native.js.map +1 -0
- package/dist/jsx/Button/index.mjs +153 -28
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +156 -27
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/ContextualSaveBar/index.mjs +7 -9
- package/dist/jsx/ContextualSaveBar/index.mjs.map +1 -1
- package/dist/jsx/ContextualSaveBar/index.native.js +6 -8
- package/dist/jsx/ContextualSaveBar/index.native.js.map +1 -1
- package/dist/jsx/DescriptionList/index.mjs +0 -1
- package/dist/jsx/DescriptionList/index.mjs.map +1 -1
- package/dist/jsx/DescriptionList/index.native.js +0 -1
- package/dist/jsx/DescriptionList/index.native.js.map +1 -1
- 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/Barcode/BarcodeScanner.mjs +8 -9
- package/dist/jsx/fields/Barcode/BarcodeScanner.mjs.map +1 -1
- package/dist/jsx/fields/Barcode/BarcodeScanner.native.js +7 -8
- package/dist/jsx/fields/Barcode/BarcodeScanner.native.js.map +1 -1
- package/dist/jsx/fields/Combobox/index.mjs +1 -1
- package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
- package/dist/jsx/fields/Combobox/index.native.js +3 -1
- package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload/index.mjs +84 -61
- package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload/index.native.js +96 -73
- package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
- package/dist/jsx/fields/Geolocation/index.mjs +8 -9
- package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
- package/dist/jsx/fields/Geolocation/index.native.js +7 -8
- package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
- package/dist/jsx/fields/ImageField/index.mjs +6 -8
- package/dist/jsx/fields/ImageField/index.mjs.map +1 -1
- package/dist/jsx/fields/ImageField/index.native.js +4 -6
- package/dist/jsx/fields/ImageField/index.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 +64 -5
- package/dist/jsx/fields/Select/index.mjs.map +1 -1
- package/dist/jsx/fields/Select/index.native.js +85 -26
- 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/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 +56 -49
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
- package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +64 -49
- 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 +5 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +5 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +18 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/shared/colorRamps.mjs +0 -8
- package/dist/jsx/shared/colorRamps.mjs.map +1 -1
- package/dist/jsx/shared/colorRamps.native.js +0 -8
- package/dist/jsx/shared/colorRamps.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/dist/jsx/standardActions.mjs +91 -0
- package/dist/jsx/standardActions.mjs.map +1 -0
- package/dist/jsx/standardActions.native.js +120 -0
- package/dist/jsx/standardActions.native.js.map +1 -0
- package/package.json +20 -8
- package/src/AdaptivePopup/AdaptivePopup.spec.tsx +44 -0
- package/src/AdaptivePopup/AdaptivePopup.stories.tsx +12 -32
- package/src/AdaptivePopup/index.tsx +65 -13
- package/src/Button/Button.disabledGlyph.spec.tsx +111 -0
- package/src/Button/Button.iconButton.spec.tsx +279 -0
- package/src/Button/Button.stories.tsx +59 -3
- package/src/Button/glass.native.ts +38 -0
- package/src/Button/glass.ts +18 -0
- package/src/Button/index.tsx +272 -40
- package/src/ContextualSaveBar/ContextualSaveBar.spec.tsx +3 -1
- package/src/ContextualSaveBar/ContextualSaveBar.stories.tsx +2 -2
- package/src/ContextualSaveBar/index.tsx +7 -10
- package/src/ControlGroup/ControlGroup.stories.tsx +3 -2
- package/src/DescriptionList/index.tsx +0 -1
- package/src/ErrorSummary.stories.tsx +2 -1
- package/src/FieldLayout.stories.tsx +3 -2
- package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +73 -3
- package/src/FloatingPanel/FloatingPanel.regularWidth.native.spec.tsx +193 -0
- package/src/FloatingPanel/FloatingPanel.stories.tsx +6 -10
- 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/Form/Form.stories.tsx +6 -5
- package/src/errorSummaryStories.spec.tsx +4 -4
- package/src/fields/Barcode/BarcodeScanner.native.tsx +10 -9
- package/src/fields/Barcode/BarcodeScanner.tsx +10 -9
- package/src/fields/Checkbox/Checkbox.stories.tsx +3 -3
- package/src/fields/Checkbox/CheckboxGroup.stories.tsx +2 -2
- package/src/fields/ColorPicker/ColorPicker.stories.tsx +2 -2
- package/src/fields/Combobox/Combobox.regularWidth.native.spec.tsx +94 -0
- package/src/fields/Combobox/Combobox.stories.tsx +2 -2
- package/src/fields/Combobox/index.tsx +3 -1
- package/src/fields/DatePicker/DatePicker.stories.tsx +2 -1
- package/src/fields/DatePicker/DateRangePicker.stories.tsx +2 -2
- package/src/fields/DatePicker/DatetimePicker.stories.tsx +2 -1
- package/src/fields/DatePicker/MonthPicker.stories.tsx +2 -2
- package/src/fields/DatePicker/MultiDatePicker.stories.tsx +2 -2
- package/src/fields/FileUpload/FileUpload.spec.tsx +11 -6
- package/src/fields/FileUpload/FileUpload.stories.tsx +2 -2
- package/src/fields/FileUpload/index.tsx +101 -77
- package/src/fields/Geolocation/index.tsx +12 -7
- package/src/fields/ImageField/ImageField.spec.tsx +5 -5
- package/src/fields/ImageField/ImageField.stories.tsx +2 -2
- package/src/fields/ImageField/index.tsx +6 -9
- package/src/fields/Input/Input.formName.spec.tsx +53 -0
- package/src/fields/Input/Input.stories.tsx +2 -2
- package/src/fields/Input/index.tsx +6 -1
- package/src/fields/MentionInput/MentionInput.stories.tsx +2 -1
- package/src/fields/Progress/Progress.stories.tsx +2 -1
- package/src/fields/RadioGroup/RadioGroup.stories.tsx +2 -1
- package/src/fields/Select/InlineChoices.tsx +6 -3
- package/src/fields/Select/SheetPickerRow.tsx +160 -0
- package/src/fields/Select/index.tsx +65 -4
- package/src/fields/Select/shouldInlineChoices.spec.ts +21 -1
- package/src/fields/Select/shouldInlineChoices.ts +26 -0
- package/src/fields/Signature/Signature.stories.tsx +2 -2
- package/src/fields/Slider/Slider.system.native.spec.tsx +168 -0
- package/src/fields/Slider/index.tsx +166 -30
- package/src/fields/Stepper/Stepper.stories.tsx +2 -2
- package/src/fields/Switch/Switch.system.native.spec.tsx +162 -0
- package/src/fields/Switch/index.tsx +98 -0
- package/src/fields/TextArea/TextArea.stories.tsx +2 -2
- package/src/fields/ToggleGroup/ToggleGroup.stories.tsx +2 -2
- 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 +168 -0
- package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +60 -30
- package/src/fields/nativeDateTime/sheetKeyboard.spec.ts +60 -0
- package/src/fields/nativeDateTime/sheetKeyboard.ts +45 -0
- package/src/index.ts +25 -2
- package/src/shared/colorRamps.ts +1 -11
- 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/src/standardActions.ts +96 -0
- package/types/AdaptivePopup/index.d.ts +13 -1
- package/types/AdaptivePopup/index.d.ts.map +1 -1
- package/types/Button/glass.d.ts +15 -0
- package/types/Button/glass.d.ts.map +1 -0
- package/types/Button/glass.native.d.ts +11 -0
- package/types/Button/glass.native.d.ts.map +1 -0
- package/types/Button/index.d.ts +45 -1
- package/types/Button/index.d.ts.map +1 -1
- package/types/ContextualSaveBar/index.d.ts.map +1 -1
- package/types/DescriptionList/index.d.ts.map +1 -1
- 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/Barcode/BarcodeScanner.d.ts.map +1 -1
- package/types/fields/Barcode/BarcodeScanner.native.d.ts.map +1 -1
- package/types/fields/Combobox/index.d.ts.map +1 -1
- package/types/fields/FileUpload/index.d.ts.map +1 -1
- package/types/fields/Geolocation/index.d.ts.map +1 -1
- package/types/fields/ImageField/index.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/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 +8 -2
- package/types/index.d.ts.map +1 -1
- package/types/shared/colorRamps.d.ts +1 -11
- package/types/shared/colorRamps.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
- package/types/standardActions.d.ts +24 -0
- package/types/standardActions.d.ts.map +1 -0
|
@@ -7,12 +7,14 @@ import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
|
7
7
|
import { act } from "@testing-library/react";
|
|
8
8
|
import { useState, type ReactNode } from "react";
|
|
9
9
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
10
|
-
import { Text } from "tamagui";
|
|
10
|
+
import { Text, XStack, YStack } from "tamagui";
|
|
11
11
|
import { OverlayStackProvider } from "../shared/overlayStack";
|
|
12
|
-
import type
|
|
12
|
+
import { MENU_MIN_WIDTH, type CompactFace } from "./compactFace";
|
|
13
13
|
import { FloatingPanel } from "./index.native";
|
|
14
14
|
import { panelViewportPadding } from "./useFloatingPanel";
|
|
15
15
|
|
|
16
|
+
const win = vi.hoisted(() => ({ width: 390 }));
|
|
17
|
+
|
|
16
18
|
vi.mock("react-native-web", async (importOriginal) => {
|
|
17
19
|
const actual = await importOriginal<typeof import("react-native")>();
|
|
18
20
|
return {
|
|
@@ -20,7 +22,7 @@ vi.mock("react-native-web", async (importOriginal) => {
|
|
|
20
22
|
ActionSheetIOS: undefined,
|
|
21
23
|
Modal: ({ children, visible }: { children: ReactNode; visible: boolean }) =>
|
|
22
24
|
visible ? children : null,
|
|
23
|
-
useWindowDimensions: () => ({ width:
|
|
25
|
+
useWindowDimensions: () => ({ width: win.width, height: 844, scale: 3, fontScale: 1 }),
|
|
24
26
|
};
|
|
25
27
|
});
|
|
26
28
|
|
|
@@ -28,6 +30,7 @@ let trigger = { x: 20, y: 240, width: 120, height: 44 };
|
|
|
28
30
|
beforeEach(() => {
|
|
29
31
|
vi.useFakeTimers();
|
|
30
32
|
trigger = { x: 20, y: 240, width: 120, height: 44 };
|
|
33
|
+
win.width = 390;
|
|
31
34
|
// RN-web's measureInWindow reads the node's client rect on a timer.
|
|
32
35
|
vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(() => ({
|
|
33
36
|
x: trigger.x,
|
|
@@ -120,6 +123,16 @@ describe("FloatingPanel native menu face (FZ-7830)", () => {
|
|
|
120
123
|
expect(row.getAttribute("aria-expanded")).toBe("true");
|
|
121
124
|
});
|
|
122
125
|
|
|
126
|
+
it("keeps its shadow: an inner view clips, not the elevated surface (FZ-8116)", () => {
|
|
127
|
+
const result = renderWithProviders(<Menu face="menu" />);
|
|
128
|
+
tap(result.getByRole("button", { name: "Stack actions" }));
|
|
129
|
+
const surface = document.querySelector('[data-testid="floating-panel-menu-surface"]');
|
|
130
|
+
const clip = document.querySelector('[data-testid="floating-panel-menu-clip"]');
|
|
131
|
+
expect(surface?.contains(clip)).toBe(true);
|
|
132
|
+
expect(surface?.className).not.toContain("_ox-hidden");
|
|
133
|
+
expect(clip?.className).toContain("_ox-hidden");
|
|
134
|
+
});
|
|
135
|
+
|
|
123
136
|
it("closes when the repeated trigger row is pressed", () => {
|
|
124
137
|
const result = renderWithProviders(<Menu face="menu" />);
|
|
125
138
|
tap(result.getByRole("button", { name: "Stack actions" }));
|
|
@@ -193,3 +206,60 @@ describe("FloatingPanel native menu face (FZ-7830)", () => {
|
|
|
193
206
|
expect(sheet()).toBeNull();
|
|
194
207
|
});
|
|
195
208
|
});
|
|
209
|
+
|
|
210
|
+
/** The SHC account menu's shape: an avatar-sized trigger over rows that fill their width. */
|
|
211
|
+
function AccountMenu() {
|
|
212
|
+
const [open, setOpen] = useState(false);
|
|
213
|
+
return (
|
|
214
|
+
<FloatingPanel
|
|
215
|
+
open={open}
|
|
216
|
+
onOpenChange={setOpen}
|
|
217
|
+
compactFace="menu"
|
|
218
|
+
anchorMode="attach"
|
|
219
|
+
triggerEcho={false}
|
|
220
|
+
triggerSizing="content"
|
|
221
|
+
contentPadding="none"
|
|
222
|
+
trigger={<Text>A</Text>}
|
|
223
|
+
triggerA11y={{ label: "Account" }}
|
|
224
|
+
>
|
|
225
|
+
<XStack testID="identity-row" width="100%">
|
|
226
|
+
<YStack flex={1} minWidth={0}>
|
|
227
|
+
<Text numberOfLines={1}>Clay Risser</Text>
|
|
228
|
+
<Text numberOfLines={1}>clayrisser@gmail.com</Text>
|
|
229
|
+
</YStack>
|
|
230
|
+
</XStack>
|
|
231
|
+
<Text>Sign out</Text>
|
|
232
|
+
</FloatingPanel>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
describe("FloatingPanel native menu face width (FZ-8220)", () => {
|
|
237
|
+
it("opens rows with no intrinsic width at the platform minimum, not the trigger's 44pt", () => {
|
|
238
|
+
trigger = { x: 336, y: 52, width: 44, height: 44 };
|
|
239
|
+
const result = renderWithProviders(<AccountMenu />);
|
|
240
|
+
tap(result.getByRole("button", { name: "Account" }));
|
|
241
|
+
const panel = menu() as HTMLElement;
|
|
242
|
+
expect(MENU_MIN_WIDTH).toBe(250);
|
|
243
|
+
expect(panel.style.minWidth).toBe(`${MENU_MIN_WIDTH}px`);
|
|
244
|
+
expect(panel.style.maxWidth).toBe(`${390 - 2 * panelViewportPadding}px`);
|
|
245
|
+
layout(panel, MENU_MIN_WIDTH, 160);
|
|
246
|
+
expect(panel.style.left).toBe(`${390 - panelViewportPadding - MENU_MIN_WIDTH}px`);
|
|
247
|
+
expect(panel.style.top).toBe(`${52 + 44}px`);
|
|
248
|
+
expect(echo()).toBeNull();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("clamps the minimum to the screen less its margins on a narrow window", () => {
|
|
252
|
+
win.width = 240;
|
|
253
|
+
trigger = { x: 186, y: 52, width: 44, height: 44 };
|
|
254
|
+
const result = renderWithProviders(<AccountMenu />);
|
|
255
|
+
tap(result.getByRole("button", { name: "Account" }));
|
|
256
|
+
expect(menu()?.style.minWidth).toBe(`${240 - 2 * panelViewportPadding}px`);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("keeps a trigger wider than the minimum as the floor", () => {
|
|
260
|
+
trigger = { x: 20, y: 240, width: 320, height: 44 };
|
|
261
|
+
const result = renderWithProviders(<Menu face="menu" />);
|
|
262
|
+
tap(result.getByRole("button", { name: "Stack actions" }));
|
|
263
|
+
expect(menu()?.style.minWidth).toBe("320px");
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
|
|
3
|
-
import { Preset, Paragraph,
|
|
4
|
-
import { ScrollView,
|
|
3
|
+
import { Preset, Paragraph, Text } from "@multiplatform.one/theme";
|
|
4
|
+
import { ScrollView, View, XStack, YStack } from "tamagui";
|
|
5
|
+
import { OverlayHeader } from "@multiplatform.one/components";
|
|
5
6
|
import { FloatingPanel } from "./index";
|
|
6
7
|
import { Button } from "../Button";
|
|
7
8
|
import { Select } from "../fields/Select";
|
|
@@ -38,13 +39,11 @@ export const Basic: Story = {
|
|
|
38
39
|
trigger={<Button>{open ? "Panel is open" : "Click to open panel"}</Button>}
|
|
39
40
|
>
|
|
40
41
|
<YStack gap="$3">
|
|
41
|
-
<
|
|
42
|
+
<OverlayHeader title="Panel Content" onClose={() => setOpen(false)} />
|
|
42
43
|
<Paragraph>
|
|
43
44
|
Opens over its trigger: the top edge sits on the trigger's top edge and the trigger is
|
|
44
45
|
the first row. Escape or an outside click dismisses and returns focus.
|
|
45
46
|
</Paragraph>
|
|
46
|
-
<Separator />
|
|
47
|
-
<Button onPress={() => setOpen(false)}>Close</Button>
|
|
48
47
|
</YStack>
|
|
49
48
|
</FloatingPanel>
|
|
50
49
|
</YStack>
|
|
@@ -185,9 +184,8 @@ export const ForceSheet: Story = {
|
|
|
185
184
|
trigger={<Button>{open ? "Sheet open" : "Click for Sheet (forced)"}</Button>}
|
|
186
185
|
>
|
|
187
186
|
<YStack gap="$3">
|
|
188
|
-
<
|
|
187
|
+
<OverlayHeader title="Forced Sheet" onClose={() => setOpen(false)} />
|
|
189
188
|
<Paragraph>This panel always uses Sheet, even on large screens.</Paragraph>
|
|
190
|
-
<Button onPress={() => setOpen(false)}>Close</Button>
|
|
191
189
|
</YStack>
|
|
192
190
|
</FloatingPanel>
|
|
193
191
|
</YStack>
|
|
@@ -224,13 +222,11 @@ function ScrollClipPair({ where }: { where: string }) {
|
|
|
224
222
|
trigger={<Button>{`FloatingPanel (${where})`}</Button>}
|
|
225
223
|
>
|
|
226
224
|
<YStack gap="$3" data-testid={`scroll-clip-panel-${where}`}>
|
|
227
|
-
<
|
|
225
|
+
<OverlayHeader title={`Panel ${where}`} onClose={() => setOpen(false)} />
|
|
228
226
|
<Paragraph>
|
|
229
227
|
This body is taller than the space left in the scroll view, so a clipped panel loses its
|
|
230
228
|
lower half.
|
|
231
229
|
</Paragraph>
|
|
232
|
-
<Separator />
|
|
233
|
-
<Button onPress={() => setOpen(false)}>Close</Button>
|
|
234
230
|
</YStack>
|
|
235
231
|
</FloatingPanel>
|
|
236
232
|
</YStack>
|
|
@@ -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
|
+
}
|