/** * Current Adapter Example * This is a simple adapter, some are extremely complex... * It is not immediately obvious why some code lives in the adapter and some in the foundation * The Select alone is over 700 lines of component logic... **/ MDCCheckboxFoundation({ addClass: (className) => this.root_.classList.add(className), removeClass: (className) => this.root_.classList.remove(className), setNativeControlAttr: (attr, value) => this.nativeCb_.setAttribute(attr, value), removeNativeControlAttr: (attr) => this.nativeCb_.removeAttribute(attr), getNativeControl: () => this.nativeCb_, isIndeterminate: () => this.indeterminate, isChecked: () => this.checked, hasNativeControl: () => !!this.nativeCb_, setNativeControlDisabled: (disabled) => this.nativeCb_.disabled = disabled, forceLayout: () => this.root_.offsetWidth, isAttachedToDOM: () => Boolean(this.root_.parentNode), }); /** * Proposal, turn the foundation into a state machine! * Instead of having the foundation figure out how to instrument behaviors, * have it be a declaration of what the state of the component should look like. * This includes a mapping of classes, attributes, and event handlers for any given element. * * This should help with just about every third party library integration. * This example is React, but the same applies for Angular, AngularJS, Vue, and Polymer. * * The Vanilla JS components would just have to instrument their own way to apply * classes and attributes, but it would be a small framework that would apply to all components. */ class extends React.Component { constructor(props) { super(props); // create the foundation. This doesn't do any DOM manipulation, it just creates the source of truth. // do this here so frameworks can render the initial content with the appropriate classes // Removes need for // - addClass // - removeClass // - setNativeControlAttr // - removeNativeControlAttr // - isIndeterminate // - isChecked // - setNativeControlDisabled this.foundation = new CheckboxFoundation(); /** * this.foundation = { * root: { * classes: 'mdc-checkbox', * attributes: {}, * domNode: null * }, * nativeControl: { * classes: 'mdc-checkbox__native-control', * attributes: { * checked: false, * indeterminate: false * disabled: false * }, * domNode: null * }, * ... * } */ } componentDidMount() { // There is rendered code with classes in the DOM // Pass the root element and now internally you can get all of the DOM nodes you need // i.e. getNativeControl // Removes need for // - getNativeControl // - hasNativeControl // - isAttachedToDOM // - forceLayout should be the same in any framework... dont know why it has its own method this.foundation.getDomNodes(this.root); /** * this.foundation = { * root: { * classes: 'mdc-checkbox', * attributes: {}, * domNode:
* }, * nativeControl: { * classes: 'mdc-checkbox__native-control', * attributes: { * checked: false, * indeterminate: false * disabled: false * }, * domNode: * }, * ... * } */ } render() { // whenever we need to, we can update the foundation state // remember that all the foundation is doing is telling us a list of our classes and attributes // so this is safe to call whenever we want in our update cycle. // For react, we would want to call this on every render this.foundation.setState({ checked: true, disabled: false }); return (
(this.root = el)} class={foundation.root.classes}> {...foundation.root.attributes} (this.nativeCb = el)} class={foundation.nativeControl.classes} {...foundation.nativeControl.attributes} />
) } } /** * Same code, sans comments */ class extends React.Component { constructor(props) { super(props); this.foundation = new CheckboxFoundation(); } componentDidMount() { this.foundation.getDomNodes(this.root); } render() { this.foundation.setState({ checked: true, disabled: false }); return (
(this.root = el)} class={foundation.root.classes}> {...foundation.root.attributes} (this.nativeCb = el)} class={foundation.nativeControl.classes} {...foundation.nativeControl.attributes} />
) } }