Giter VIP home page Giter VIP logo

chicio / rangeuislider Goto Github PK

View Code? Open in Web Editor NEW
139.0 8.0 22.0 12.28 MB

:iphone: :large_blue_circle::heavy_minus_sign::large_blue_circle: An iOS range selection slider compatible with UIKit and SwiftUI. Developed using autolayout and highly customizable using IBDesignabled and IBInspectable or programmatically. It support also RTL (right to left) languages automatically out of the box.

Home Page: http://rangeuislider.fabrizioduroni.it

License: MIT License

Swift 98.92% Objective-C 0.20% Ruby 0.63% Shell 0.26%
ios slider-range autolayout ibdesignable ibinspectable uislider range-slider range-picker rangeslider range-slider-component

rangeuislider's Introduction

RangeUISlider

Build iOS SwiftLint Supported platform CocoaPods Version CocoaPods Doc Coverage Percentage codebeat badge GitHub license

An iOS range selection slider compatible with UIKit and SwiftUI. Developed using autolayout and highly customizable using @IBDesignabled and @IBInspectable or programmatically. It support also RTL (right to left) languages automatically out of the box.


Installation

There are three ways to install RangeUISlider in your project: manual installation, as a stand-alone framework or using cocoapods.

Manual installation

To manually install RangeUISlider simply drag and drop all the file contained in the Source folder inside your project.

Framework

RangeUISlider is available also as a framework. To install it follow the standard procedure used to install a custom cocoa touch framework:

  • drag the RangeUISlider.xcodeproj inside your project
  • add it to the Embedded Binaries/Linked Frameworks and Libraries section of your project.

See the RangeUISliderDemo demo project/target for an example of the setup of the framework.

CocoaPods

RangeUISlider is also available as a pod on CocoaPods. Add the dependency to your Podfile similar to the following:

target 'MyApp' do
    pod 'RangeUISlider', '~> 3.0'
end

and then run pod install (or pod update).

Swift Package Manager (SPM)

RangeUISlider is also available as a SPM package. Add it from the project configuration using the Github repository url. Choose master or a tag. If you choose the tag it must be >= 1.11.0.

spm 1 spm 2 spm 3


Usage

You can use RangeUISlider in three ways:

  • in a UIKit project using Interface Builder (thanks to @IBDesignable and @IBInspectable )
  • in a UIKit project programmatically
  • in a SwiftUI project using the RangeSlider wrapper created using UIViewRepresentable

Interface builder

To levearege the power of the RangeUISlider in interface builder:

  • drag a UIView into you storyboard
  • set RangeUISlider as custom class of that view
    • IMPORTANT: set also the Module to RangeUISlider if you used cocoapods or the framework version during installation
  • start editing it using interface builder (and levearage the power of @IBDesignabled and @IBInspectable)

Here you can find a video tutorial for the setup with Interface Builder.

Programmatic

You can also use RangeUISlider as a programmatic UI component by setting all the property you need in your code. Take a look at the RangeUISliderDemo project to see multiple example (e.g. take a look at this contrroller. In particular, remember to set translatesAutoresizingMaskIntoConstraints = false for the slider to use autolayout. Below you can find a simple example.

override func viewDidLoad() {
    // ...other code

    super.viewDidLoad()
    rangeSlider = RangeUISlider(frame: CGRect(origin: CGPoint(x: 20, y: 20), size: CGSize(width: 100, height: 50)))
    rangeSlider.translatesAutoresizingMaskIntoConstraints = false
    rangeSlider.delegate = self
    rangeSlider.barHeight = 20
    rangeSlider.barCorners = 10
    rangeSlider.leftKnobColor = #colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)
    rangeSlider.leftKnobWidth = 40
    rangeSlider.leftKnobHeight = 40
    rangeSlider.leftKnobCorners = 20
    rangeSlider.rightKnobColor = #colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)
    rangeSlider.rightKnobWidth = 40
    rangeSlider.rightKnobHeight = 40
    rangeSlider.rightKnobCorners = 20
    self.view.addSubview(rangeSlider)
    
    // ...other code
}

SwiftUI

You can use RangeUISlider in a SwiftUI application/screen by leveraging the RangeSlider wrapper created using UIViewRepresentable. Below you can find a small example of the usage in a simple screen. You can find more example in the RangeUISliderDemo demo project (look here).

var body: some View {
        VStack {
            // ...other code
    
            RangeSlider(minValueSelected: <binding value>, maxValueSelected: <binding value>)
                .leftKnobColor(Color(#colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)))
                .leftKnobWidth(40)
                .leftKnobHeight(40)
                .leftKnobCorners(20)
                .rightKnobColor(Color(#colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)))
                .rightKnobWidth(40)
                .rightKnobHeight(40)
                .rightKnobCorners(20)
                
             // ...other code
        }
}

Access range values

You can access the range values in two ways, depending on the fact that you're using RangeUISlider in a UIKit or SwiftUI view:

  • for UIKit, use RangeUISliderDelegate and the delegate property
  • for SwiftUI, use the RangeSlider.minValueSelected and RangeSlider.maxValueSelected binding values

UIKit - RangeUISliderDelegate

To get the current values from the slider in a UIKit project, set the slider delegate property. The delegate of RangeUISlider must implement the RangeUISliderDelegate protocol, that has three methods. See code below.

@objc public protocol RangeUISliderDelegate {
    /**
     Calls the delegate when the user has started the change of the range.
     */
    @objc optional func rangeChangeStarted()

    /**
     Calls the delegate when the user is changing the range by moving the knobs.
     
     - parameter event: the change event data. See `RangeUISliderChangeEvent`.
     */
    @objc optional func rangeIsChanging(event: RangeUISliderChangeEvent)

    /**
     Calls the delegate when the user has finished the change of the range.
     
     - parameter event: the change finish event data. See `RangeUISliderChangeFinishedEvent`.
     */
    @objc func rangeChangeFinished(event: RangeUISliderChangeFinishedEvent)
}

SwiftUI - Binding values

You can access the values of the slider in a SwiftUI project by passing two bindings properties to the RangeSlider init. See the example below.

struct SwiftUIHostingView: View {
    @State private var minValueSelected: CGFloat = 10
    @State private var maxValueSelected: CGFloat = 40

    var body: some View {
        VStack {
            RangeSlider(minValueSelected: self.$minValueSelected, maxValueSelected: self.$maxValueSelected)
                .scaleMinValue(5)
                .scaleMaxValue(80)
                .defaultValueLeftKnob(10)
                .defaultValueRightKnob(40)
                .leftKnobWidth(40)
                .leftKnobHeight(40)
                .leftKnobCorners(20)
                .rightKnobColor(Color(#colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)))
                .rightKnobWidth(40)
                .rightKnobHeight(40)
                .rightKnobCorners(20)
        }
    }
}

Change knob current values programmatically (only UIKit)

You can also change the values of the slider knobs by calling this two API:

  • func changeLeftKnob(value: CGFloat) to change programmatically the left knob value
  • func changeRightKnob(value: CGFloat) to change programmatically the right knob value

The value passed to these methods should be in the slider range values (see the next section of the documentation to understand how to customize the slider range). Take a look at the example in the ChangeProgrammaticViewController contained in the demo project to understand how to use these API.

Customizable properties

This is the list of the RangeUISlider customizable properties directly from Interface Builder/programmatically (UIKit) or by using the RangeSlider access modifiers (SwiftUI):

  • identifier of the slider (Int )
  • range minimum value (CGFloat)
  • range maximum value (CGFloat)
  • step increment value (CGFloat)
  • default starting value left knob (CGFloat)
  • default starting value right knob (CGFloat)
  • range selected color
  • range selected image (override range selected color property)
  • range selected edge inset top, left, bottom, right (used only if range selected image has been setted)
  • range selected gradient color 1 (override range selected color and image)
  • range selected gradient color 1 (override range selected color and image)
  • range selected gradient start point (used only if range selected gradients color has been choosed)
  • range selected gradient end point (used only if range selected gradients color has been choosed)
  • range not selected color
  • range not selected image (override range not selected color property)
  • range not selected edge inset top, left, bottom, right (used only if range not selected image has been setted)
  • range not selected gradient color 1 (override range not selected color and image)
  • range not selected gradient color 1 (override range not selected color and image)
  • range not selected gradient start point (used only if range not selected gradients color has been choosed)
  • range not selected gradient end point (used only if range not selected gradients color has been choosed)
  • left knob width
  • left knob height
  • left knob corners radius
  • left knob color
  • left knob image (override color)
  • left knob shadow opacity
  • left knob shadow color
  • left knob shadow offset
  • left knob shadow radius
  • left knob gradient color 1 (override left knob color and image)
  • left knob gradient color 2 (override left knob color and image)
  • left knob gradient start point (used only if left knob gradients color has been choosed)
  • left knob gradient end point (used only if left knob gradients color has been choosed)
  • left knob border width
  • left knob border color
  • right knob width
  • right knob height
  • right knob corners radius
  • right knob color
  • right knob image (override color)
  • right knob shadow opacity
  • right knob shadow color
  • right knob shadow offset
  • right knob shadow radius
  • right knob gradient color 1 (override right knob color and image)
  • right knob gradient color 2 (override right knob color and image)
  • right knob gradient start point (used only if right knob gradients color has been choosed)
  • right knob gradient end point (used only if right knob gradients color has been choosed)
  • right knob border width
  • right knob border color
  • bar height
  • bar leading distance from container view
  • bar trailing distance from container view
  • bar corners
  • bar shadow opacity
  • bar shadow color
  • bar shadow offset
  • bar shadow radius
  • bar border width
  • bar border color
  • show knobs labels
  • knobs label top position
  • knobs label font size
  • knobs label font color
  • knobs label number of decimal

Documentation

You can find the complete api documentation on fabrizioduroni.it.


Examples

In the following screenshot you can find some examples of the level of customization that it is possible to reach. You can find this examples in the demo project.

rangeuislider's People

Contributors

chicio avatar jonfriskics avatar lific-rohan avatar sjongejan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rangeuislider's Issues

barBorderColor crash

Hi!
i see "barBorderColor" has crash in Swiftui, the reason i find is UIColor from UIkit and Color from Swiftui not compatible.
Way to fix: RangeSlider+Modifiers > func barBorderColor > change parameter "UIColor" to Color. Or convert Color to UIColor
I have to stand on "pod 'RangeUISlider', '~> 3.0'". If this has fixed, please ignore this issues.

Step value

When working when ranges there are use cases when it's necessary to step by 0.5 or 5... etc, possibilities are infinite, I couldn't find a property to define the step value.

It would be nice to have an ibdesignable property called step of type double so that it's open for any value.

Not working when used as a part of my SwiftUI View.

First of All Thanks for your effort providing us with this pod that also support language flipping, But unfortunately I have faced this issue after integrating it in my SwiftUI project.

Describe the bug

  1. Not respond to user interacts when putting it in my swiftui view hierachy (Design) but worked only when it's the only component inside the Whole view.
  2. Also didn't work when wrapped in scrollView even if it's the only component inside the view.

To Reproduce
Steps to reproduce the behavior:

  1. After integrating RangeSlider in my view it doesn't work i will provide you by my view structure and video showing not responding slider.
  2. Specially After wrapping it in simple view that consists of vstak wrapped in scrollview it doesn't work also.
  3. Finally i will provide you with RangeSliderView Struct and video showing that the slider works if it is the only component in the view.

Expected behavior
The expected behavior is to respond to user interactions as i gave it appropriate frame to allow user change min and max value Knobs.

Screenshots

This my view structure
Screenshot 2023-11-25 at 1 40 03 AM
And this the video showing the issue
https://github.com/chicio/RangeUISlider/assets/47571955/1e21ccf0-eec4-448e-b49c-2652c2212c4f

This is RangeSliderView itself
Screenshot 2023-11-25 at 1 40 39 AM
**Here is a video after showing navigation to the RangeSliderView and it works here **
https://github.com/chicio/RangeUISlider/assets/47571955/82a73f31-e09c-4b97-995c-ab911e719af7

changeLeftKnob(value:), changeRightKnob(value:) and Rxswift is not working.

Functions, changeLeftKnob(value:), changeRightKnob(value:), is not working.
Each function does not change the defaultValueLeftKnob value and the defaultValueRightKnob value.
Also, is it not possible to use this library by wrapping RxSwift?
The code below is not working

extension Reactive where Base: RangeUISlider {
  public var upperValue: ControlProperty<CGFloat> {
    let source = self.base.rx.methodInvoked(#selector(setter: self.base.defaultValueRightKnob))
      .compactMap { $0.first as? CGFloat }
      .map { $0.rounded() }
      .distinctUntilChanged()
    
    let bindingObserver = Binder(self.base) { (slider, value: CGFloat) in
      slider.defaultValueRightKnob = value
    }
    
    return ControlProperty(values: source, valueSink: bindingObserver)
  }
  
  public var lowerValue: ControlProperty<CGFloat> {
    let source = self.base.rx.methodInvoked(#selector(setter: self.base.defaultValueLeftKnob))
      .compactMap { $0.first as? CGFloat }
      .map { $0.rounded() }
      .distinctUntilChanged()
    
    let bindingObserver = Binder(self.base) { (slider, value: CGFloat) in
      slider.defaultValueLeftKnob = value
    }

    return ControlProperty(values: source, valueSink: bindingObserver)
  }
}

Refresh View On Programmatic Value Change

I can't seem to find a solution regarding updating the view using code. If I set the default Left Knob value in the code after it has been loaded, is there any way to refresh the view so that the value can be updated in the slider ?

Kindly look into this :)
Thanks !

Usman.

Add UI Tests

Add UI tests to the project in order to proceed with some refactoring.

Describe the solution you'd like
Add XCUITest. Use demo app (and other demo targets created ad hoc) as test container.

Default value programmatically

Hi, is it possible to set values programmatically ? I tried this

ageSlider.delegage = self
ageSlider.defaultValueLeftKnob = 20
ageSlider.defaultValueRightKnob = 33

but it seems to have an error : 'defaultValueLeftKnob' is inaccessible due to 'internal' protection level'

Thank you for any help !

can't get the selected values

hi,

can someone help me to access values from the slider while the user is changing it ? I just need to print those values.

this is what I have done but nothing is happening

@IBOutlet weak var ageSlider: RangeUISlider!
  
@objc func rangeIsChanging(minValueSelected: CGFloat, maxValueSelected: CGFloat, slider: RangeUISlider){
    }

Thank you

When the 2 knobs are on the lowest value

Hi,
first of all, congratulations for the amazing job!

I would like to share one thing that I came across while using your RangeUISlider. I'm using it as a Age Ranger control and the values could be the same, no problem until then. However, if both knobs are set to the minimum value there is a problem because the first responder on this case is the left knob and there is no room for it to move.

I ended up by doing a dirty fix on the code for now as below.

on the moveLeftKnob function, I included the else on your if clause:

if positionForKnob >= 0 && positionForKnob <= positionRightKnob {
    self.leftKnob.xPositionConstraint.constant = positionForKnob
}else{
    if gestureRecognizer.state == .began && positionForKnob <= 30 && positionRightKnob <= 10 {
        self.rightKnob.xPositionConstraint.constant = self.rightKnob.xPositionConstraint.constant + 100
    }
}

So, I basically check if it is starting the touch, check the finger position and if the right knob is so close to the left. With that, I push the right knob further to give the left one some space.

Thank you once again for the amazing piece of code.

Thiago

Unable to Refresh View On Programmatic Value Change

Hi @chicio I can't update scaleMaxValue programmatically after it has been loaded, is there any way to refresh the view so that the value can be updated in the slider ?
I'm updating scaleMaxValue in my web service success and also I tested that the value was updated, But view is not updating accordingly.

Pls Look into this....

Thanks!

Add Unit test

Extract testable logic and test it. Create a Unit test target that could run with the CI. Nothing to add ๐Ÿ™‚

View does not respond if wrapped in a scrollview.

Describe the bug
RangeUISlider's handles do not respond to touches, if it's placed inside a UIScrollView.

To Reproduce
Steps to reproduce the behavior:
Create a full screen UIScrollView, place some views inside it, along with RangeUISlider, so the content is larger than the scroll view, so it has a space to scroll.

Expected behavior
RangeUISlider responds to touches.

Screenshots
If applicable, add screenshots to help explain your problem.

Device (please complete the following information):

  • Model: Simulator and
  • OS: iOS 15

Building for "Any iOS Device (arm64)" fails

Hello Fabrizio,
I used your really fantastic RangeUISlider in one of my small iOS Apps.
I installed it as Package Dependency in Xcode 13.3 under Monterey 12.2.1 (Version rule: master).
My app with your slider works properly on different connected iPhones as well as on different Xcode iPhone simulators. No errors at all.
But as soon as I try to "Archive" it, the build for "Any iOS Device (arm64)" fails with 49 issues.
I'm pretty sure, that it is not a bug in your RangeUISlider. Do you have any clue, what might goes wrong? I'm running out of ideas.
I attached the list of issues and an error log file.
Thank you very much for your help.
All the best, Stephan
Compiler Error List.pdf
Build target RangeUISlider_2022-03-19T20-44-35.txt

Issue when change dynamically defaultValueLeftKnob and defaultValueRightKnob

Describe the bug
I will want to dynamically initialize defaultValueLeftKnob and defaultValueRightKnob

To Reproduce
In a viewDidLoad:

slideRange.rangeSelectedColor = .red
slideRange.rangeNotSelectedColor = UIColor.lightGray.withAlphaComponent(0.5)
slideRange.leftKnobWidth = 20
slideRange.leftKnobHeight = 20
slideRange.leftKnobCorners = 10
slideRange.leftKnobColor = .red
slideRange.rightKnobWidth = 20
slideRange.rightKnobHeight = 20
slideRange.rightKnobCorners = 10
slideRange.rightKnobColor = .red
slideRange.delegate = self

Change dynamically after a callback in the main thread:

slideRange.defaultValueLeftKnob = 13.70   // example of value
slideRange.defaultValueLeftKnob = 17.50  // example of value

slideRange.scaleMinValue = 10   // example of value
slideRange.scaleMaxValue = 20  // example of value

Expected behavior
Display Knobs at the right place when I initialize defaultValueLeftKnob and defaultValueRightKnob
Screenshots (2) and (3) must be the same

Screenshots
(1) Initial state
image

(2) Select values
image

(3) By initialize defaultValueLeftKnob and defaultValueRightKnob
image

Device (please complete the following information):

  • Model: iPhone Xr
  • OS: 14.4

Additional context
UIKit application
Define RangeUISlider in a Storyboard
Same with changeLeftKnob and changeRightKnob

Support RTL in seeking Slider

Describe the bug
seeking is scrolling in the opposite direction in RTL.

To Reproduce

  1. Using RangUISlider in App Support RTL.

Expected behaviour
seeking should work from RTL for min and LTR for max.

Add SwiftUI support

Describe the solution you'd like
Expose RangeUISlider using UIViewRepresentable to SwiftUI in order to use it in SwiftUI apps. Try to understand the best way to return selected values (I think bindings will be fine but let's check during implementation).

Programmatically Access

Hi, I want to know if there is support for programmatically access on properties so i can change on Run time.
Thanks

One Knob

Is there a way to have just one knob? I couldn't see one so went with another one I found, but would have preferred yours given all the other customization options.

rangeNotSelectedColor issue

Describe the bug
I try to change rangeNotSelectedColor

To Reproduce

slideRange.rangeSelectedColor = .red
slideRange.rangeNotSelectedColor = .green
slideRange.leftKnobWidth = 20
slideRange.leftKnobHeight = 20
slideRange.leftKnobCorners = 10
slideRange.leftKnobColor = .red
slideRange.rightKnobWidth = 20
slideRange.rightKnobHeight = 20
slideRange.rightKnobCorners = 10
slideRange.rightKnobColor = .red
slideRange.delegate = self

Expected behavior
No select range with green color

Screenshots
image

Device (please complete the following information):

  • Model: iPhone Xr
  • OS: 14.4

Additional context
UIKit application

Add UI Test to CI

Add UI Test to CI. New GitHub Action test that execute all the tests.

Detect Programatic change.

Programmatic calling of rangeChangeFinished is causing a lot of issues for me. Is there any way to detect if it is from a human or not?

I see the programmaticChangeCompleted method getting called internally to RangeUISlider. This could easily pass a "isFromUser" bool to make it easier to discern, "real" changes and merely the range slider initialising itself.

Can't drag the range handles

I've used the library as a Cocoapod in a project and found that it's very very difficult to actually grab the range handles. It takes many attempts.

I've also tried your demo project and it suffers the same problem. While it seems highly customisable it doesn't actually work.

I'm running on iOS 10.3.1.

How to reset Slider

On click on a UIButton like Reset Button. How can I reset the Slider to initial value/default values?

Constraints Errors and can't get values from the slider

Hi, when I try to print the values from the slider nothing is happening, I only have errors in the console like this :

[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x604000283110 H:|-(20)-[RangeUISlider.Bar:0x7fcc1854c2a0] (active, names: '|':RangeUISlider.RangeUISlider:0x7fcc198bc400 )>",
"<NSLayoutConstraint:0x604000284b50 RangeUISlider.Bar:0x7fcc1854c2a0.trailing == RangeUISlider.RangeUISlider:0x7fcc198bc400.trailing (active)>",
"<NSLayoutConstraint:0x604000099e60 RangeUISlider.Bar:0x7fcc1854c2a0.centerX == RangeUISlider.RangeUISlider:0x7fcc198bc400.centerX (active)>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x604000099e60 RangeUISlider.Bar:0x7fcc1854c2a0.centerX == RangeUISlider.RangeUISlider:0x7fcc198bc400.centerX (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

thank you for helping

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.