Skip to content

Commit

Permalink
Delegate MDComponent notification to MaterialComponent (#931)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cromefire_ authored Aug 30, 2018
2 parents 87f9dd2 + 7e2f614 commit 6833101
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 222 deletions.
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ CssMigrationWebpackPlugin.js
.babelrc
.prettierignore
.eslintignore
/docs
.idea
yarn.lock
2 changes: 1 addition & 1 deletion docs/src/routes/linear-progress/sample.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default class SnackbarPage extends Component {
render(){
return (
<div>
<LinearProgress reversed={true} />
<LinearProgress reversed />
</div>
);
}
Expand Down
48 changes: 16 additions & 32 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "preact-material-components",
"version": "1.5.1-alpha3",
"version": "1.5.1",
"description": "preact wrapper for \"Material Components for the web\"",
"module": "index.js",
"main": "dist",
Expand Down
64 changes: 53 additions & 11 deletions ts/Base/MaterialComponent.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import MDCComponent from '@material/base/component';
import {MDCRipple} from '@material/ripple';
import autobind from 'autobind-decorator';
import {Component, VNode} from 'preact';
import {OmitAttrs} from './types';
import {SoftMerge} from './types';

export interface IMaterialComponentOwnProps {
ripple?: boolean;
}

export interface IMaterialComponentOwnState {}

type MaterialComponentProps<PropType> = PropType &
IMaterialComponentOwnProps &
OmitAttrs<JSX.HTMLAttributes, PropType>;
export type MaterialComponentProps<PropType> = SoftMerge<
PropType & IMaterialComponentOwnProps,
JSX.HTMLAttributes
>;

type MaterialComponentState<StateType> = StateType & IMaterialComponentOwnState;
export type MaterialComponentState<StateType> = StateType &
IMaterialComponentOwnState;

const doNotRemoveProps = ['disabled'];

/**
* Base class for every Material component in this package
Expand All @@ -38,15 +43,23 @@ export abstract class MaterialComponent<
/** This will again be used to add apt classname to the component */
protected abstract componentName: string;

/**
* Props of which change the MDComponent will be informed.
* Override to use.
* When used do not forget to include this.afterComponentDidMount() at the end of your componentDidMount function.
* Requires this.MDComponent to be defined.
*/
protected mdcNotifyProps?: string[];

/** The final class name given to the dom */
protected classText?: string | null;
protected ripple?: MDCRipple | null;

protected control?: Element;
protected MDComponent?: MDCComponent<any, any>;

public render(props): VNode {
if (!this.classText) {
this.classText = this.buildClassName();
this.classText = this.buildClassName(props);
}
// Fetch a VNode
const componentProps = props;
Expand Down Expand Up @@ -75,6 +88,10 @@ export abstract class MaterialComponent<
.join(' ');
// Clean this shit of proxy attributes
this.mdcProps.forEach(prop => {
// TODO: Fix this better
if (prop in doNotRemoveProps) {
return;
}
delete element.attributes[prop];
});
return element;
Expand All @@ -87,12 +104,37 @@ export abstract class MaterialComponent<
}
}

public componentWillUpdate(nextProps: MaterialComponentProps<PropType>) {
if (this.MDComponent && this.mdcNotifyProps) {
for (const prop of this.mdcNotifyProps) {
if (this.props[prop] !== nextProps[prop]) {
this.MDComponent[prop] = nextProps[prop];
}
}
}
for (const prop of this.mdcProps) {
if (this.props[prop] !== nextProps[prop]) {
this.classText = this.buildClassName(nextProps);
break;
}
}
}

public componentWillUnmount() {
if (this.ripple) {
this.ripple.destroy();
}
}

@autobind
protected afterComponentDidMount() {
if (this.MDComponent && this.mdcNotifyProps) {
for (const prop of this.mdcNotifyProps) {
this.MDComponent[prop] = this.props[prop];
}
}
}

// Shared setter for the root element ref
@autobind
protected setControlRef(control?: Element) {
Expand All @@ -101,14 +143,14 @@ export abstract class MaterialComponent<

/** Build the className based on component names and mdc props */
@autobind
protected buildClassName() {
protected buildClassName(props: MaterialComponentProps<PropType>) {
// Class name based on component name
let classText = 'mdc-' + this.componentName;

// Loop over mdcProps to turn them into classNames
for (const propKey in this.props) {
if (this.props.hasOwnProperty(propKey)) {
const prop = this.props[propKey];
for (const propKey in props) {
if (props.hasOwnProperty(propKey)) {
const prop = props[propKey];
if (typeof prop === 'boolean' && prop) {
if (this.mdcProps.indexOf(propKey) !== -1) {
classText += ` mdc-${this.componentName}--${propKey}`;
Expand Down
23 changes: 15 additions & 8 deletions ts/Base/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
export type Diff<
T extends string | number | symbol,
U extends string | number | symbol
> = ({[P in T]: P} & {[P in U]: never} & {[x: string]: never})[T];

export type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;

/**
* Excludes all keys of the first type, that are also on the second type
*
* Example:
* type X = OmitAttrs<{b: () => void, c: any}, {a: number, b: string}>; // {c: any}
*/
export type OmitAttrs<
T extends {[attr: string]: any},
O extends {[attr: string]: any}
> = Pick<T, Diff<keyof T, keyof O>>;
> = Pick<T, Exclude<keyof T, keyof O>>;

/**
* Merge two types and any keys that are also in the first get deleted in the second
*
* Example:
* type Y = SoftMerge<{a: number, b: string}, {b: () => void, c: any}>; // {a: number, b: string, c: any}
*/
export type SoftMerge<A, B> = A & OmitAttrs<B, A>;
28 changes: 2 additions & 26 deletions ts/Checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ export class Checkbox extends MaterialComponent<
protected componentName = 'checkbox';
protected mdcProps = ['disabled'];
protected MDComponent?: MDCCheckbox;
protected mdcNotifyProps = ['checked', 'indeterminate', 'disabled'];

public componentDidMount() {
super.componentDidMount();
if (this.control) {
this.MDComponent = new MDCCheckbox(this.control);
toggleCheckbox(defaultProps, this.props, this.MDComponent);
}
this.afterComponentDidMount();
}

public componentWillUnmount() {
Expand All @@ -43,10 +44,6 @@ export class Checkbox extends MaterialComponent<
}
}

public componentWillUpdate(nextProps) {
toggleCheckbox(this.props, nextProps, this.MDComponent);
}

@autobind
protected materialDom(allprops) {
return (
Expand Down Expand Up @@ -76,25 +73,4 @@ export class Checkbox extends MaterialComponent<
}
}

/*
* Function to add declarative opening/closing to drawer
*/
function toggleCheckbox(oldprops, newprops, cbox) {
if (
'checked' in oldprops &&
'checked' in newprops &&
oldprops.checked !== newprops.checked
) {
cbox.checked = newprops.checked;
}

if (
'indeterminate' in oldprops &&
'indeterminate' in newprops &&
oldprops.indeterminate !== newprops.indeterminate
) {
cbox.indeterminate = newprops.indeterminate;
}
}

export default Checkbox;
Loading

0 comments on commit 6833101

Please sign in to comment.