react-native-platform-components 1.4.0 → 1.5.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/PlatformComponents.podspec +1 -1
- package/README.md +33 -31
- package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +175 -9
- package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +52 -2
- package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +44 -12
- package/android/src/main/java/com/platformcomponents/PCButtonView.kt +187 -5
- package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +85 -7
- package/android/src/main/java/com/platformcomponents/PCContextMenuView.kt +41 -151
- package/android/src/main/java/com/platformcomponents/PCContextMenuViewManager.kt +7 -63
- package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +310 -115
- package/android/src/main/java/com/platformcomponents/PCDatePickerViewManager.kt +23 -3
- package/android/src/main/java/com/platformcomponents/PCExpressive.kt +6 -1
- package/android/src/main/java/com/platformcomponents/PCFloatingActionButtonView.kt +485 -0
- package/android/src/main/java/com/platformcomponents/PCFloatingActionButtonViewManager.kt +109 -0
- package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +132 -0
- package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +8 -0
- package/android/src/main/java/com/platformcomponents/PCHaptics.kt +46 -0
- package/android/src/main/java/com/platformcomponents/PCImageLoader.kt +42 -7
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassContainerView.kt +32 -0
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassContainerViewManager.kt +31 -0
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassView.kt +32 -6
- package/android/src/main/java/com/platformcomponents/PCLiquidGlassViewManager.kt +4 -0
- package/android/src/main/java/com/platformcomponents/PCMenuSupport.kt +280 -0
- package/android/src/main/java/com/platformcomponents/PCNavigationBarSupport.kt +332 -0
- package/android/src/main/java/com/platformcomponents/PCNavigationRailView.kt +448 -0
- package/android/src/main/java/com/platformcomponents/PCNavigationRailViewManager.kt +176 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +24 -14
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +14 -2
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +371 -39
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuViewManager.kt +18 -4
- package/android/src/main/java/com/platformcomponents/PCTabBarView.kt +397 -0
- package/android/src/main/java/com/platformcomponents/PCTabBarViewManager.kt +182 -0
- package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +415 -40
- package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +109 -3
- package/android/src/main/java/com/platformcomponents/PCThemeSupport.kt +37 -0
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +4 -0
- package/android/src/main/res/drawable/pc_ic_search.xml +12 -0
- package/android/src/main/res/values/ids.xml +5 -0
- package/android/src/main/res/values/styles.xml +24 -0
- package/ios/PCButton.mm +122 -7
- package/ios/PCButtonGroup.mm +68 -1
- package/ios/PCButtonGroupView.swift +225 -6
- package/ios/PCButtonSupport.swift +181 -10
- package/ios/PCButtonView.swift +297 -14
- package/ios/PCConstants.swift +23 -2
- package/ios/PCContextMenu.mm +28 -110
- package/ios/PCContextMenu.swift +106 -167
- package/ios/PCDatePicker.mm +21 -9
- package/ios/PCDatePickerView.swift +94 -20
- package/ios/PCFloatingActionButton.h +10 -0
- package/ios/PCFloatingActionButton.mm +177 -0
- package/ios/PCFloatingActionButtonView.swift +426 -0
- package/ios/PCFloatingToolbar.mm +27 -0
- package/ios/PCFloatingToolbarView.swift +241 -0
- package/ios/PCHaptics.swift +91 -0
- package/ios/PCImageLoader.swift +76 -12
- package/ios/PCLiquidGlass.mm +36 -0
- package/ios/PCLiquidGlass.swift +221 -114
- package/ios/PCLiquidGlassContainer.h +10 -0
- package/ios/PCLiquidGlassContainer.mm +84 -0
- package/ios/PCLiquidGlassContainer.swift +69 -0
- package/ios/PCMenuItems.h +76 -0
- package/ios/PCMenuSupport.swift +350 -0
- package/ios/PCNavigationRail.h +10 -0
- package/ios/PCNavigationRail.mm +270 -0
- package/ios/PCNavigationRailView.swift +415 -0
- package/ios/PCSegmentedControl.mm +17 -2
- package/ios/PCSegmentedControl.swift +57 -7
- package/ios/PCSelectionMenu.mm +36 -8
- package/ios/PCSelectionMenu.swift +224 -48
- package/ios/PCTabBar.h +10 -0
- package/ios/PCTabBar.mm +285 -0
- package/ios/PCTabBarAccessory.h +10 -0
- package/ios/PCTabBarAccessory.mm +93 -0
- package/ios/PCTabBarAccessoryView.swift +96 -0
- package/ios/PCTabBarView.swift +671 -0
- package/ios/PCTextField.mm +159 -4
- package/ios/PCTextFieldView.swift +603 -57
- package/lib/commonjs/Button.js +73 -1
- package/lib/commonjs/Button.js.map +1 -1
- package/lib/commonjs/ButtonGroup.js +13 -3
- package/lib/commonjs/ButtonGroup.js.map +1 -1
- package/lib/commonjs/ButtonGroupNativeComponent.ts +74 -4
- package/lib/commonjs/ButtonNativeComponent.ts +119 -3
- package/lib/commonjs/ContextMenu.js +9 -48
- package/lib/commonjs/ContextMenu.js.map +1 -1
- package/lib/commonjs/ContextMenuNativeComponent.ts +47 -49
- package/lib/commonjs/DatePicker.js +98 -2
- package/lib/commonjs/DatePicker.js.map +1 -1
- package/lib/commonjs/DatePickerNativeComponent.ts +19 -2
- package/lib/commonjs/FloatingActionButton.js +60 -0
- package/lib/commonjs/FloatingActionButton.js.map +1 -0
- package/lib/commonjs/FloatingActionButtonNativeComponent.ts +58 -0
- package/lib/commonjs/FloatingToolbar.js +9 -1
- package/lib/commonjs/FloatingToolbar.js.map +1 -1
- package/lib/commonjs/FloatingToolbarNativeComponent.ts +16 -0
- package/lib/commonjs/LiquidGlass.js +7 -1
- package/lib/commonjs/LiquidGlass.js.map +1 -1
- package/lib/commonjs/LiquidGlassContainer.js +32 -0
- package/lib/commonjs/LiquidGlassContainer.js.map +1 -0
- package/lib/commonjs/LiquidGlassContainerNativeComponent.ts +17 -0
- package/lib/commonjs/LiquidGlassNativeComponent.ts +8 -0
- package/lib/commonjs/NavigationRail.js +104 -0
- package/lib/commonjs/NavigationRail.js.map +1 -0
- package/lib/commonjs/NavigationRailNativeComponent.ts +107 -0
- package/lib/commonjs/PlatformComponentsProvider.js +18 -0
- package/lib/commonjs/PlatformComponentsProvider.js.map +1 -0
- package/lib/commonjs/SegmentedControl.js +7 -0
- package/lib/commonjs/SegmentedControl.js.map +1 -1
- package/lib/commonjs/SegmentedControlNativeComponent.ts +11 -0
- package/lib/commonjs/SelectionMenu.js +27 -3
- package/lib/commonjs/SelectionMenu.js.map +1 -1
- package/lib/commonjs/SelectionMenuNativeComponent.ts +26 -4
- package/lib/commonjs/SplitButton.js +98 -0
- package/lib/commonjs/SplitButton.js.map +1 -0
- package/lib/commonjs/TabBar.js +203 -0
- package/lib/commonjs/TabBar.js.map +1 -0
- package/lib/commonjs/TabBarAccessoryNativeComponent.ts +19 -0
- package/lib/commonjs/TabBarNativeComponent.ts +145 -0
- package/lib/commonjs/TextField.js +171 -8
- package/lib/commonjs/TextField.js.map +1 -1
- package/lib/commonjs/TextFieldNativeComponent.ts +110 -4
- package/lib/commonjs/focusRegistry.js +2 -1
- package/lib/commonjs/focusRegistry.js.map +1 -1
- package/lib/commonjs/haptics.js +2 -0
- package/lib/commonjs/haptics.js.map +1 -0
- package/lib/commonjs/icons.js +15 -1
- package/lib/commonjs/icons.js.map +1 -1
- package/lib/commonjs/index.js +77 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +156 -92
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/jest.js +910 -0
- package/lib/commonjs/jest.js.map +1 -0
- package/lib/commonjs/menuItems.js +68 -0
- package/lib/commonjs/menuItems.js.map +1 -0
- package/lib/commonjs/selectionIdentifiers.js +18 -0
- package/lib/commonjs/selectionIdentifiers.js.map +1 -0
- package/lib/commonjs/submitBehavior.js +19 -0
- package/lib/commonjs/submitBehavior.js.map +1 -0
- package/lib/commonjs/tabItems.js +49 -0
- package/lib/commonjs/tabItems.js.map +1 -0
- package/lib/commonjs/web/Button.js +170 -0
- package/lib/commonjs/web/Button.js.map +1 -0
- package/lib/commonjs/web/ButtonGroup.js +119 -0
- package/lib/commonjs/web/ButtonGroup.js.map +1 -0
- package/lib/commonjs/web/DatePicker.js +168 -0
- package/lib/commonjs/web/DatePicker.js.map +1 -0
- package/lib/commonjs/web/DateRangePicker.js +137 -0
- package/lib/commonjs/web/DateRangePicker.js.map +1 -0
- package/lib/commonjs/web/Dialog.js +54 -0
- package/lib/commonjs/web/Dialog.js.map +1 -0
- package/lib/commonjs/web/FloatingActionButton.js +98 -0
- package/lib/commonjs/web/FloatingActionButton.js.map +1 -0
- package/lib/commonjs/web/Icon.js +34 -0
- package/lib/commonjs/web/Icon.js.map +1 -0
- package/lib/commonjs/web/NativeTheme.js +28 -0
- package/lib/commonjs/web/NativeTheme.js.map +1 -0
- package/lib/commonjs/web/NavigationRail.js +139 -0
- package/lib/commonjs/web/NavigationRail.js.map +1 -0
- package/lib/commonjs/web/PlatformComponentsProvider.js +51 -0
- package/lib/commonjs/web/PlatformComponentsProvider.js.map +1 -0
- package/lib/commonjs/web/SegmentedControl.js +117 -0
- package/lib/commonjs/web/SegmentedControl.js.map +1 -0
- package/lib/commonjs/web/SelectionMenu.js +142 -0
- package/lib/commonjs/web/SelectionMenu.js.map +1 -0
- package/lib/commonjs/web/SplitButton.js +35 -0
- package/lib/commonjs/web/SplitButton.js.map +1 -0
- package/lib/commonjs/web/TabBar.js +131 -0
- package/lib/commonjs/web/TabBar.js.map +1 -0
- package/lib/commonjs/web/TextField.js +322 -0
- package/lib/commonjs/web/TextField.js.map +1 -0
- package/lib/commonjs/web/components.js +36 -0
- package/lib/commonjs/web/components.js.map +1 -0
- package/lib/commonjs/web/containers.js +121 -0
- package/lib/commonjs/web/containers.js.map +1 -0
- package/lib/commonjs/web/dateInput.js +116 -0
- package/lib/commonjs/web/dateInput.js.map +1 -0
- package/lib/commonjs/web/shared.js +192 -0
- package/lib/commonjs/web/shared.js.map +1 -0
- package/lib/commonjs/webComponents.js +6 -0
- package/lib/commonjs/webComponents.js.map +1 -0
- package/lib/module/Button.js +74 -2
- package/lib/module/Button.js.map +1 -1
- package/lib/module/ButtonGroup.js +13 -3
- package/lib/module/ButtonGroup.js.map +1 -1
- package/lib/module/ButtonGroupNativeComponent.ts +74 -4
- package/lib/module/ButtonNativeComponent.ts +119 -3
- package/lib/module/ContextMenu.js +9 -48
- package/lib/module/ContextMenu.js.map +1 -1
- package/lib/module/ContextMenuNativeComponent.ts +47 -49
- package/lib/module/DatePicker.js +98 -4
- package/lib/module/DatePicker.js.map +1 -1
- package/lib/module/DatePickerNativeComponent.ts +19 -2
- package/lib/module/FloatingActionButton.js +53 -0
- package/lib/module/FloatingActionButton.js.map +1 -0
- package/lib/module/FloatingActionButtonNativeComponent.ts +58 -0
- package/lib/module/FloatingToolbar.js +9 -1
- package/lib/module/FloatingToolbar.js.map +1 -1
- package/lib/module/FloatingToolbarNativeComponent.ts +16 -0
- package/lib/module/LiquidGlass.js +7 -1
- package/lib/module/LiquidGlass.js.map +1 -1
- package/lib/module/LiquidGlassContainer.js +26 -0
- package/lib/module/LiquidGlassContainer.js.map +1 -0
- package/lib/module/LiquidGlassContainerNativeComponent.ts +17 -0
- package/lib/module/LiquidGlassNativeComponent.ts +8 -0
- package/lib/module/NavigationRail.js +99 -0
- package/lib/module/NavigationRail.js.map +1 -0
- package/lib/module/NavigationRailNativeComponent.ts +107 -0
- package/lib/module/PlatformComponentsProvider.js +13 -0
- package/lib/module/PlatformComponentsProvider.js.map +1 -0
- package/lib/module/SegmentedControl.js +9 -1
- package/lib/module/SegmentedControl.js.map +1 -1
- package/lib/module/SegmentedControlNativeComponent.ts +11 -0
- package/lib/module/SelectionMenu.js +27 -3
- package/lib/module/SelectionMenu.js.map +1 -1
- package/lib/module/SelectionMenuNativeComponent.ts +26 -4
- package/lib/module/SplitButton.js +91 -0
- package/lib/module/SplitButton.js.map +1 -0
- package/lib/module/TabBar.js +196 -0
- package/lib/module/TabBar.js.map +1 -0
- package/lib/module/TabBarAccessoryNativeComponent.ts +19 -0
- package/lib/module/TabBarNativeComponent.ts +145 -0
- package/lib/module/TextField.js +172 -9
- package/lib/module/TextField.js.map +1 -1
- package/lib/module/TextFieldNativeComponent.ts +110 -4
- package/lib/module/focusRegistry.js +1 -0
- package/lib/module/focusRegistry.js.map +1 -1
- package/lib/module/haptics.js +2 -0
- package/lib/module/haptics.js.map +1 -0
- package/lib/module/icons.js +15 -1
- package/lib/module/icons.js.map +1 -1
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +12 -87
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/jest.js +840 -0
- package/lib/module/jest.js.map +1 -0
- package/lib/module/menuItems.js +65 -0
- package/lib/module/menuItems.js.map +1 -0
- package/lib/module/selectionIdentifiers.js +14 -0
- package/lib/module/selectionIdentifiers.js.map +1 -0
- package/lib/module/submitBehavior.js +15 -0
- package/lib/module/submitBehavior.js.map +1 -0
- package/lib/module/tabItems.js +45 -0
- package/lib/module/tabItems.js.map +1 -0
- package/lib/module/web/Button.js +164 -0
- package/lib/module/web/Button.js.map +1 -0
- package/lib/module/web/ButtonGroup.js +113 -0
- package/lib/module/web/ButtonGroup.js.map +1 -0
- package/lib/module/web/DatePicker.js +162 -0
- package/lib/module/web/DatePicker.js.map +1 -0
- package/lib/module/web/DateRangePicker.js +131 -0
- package/lib/module/web/DateRangePicker.js.map +1 -0
- package/lib/module/web/Dialog.js +48 -0
- package/lib/module/web/Dialog.js.map +1 -0
- package/lib/module/web/FloatingActionButton.js +94 -0
- package/lib/module/web/FloatingActionButton.js.map +1 -0
- package/lib/module/web/Icon.js +29 -0
- package/lib/module/web/Icon.js.map +1 -0
- package/lib/module/web/NativeTheme.js +23 -0
- package/lib/module/web/NativeTheme.js.map +1 -0
- package/lib/module/web/NavigationRail.js +133 -0
- package/lib/module/web/NavigationRail.js.map +1 -0
- package/lib/module/web/PlatformComponentsProvider.js +44 -0
- package/lib/module/web/PlatformComponentsProvider.js.map +1 -0
- package/lib/module/web/SegmentedControl.js +112 -0
- package/lib/module/web/SegmentedControl.js.map +1 -0
- package/lib/module/web/SelectionMenu.js +137 -0
- package/lib/module/web/SelectionMenu.js.map +1 -0
- package/lib/module/web/SplitButton.js +30 -0
- package/lib/module/web/SplitButton.js.map +1 -0
- package/lib/module/web/TabBar.js +126 -0
- package/lib/module/web/TabBar.js.map +1 -0
- package/lib/module/web/TextField.js +316 -0
- package/lib/module/web/TextField.js.map +1 -0
- package/lib/module/web/components.js +33 -0
- package/lib/module/web/components.js.map +1 -0
- package/lib/module/web/containers.js +112 -0
- package/lib/module/web/containers.js.map +1 -0
- package/lib/module/web/dateInput.js +109 -0
- package/lib/module/web/dateInput.js.map +1 -0
- package/lib/module/web/shared.js +179 -0
- package/lib/module/web/shared.js.map +1 -0
- package/lib/module/webComponents.js +4 -0
- package/lib/module/webComponents.js.map +1 -0
- package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/Button.d.ts +111 -3
- package/lib/typescript/commonjs/src/Button.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ButtonGroup.d.ts +21 -6
- package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +64 -3
- package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +94 -3
- package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ContextMenu.d.ts +20 -33
- package/lib/typescript/commonjs/src/ContextMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +45 -47
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DatePicker.d.ts +74 -1
- package/lib/typescript/commonjs/src/DatePicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +16 -1
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/FloatingActionButton.d.ts +67 -0
- package/lib/typescript/commonjs/src/FloatingActionButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/FloatingActionButtonNativeComponent.d.ts +43 -0
- package/lib/typescript/commonjs/src/FloatingActionButtonNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +30 -0
- package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +12 -0
- package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts +17 -0
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlassContainer.d.ts +27 -0
- package/lib/typescript/commonjs/src/LiquidGlassContainer.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/LiquidGlassContainerNativeComponent.d.ts +13 -0
- package/lib/typescript/commonjs/src/LiquidGlassContainerNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +7 -0
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/NavigationRail.d.ts +86 -0
- package/lib/typescript/commonjs/src/NavigationRail.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/NavigationRailNativeComponent.d.ts +81 -0
- package/lib/typescript/commonjs/src/NavigationRailNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/PlatformComponentsProvider.d.ts +6 -0
- package/lib/typescript/commonjs/src/PlatformComponentsProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts +18 -1
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +9 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SelectionMenu.d.ts +44 -2
- package/lib/typescript/commonjs/src/SelectionMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +20 -4
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SplitButton.d.ts +83 -0
- package/lib/typescript/commonjs/src/SplitButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/TabBar.d.ts +144 -0
- package/lib/typescript/commonjs/src/TabBar.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/TabBarAccessoryNativeComponent.d.ts +13 -0
- package/lib/typescript/commonjs/src/TabBarAccessoryNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/TabBarNativeComponent.d.ts +110 -0
- package/lib/typescript/commonjs/src/TabBarNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/TextField.d.ts +166 -8
- package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +81 -3
- package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/haptics.d.ts +20 -0
- package/lib/typescript/commonjs/src/haptics.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/icons.d.ts +7 -1
- package/lib/typescript/commonjs/src/icons.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +7 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.web.d.ts +25 -254
- package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/jest.d.ts +139 -0
- package/lib/typescript/commonjs/src/jest.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/menuItems.d.ts +100 -0
- package/lib/typescript/commonjs/src/menuItems.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/selectionIdentifiers.d.ts +3 -0
- package/lib/typescript/commonjs/src/selectionIdentifiers.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/submitBehavior.d.ts +9 -0
- package/lib/typescript/commonjs/src/submitBehavior.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/tabItems.d.ts +55 -0
- package/lib/typescript/commonjs/src/tabItems.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/Button.d.ts +9 -0
- package/lib/typescript/commonjs/src/web/Button.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/ButtonGroup.d.ts +11 -0
- package/lib/typescript/commonjs/src/web/ButtonGroup.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/DatePicker.d.ts +14 -0
- package/lib/typescript/commonjs/src/web/DatePicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/DateRangePicker.d.ts +11 -0
- package/lib/typescript/commonjs/src/web/DateRangePicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/Dialog.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/Dialog.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/FloatingActionButton.d.ts +8 -0
- package/lib/typescript/commonjs/src/web/FloatingActionButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/Icon.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/Icon.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/NativeTheme.d.ts +10 -0
- package/lib/typescript/commonjs/src/web/NativeTheme.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/NavigationRail.d.ts +8 -0
- package/lib/typescript/commonjs/src/web/NavigationRail.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/PlatformComponentsProvider.d.ts +10 -0
- package/lib/typescript/commonjs/src/web/PlatformComponentsProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/SegmentedControl.d.ts +8 -0
- package/lib/typescript/commonjs/src/web/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/SelectionMenu.d.ts +10 -0
- package/lib/typescript/commonjs/src/web/SelectionMenu.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/SplitButton.d.ts +9 -0
- package/lib/typescript/commonjs/src/web/SplitButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/TabBar.d.ts +9 -0
- package/lib/typescript/commonjs/src/web/TabBar.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/TextField.d.ts +9 -0
- package/lib/typescript/commonjs/src/web/TextField.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/components.d.ts +17 -0
- package/lib/typescript/commonjs/src/web/components.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/containers.d.ts +24 -0
- package/lib/typescript/commonjs/src/web/containers.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/dateInput.d.ts +20 -0
- package/lib/typescript/commonjs/src/web/dateInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/shared.d.ts +43 -0
- package/lib/typescript/commonjs/src/web/shared.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/webComponents.d.ts +43 -0
- package/lib/typescript/commonjs/src/webComponents.d.ts.map +1 -0
- package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
- package/lib/typescript/module/src/Button.d.ts +111 -3
- package/lib/typescript/module/src/Button.d.ts.map +1 -1
- package/lib/typescript/module/src/ButtonGroup.d.ts +21 -6
- package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -1
- package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +64 -3
- package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/ButtonNativeComponent.d.ts +94 -3
- package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/ContextMenu.d.ts +20 -33
- package/lib/typescript/module/src/ContextMenu.d.ts.map +1 -1
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +45 -47
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/DatePicker.d.ts +74 -1
- package/lib/typescript/module/src/DatePicker.d.ts.map +1 -1
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +16 -1
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/FloatingActionButton.d.ts +67 -0
- package/lib/typescript/module/src/FloatingActionButton.d.ts.map +1 -0
- package/lib/typescript/module/src/FloatingActionButtonNativeComponent.d.ts +43 -0
- package/lib/typescript/module/src/FloatingActionButtonNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/FloatingToolbar.d.ts +30 -0
- package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -1
- package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +12 -0
- package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlass.d.ts +17 -0
- package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlassContainer.d.ts +27 -0
- package/lib/typescript/module/src/LiquidGlassContainer.d.ts.map +1 -0
- package/lib/typescript/module/src/LiquidGlassContainerNativeComponent.d.ts +13 -0
- package/lib/typescript/module/src/LiquidGlassContainerNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +7 -0
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/NavigationRail.d.ts +86 -0
- package/lib/typescript/module/src/NavigationRail.d.ts.map +1 -0
- package/lib/typescript/module/src/NavigationRailNativeComponent.d.ts +81 -0
- package/lib/typescript/module/src/NavigationRailNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/PlatformComponentsProvider.d.ts +6 -0
- package/lib/typescript/module/src/PlatformComponentsProvider.d.ts.map +1 -0
- package/lib/typescript/module/src/SegmentedControl.d.ts +18 -1
- package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +9 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/SelectionMenu.d.ts +44 -2
- package/lib/typescript/module/src/SelectionMenu.d.ts.map +1 -1
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +20 -4
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/SplitButton.d.ts +83 -0
- package/lib/typescript/module/src/SplitButton.d.ts.map +1 -0
- package/lib/typescript/module/src/TabBar.d.ts +144 -0
- package/lib/typescript/module/src/TabBar.d.ts.map +1 -0
- package/lib/typescript/module/src/TabBarAccessoryNativeComponent.d.ts +13 -0
- package/lib/typescript/module/src/TabBarAccessoryNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/TabBarNativeComponent.d.ts +110 -0
- package/lib/typescript/module/src/TabBarNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/TextField.d.ts +166 -8
- package/lib/typescript/module/src/TextField.d.ts.map +1 -1
- package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +81 -3
- package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/haptics.d.ts +20 -0
- package/lib/typescript/module/src/haptics.d.ts.map +1 -0
- package/lib/typescript/module/src/icons.d.ts +7 -1
- package/lib/typescript/module/src/icons.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +7 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.web.d.ts +25 -254
- package/lib/typescript/module/src/index.web.d.ts.map +1 -1
- package/lib/typescript/module/src/jest.d.ts +139 -0
- package/lib/typescript/module/src/jest.d.ts.map +1 -0
- package/lib/typescript/module/src/menuItems.d.ts +100 -0
- package/lib/typescript/module/src/menuItems.d.ts.map +1 -0
- package/lib/typescript/module/src/selectionIdentifiers.d.ts +3 -0
- package/lib/typescript/module/src/selectionIdentifiers.d.ts.map +1 -0
- package/lib/typescript/module/src/submitBehavior.d.ts +9 -0
- package/lib/typescript/module/src/submitBehavior.d.ts.map +1 -0
- package/lib/typescript/module/src/tabItems.d.ts +55 -0
- package/lib/typescript/module/src/tabItems.d.ts.map +1 -0
- package/lib/typescript/module/src/web/Button.d.ts +9 -0
- package/lib/typescript/module/src/web/Button.d.ts.map +1 -0
- package/lib/typescript/module/src/web/ButtonGroup.d.ts +11 -0
- package/lib/typescript/module/src/web/ButtonGroup.d.ts.map +1 -0
- package/lib/typescript/module/src/web/DatePicker.d.ts +14 -0
- package/lib/typescript/module/src/web/DatePicker.d.ts.map +1 -0
- package/lib/typescript/module/src/web/DateRangePicker.d.ts +11 -0
- package/lib/typescript/module/src/web/DateRangePicker.d.ts.map +1 -0
- package/lib/typescript/module/src/web/Dialog.d.ts +12 -0
- package/lib/typescript/module/src/web/Dialog.d.ts.map +1 -0
- package/lib/typescript/module/src/web/FloatingActionButton.d.ts +8 -0
- package/lib/typescript/module/src/web/FloatingActionButton.d.ts.map +1 -0
- package/lib/typescript/module/src/web/Icon.d.ts +12 -0
- package/lib/typescript/module/src/web/Icon.d.ts.map +1 -0
- package/lib/typescript/module/src/web/NativeTheme.d.ts +10 -0
- package/lib/typescript/module/src/web/NativeTheme.d.ts.map +1 -0
- package/lib/typescript/module/src/web/NavigationRail.d.ts +8 -0
- package/lib/typescript/module/src/web/NavigationRail.d.ts.map +1 -0
- package/lib/typescript/module/src/web/PlatformComponentsProvider.d.ts +10 -0
- package/lib/typescript/module/src/web/PlatformComponentsProvider.d.ts.map +1 -0
- package/lib/typescript/module/src/web/SegmentedControl.d.ts +8 -0
- package/lib/typescript/module/src/web/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/module/src/web/SelectionMenu.d.ts +10 -0
- package/lib/typescript/module/src/web/SelectionMenu.d.ts.map +1 -0
- package/lib/typescript/module/src/web/SplitButton.d.ts +9 -0
- package/lib/typescript/module/src/web/SplitButton.d.ts.map +1 -0
- package/lib/typescript/module/src/web/TabBar.d.ts +9 -0
- package/lib/typescript/module/src/web/TabBar.d.ts.map +1 -0
- package/lib/typescript/module/src/web/TextField.d.ts +9 -0
- package/lib/typescript/module/src/web/TextField.d.ts.map +1 -0
- package/lib/typescript/module/src/web/components.d.ts +17 -0
- package/lib/typescript/module/src/web/components.d.ts.map +1 -0
- package/lib/typescript/module/src/web/containers.d.ts +24 -0
- package/lib/typescript/module/src/web/containers.d.ts.map +1 -0
- package/lib/typescript/module/src/web/dateInput.d.ts +20 -0
- package/lib/typescript/module/src/web/dateInput.d.ts.map +1 -0
- package/lib/typescript/module/src/web/shared.d.ts +43 -0
- package/lib/typescript/module/src/web/shared.d.ts.map +1 -0
- package/lib/typescript/module/src/webComponents.d.ts +43 -0
- package/lib/typescript/module/src/webComponents.d.ts.map +1 -0
- package/package.json +32 -2
- package/plugin/build/index.d.ts +3 -2
- package/plugin/build/index.d.ts.map +1 -1
- package/react-native.config.js +3 -0
- package/shared/PCFloatingActionButtonComponentDescriptors-custom.h +22 -0
- package/shared/PCFloatingActionButtonShadowNode-custom.cpp +48 -0
- package/shared/PCFloatingActionButtonShadowNode-custom.h +54 -0
- package/shared/PCFloatingActionButtonState-custom.h +61 -0
- package/shared/PCNavigationRailComponentDescriptors-custom.h +47 -0
- package/shared/PCNavigationRailShadowNode-custom.h +42 -0
- package/shared/PCNavigationRailState-custom.h +62 -0
- package/shared/PCTabBarComponentDescriptors-custom.h +22 -0
- package/shared/PCTabBarShadowNode-custom.cpp +54 -0
- package/shared/PCTabBarShadowNode-custom.h +54 -0
- package/shared/PCTabBarState-custom.h +62 -0
- package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
- package/src/Button.tsx +222 -7
- package/src/ButtonGroup.tsx +29 -11
- package/src/ButtonGroupNativeComponent.ts +74 -4
- package/src/ButtonNativeComponent.ts +119 -3
- package/src/ContextMenu.tsx +34 -81
- package/src/ContextMenuNativeComponent.ts +47 -49
- package/src/DatePicker.tsx +182 -4
- package/src/DatePickerNativeComponent.ts +19 -2
- package/src/FloatingActionButton.tsx +121 -0
- package/src/FloatingActionButtonNativeComponent.ts +58 -0
- package/src/FloatingToolbar.tsx +54 -3
- package/src/FloatingToolbarNativeComponent.ts +16 -0
- package/src/LiquidGlass.tsx +24 -1
- package/src/LiquidGlassContainer.tsx +42 -0
- package/src/LiquidGlassContainerNativeComponent.ts +17 -0
- package/src/LiquidGlassNativeComponent.ts +8 -0
- package/src/NavigationRail.tsx +203 -0
- package/src/NavigationRailNativeComponent.ts +107 -0
- package/src/PlatformComponentsProvider.tsx +15 -0
- package/src/SegmentedControl.tsx +31 -1
- package/src/SegmentedControlNativeComponent.ts +11 -0
- package/src/SelectionMenu.tsx +81 -6
- package/src/SelectionMenuNativeComponent.ts +26 -4
- package/src/SplitButton.tsx +198 -0
- package/src/TabBar.tsx +373 -0
- package/src/TabBarAccessoryNativeComponent.ts +19 -0
- package/src/TabBarNativeComponent.ts +145 -0
- package/src/TextField.tsx +428 -14
- package/src/TextFieldNativeComponent.ts +110 -4
- package/src/focusRegistry.ts +1 -0
- package/src/haptics.ts +31 -0
- package/src/icons.ts +28 -1
- package/src/index.tsx +7 -0
- package/src/index.web.tsx +51 -391
- package/src/jest.tsx +958 -0
- package/src/menuItems.ts +152 -0
- package/src/selectionIdentifiers.ts +17 -0
- package/src/submitBehavior.ts +16 -0
- package/src/tabItems.ts +113 -0
- package/src/web/Button.tsx +201 -0
- package/src/web/ButtonGroup.tsx +154 -0
- package/src/web/DatePicker.tsx +204 -0
- package/src/web/DateRangePicker.tsx +135 -0
- package/src/web/Dialog.tsx +54 -0
- package/src/web/FloatingActionButton.tsx +76 -0
- package/src/web/Icon.tsx +33 -0
- package/src/web/NativeTheme.ts +23 -0
- package/src/web/NavigationRail.tsx +148 -0
- package/src/web/PlatformComponentsProvider.tsx +48 -0
- package/src/web/SegmentedControl.tsx +127 -0
- package/src/web/SelectionMenu.tsx +149 -0
- package/src/web/SplitButton.tsx +32 -0
- package/src/web/TabBar.tsx +150 -0
- package/src/web/TextField.tsx +361 -0
- package/src/web/components.tsx +71 -0
- package/src/web/containers.tsx +130 -0
- package/src/web/dateInput.ts +137 -0
- package/src/web/shared.ts +176 -0
- package/src/webComponents.ts +45 -0
- package/android/src/main/java/com/platformcomponents/DateConstraints.kt +0 -83
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// A rail destination, bridged from ObjC++ as a dictionary.
|
|
4
|
+
struct PCNavigationRailItem {
|
|
5
|
+
let label: String
|
|
6
|
+
let value: String
|
|
7
|
+
let disabled: Bool
|
|
8
|
+
let icon: PCButtonSupport.Icon
|
|
9
|
+
let selectedIcon: PCButtonSupport.Icon
|
|
10
|
+
/// "" = no badge, " " = a dot, anything else is the badge text
|
|
11
|
+
let badge: String
|
|
12
|
+
let accessibilityLabel: String
|
|
13
|
+
let testID: String
|
|
14
|
+
/// "" | "search": a search destination without an icon gets the magnifying glass
|
|
15
|
+
let role: String
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// iOS has no navigation rail (the iPad sidebar belongs to the navigation
|
|
19
|
+
/// controller), so this is a column of tab-style `UIButton`s: the plain
|
|
20
|
+
/// configuration with the image above the title, the selected one in the
|
|
21
|
+
/// accent color as `UITabBar` shows it, badges, and the React header above
|
|
22
|
+
/// them. Expanded, the image sits before the title. Selection is controlled
|
|
23
|
+
/// from JS; a press reports the destination and whether it was selected.
|
|
24
|
+
@objcMembers
|
|
25
|
+
public final class PCNavigationRailView: UIView {
|
|
26
|
+
// MARK: - Props (set from ObjC++)
|
|
27
|
+
|
|
28
|
+
/// ObjC++ sets this as an array of dictionaries; see `rebuildItems` for keys.
|
|
29
|
+
public var items: [Any] = [] { didSet { rebuildItems() } }
|
|
30
|
+
|
|
31
|
+
/// Controlled selection by value; "" = none.
|
|
32
|
+
public var selectedValue: String = "" {
|
|
33
|
+
didSet { if oldValue != selectedValue { applyConfigurations() } }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// "auto" | "labeled" | "selected" | "unlabeled"
|
|
37
|
+
public var labelVisibility: String = "auto" {
|
|
38
|
+
didSet { if oldValue != labelVisibility { applyConfigurations(); onNeedsRemeasure?() } }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// "top" | "center" | "bottom"
|
|
42
|
+
public var menuGravity: String = "top" {
|
|
43
|
+
didSet { if oldValue != menuGravity { setNeedsLayout() } }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// The expanded rail: the image before the title
|
|
47
|
+
public var expanded: Bool = false {
|
|
48
|
+
didSet { if oldValue != expanded { updateExpanded() } }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public var activeTintColor: UIColor? { didSet { applyConfigurations() } }
|
|
52
|
+
public var inactiveTintColor: UIColor? { didSet { applyConfigurations() } }
|
|
53
|
+
public var railColor: UIColor? { didSet { backgroundColor = railColor } }
|
|
54
|
+
public var badgeBackgroundColor: UIColor? { didSet { updateBadges() } }
|
|
55
|
+
public var badgeTextColor: UIColor? { didSet { updateBadges() } }
|
|
56
|
+
|
|
57
|
+
/// Label font; nil keeps the default (caption, medium)
|
|
58
|
+
public var labelFont: UIFont? {
|
|
59
|
+
didSet { applyConfigurations(); onNeedsRemeasure?() }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// The `haptics` prop; PCNavigationRail.mm plays it on a destination press
|
|
63
|
+
public let haptics = PCHaptics()
|
|
64
|
+
|
|
65
|
+
// MARK: - Events back to ObjC++
|
|
66
|
+
|
|
67
|
+
/// (index, value, reselected)
|
|
68
|
+
public var onItemPress: ((Int, String, Bool) -> Void)?
|
|
69
|
+
|
|
70
|
+
/// Called when the rail's natural width may have changed.
|
|
71
|
+
public var onNeedsRemeasure: (() -> Void)?
|
|
72
|
+
|
|
73
|
+
/// Where ObjC++ mounts the React header.
|
|
74
|
+
public let headerContainer = PCRailHeaderContainer()
|
|
75
|
+
|
|
76
|
+
// MARK: - Internal
|
|
77
|
+
|
|
78
|
+
private var railItems: [PCNavigationRailItem] = []
|
|
79
|
+
private var buttons: [UIButton] = []
|
|
80
|
+
private var badges: [UILabel] = []
|
|
81
|
+
private var images: [(normal: UIImage?, selected: UIImage?)] = []
|
|
82
|
+
|
|
83
|
+
/// Bumped on every rebuild so late image loads can't touch stale buttons.
|
|
84
|
+
private var generation = 0
|
|
85
|
+
|
|
86
|
+
private let inset: CGFloat = 8
|
|
87
|
+
private let topInset: CGFloat = 12
|
|
88
|
+
private let headerSpacing: CGFloat = 20
|
|
89
|
+
private let itemSpacing: CGFloat = 4
|
|
90
|
+
|
|
91
|
+
public override init(frame: CGRect) {
|
|
92
|
+
super.init(frame: frame)
|
|
93
|
+
setup()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public required init?(coder: NSCoder) {
|
|
97
|
+
super.init(coder: coder)
|
|
98
|
+
setup()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private func setup() {
|
|
102
|
+
addSubview(headerContainer)
|
|
103
|
+
headerContainer.onSizeChange = { [weak self] in
|
|
104
|
+
self?.setNeedsLayout()
|
|
105
|
+
self?.onNeedsRemeasure?()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// MARK: - Items
|
|
110
|
+
|
|
111
|
+
private func rebuildItems() {
|
|
112
|
+
railItems = items.compactMap { any in
|
|
113
|
+
guard let dict = any as? [String: Any] else { return nil }
|
|
114
|
+
func icon(_ prefix: String) -> PCButtonSupport.Icon {
|
|
115
|
+
let key = { (name: String) in prefix.isEmpty ? name : prefix + name.prefix(1).uppercased() + name.dropFirst() }
|
|
116
|
+
let scale = (dict[key("iconScale")] as? NSNumber).map { CGFloat(truncating: $0) } ?? 1
|
|
117
|
+
return PCButtonSupport.Icon(
|
|
118
|
+
type: (dict[key("iconType")] as? String) ?? "",
|
|
119
|
+
name: (dict[key("iconName")] as? String) ?? "",
|
|
120
|
+
uri: (dict[key("iconUri")] as? String) ?? "",
|
|
121
|
+
scale: scale > 0 ? scale : 1,
|
|
122
|
+
tinted: (dict[key("iconTinted")] as? String) != "false",
|
|
123
|
+
request: (dict[key("iconRequest")] as? String) ?? ""
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
return PCNavigationRailItem(
|
|
127
|
+
label: (dict["label"] as? String) ?? "",
|
|
128
|
+
value: (dict["value"] as? String) ?? "",
|
|
129
|
+
disabled: (dict["disabled"] as? String) == "disabled",
|
|
130
|
+
icon: icon(""),
|
|
131
|
+
selectedIcon: icon("selected"),
|
|
132
|
+
badge: (dict["badge"] as? String) ?? "",
|
|
133
|
+
accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? "",
|
|
134
|
+
testID: (dict["testID"] as? String) ?? "",
|
|
135
|
+
role: (dict["role"] as? String) ?? ""
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
generation += 1
|
|
140
|
+
let current = generation
|
|
141
|
+
buttons.forEach { $0.removeFromSuperview() }
|
|
142
|
+
buttons = []
|
|
143
|
+
badges = []
|
|
144
|
+
images = []
|
|
145
|
+
|
|
146
|
+
for (index, item) in railItems.enumerated() {
|
|
147
|
+
let button = UIButton(type: .system)
|
|
148
|
+
button.tag = index
|
|
149
|
+
button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)
|
|
150
|
+
button.addTarget(self, action: #selector(touchedDown), for: .touchDown)
|
|
151
|
+
button.accessibilityIdentifier = item.testID.isEmpty ? nil : item.testID
|
|
152
|
+
let badge = UILabel()
|
|
153
|
+
badge.textAlignment = .center
|
|
154
|
+
badge.clipsToBounds = true
|
|
155
|
+
badge.isAccessibilityElement = false
|
|
156
|
+
button.addSubview(badge)
|
|
157
|
+
addSubview(button)
|
|
158
|
+
buttons.append(button)
|
|
159
|
+
badges.append(badge)
|
|
160
|
+
|
|
161
|
+
let icon = item.role == "search" && !item.icon.isPresent
|
|
162
|
+
? PCButtonSupport.Icon(type: "sfSymbol", name: "magnifyingglass", uri: "", scale: 1, tinted: true)
|
|
163
|
+
: item.icon
|
|
164
|
+
let normal = PCButtonSupport.image(for: icon) { [weak self] image in
|
|
165
|
+
guard let self, self.generation == current, index < self.images.count else { return }
|
|
166
|
+
self.images[index].normal = image
|
|
167
|
+
self.applyConfigurations()
|
|
168
|
+
}
|
|
169
|
+
let selected = item.selectedIcon.isPresent
|
|
170
|
+
? PCButtonSupport.image(for: item.selectedIcon) { [weak self] image in
|
|
171
|
+
guard let self, self.generation == current, index < self.images.count else { return }
|
|
172
|
+
self.images[index].selected = image
|
|
173
|
+
self.applyConfigurations()
|
|
174
|
+
}
|
|
175
|
+
: nil
|
|
176
|
+
images.append((normal, selected))
|
|
177
|
+
}
|
|
178
|
+
applyConfigurations()
|
|
179
|
+
updateBadges()
|
|
180
|
+
onNeedsRemeasure?()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// Readies the haptic for the press that is likely to follow.
|
|
184
|
+
@objc private func touchedDown() {
|
|
185
|
+
haptics.prepare(in: self)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@objc private func pressed(_ sender: UIButton) {
|
|
189
|
+
let index = sender.tag
|
|
190
|
+
guard index >= 0, index < railItems.count else { return }
|
|
191
|
+
let value = railItems[index].value
|
|
192
|
+
onItemPress?(index, value, value == selectedValue)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// MARK: - Appearance
|
|
196
|
+
|
|
197
|
+
private var defaultLabelFont: UIFont {
|
|
198
|
+
let style: UIFont.TextStyle = expanded ? .subheadline : .caption1
|
|
199
|
+
let base = UIFont.systemFont(ofSize: UIFont.preferredFont(forTextStyle: style).pointSize, weight: .medium)
|
|
200
|
+
return base
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// The symbol configuration of a destination's image.
|
|
204
|
+
private func symbolConfiguration(selected: Bool) -> UIImage.SymbolConfiguration {
|
|
205
|
+
UIImage.SymbolConfiguration(pointSize: expanded ? 18 : 20, weight: selected ? .semibold : .regular)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/// The image a destination shows in its current state.
|
|
209
|
+
private func image(for index: Int) -> UIImage? {
|
|
210
|
+
let isSelected = railItems[index].value == selectedValue
|
|
211
|
+
return isSelected ? (images[index].selected ?? images[index].normal) : images[index].normal
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/// Expanded, the titles line up: each image gets the padding that makes
|
|
215
|
+
/// up the difference to the widest one.
|
|
216
|
+
private var widestImage: CGFloat {
|
|
217
|
+
buttons.indices.compactMap { index -> CGFloat? in
|
|
218
|
+
guard index < railItems.count, let shown = image(for: index) else { return nil }
|
|
219
|
+
let selected = railItems[index].value == selectedValue
|
|
220
|
+
return (shown.applyingSymbolConfiguration(symbolConfiguration(selected: selected)) ?? shown).size.width
|
|
221
|
+
}.max() ?? 0
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private func applyConfigurations() {
|
|
225
|
+
let widest = expanded ? widestImage : 0
|
|
226
|
+
for (index, button) in buttons.enumerated() where index < railItems.count {
|
|
227
|
+
button.configuration = configuration(for: index, widestImage: widest)
|
|
228
|
+
let item = railItems[index]
|
|
229
|
+
button.isEnabled = !item.disabled
|
|
230
|
+
let isSelected = item.value == selectedValue
|
|
231
|
+
button.accessibilityTraits = isSelected ? [.button, .selected] : .button
|
|
232
|
+
let spoken = item.accessibilityLabel.isEmpty ? item.label : item.accessibilityLabel
|
|
233
|
+
button.accessibilityLabel = item.badge.isEmpty || item.badge == " " ? spoken : "\(spoken), \(item.badge)"
|
|
234
|
+
}
|
|
235
|
+
setNeedsLayout()
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private func configuration(for index: Int, widestImage: CGFloat) -> UIButton.Configuration {
|
|
239
|
+
let item = railItems[index]
|
|
240
|
+
let isSelected = item.value == selectedValue
|
|
241
|
+
var config = UIButton.Configuration.plain()
|
|
242
|
+
let shown = image(for: index)
|
|
243
|
+
let symbols = symbolConfiguration(selected: isSelected)
|
|
244
|
+
config.image = shown
|
|
245
|
+
config.preferredSymbolConfigurationForImage = symbols
|
|
246
|
+
let showsLabel = labelVisibility != "unlabeled" && (labelVisibility != "selected" || isSelected)
|
|
247
|
+
config.title = showsLabel ? item.label : nil
|
|
248
|
+
config.imagePlacement = expanded ? .leading : .top
|
|
249
|
+
if showsLabel, let shown {
|
|
250
|
+
let width = (shown.applyingSymbolConfiguration(symbols) ?? shown).size.width
|
|
251
|
+
config.imagePadding = expanded ? 12 + max(0, widestImage - width) : 4
|
|
252
|
+
} else {
|
|
253
|
+
config.imagePadding = 0
|
|
254
|
+
}
|
|
255
|
+
config.titleAlignment = expanded ? .leading : .center
|
|
256
|
+
config.titleLineBreakMode = .byTruncatingTail
|
|
257
|
+
config.contentInsets = expanded
|
|
258
|
+
? NSDirectionalEdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12)
|
|
259
|
+
: NSDirectionalEdgeInsets(top: 8, leading: 4, bottom: 8, trailing: 4)
|
|
260
|
+
// The selected destination takes the accent color, as UITabBar shows it
|
|
261
|
+
config.baseForegroundColor = isSelected
|
|
262
|
+
? (activeTintColor ?? tintColor)
|
|
263
|
+
: (inactiveTintColor ?? .secondaryLabel)
|
|
264
|
+
let font = labelFont ?? defaultLabelFont
|
|
265
|
+
config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
|
|
266
|
+
var outgoing = incoming
|
|
267
|
+
outgoing.font = font
|
|
268
|
+
return outgoing
|
|
269
|
+
}
|
|
270
|
+
return config
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
public override func tintColorDidChange() {
|
|
274
|
+
super.tintColorDidChange()
|
|
275
|
+
applyConfigurations()
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
279
|
+
super.traitCollectionDidChange(previousTraitCollection)
|
|
280
|
+
guard previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory
|
|
281
|
+
else { return }
|
|
282
|
+
applyConfigurations()
|
|
283
|
+
onNeedsRemeasure?()
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/// Badges in the system's badge colors: a count or text in a red capsule, or a dot.
|
|
287
|
+
private func updateBadges() {
|
|
288
|
+
for (index, badge) in badges.enumerated() where index < railItems.count {
|
|
289
|
+
let text = railItems[index].badge
|
|
290
|
+
badge.isHidden = text.isEmpty
|
|
291
|
+
badge.text = text == " " ? nil : text
|
|
292
|
+
badge.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
|
|
293
|
+
badge.textColor = badgeTextColor ?? .white
|
|
294
|
+
badge.backgroundColor = badgeBackgroundColor ?? .systemRed
|
|
295
|
+
}
|
|
296
|
+
setNeedsLayout()
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private func updateExpanded() {
|
|
300
|
+
onNeedsRemeasure?()
|
|
301
|
+
guard window != nil else {
|
|
302
|
+
applyConfigurations()
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
UIView.animate(withDuration: 0.3, delay: 0, options: [.beginFromCurrentState, .curveEaseInOut]) {
|
|
306
|
+
self.applyConfigurations()
|
|
307
|
+
self.layoutIfNeeded()
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// MARK: - Sizing
|
|
312
|
+
|
|
313
|
+
private func fittedSize(_ button: UIButton) -> CGSize {
|
|
314
|
+
let size = button.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
|
|
315
|
+
return CGSize(width: ceil(size.width), height: ceil(size.height))
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/// The width the rail wants: its widest destination or header, and at
|
|
319
|
+
/// least 80pt (200pt expanded).
|
|
320
|
+
@objc public func naturalWidth() -> CGFloat {
|
|
321
|
+
let buttonWidth = buttons.map { fittedSize($0).width }.max() ?? 0
|
|
322
|
+
let headerWidth = headerContainer.contentSize.width
|
|
323
|
+
let minimum: CGFloat = expanded ? 200 : 80
|
|
324
|
+
return ceil(max(minimum, buttonWidth + inset * 2, headerWidth + inset * 2))
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
public override func layoutSubviews() {
|
|
328
|
+
super.layoutSubviews()
|
|
329
|
+
let headerSize = headerContainer.contentSize
|
|
330
|
+
let hasHeader = headerSize.width > 0 && headerSize.height > 0
|
|
331
|
+
// Centered over the destinations, at their leading edge when expanded
|
|
332
|
+
let headerX = expanded
|
|
333
|
+
? (effectiveUserInterfaceLayoutDirection == .rightToLeft
|
|
334
|
+
? bounds.width - inset - 4 - headerSize.width
|
|
335
|
+
: inset + 4)
|
|
336
|
+
: (bounds.width - headerSize.width) / 2
|
|
337
|
+
headerContainer.frame = CGRect(
|
|
338
|
+
x: headerX,
|
|
339
|
+
y: topInset,
|
|
340
|
+
width: headerSize.width,
|
|
341
|
+
height: headerSize.height
|
|
342
|
+
)
|
|
343
|
+
let regionTop = hasHeader ? headerContainer.frame.maxY + headerSpacing : topInset
|
|
344
|
+
let regionBottom = bounds.height - topInset
|
|
345
|
+
|
|
346
|
+
let buttonWidth = bounds.width - inset * 2
|
|
347
|
+
let heights = buttons.map { max(expanded ? 44 : 56, fittedSize($0).height) }
|
|
348
|
+
let total = heights.reduce(0, +) + itemSpacing * CGFloat(max(0, buttons.count - 1))
|
|
349
|
+
// As the Material rail does it: placed in the rail's height, and
|
|
350
|
+
// never above the header
|
|
351
|
+
var y: CGFloat
|
|
352
|
+
switch menuGravity {
|
|
353
|
+
case "center": y = max(regionTop, (bounds.height - total) / 2)
|
|
354
|
+
case "bottom": y = max(regionTop, regionBottom - total)
|
|
355
|
+
default: y = regionTop
|
|
356
|
+
}
|
|
357
|
+
for (index, button) in buttons.enumerated() {
|
|
358
|
+
button.frame = CGRect(x: inset, y: y, width: buttonWidth, height: heights[index])
|
|
359
|
+
button.contentHorizontalAlignment = expanded ? .leading : .center
|
|
360
|
+
y += heights[index] + itemSpacing
|
|
361
|
+
layoutBadge(index)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/// The badge at the image's top trailing corner.
|
|
366
|
+
private func layoutBadge(_ index: Int) {
|
|
367
|
+
let badge = badges[index]
|
|
368
|
+
guard !badge.isHidden else { return }
|
|
369
|
+
let button = buttons[index]
|
|
370
|
+
button.layoutIfNeeded()
|
|
371
|
+
let dot = badge.text == nil
|
|
372
|
+
let height: CGFloat = dot ? 8 : 18
|
|
373
|
+
let width = dot ? 8 : max(18, ceil(badge.intrinsicContentSize.width) + 10)
|
|
374
|
+
badge.layer.cornerRadius = height / 2
|
|
375
|
+
let imageFrame = button.imageView.map { button.convert($0.bounds, from: $0) } ?? .zero
|
|
376
|
+
let anchorX = imageFrame.maxX
|
|
377
|
+
let anchorY = imageFrame.minY
|
|
378
|
+
badge.frame = CGRect(
|
|
379
|
+
x: anchorX - (dot ? 4 : 8),
|
|
380
|
+
y: anchorY - (dot ? 2 : 6),
|
|
381
|
+
width: width,
|
|
382
|
+
height: height
|
|
383
|
+
)
|
|
384
|
+
button.bringSubviewToFront(badge)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/// Holds the React header, reporting when React resizes it.
|
|
389
|
+
@objcMembers
|
|
390
|
+
public final class PCRailHeaderContainer: UIView {
|
|
391
|
+
var onSizeChange: (() -> Void)?
|
|
392
|
+
private var observations: [ObjectIdentifier: NSKeyValueObservation] = [:]
|
|
393
|
+
|
|
394
|
+
/// The header's size, as React laid it out.
|
|
395
|
+
var contentSize: CGSize {
|
|
396
|
+
subviews.reduce(CGSize.zero) { size, view in
|
|
397
|
+
CGSize(width: max(size.width, view.frame.maxX), height: max(size.height, view.frame.maxY))
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
public override func didAddSubview(_ subview: UIView) {
|
|
402
|
+
super.didAddSubview(subview)
|
|
403
|
+
observations[ObjectIdentifier(subview)] = subview.layer.observe(\.bounds, options: [.old, .new]) { [weak self] _, change in
|
|
404
|
+
guard change.oldValue?.size != change.newValue?.size else { return }
|
|
405
|
+
DispatchQueue.main.async { self?.onSizeChange?() }
|
|
406
|
+
}
|
|
407
|
+
onSizeChange?()
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
public override func willRemoveSubview(_ subview: UIView) {
|
|
411
|
+
super.willRemoveSubview(subview)
|
|
412
|
+
observations.removeValue(forKey: ObjectIdentifier(subview))?.invalidate()
|
|
413
|
+
DispatchQueue.main.async { [weak self] in self?.onSizeChange?() }
|
|
414
|
+
}
|
|
415
|
+
}
|
|
@@ -35,11 +35,12 @@ static inline bool SegmentsEqual(
|
|
|
35
35
|
if (a[i].disabled != b[i].disabled) return false;
|
|
36
36
|
if (a[i].iconType != b[i].iconType) return false;
|
|
37
37
|
if (a[i].iconName != b[i].iconName) return false;
|
|
38
|
-
if (a[i].iconUri != b[i].iconUri) return false;
|
|
38
|
+
if (a[i].iconRequest != b[i].iconRequest || a[i].iconUri != b[i].iconUri) return false;
|
|
39
39
|
if (a[i].iconScale != b[i].iconScale) return false;
|
|
40
40
|
if (a[i].iconTinted != b[i].iconTinted) return false;
|
|
41
41
|
if (a[i].badge != b[i].badge) return false;
|
|
42
42
|
if (a[i].accessibilityLabel != b[i].accessibilityLabel) return false;
|
|
43
|
+
if (a[i].testID != b[i].testID) return false;
|
|
43
44
|
}
|
|
44
45
|
return true;
|
|
45
46
|
}
|
|
@@ -93,6 +94,12 @@ static UIFont *FontFromLabelStyle(
|
|
|
93
94
|
|
|
94
95
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
95
96
|
if (self = [super initWithFrame:frame]) {
|
|
97
|
+
// Fabric views seed _props with their own defaults: RCTViewComponentView
|
|
98
|
+
// asserts on it in debug builds of React Native core, and the first
|
|
99
|
+
// updateProps would otherwise read the base ViewProps as PCSegmentedControlProps.
|
|
100
|
+
static const auto defaultProps = std::make_shared<const PCSegmentedControlProps>();
|
|
101
|
+
_props = defaultProps;
|
|
102
|
+
|
|
96
103
|
_view = [PCSegmentedControlView new];
|
|
97
104
|
self.contentView = _view;
|
|
98
105
|
|
|
@@ -102,6 +109,8 @@ static UIFont *FontFromLabelStyle(
|
|
|
102
109
|
__typeof(self) strongSelf = weakSelf;
|
|
103
110
|
if (!strongSelf) return;
|
|
104
111
|
|
|
112
|
+
[strongSelf->_view.haptics performIn:strongSelf->_view];
|
|
113
|
+
|
|
105
114
|
auto eventEmitter =
|
|
106
115
|
std::static_pointer_cast<const PCSegmentedControlEventEmitter>(
|
|
107
116
|
strongSelf->_eventEmitter);
|
|
@@ -132,7 +141,7 @@ static UIFont *FontFromLabelStyle(
|
|
|
132
141
|
std::static_pointer_cast<const PCSegmentedControlProps>(oldProps);
|
|
133
142
|
|
|
134
143
|
// segments: [{label, value, disabled, iconType, iconName, iconUri, iconScale,
|
|
135
|
-
// iconTinted, accessibilityLabel}]
|
|
144
|
+
// iconTinted, accessibilityLabel, testID}]
|
|
136
145
|
if (!prevProps || !SegmentsEqual(newProps.segments, prevProps->segments)) {
|
|
137
146
|
NSMutableArray *arr = [NSMutableArray new];
|
|
138
147
|
for (const auto &seg : newProps.segments) {
|
|
@@ -142,11 +151,13 @@ static UIFont *FontFromLabelStyle(
|
|
|
142
151
|
@"disabled": NSStringFromStd(seg.disabled, @"enabled"),
|
|
143
152
|
@"iconType": NSStringFromStd(seg.iconType, @""),
|
|
144
153
|
@"iconName": NSStringFromStd(seg.iconName, @""),
|
|
154
|
+
@"iconRequest": NSStringFromStd(seg.iconRequest, @""),
|
|
145
155
|
@"iconUri": NSStringFromStd(seg.iconUri, @""),
|
|
146
156
|
@"iconScale": @(seg.iconScale),
|
|
147
157
|
@"iconTinted": NSStringFromStd(seg.iconTinted, @"true"),
|
|
148
158
|
@"badge": NSStringFromStd(seg.badge, @""),
|
|
149
159
|
@"accessibilityLabel": NSStringFromStd(seg.accessibilityLabel, @""),
|
|
160
|
+
@"testID": NSStringFromStd(seg.testID, @""),
|
|
150
161
|
}];
|
|
151
162
|
}
|
|
152
163
|
_view.segments = arr;
|
|
@@ -208,6 +219,10 @@ static UIFont *FontFromLabelStyle(
|
|
|
208
219
|
_view.labelFont = FontFromLabelStyle(newProps.labelStyle);
|
|
209
220
|
}
|
|
210
221
|
|
|
222
|
+
if (!prevProps || newProps.haptics != prevProps->haptics) {
|
|
223
|
+
_view.haptics.kind = NSStringFromStd(newProps.haptics, @"");
|
|
224
|
+
}
|
|
225
|
+
|
|
211
226
|
if (!prevProps || newProps.badgeBackgroundColor != prevProps->badgeBackgroundColor) {
|
|
212
227
|
_view.badgeBackgroundColor = RCTUIColorFromSharedColor(newProps.badgeBackgroundColor);
|
|
213
228
|
}
|
|
@@ -9,11 +9,13 @@ struct PCSegmentedControlSegment {
|
|
|
9
9
|
/// "", "sfSymbol", "drawable" (ignored on iOS) or "image"
|
|
10
10
|
let iconType: String
|
|
11
11
|
let iconName: String
|
|
12
|
+
let iconRequest: String
|
|
12
13
|
let iconUri: String
|
|
13
14
|
let iconScale: CGFloat
|
|
14
15
|
let iconTinted: Bool
|
|
15
16
|
let badge: String
|
|
16
17
|
let accessibilityLabel: String
|
|
18
|
+
let testID: String
|
|
17
19
|
|
|
18
20
|
var hasIcon: Bool { iconType == "sfSymbol" || iconType == "image" }
|
|
19
21
|
|
|
@@ -102,6 +104,9 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
102
104
|
/// Badge text color; nil = white
|
|
103
105
|
public var badgeTextColor: UIColor? { didSet { updateBadgeColors() } }
|
|
104
106
|
|
|
107
|
+
/// The `haptics` prop; PCSegmentedControl.mm plays it on a user selection
|
|
108
|
+
public let haptics = PCHaptics()
|
|
109
|
+
|
|
105
110
|
// MARK: - Events back to ObjC++
|
|
106
111
|
|
|
107
112
|
public var onSelect: ((Int, String) -> Void)? // (index, value)
|
|
@@ -157,6 +162,11 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
157
162
|
|
|
158
163
|
let segment = parsedSegments[index]
|
|
159
164
|
onSelect?(index, segment.value)
|
|
165
|
+
if !momentary {
|
|
166
|
+
// UIKit selects immediately; restore the controlled value if
|
|
167
|
+
// the parent keeps its previous selection.
|
|
168
|
+
DispatchQueue.main.async { [weak self] in self?.updateSelection() }
|
|
169
|
+
}
|
|
160
170
|
}
|
|
161
171
|
|
|
162
172
|
// MARK: - Props handling
|
|
@@ -171,11 +181,13 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
171
181
|
disabled: (dict["disabled"] as? String) == "disabled",
|
|
172
182
|
iconType: (dict["iconType"] as? String) ?? "",
|
|
173
183
|
iconName: (dict["iconName"] as? String) ?? "",
|
|
184
|
+
iconRequest: (dict["iconRequest"] as? String) ?? "",
|
|
174
185
|
iconUri: (dict["iconUri"] as? String) ?? "",
|
|
175
186
|
iconScale: scale > 0 ? scale : 1,
|
|
176
187
|
iconTinted: (dict["iconTinted"] as? String) != "false",
|
|
177
188
|
badge: (dict["badge"] as? String) ?? "",
|
|
178
|
-
accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? ""
|
|
189
|
+
accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? "",
|
|
190
|
+
testID: (dict["testID"] as? String) ?? ""
|
|
179
191
|
)
|
|
180
192
|
}
|
|
181
193
|
|
|
@@ -197,6 +209,7 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
197
209
|
rebuildBadges()
|
|
198
210
|
updateSelection()
|
|
199
211
|
invalidateIntrinsicContentSize()
|
|
212
|
+
setNeedsLayout()
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
// MARK: - Badges
|
|
@@ -231,11 +244,9 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
231
244
|
let count = control.numberOfSegments
|
|
232
245
|
guard count > 0 else { return [] }
|
|
233
246
|
|
|
234
|
-
let segmentViews =
|
|
235
|
-
.filter { NSStringFromClass(type(of: $0)) == "UISegment" }
|
|
236
|
-
.sorted { $0.frame.minX < $1.frame.minX }
|
|
247
|
+
let segmentViews = self.segmentViews()
|
|
237
248
|
if segmentViews.count == count {
|
|
238
|
-
return segmentViews.map { $0.
|
|
249
|
+
return segmentViews.map { control.convert($0.bounds, from: $0) }
|
|
239
250
|
}
|
|
240
251
|
|
|
241
252
|
let width = control.bounds.width / CGFloat(count)
|
|
@@ -244,6 +255,44 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
244
255
|
}
|
|
245
256
|
}
|
|
246
257
|
|
|
258
|
+
/// The control's segment views in index order (right to left in RTL).
|
|
259
|
+
private func segmentViews() -> [UIView] {
|
|
260
|
+
// Direct subviews before iOS 26; inside a container view on iOS 26
|
|
261
|
+
var found: [UIView] = []
|
|
262
|
+
func collect(_ view: UIView) {
|
|
263
|
+
for sub in view.subviews {
|
|
264
|
+
if NSStringFromClass(type(of: sub)) == "UISegment" {
|
|
265
|
+
found.append(sub)
|
|
266
|
+
} else {
|
|
267
|
+
collect(sub)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
collect(control)
|
|
272
|
+
let views = found.sorted {
|
|
273
|
+
control.convert($0.bounds, from: $0).minX < control.convert($1.bounds, from: $1).minX
|
|
274
|
+
}
|
|
275
|
+
return control.effectiveUserInterfaceLayoutDirection == .rightToLeft ? views.reversed() : views
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/// Puts each segment's testID on the segment's title label or image view.
|
|
279
|
+
/// A UISegment hands its hit-tests to the control, so E2E drivers (Detox)
|
|
280
|
+
/// reject a tap on the segment itself as not hittable; its content view
|
|
281
|
+
/// passes. The views exist once laid out, and are replaced when a
|
|
282
|
+
/// segment's title or image changes.
|
|
283
|
+
private func applySegmentTestIDs() {
|
|
284
|
+
guard parsedSegments.contains(where: { !$0.testID.isEmpty }) else { return }
|
|
285
|
+
control.layoutIfNeeded()
|
|
286
|
+
let views = segmentViews()
|
|
287
|
+
guard views.count == parsedSegments.count else { return }
|
|
288
|
+
for (view, segment) in zip(views, parsedSegments) {
|
|
289
|
+
let content = view.subviews.first {
|
|
290
|
+
($0 is UILabel || $0 is UIImageView) && !$0.isHidden
|
|
291
|
+
} ?? view
|
|
292
|
+
content.accessibilityIdentifier = segment.testID.isEmpty ? nil : segment.testID
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
247
296
|
private func layoutBadges() {
|
|
248
297
|
guard !badgeLabels.isEmpty else { return }
|
|
249
298
|
control.layoutIfNeeded()
|
|
@@ -269,6 +318,7 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
269
318
|
public override func layoutSubviews() {
|
|
270
319
|
super.layoutSubviews()
|
|
271
320
|
layoutBadges()
|
|
321
|
+
applySegmentTestIDs()
|
|
272
322
|
}
|
|
273
323
|
|
|
274
324
|
/// Resolves the image shown for a segment, or nil when the segment shows
|
|
@@ -282,10 +332,10 @@ public final class PCSegmentedControlView: UIControl {
|
|
|
282
332
|
|
|
283
333
|
switch segment.iconType {
|
|
284
334
|
case "sfSymbol":
|
|
285
|
-
return
|
|
335
|
+
return PCImageLoader.symbol(named: segment.iconName).map { decorate($0, for: segment) }
|
|
286
336
|
|
|
287
337
|
case "image":
|
|
288
|
-
let cached = PCImageLoader.shared.image(uri: segment.iconUri, scale: segment.iconScale) { [weak self] image in
|
|
338
|
+
let cached = PCImageLoader.shared.image(uri: segment.iconUri, scale: segment.iconScale, request: segment.iconRequest) { [weak self] image in
|
|
289
339
|
guard let self, let image,
|
|
290
340
|
self.rebuildGeneration == generation,
|
|
291
341
|
let index = self.parsedSegments.firstIndex(where: { $0.value == segment.value }),
|