GithubHelp home page GithubHelp logo

reactive's Introduction

reactive Build Status

Simple and Flexible template and view binding engine with support for custom bindings and real-time updates on model changes.

Installation

With component:

$ component install component/reactive

With npm via browserify:

$ npm install reactive

Quickstart

Rendering a basic html template with a predefined data model.

var view = reactive('<p>Hello {name}!</p>', {
  name: 'Adam'
});

// you can add the view "element" to the html whenever you want
// view.el contains the html element
document.body.appendChild(view.el);
<p>Hello Adam!</p>

Handling events

Reactive provides an easy way to register handlers for dom events via predefined "bindings".

var handlers = {
  clickme: function(ev) {
    // console.log('button clicked');
  }
};

var template = '<button on-click="clickme">clickme</button>';
var view = reactive(template, {}, {
  delegate: handlers
});

A recommended approach is to wrap the reactive instance inside of your own View classes. See the Views example.

Iteration

Iteration is achieved by using the each binding on the element you wish to iterate.

var template = '<ul><li each="people">{this}</li></ul>';
var model = {
  people: ['Sally', 'Billy']
};

var view = reactive(template, model);
<ul>
  <li>Sally</li>
  <li>Billy</li>
</ul>

You can push (pop, shift, etc) to the array and the view will be updated accordingly.

model.people.push('Eve');
<ul>
  <li>Sally</li>
  <li>Billy</li>
  <li>Eve</li>
</ul>

Hiding and showing elements

DOM elements can be shown or hidden via the data-visible and data-hidden bindings.

Using the following html template.

var tmpl = '<p data-hidden="items.length">no items</p>' +
  '<ul data-visible="items.length"><li each="items">{this}</li></ul>';
var model = { items: [] };
var view = reactive(tmpl, model);

When rendering the above, we will see no items, because the array is empty.

model.items.push('one');

Will change the output to · one and hide no items. Notice how data-visible and data-hidden act in opposite directions.

API

reactive(string | element, model, [options])

Create a new reactive instance using string or element as the template and model as the data object. This binds a DOM element to a model.

If you do not have a data model and want to specify options, you can pass null or {}. Remember you must have this argument before the options argument.

Options

option type description
delegate object, instance an object or instance defining overrides and handlers for properties and events
adapter function defines how reactive will interact with the model to listen for changes
bindings object define custom bindings (see bindings docs below)

Bind object to the given element with optional view object. When a view object is present it will be checked first for overrides, which otherwise delegate to the model object.

set(prop, val)

Set the property prop to the given value val in the view.

set({prop: val})

Set multiple properties prop and given values val in the view.

get(prop)

Get the value for property prop.

bind(name, fn)

Recommend using bindings option during construction instead. Will be removed in the future.

Create a new binding called name defined by fn. See the writing bindings section for details.

use(fn)

Use a reactive plugin. fn is invoked immediately and passed the reactive instance.

destroy()

Destroy the reactive instance. This will remove all event listeners on the instance as well as remove the element from the dom.

Fires a destroyed event upon completion.

Model Adapters

Model Adapters provide the interface for reactive to interact with your model implementation. By using a custom adapter you can support models from backbone.js, modella, bamboo, etc..

You can make reactive compatible with your favorite model layer by creating a custom adapter. Changes to your model will cause the reactive view to update dynamically. The following API is required for all adapters.

constructor

The adapter option is a function which accepts one argument, the model and should return an instance with all of the adapter methods implemented. The constructor will be called as a function - without the new keyword.

As an example, the builtin adapter's constructor is:

function Adapter(model) {
  if (!(this instanceof Adapter)) {
    return new Adapter(model);
  }

  var self = this;
  self.model = model;
};

In addition to the constructor, the adapter must implement these methods:

  • subscribe
  • unsubscribe
  • unsubscribeAll
  • set
  • get

subscribe(prop, fn)

Subscribe to changes for the given property. When the property changes, fn should be called.

Adapter.prototype.subscribe = function(prop, fn) { ... };

unsubscribe(prop, fn)

Unsubscribe from changes for the given property. The fn should no longer be called on property changes for prop.

unsubscribeAll

Unsubscribe all property change events. Used when a reactive instance is being torn down.

set(prop, val)

Set the property prop to the given value val.

get(prop)

Get the value for property prop

Stock Adapters

Plugins

Custom bindings to extend reactive are listed on the plugins wiki page

Interpolation

Bindings may be applied via interoplation on attributes or text. For example here is a simple use of this feature to react to changes of an article's .name property:

<article>
  <h2>{name}</h2>
</article>

Text interpolation may appear anywhere within the copy, and may contain complex JavaScript expressions for defaulting values or other operations.

<article>
  <h2>{ name || 'Untitled' }</h2>
  <p>Summary: { body.slice(0, 10) }</p>
</article>

Reactive is smart enough to pick out multiple properties that may be used, and react to any of their changes:

<p>Welcome { first + ' ' + last }.</p>

Interpolation works for attributes as well, reacting to changes as you'd expect:

<li class="file-{id}">
  <h3>{filename}</h3>
  <p><a href="/files/{id}/download">Download {filename}</a></p>
<li>

Declarative Bindings

By default reactive supplies bindings for setting properties, listening to events, toggling visibility, appending and replacing elements. Most of these start with "data-*" however this is not required.

data-text

The data-text binding sets the text content of an element.

data-html

The data-html binding sets the inner html of an element.

data-<attr>

The data-<attr> bindings allows you to set an attribute:

<a data-href="download_url">Download</a>

each

The each binding allows you to iterate a collection of objects within the model:

<ul>
  <li each="children">{name}</li>
</ul>

The model is expected to have a children property whose value is an array.

on-<event>

The on-<event> bindings allow you to listen on an event:

<li data-text="title"><a on-click="remove">x</a></li>

remove is expected to be a method on the specified delegate object:

var delegate = {
  remove: function(ev) {
    console.log('Removing thing!');
    ...
  }
}

reactive(template, model, {
  delegate: delegate
});

data-append

The data-append binding allows you to append an existing element:

<div class="photo" data-append="histogram"></div>

The histogram property on the model is expected to contain a DOM element.

data-replace

The data-replace binding allows you to replace an existing element, and carryover its attributes:

<div class="photo" data-replace="histogram"></div>

The histogram property on the model is expected to contain a DOM element.

data-{visible,hidden}

The data-visible and data-hidden bindings conditionally add "visible" or "hidden" classnames so that you may style an element as hidden or visible.

<p data-visible="hasDescription" data-text="truncatedDescription"></p>

data-visible will add a visible class if the property is truthy. For arrays, use the .length property to trigger on empty or non-empty arrays.

data-hidden is the opposite of visible and will add a visibile class if the value is false and .hidden class if the value is truthy.

data-checked

Toggles checkbox state:

<input type="checkbox" data-checked="agreed_to_terms">

data-selected

Toggles option state:

<option data-selected="selected"></option>

Writing bindings

To author bindings, simply create a function that will accept two arguments, the element and binding value. For example, here is a binding which removes an element when truthy:

function removeIf(el, property){
  var binding = this;
  binding.change(function() {
    if (binding.value(property)) {
      el.parentNode.removeChild(el);
    }
  });
};

var template = '<span remove-if="name">no name</span>';
var view = reactive(template, { name: 'foobar' }, {
 bindings: {
  'remove-if': removeIf
 }
});

Notice that you can call the binding whatever you want when you create your view allowing you to select appropriate names. Binding authors should recommend names that make sense.

Here is another binding which uses momentjs to pretty print a javascript date.

var template = '<span moment="timestamp" format="MMM Do YY"></span>';
var view = reactive(template, { timestamp: new Date() }, {
 bindings: {
  'moment': momentFormat
 }
});

function momentFormat(el, property) {
  var binding = this;
  var format = el.getAttribute('format');
  binding.change(function () {
     var val = binding.value(property);
     el.innerText = moment(val).format(format);
  });
};

Would output the following html

<span>Mar 3rd 14</span>

You can easily re-use such bindings by making them plugins and enabling them on your instance with .use()

Interpolation

Some bindings such as data-text and data-<attr> support interpolation. These properties are automatically added to the subscription, and react to changes:

<a data-href="/download/{id}" data-text="Download {filename}"></a>

Notes

Get creative! There's a lot of application-specific logic that can be converted to declarative Reactive bindings. For example here's a naive "auto-submit" form binding:

<div class="login">
  <form action="/user" method="post" autosubmit>
    <input type="text" name="name" placeholder="Username" />
    <input type="password" name="pass" placeholder="Password" />
    <input type="submit" value="Login" />
  </form>
</div>
var reactive = require('reactive');

var view = reactive(document.querySelector('.login'), {}, {
 bindings: {
  autosubmit: autosubmit
 }
});

function autosubmit(el){
  el.onsubmit = function(e){
    e.preventDefault();
    var path = el.getAttribute('action');
    var method = el.getAttribute('method').toUpperCase();
    console.log('submit to %s %s', method, path);
  }
};

View patterns

Typically a view object wraps a model to provide additional functionality, this may look something like the following:

function UserView(user) {
  this.user = user;
  this.view = reactive(tmpl, user, {
    delegate: this
  });
}

UserView.prototype.clickme = function(ev){ ... }

Often a higher-level API is built on top of this pattern to keep things DRY but this is left to your application / other libraries.

For more examples view the ./examples directory.

Run examples and tests

$ git clone https://github.com/component/reactive.git
$ cd reactive
$ npm i
$ make
$ open examples

$ make test

License

MIT

reactive's People

Contributors

airportyh avatar anthonyshort avatar bendik avatar chrisbuttery avatar dabanlee avatar defunctzombie avatar edef1c avatar fredsterss avatar ianstormtaylor avatar jameslnewell avatar jonathanong avatar karlbohlmark avatar luka5 avatar matthewmueller avatar ooflorent avatar poying avatar stereosteve avatar swatinem avatar timaschew avatar timoxley avatar tj avatar tonistiigi avatar tootallnate avatar vendethiel avatar yanatan16 avatar yields 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactive's Issues

Iteration API

Adding child items to the parent element manually sucks. Also means the list itself isn't reactive, only it's elements (and only while they exist).

Also made more painful by #5 because you have to do a little dance to remove the parent and render the child element (e.g.<li> or <option>) as in example below:

<!-- Target Result -->
<ul>
  <li data-text="name">Tim</li>
  <li data-text="name">Bob</li>
</ul>
<div id="user-item-template">
  <li data-text="name"></li>
</div>
var userItemTemplate = document.getElementById('#user-item-template').innerHTML
var parentListEl = document.getElementById('#parentList')
var users = [{name: 'Tim'}, {name: 'Bob'}]

users.forEach(function(user) {
    var itemEl = domify(userItemTemplate)
    reactive(itemEl, react(user))
    itemEl = itemEl.children[0] //  Remove el from parent element. Gross.
    parentListEl.appendChild(itemEl)
})

I guess copying rivet's style again wouldn't be too bad:

<ul>
  <li data-each-todo="list.todos">
    <input type="checkbox" data-checked="todo.done">
    <span data-text="todo.summary"></span>
  </li>
<ul>

What do you think? Is there a better API?

'data-value' use el.value replace el.setAttribute

var attrs = [
    ...
    // remove value
    ...
];


bind('data-value', function(el, name){
      this.change(function(){
        el.value = this.interpolate(name);
      });
 });

why ? because when we write content at input element , then setTimeout execute el.setAttribute("value","xxx") cann't update UI view.

Thoughts on a runloop?

This project looks awesome. I'm excited to use this instead of Ember soon.

I get the goal of component in general, keeping the modules small and accomplishing one specific task. But I'm wondering what you guys think of including a run-loop (like in Ember).

Basically, instead of emitting events and having them directly update the DOM, you wait until the next frame to update the DOM in one big chunk. To do this, it requires:

  • Grabbing the property/method value on the next frame, rather than emitting the event and grabbing the property all in the current frame (examples/computed.html#L58). This way if the property changes multiple times, the DOM only gets modified once.
  • Having the dom render/paint only once when any number of properties change. I'm not sure exactly how browser rendering works, but say you had a table with 20 rows with a column status and the properties all changed from pending to active. With the current implementation it would update the DOM one row at a time, which slows down as there are more elements. Eventually this method slows to a crawl (even with a modest number of elements). From my knowledge the ideal way of handling this is to remove the parent-most DOM element containing the elements that will be updated, and then updating all of the properties, then re-appending the DOM element to the page. Is this correct?

What are your guys' thoughts on the ideal implementation for this? It seems that this sort of "run loop" would be implemented at the level of the require('emitter'), which wouldn't actually dispatch the events until the next frame. Not sure though.

support passing arguments to methods

e.g:

<div>{render(items)}</div>

This almost works already but is just a little broken since it gets transformed to

'<div>' + model.render(call(model, view, 'items')) + '</div>'

where's what I wanted was to call the view's render method.

The use case is to make it easier to jump back to JS when you need the power. Though it could be used in place of computed properties in some cases.

dirty data checking

ever considered this as opposed to using emitters ? (i.e. like Angular)

Would simplify a lot of things.

Support properties other than value

Often need to control things like display or class of an element.

For inspiration, these are the things you can change with rivets:

  • text
  • html
  • value
  • show/hide
  • enabled/disabled
  • checked/unchecked
  • any attribute
  • classes

See http://rivetsjs.com/#binders

This is possible with the reactive options object, but this is rather verbose, and not much better over just having a custom 'change' handler.

Preprocessing data

Considering we already have "post-processing" filters via data-attr="data | filter", perhaps it makes sense to be able to pre-process data as well.

For example, say all Dates should be formatted in a particular way, rather than having to add this filter to every date output in my template, I could do something more generic, such as:

reactive(el, data, view)
.filter(function(content) {
   if (content instanceof Date) return moment(content).format('LLL')
   return content
})

or perhaps I want to handle undefined/null in a particular way (this solves #11, #8):

reactive(el, data, view)
.filter(function(content) {
   if (content == null) return ''
})

Possibly related to #6.

layouts and nested views

I'm implementing this fairly standard layout with "header", "sidebar" and "content" panels:

_ _ _ _ _ _ _ _ _ _ _
|       header       |
| _ _ _ _ _ _ _ _ _  |
|  s  |              |
|  i  |              |
|  d  |              |
|  e  |    content   |
|  b  |              |
|  a  |              |
|  r  |              |
| _ _ _ _ _ _ _ _ _ _|
  • "sidebar" is a dynamic list of links. It changes based on filters set in the "header"
  • "content" displays some content. This may contain sub-views itself (e.g. tabs along the top) and or subview widgets for handling different sections of the content.
  • "header" displays the title of current content, filter buttons and some persistent links, e.g. to "help".

Currently I have a big container view that instantiates subviews and injets their dom elements one by one. It's simple albeit wordy. Is this the best approach? How you would set this up? Trying to find a good pattern, turtles all the way down.

Perhaps we need an example along these lines: http://spine-contacts.herokuapp.com/

fixing interpolation of model attributes

i think there's room to make reactive a little more useful for people dealing with models (by that i actually just mean getter-setter methods) instead of simple objects.

the one principle i'm using here is that objects that are reacted to should always be accessed as objects. by that i mean that this:

<p>{name}</p>

should be the way you access the reactive object's name property even if the property is actually a getter-setter, that should be transparent to the template. i think that makes sense, so that reactive doesnt need to care about what kind of model you're using.

if that's the case though, the current implementation (after #62) has one hole in its logic still.

<p>{name}</p>                    <!-- works for regular objects -->
<p>{name}</p>                    <!-- works for models -->
<p>{enabled ? 'yes' : 'no'}</p>  <!-- works for regular objects -->
<p>{enabled ? 'yes' : 'no'}</p>  <!-- DOESN'T work for models -->

in the complicated interpolation case, the expr is determined to be !isSimple() so then all of the props are accessed via:

new Function('model', 'return ' + props(expr, 'model.'));

which doesn't handle methods, only regular properties. instead, our "prefixing" needs to use this kind of logic for accessing properties:

'("function" == typeof model.' + prop + ' ? model.' + prop + '() : model.' + prop + ')'

what do you all think?

handling undefined, null, false for data-text & data-value

Right now they will show up literally as undefined, null, & false. Personally I think that undefined and null should probably just be ignored (use the defaults). So in:

<span class="tag" data-text="tag">tag</span>
<input class="url" data-value="url" placeholder="url...">

These values would default back to tag and blank (leading to url... as placeholder).

I think false might be good to either show or not show, but I think that's covered in another attribute.

+ operator for concatenating text

A common usecase for creating View helpers is simply concatenating text onto existing data… perhaps this could be handled simply in the template.

e.g.

<a data-href="id + /comments">comments</a>

Though then you might end up still needing view helper if you need to prepend text or other types of interpolation

Just a thought.

a little confused from the docs

  1. Am I supposed to be able to do this: <h1>{name}</h1> and have that call a function on my model/view, without having to use parens: name()?
  2. Am I supposed to be able to do this: <h1>{name()}</h1> and have that auto subscribe to changes for me?
  3. Am I supposed to be able to to this: <h1>{name()}</h1> and have that reference View.prototype.name instead of only Model.prototype.name?
  4. Am I supposed to be able to do this: <div class="{enabled() ? 'enabled' : 'disabled'}"></div> and have that automatically be smart and bind a subscription to change enabled?

None of these things seem to be working for me right now.

I should mention that I'm working with component/model and a view, not just plain objects with emitters. I can't seem to get some of this magic working. I really wish it did cuz reactive seems like potentially the coolest thing ever made.

Sorry if I'm doing something incredibly stupid.

consider removing data-* in place of interpolation

related to #44. This would be more expensive in terms of walking the dom tree to discover bindings but if we measure this out and it's reasonable it would probably be worth it. Ex:

<a href="/download/{id}">Download {title}</a>

vs

<a data-href="/download/{id}" data-text="Download {title}"></a>

remove format support

kinda lame and goes against localized code, if you want to format something it might as well just be on the view (or base view)'s prototype

Issue with JSON / interpolation

Recently I had an issue with having JSON passed from the backend to a hidden input bound by data-text.

Reactive saw the curly braces and tried to interpolate data, instead of trigger a change event.

Perhaps we could have some attributes that allow us to ignore certain functionality? Such as data-ignore-interpolation

idea: carryover replaced elements classes

this is a common use case i find myself doing:

<div class="integration">
  <nav class="integration-nav" data-replace="replaceNav"></nav>
</div>
View.prototype.replaceNav = function () {
  var el = magic();
  dom(el).addClass('integration-nav');
};

would be cool if the replaced element just carried over the other elements classes, since i can't think of reason i'd apply a data-replace and not want that functionality.

Pause and resume DOM operations globally

This would make it possible to manually implement a run-loop myself using RAF or maybe some interesting animations or undo/redo functionality maybe. Cf. #31

Or would it be better to have this feature in Emitter instead?

add .computed()

to reactive instead of doing it in the template, this is necessary for our interpolation support as well

remove the need for @

in expressions like {siblings[@siblings.length - 1]}. this is to prevent collisions with words in strings such as foo + "bar", but if we do some simple parsing we can avoid this

Binding on body (html, head, etc)

Hi,

I get the following error when I try to bind a view on the body element :

Cannot read property 'on' of undefined 

It would be great to bind a view on the body element or even on the html, head, etc. For example:

<link rel="stylesheet" data-href="theme">

support root-level selectors

for example

<div class="login">
  <form action="/user" method="post" autosubmit>
    <input type="text" name="name" placeholder="Username" />
    <input type="password" name="pass" placeholder="Password" />
    <input type="submit" value="Login" />
  </form>
</div>

is fine, however the following is not:

  <form action="/user" method="post" autosubmit>
    <input type="text" name="name" placeholder="Username" />
    <input type="password" name="pass" placeholder="Password" />
    <input type="submit" value="Login" />
  </form>

Refactor rendering?

Reactive.prototype.set = function(name, val){
... 
    this.renderElement( el, obj[name](), name );
...
}

// By default we just set the textContent
// but perhaps we might want to do something else? 
Reactive.prototype.renderElement = function( el ,  value, name ) {
   el.textContent = value
}

Events get bound multiple times with nested reactive elements

When you pass a reactive DOM node through a data-append or data-replace binding, the parent call to reactive() will re-bind to the child element. This means you can't compose reactive elements, which is a bummer.

Perhaps we need a way to say "don't bind anything on this node or its children"?

Example

var
reactive = require('reactive'),
domify = require('domify'),
html = [
  '<div class="wrapper">',
  '<div data-replace="sidebar"></div>',
  '<div class="content">Content</div>',
  '</div>'].join('\n'),
page = domify(html)[0],
sidebar = domify('<a href="#" on-click="greet">Sidebar</a>')[0];

reactive(sidebar, {}, {greet: function() { alert('Hello!'); }});
reactive(page, {sidebar: sidebar}, {});
document.body.appendChild(page);

When you click, the greet() function will fire and so will a "no method error".

Child nodes overwritten in reactive element

When the textContent of the reactive DOM element changes, reactive's function overwrites the entire textContent of the DOM element. If there are other child nodes in the reactive element those get overwritten as well, e.g. or other elements that may or may not be reactive.

The simple solution to this, IMO, is to change:

this.el.textContent = "newTextContent"

to

this.el.childNodes[0].textContent = "newTextContent"

Let me know if this is okay and I'll submit a pull request.

present undefined values as empty string

reactive renders an undefined value as 'undefined' which is problematic in many ways. i saw that jade handles this case with an empty string which i think is a much better solution.

better docs

talk about how interpolation now supports view delegation etc

integrate to-function

Can't recall if we've had this discussion before, but if component/to-function was used to evaluate Binding.prototype.value, it would be possible to do stuff using expressions like:

<a href="#" data-hide="users.length < 10">More</a>

Could put this in the options/fns object passed to reactive. How do you trigger a change for an expression? I don't know. Perhaps some kind of loop ala angular (#26, #31).

This will conflict with "computed properties" syntax, but I'm not really sure what's going on there. Ugh this is probably a bad idea I guess.

Advanced examples?

I would love to see a full featured application using reactive so I can get a sense for how to do more complicated things. Are there any out there that could be listed in the Readme/wiki?

2 way binding?

Angular has this "2 way binding" feature where if you change the value of the thing that is bound, then the object it was bound from is also updated, might warrant another "cooperating" component. How would you go about implementing this?

attribute-specific rendering

Re-rendering everything after each change of the model is usually too expensive.

Different models have different ways of listening to attributes (change title, change:title, etc), but I think this could be configured. I like how rivets does the adapter configuration, although it could be simplified and have sensible defaults.

support of nested properties

Is there support of nested properties:

<p data-text="profile.about"></p>
var model = { profile: { about: "blabla" } };

If not is there an easy workaround or would their be a possible feature request?

Bodo

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.