Edison  Stark

Edison Stark

1600872780

Reactstrap — Popovers

Reactstrap is a version Bootstrap made for React.

It’s a set of React components that have Boostrap styles.

In this article, we’ll look at how to add popovers with Reactstrap.

Popovers

Popovers are elements that pop up when we trigger them to.

Reactstrap popovers are built with the react-popper library.

For instance, we can add one by adding:

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Button, Popover, PopoverHeader, PopoverBody } from "reactstrap";

export default function App() {
  const [popoverOpen, setPopoverOpen] = React.useState(false);
  const toggle = () => setPopoverOpen(!popoverOpen);
  return (
    <div>
      <Button id="Popover" type="button">
        Launch Popover
      </Button>
      <Popover
        placement="bottom"
        isOpen={popoverOpen}
        target="Popover"
        toggle={toggle}
      >
        <PopoverHeader>Popover Title</PopoverHeader>
        <PopoverBody>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus
          fermentum lacus
        </PopoverBody>
      </Popover>
    </div>
  );
}

We add the Button component to let us trigger the popover.

The id is used with the target prop of the Popover to trigger it.

The Popover component has the popover.

The placement has the placement of the popover.

toggle is a function that lets us toggle the popover.

The PopoverHeader has the popover header.

And the PopoverBody has the popover body.

When we click the button, we should see the popover visible.

The isOpen prop controls whether the popover is shown.

#software-development #technology #web-development #programming #javascript

What is GEEK

Buddha Community

Reactstrap — Popovers
Castore  DeRose

Castore DeRose

1583824065

Learn about Reactstrap Components in ReactJS

Reactstrap is a component library for Reactjs. It provides in-built Bootstrap components that  provide flexibility and inbuilt validations, making it easy to create a UI. Reactstrap is similar to Bootstrap, but it has self-contained components.

In this article we will discuss the following Reactstrap components,

  • Navbar
  • Collapse
  • Tabs

Prerequisites

  • We should have a basic knowledge of HTML and JavaScript.
  • Visual Studio Code be installed
  • Node and NPM installed

Let’s create a new React project by using the following command,

npx create-react-app reactstrapcomponent  

Install Reactstrap by using the following command,

npm install --save reactstrap react react-dom    

Now install Bootstrap in this project by using the following command.

npm install --save bootstrap 

Now, open the index.js file and add import Bootstrap.

import 'bootstrap/dist/css/bootstrap.min.css';   

Now, in Visual Studio code, go to src folder and create a new folder and inside this folder add 3 new components,

  1. NavbarDemo.js
  2. Collapsedemo.js
  3. Tabsdemo.js

Now open NavbarDemo.js file and add the following code in this component,

import React, { Component } from 'react'  
import './App.css';  
import {  
        Collapse,  
        Navbar,  
        NavbarToggler,  
        Nav,  
        NavItem,  
        NavLink,  
        UncontrolledDropdown,  
        DropdownToggle,  
        DropdownMenu,  
        DropdownItem,  
} from 'reactstrap';  
export class NavbarDemo extends Component {  
        render() {  
                return (  
                        <div>  
                                <Navbar className="light" color="light" light expand="md">  
                                        <NavbarToggler />  
                                        <Collapse navbar>  
                                                <Nav navbar>  
                                                        <NavItem>  
                                                                <NavLink>Home</NavLink>  
                                                        </NavItem>  
                                                        <NavItem>  
                                                                <NavLink>About</NavLink>  
                                                        </NavItem>  
                                                        <UncontrolledDropdown nav inNavbar>  
                                                                <DropdownToggle nav caret>  
                                                                        Options  
              </DropdownToggle>  
                                                                <DropdownMenu right>  
                                                                        <DropdownItem>  
                                                                                Option 1  
                </DropdownItem>  
                                                                        <DropdownItem>  
                                                                                Option 2  
                </DropdownItem>  
                                                                </DropdownMenu>  
                                                        </UncontrolledDropdown>  
                                                </Nav>  
                                        </Collapse>  
                                </Navbar>  
  
                        </div>  
                )  
        }  
}  
  
export default NavbarDemo  

Now open App.js file and add the following code:

import React from 'react';  
import logo from './logo.svg';  
import './App.css';  
import NavbarDemo from './NavbarDemo'  
function App() {  
  return (  
    <div className="App">  
      <NavbarDemo></NavbarDemo>  
    </div>  
  );  
}  
  
export default App;  

Run the project by using ‘npm start’ and check the result.

This is image title

Now open Collapsedemo.js file and add the following code in this component:

import React, { Component } from 'react'  
import { UncontrolledCollapse, Button, CardBody, Card } from 'reactstrap';  
import { Collapse, Navbar, Nav, NavItem, NavLink } from 'reactstrap';  
export class CollapseDemo extends Component {  
        render() {  
                return (  
                 <div>  
                 <Navbar color="info" light expand="md">  
                                <Nav color="info" navbar>  
                                  <NavItem className="hdr">  
                                   <NavLink>Collapse Panel Using Reactstrap</NavLink>  
                                     </NavItem>  
                                 </Nav>  
                                </Navbar>  
                                <Button color="info" id="toggler" style={{ marginTop: '1rem' }}>  
                                        Collapse  
                                 </Button>  
                                <UncontrolledCollapse toggler="#toggler">  
                                        <Card>  
                                         <CardBody>  
                                          Jaipur (/ˈdʒaɪpʊər/ (About this soundlisten))[6][7][8] is the capital and the largest city of the Indian state of Rajasthan. As of 2011, the city had a population of 3.1 million, making it the tenth most populous city in the country  
                                         </CardBody>  
                                        </Card>  
                                </UncontrolledCollapse>  
                        </div>  
  
                )  
        }  
}  
  
export default CollapseDemo  

Run the project by using ‘npm start’ and check the result.

This is image title

Now open Tabsdemo.js file and add the following code in this component.

import React, { useState } from 'react';  
import { TabContent, TabPane, Navbar,Nav, NavItem, NavLink, Card, Button, CardTitle, CardText, Row, Col } from 'reactstrap';  
  
const TabsDemo = (props) => {  
  const [activeTab, setActiveTab] = useState('1');  
  
  const toggle = tab => {  
    if(activeTab !== tab) setActiveTab(tab);  
  }  
  
  return (  
    <div>  
            <Navbar color="info" light expand="md">  
                                <Nav color="info" navbar>  
                                  <NavItem className="hdr">  
                                   <NavLink>Reactstrap Tabs Components</NavLink>  
                                     </NavItem>  
                                 </Nav>  
                                </Navbar>  
      <Nav tabs>  
        <NavItem>  
          <NavLink  
            className={({ active: activeTab === '1' })}  
            onClick={() => { toggle('1'); }}  
          >  
            Tab1  
          </NavLink>  
        </NavItem>  
        <NavItem>  
          <NavLink  
            className={({ active: activeTab === '2' })}  
            onClick={() => { toggle('2'); }}  
          >  
            Tab2  
          </NavLink>  
        </NavItem>  
        <NavItem>  
          <NavLink  
            className={({ active: activeTab === '3' })}  
            onClick={() => { toggle('3'); }}  
          >  
           Tab3  
          </NavLink>  
        </NavItem>  
      </Nav>  
      <TabContent activeTab={activeTab}>  
        <TabPane tabId="1">  
          <Row>  
            <Col sm="12">  
              <h4>Tab 1 Contents</h4>  
            </Col>  
          </Row>  
        </TabPane>  
        <TabPane tabId="2">  
          <Row>  
            <Col sm="12">  
              <h4>Tab 2 Contents</h4>  
            </Col>  
          </Row>  
        </TabPane>  
        <TabPane tabId="3">  
          <Row>  
            <Col sm="12">  
              <h4>Tab 3 Contents</h4>  
            </Col>  
          </Row>  
        </TabPane>  
      </TabContent>  
    </div>  
  );  
}  
  
export default TabsDemo;  

Now open App.js file and add the following code,

import React from 'react';  
import logo from './logo.svg';  
import './App.css';  
import TabsDemo from './TabsDemo'  
function App() {  
  return (  
    <div className="App">  
      <TabsDemo></TabsDemo>  
    </div>  
  );  
}  
  
export default App;  

Run the project by using ‘npm start’ and check the result.

This is image title

Summary

In this article we learned how to use navbar, collapse, and tabs in Reactstrap components. Reactstrap is a component library for ReactJS.

Thanks for reading!

#react #reactjs #reactstrap

Edison  Stark

Edison Stark

1600872780

Reactstrap — Popovers

Reactstrap is a version Bootstrap made for React.

It’s a set of React components that have Boostrap styles.

In this article, we’ll look at how to add popovers with Reactstrap.

Popovers

Popovers are elements that pop up when we trigger them to.

Reactstrap popovers are built with the react-popper library.

For instance, we can add one by adding:

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Button, Popover, PopoverHeader, PopoverBody } from "reactstrap";

export default function App() {
  const [popoverOpen, setPopoverOpen] = React.useState(false);
  const toggle = () => setPopoverOpen(!popoverOpen);
  return (
    <div>
      <Button id="Popover" type="button">
        Launch Popover
      </Button>
      <Popover
        placement="bottom"
        isOpen={popoverOpen}
        target="Popover"
        toggle={toggle}
      >
        <PopoverHeader>Popover Title</PopoverHeader>
        <PopoverBody>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus
          fermentum lacus
        </PopoverBody>
      </Popover>
    </div>
  );
}

We add the Button component to let us trigger the popover.

The id is used with the target prop of the Popover to trigger it.

The Popover component has the popover.

The placement has the placement of the popover.

toggle is a function that lets us toggle the popover.

The PopoverHeader has the popover header.

And the PopoverBody has the popover body.

When we click the button, we should see the popover visible.

The isOpen prop controls whether the popover is shown.

#software-development #technology #web-development #programming #javascript

Kole  Haag

Kole Haag

1600974000

Reactstrap — Customize Popovers

Reactstrap is a version Bootstrap made for React.

It’s a set of React components that have Boostrap styles.

In this article, we’ll look at how to add popovers with Reactstrap.

Popovers Placements

Popover placements can be placed in various positions.

We just have to change the placement prop to change the placement.

#programming #software-development #technology #javascript #web-development

Rupert  Beatty

Rupert Beatty

1673170080

Popovers: A Library to Present Popovers

Popovers

A library to present popovers.

  • Present any view above your app's main content.
  • Attach to source views or use picture-in-picture positioning.
  • Display multiple popovers at the same time with smooth transitions.
  • Supports SwiftUI, UIKit, and multitasking windows on iPadOS.
  • Highly customizable API that's super simple — just add .popover.
  • Drop-in replacement for iOS 14's Menu that works on iOS 13.
  • SwiftUI-based core for a lightweight structure. 0 dependencies.
  • It's 2022 — about time that popovers got interesting!

Showroom

AlertColorMenuTipStandard
AlertColorMenuTipStandard
TutorialPicture-in-PictureNotification
TutorialPicture in PictureNotification

Example

Includes ~20 popover examples. Download

Example app

Installation

Requires iOS 13+. Popovers can be installed through the Swift Package Manager (recommended) or Cocoapods.

Swift Package Manager 
Add the Package URL:
Cocoapods 
Add this to your Podfile:


 

https://github.com/aheze/Popovers


 

pod 'Popovers'

Usage

To present a popover in SwiftUI, use the .popover(present:attributes:view) modifier. By default, the popover uses its parent view as the source frame.

import SwiftUI
import Popovers

struct ContentView: View {
    @State var present = false
    
    var body: some View {
        Button("Present popover!") {
            present = true
        }
        .popover(present: $present) { /// here!
            Text("Hi, I'm a popover.")
                .padding()
                .foregroundColor(.white)
                .background(.blue)
                .cornerRadius(16)
        }
    }
}

In UIKit, create a Popover instance, then present with UIViewController.present(_:). You should also set the source frame.

import SwiftUI
import Popovers

class ViewController: UIViewController {
    @IBOutlet weak var button: UIButton!
    @IBAction func buttonPressed(_ sender: Any) {
        var popover = Popover { PopoverView() }
        popover.attributes.sourceFrame = { [weak button] in
            button.windowFrame()
        }
        
        present(popover) /// here!
    }
}

struct PopoverView: View {
    var body: some View {
        Text("Hi, I'm a popover.")
            .padding()
            .foregroundColor(.white)
            .background(.blue)
            .cornerRadius(16)
    }
}

Button 'Present popover!' with a popover underneath. 
 

Customization

🔖💠🔲🟩🟥🎾🛑👓👉🎈🔰

Customize popovers through the Attributes struct. Pretty much everything is customizable, including positioning, animations, and dismissal behavior.

SwiftUI 
Configure in the attributes parameter.
UIKit 
Modify the attributes property.


 

.popover(
    present: $present,
    attributes: {
        $0.position = .absolute(
            originAnchor: .bottom,
            popoverAnchor: .topLeft
        )
    }
) {
    Text("Hi, I'm a popover.")
}


 

var popover = Popover {
    Text("Hi, I'm a popover.")
}

popover.attributes.position = .absolute(
    originAnchor: .bottom,
    popoverAnchor: .topLeft
)

present(popover)

🔖 Tag • AnyHashable?

Tag popovers to access them later from anywhere. This is useful for updating existing popovers.

/// Set the tag.
$0.tag = "Your Tag"

/// Access it later.
let popover = popover(tagged: "Your Tag") /// Where `self` is a `UIView` or `UIViewController`.

/// If inside a SwiftUI View, use a `WindowReader`:
WindowReader { window in
    let popover = window.popover(tagged: "Your Tag")
}

Note: When you use the .popover(selection:tag:attributes:view:) modifier, this tag is automatically set to what you provide in the parameter.

💠 Position • Position

The popover's position can either be .absolute (attached to a view) or .relative (picture-in-picture). The enum's associated value additionally configures which sides and corners are used.

  • Anchors represent sides and corners.
  • For .absolute, provide the origin anchor and popover anchor.
  • For .relative, provide the popover anchors. If there's multiple, the user will be able to drag between them like a PIP.
Anchor Reference.absolute(originAnchor: .bottom, popoverAnchor: .topLeft).relative(popoverAnchors: [.right])

⬜ Source Frame • (() -> CGRect)

This is the frame that the popover attaches to or is placed within, depending on its position. This must be in global window coordinates. Because frames are can change so often, this property is a closure. Whenever the device rotates or some other bounds update happens, the closure will be called.

SwiftUI 
By default, the source frame is automatically set to the parent view. Setting this will override it.
UIKit 
It's highly recommended to provide a source frame, otherwise the popover will appear in the top-left of the screen.


 

$0.sourceFrame = {
    /** some CGRect here */
}


 

 /// use `weak` to prevent a retain cycle
attributes.sourceFrame = { [weak button] in
    button.windowFrame()
}

🔲 Source Frame Inset • UIEdgeInsets

Edge insets to apply to the source frame. Positive values inset the frame, negative values expand it.

AbsoluteRelative
Source view has padding around it, so the popover is offset down.Source view is inset, so the popover is brought more towards the center of the screen.

⏹ Screen Edge Padding • UIEdgeInsets

Global insets for all popovers to prevent them from overflowing off the screen. Kind of like a safe area. Default value is UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16).

🟩 Presentation • Presentation

This property stores the animation and transition that's applied when the popover appears.

/// Default values:
$0.presentation.animation = .easeInOut
$0.presentation.transition = .opacity

🟥 Dismissal • Dismissal

This property stores the popover's dismissal behavior. There's a couple sub-properties here.

/// Same thing as `Presentation`.
$0.dismissal.animation = .easeInOut
$0.dismissal.transition = .opacity

/// Advanced stuff! Here's their default values:
$0.dismissal.mode = .tapOutside
$0.dismissal.tapOutsideIncludesOtherPopovers = false
$0.dismissal.excludedFrames = { [] }
$0.dismissal.dragMovesPopoverOffScreen = true
$0.dismissal.dragDismissalProximity = CGFloat(0.25)

Mode: Configure how the popover should auto-dismiss. You can have multiple at the same time!

  • .tapOutside - dismiss the popover when the user taps outside it.
  • .dragDown - dismiss the popover when the user drags it down.
  • .dragUp - dismiss the popover when the user drags it up.
  • .none - don't automatically dismiss the popover.

Tap Outside Includes Other Popovers: Only applies when mode is .tapOutside. If this is enabled, the popover will be dismissed when the user taps outside, even when another presented popover is what's tapped. Normally when you tap another popover that's presented, the current one will not dismiss.

Excluded Frames: Only applies when mode is .tapOutside. When the user taps outside the popover, but the tap lands on one of these frames, the popover will stay presented. If you want multiple popovers, you should set the source frames of your other popovers as the excluded frames.

/// Set one popover's source frame as the other's excluded frame.
/// This prevents the the current popover from being dismissed before animating to the other one.

let popover1 = Popover { Text("Hello") }
popover1.attributes.sourceFrame = { [weak button1] in button1.windowFrame() }
popover1.attributes.dismissal.excludedFrames = { [weak button2] in [ button2.windowFrame() ] }

let popover2 = Popover { Text("Hello") }
popover2.attributes.sourceFrame = { [weak button2] in button2.windowFrame() }
popover2.attributes.dismissal.excludedFrames = { [weak button1] in [ button1.windowFrame() ] }

Drag Moves Popover Off Screen: Only applies when mode is .dragDown or .dragUp. If this is enabled, the popover will continue moving off the screen after the user drags.

Drag Dismissal Proximity: Only applies when mode is .dragDown or .dragUp. Represents the point on the screen that the drag must reach in order to auto-dismiss. This property is multiplied by the screen's height.

Diagram with the top 25% of the screen highlighted in blue.

🎾 Rubber Banding Mode • RubberBandingMode

Configures which axes the popover can "rubber-band" on when dragged. The default is [.xAxis, .yAxis].

  • .xAxis - enable rubber banding on the x-axis.
  • .yAxis - enable rubber banding on the y-axis.
  • .none - disable rubber banding.

🛑 Blocks Background Touches • Bool

Set this to true to prevent underlying views from being pressed.

Popover overlaid over some buttons. Tapping on the buttons has no effect.

👓 Accessibility • Accessibilityv1.2.0

Popovers is fully accessible! The Accessibility struct provides additional options for how VoiceOver should read out content.

/// Default values:
$0.accessibility.shiftFocus = true
$0.accessibility.dismissButtonLabel = defaultDismissButtonLabel /// An X icon wrapped in `AnyView?`

Shift Focus: If enabled, VoiceOver will focus the popover as soon as it's presented.

Dismiss Button Label: A button next to the popover that appears when VoiceOver is on. By default, this is an X circle.

VoiceOver highlights the popover, which has a X button next to id.

Tip: You can also use the accessibility escape gesture (a 2-fingered Z-shape swipe) to dismiss all popovers.

👉 On Tap Outside • (() -> Void)?

A closure that's called whenever the user taps outside the popover.

🎈 On Dismiss • (() -> Void)?

A closure that's called when the popover is dismissed.

🔰 On Context Change • ((Context) -> Void)?

A closure that's called whenever the context changed. The context contains the popover's attributes, current frame, and other visible traits.


 

Utilities

📘🧩🌃📖🏷📄

Popovers comes with some features to make your life easier.

📘 Menus

New in v1.3.0! The template Menu looks and behaves pretty much exactly like the system menu, but also works on iOS 13. It's also extremely customizable with support for manual presentation and custom views.

The system menu and Popovers' custom menu, side by side

SwiftUI (Basic)

struct ContentView: View {
    var body: some View {
        Templates.Menu {
            Templates.MenuButton(title: "Button 1", systemImage: "1.circle.fill") { print("Button 1 pressed") }
            Templates.MenuButton(title: "Button 2", systemImage: "2.circle.fill") { print("Button 2 pressed") }
        } label: { fade in
            Text("Present Menu!")
                .opacity(fade ? 0.5 : 1)
        }
    }
}

SwiftUI (Customized)

Templates.Menu(
    configuration: {
        $0.width = 360
        $0.backgroundColor = .blue.opacity(0.2)
    }
) {
    Text("Hi, I'm a menu!")
        .padding()

    Templates.MenuDivider()

    Templates.MenuItem {
        print("Item tapped")
    } label: { fade in
        Color.clear.overlay(
            AsyncImage(url: URL(string: "https://getfind.app/image.png")) {
                $0.resizable().aspectRatio(contentMode: .fill)
            } placeholder: {
                Color.clear
            }
        )
        .frame(height: 180)
        .clipped()
        .opacity(fade ? 0.5 : 1)
    }

} label: { fade in
    Text("Present Menu!")
        .opacity(fade ? 0.5 : 1)
}

SwiftUI (Manual Presentation)

struct ContentView: View {
    @State var present = false
    var body: some View {
        VStack {
            Toggle("Activate", isOn: $present)
                .padding()
                .background(.regularMaterial)
                .cornerRadius(12)
                .padding()
            
            Templates.Menu(present: $present) {
                Templates.MenuButton(title: "Button 1", systemImage: "1.circle.fill") { print("Button 1 pressed") }
                Templates.MenuButton(title: "Button 2", systemImage: "2.circle.fill") { print("Button 2 pressed") }
            } label: { fade in
                Text("Present Menu!")
                    .opacity(fade ? 0.5 : 1)
            }
        }
    }
}

UIKit (Basic)

class ViewController: UIViewController {
    @IBOutlet var label: UILabel!

    lazy var menu = Templates.UIKitMenu(sourceView: label) {
        Templates.MenuButton(title: "Button 1", systemImage: "1.circle.fill") { print("Button 1 pressed") }
        Templates.MenuButton(title: "Button 2", systemImage: "2.circle.fill") { print("Button 2 pressed") }
    } fadeLabel: { [weak self] fade in
        self?.label.alpha = fade ? 0.5 : 1
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        _ = menu /// Create the menu.
    }
}

UIKit (Customized)

class ViewController: UIViewController {
    @IBOutlet var label: UILabel!

    lazy var menu = Templates.UIKitMenu(
        sourceView: label,
        configuration: {
            $0.width = 360
            $0.backgroundColor = .blue.opacity(0.2)
        }
    ) {
        Text("Hi, I'm a menu!")
            .padding()

        Templates.MenuDivider()

        Templates.MenuItem {
            print("Item tapped")
        } label: { fade in
            Color.clear.overlay(
                AsyncImage(url: URL(string: "https://getfind.app/image.png")) {
                    $0.resizable().aspectRatio(contentMode: .fill)
                } placeholder: {
                    Color.clear
                }
            )
            .frame(height: 180)
            .clipped()
            .opacity(fade ? 0.5 : 1)
        }
    } fadeLabel: { [weak self] fade in
        UIView.animate(withDuration: 0.15) {
            self?.label.alpha = fade ? 0.5 : 1
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        _ = menu /// Create the menu.
    }
}

UIKit (Manual Presentation)

class ViewController: UIViewController {
    /// ...

    @IBAction func switchPressed(_ sender: UISwitch) {
        if menu.isPresented {
            menu.dismiss()
        } else {
            menu.present()
        }
    }
}
BasicCustomizedManual Presentation
Menu with 2 buttonsMenu with image and dividerManually activate the menu with a toggle switch

🧩 Animating Between Popovers

As long as the view structure is the same, you can smoothly transition from one popover to another.

SwiftUI 
Use the .popover(selection:tag:attributes:view:) modifier.
UIKit 
Get the existing popover using UIResponder.popover(tagged:), then call UIResponder.replace(_:with:).


 

struct ContentView: View {
    @State var selection: String?
    
    var body: some View {
        HStack {
            Button("Present First Popover") { selection = "1" }
            .popover(selection: $selection, tag: "1") {

                /// Will be presented when selection == "1".
                Text("Hi, I'm a popover.")
                    .background(.blue)
            }
            
            Button("Present Second Popover") { selection = "2" }
            .popover(selection: $selection, tag: "2") {

                /// Will be presented when selection == "2".
                Text("Hi, I'm a popover.")
                    .background(.green)
            }
        }
    }
}


 

@IBAction func button1Pressed(_ sender: Any) {
    var newPopover = Popover { Text("Hi, I'm a popover.").background(.blue) }
    newPopover.attributes.sourceFrame = { [weak button1] in button1.windowFrame() }
    newPopover.attributes.dismissal.excludedFrames = { [weak button2] in [button2.windowFrame()] }
    newPopover.attributes.tag = "Popover 1"
    
    if let oldPopover = popover(tagged: "Popover 2") {
        replace(oldPopover, with: newPopover)
    } else {
        present(newPopover) /// Present if the old popover doesn't exist.
    }
}
@IBAction func button2Pressed(_ sender: Any) {
    var newPopover = Popover { Text("Hi, I'm a popover.").background(.green) }
    newPopover.attributes.sourceFrame = { [weak button2] in button2.windowFrame() }
    newPopover.attributes.dismissal.excludedFrames = { [weak button1] in [button1.windowFrame()] }
    newPopover.attributes.tag = "Popover 2"
    
    if let oldPopover = popover(tagged: "Popover 1") {
        replace(oldPopover, with: newPopover)
    } else {
        present(newPopover)
    }
}
Smooth transition between popovers (from blue to green and back.

🌃 Background

You can put anything in a popover's background.

SwiftUI 
Use the .popover(present:attributes:view:background:) modifier.
UIKit 
Use the Popover(attributes:view:background:) initializer.


 

.popover(present: $present) {
    PopoverView()
} background: { /// here!
    Color.green.opacity(0.5)
}


 

var popover = Popover {
    PopoverView()
} background: { /// here!
    Color.green.opacity(0.5)
}

Green background over the entire screen, but underneath the popover

📖 Popover Reader

This reads the popover's context, which contains its frame, window, attributes, and various other properties. It's kind of like GeometryReader, but cooler. You can put it in the popover's view or its background.

.popover(present: $present) {
    PopoverView()
} background: {
    PopoverReader { context in
        Path {
            $0.move(to: context.frame.point(at: .bottom))
            $0.addLine(to: context.windowBounds.point(at: .bottom))
        }
        .stroke(Color.blue, lineWidth: 4)
    }
}
Line connects the bottom of the popover with the bottom of the screen

🏷 Frame Tags

Popovers includes a mechanism for tagging and reading SwiftUI view frames. You can use this to provide a popover's sourceFrame or excludedFrames. Also works great when combined with PopoverReader, for connecting lines with anchor views.

Text("This is a view")
    .frameTag("Your Tag Name") /// Adds a tag inside the window.

/// ...

WindowReader { window in
    Text("Click me!")
    .popover(
        present: $present,
        attributes: {
            $0.sourceFrame = window.frameTagged("Your Tag Name") /// Retrieves a tag from the window.
        }
    )
}

📄 Templates

Get started quickly with some templates. All of them are inside Templates with example usage in the example app.

  • AlertButtonStyle - a button style resembling a system alert.
  • VisualEffectView - lets you use UIKit blurs in SwiftUI.
  • Container - a wrapper view for the BackgroundWithArrow shape.
  • Shadow - an easier way to apply shadows.
  • BackgroundWithArrow - a shape with an arrow that looks like the system popover.
  • CurveConnector - an animatable shape with endpoints that you can set.
  • Menu - the system menu, but built from scratch.

Notes

State Re-Rendering

If you directly pass a variable down to the popover's view, it might not update. Instead, move the view into its own struct and pass down a Binding.

Yes 
The popover's view is in a separate struct, with $string passed down.
No 
The button is directly inside the view parameter and receives string.


 

struct ContentView: View {
    @State var present = false
    @State var string = "Hello, I'm a popover."

    var body: some View {
        Button("Present popover!") { present = true }
        .popover(present: $present) {
            PopoverView(string: $string) /// Pass down a Binding ($).
        }
    }
}

/// Create a separate view to ensure that the button updates.
struct PopoverView: View {
    @Binding var string: String

    var body: some View {
        Button(string) { string = "The string changed." }
        .background(.mint)
        .cornerRadius(16)
    }
}


 

struct ContentView: View {
    @State var present = false
    @State var string = "Hello, I'm a popover."

    var body: some View {
        Button("Present popover!") {
            present = true
        }
        .popover(present: $present) {

            /// Directly passing down the variable (without $) is unsupported.
            /// The button might not update.
            Button(string) { 
                string = "The string changed."
            }
            .background(.mint)
            .cornerRadius(16)
        }
    }
}

Supporting Multiple Screens • v1.1.0

Popovers comes with built-in support for multiple screens, but retrieving frame tags requires a reference to the hosting window. You can get this via WindowReader or PopoverReader's context.

WindowReader { window in 

}

/// If inside a popover's `view` or `background`, use `PopoverReader` instead.
PopoverReader { context in
    let window = context.window
}

Popover Hierarchy

Manage a popover's z-axis level by attaching .zIndex(_:) to its view. A higher index will bring it forwards.

Community

AuthorContributingNeed Help?
Popovers is made by aheze.All contributions are welcome. Just fork the repo, then make a pull request.Open an issue or join the Discord server. You can also ping me on Twitter. Or read the source code — there's lots of comments.

Apps Using Popovers

Find is an app that lets you find text in real life. Popovers is used for the quick tips and as a replacements for menus — download to check it out!

Find App 

If you have an app that uses Popovers, just make a PR or message me.

Download Details:

Author: aheze
Source Code: https://github.com/aheze/Popovers 
License: MIT license

#swift #ios #alert 

React Native Popover: A <Popover /> Component for React Native

react-native-popover

A <Popover> component for react-native. This is still very much a work in progress and only handles the simplest of cases, ideas and contributions are very welcome.

Demo

Install

npm i --save react-native-popover

Usage

'use strict';

var React = require('react');
var Popover = require('react-native-popover');
var {
  AppRegistry,
  StyleSheet,
  Text,
  TouchableHighlight,
  View,
} = require('react-native');

var PopoverExample = React.createClass({
  getInitialState() {
    return {
      isVisible: false,
      buttonRect: {},
    };
  },

  showPopover() {
    this.refs.button.measure((ox, oy, width, height, px, py) => {
      this.setState({
        isVisible: true,
        buttonRect: {x: px, y: py, width: width, height: height}
      });
    });
  },

  closePopover() {
    this.setState({isVisible: false});
  },

  render() {
    return (
      <View style={styles.container}>
        <TouchableHighlight ref='button' style={styles.button} onPress={this.showPopover}>
          <Text style={styles.buttonText}>Press me</Text>
        </TouchableHighlight>

        <Popover
          isVisible={this.state.isVisible}
          fromRect={this.state.buttonRect}
          onClose={this.closePopover}>
          <Text>I'm the content of this popover!</Text>
        </Popover>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgb(43, 186, 180)',
  },
  button: {
    borderRadius: 4,
    padding: 10,
    marginLeft: 10,
    marginRight: 10,
    backgroundColor: '#ccc',
    borderColor: '#333',
    borderWidth: 1,
  },
  buttonText: {
  }
});

AppRegistry.registerComponent('PopoverExample', () => PopoverExample);

Displaying the popover on top of other elements

React Native doesn't support directly setting a zIndex on a view. What is recommended instead is to rearrange your view hierarchy and put the popover last at the root of your app. See facebook/react-native#131

However, as an alternative, I recommend you use @brentvatne's react-native-overlay library to wrap <Popover /> and bring it to the front no matter where it sits in the render tree.

Props

PropTypeOptionalDefaultDescription
isVisibleboolYesfalseShow/Hide the popover
fromRectrectNo{}Rectangle at which to anchor the popover
displayArearectYesscreen rectArea where the popover is allowed to be displayed
placementstringYes'auto'How to position the popover - top | bottom | left | right | auto. When 'auto' is specified, it will determine the ideal placement so that the popover is fully visible within displayArea.
onClosefunctionYes Callback to be fired when the user taps the popover
customShowHandlerfunctionYes Custom show animation handler - uses a react-tween-state wrapper API in order to show the modal. See default show handler.
customHideHandlerfunctionYes Custom hide animation handler - uses a react-tween-state wrapper API in order to hide the modal. See default hide handler.

rect is an object with the following properties: {x: number, y: number, width: number, height: number}

Download Details:
Author: jeanregisser
Source Code: https://github.com/jeanregisser/react-native-popover
License:

#react  #reactnative #javascript