Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ReactFauxDOM dependency for React usage and create npm module for React helper component #38

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,4 @@ language: node_js
node_js:
- stable

before_script:
- npm run build-faux-dom

script: npm test
88 changes: 68 additions & 20 deletions dist/hyperlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
var defaultConfig = {
width: '100%',
height: '100%'
};

// Check for valid number.
var isNumber = function isNumber(input) {
// Check for valid number.
};var isNumber = function isNumber(input) {
return Number(input) === Number(input);
};

Expand All @@ -35,20 +34,51 @@ var HyperList = function () {
return new HyperList(element, userProvidedConfig);
}

/**
* Update given attributes on an element
* @param {DOMElement} element
* @param {Object} values
*/

}, {
key: 'transformElement',
value: function transformElement(element, values) {
for (var i in values) {
element.setAttribute(i, values[i]);
}

return element;
}

/**
* Merge given css style on an element
* @param {DOMElement} element
* @param {Object} style
* @param {Boolean} forceClone
*/

}, {
key: 'mergeStyle',
value: function mergeStyle(element, style) {
value: function mergeStyle(element, style, forceClone) {
for (var i in style) {
if (element.style[i] !== style[i]) {
element.style[i] = style[i];
}
}

return element;
}

/**
* Return given attribute key of an element
* @param {DOMElement} element
* @param {String} key
*/

}, {
key: 'inspectElement',
value: function inspectElement(element, key) {
return element.getAttribute(key);
}
}, {
key: 'getMaxBrowserHeight',
Expand Down Expand Up @@ -90,6 +120,18 @@ var HyperList = function () {
this._lastRepaint = null;
this._maxElementHeight = HyperList.getMaxBrowserHeight();

if (!userProvidedConfig.inspectElement || typeof userProvidedConfig.inspectElement !== 'function') {
userProvidedConfig.inspectElement = HyperList.inspectElement;
}

if (!userProvidedConfig.transformElement || typeof userProvidedConfig.transformElement !== 'function') {
userProvidedConfig.transformElement = HyperList.transformElement;
}

if (!userProvidedConfig.mergeStyle || typeof userProvidedConfig.mergeStyle !== 'function') {
userProvidedConfig.mergeStyle = HyperList.mergeStyle;
}

this.refresh(element, userProvidedConfig);

var config = this._config;
Expand Down Expand Up @@ -131,7 +173,7 @@ var HyperList = function () {

Object.assign(this._config, defaultConfig, userProvidedConfig);

if (!element || element.nodeType !== 1) {
if (!element || typeof element.render !== 'function' && element.nodeType !== 1) {
throw new Error('HyperList requires a valid DOM Node container');
}

Expand Down Expand Up @@ -204,7 +246,7 @@ var HyperList = function () {
position: 'relative'
};

HyperList.mergeStyle(element, elementStyle);
config.mergeStyle(element, elementStyle);

var scrollerHeight = config.itemHeight * config.total;
var maxElementHeight = this._maxElementHeight;
Expand All @@ -218,10 +260,10 @@ var HyperList = function () {
position: 'absolute'
}, _defineProperty(_scrollerStyle, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_scrollerStyle, isHoriz ? 'width' : 'height', scrollerHeight + 'px'), _scrollerStyle);

HyperList.mergeStyle(scroller, scrollerStyle);
config.mergeStyle(scroller, scrollerStyle);

// Only append the scroller element once.
if (!this._scroller) {
// Only append the scroller element once if DOM node.
if (!this._scroller && element.nodeType === 1) {
element.appendChild(scroller);
}

Expand Down Expand Up @@ -262,18 +304,22 @@ var HyperList = function () {
height = this._itemHeights[i];
}

if (!item || item.nodeType !== 1) {
if (!item || config.transformElement === HyperList.transformElement && item.nodeType !== 1) {
throw new Error('Generator did not return a DOM Node for index: ' + i);
}

var oldClass = item.getAttribute('class') || '';
item.setAttribute('class', oldClass + ' ' + (config.rowClassName || 'vrow'));
var oldClass = config.inspectElement(item, 'class') || '';
item = config.transformElement(item, {
key: i,
class: oldClass + ' ' + (config.rowClassName || 'vrow')
});

var top = this._itemPositions[i];

HyperList.mergeStyle(item, _defineProperty({
// Possibly need to clone element
item = config.mergeStyle(item, _defineProperty({
position: 'absolute'
}, config.horizontal ? 'left' : 'top', top + 'px'));
}, config.horizontal ? 'left' : 'top', top + 'px'), true);

return item;
}
Expand Down Expand Up @@ -337,13 +383,15 @@ var HyperList = function () {
return config.applyPatch(element, fragment);
}

element.innerHTML = '';
element.appendChild(fragment);
if (element.nodeType === 1) {
element.innerHTML = '';
element.appendChild(fragment);
}
}
}, {
key: '_computePositions',
value: function _computePositions() {
var from = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0];
var from = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;

var config = this._config;
var total = config.total;
Expand All @@ -368,7 +416,7 @@ var HyperList = function () {
}, {
key: '_computeScrollHeight',
value: function _computeScrollHeight() {
var _HyperList$mergeStyle2,
var _config$mergeStyle2,
_this2 = this;

var config = this._config;
Expand All @@ -378,10 +426,10 @@ var HyperList = function () {
return a + b;
}, 0);

HyperList.mergeStyle(this._scroller, (_HyperList$mergeStyle2 = {
config.mergeStyle(this._scroller, (_config$mergeStyle2 = {
opacity: 0,
position: 'absolute'
}, _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_HyperList$mergeStyle2, isHoriz ? 'width' : 'height', scrollHeight + 'px'), _HyperList$mergeStyle2));
}, _defineProperty(_config$mergeStyle2, isHoriz ? 'height' : 'width', '1px'), _defineProperty(_config$mergeStyle2, isHoriz ? 'width' : 'height', scrollHeight + 'px'), _config$mergeStyle2));

// Calculate the height median
var sortedItemHeights = this._itemHeights.slice(0).sort(function (a, b) {
Expand Down
142 changes: 87 additions & 55 deletions examples/react-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,94 +54,126 @@
<main></main>

<script type="text/javascript" src="../dist/hyperlist.js"></script>
<script type="text/javascript" src="../dist/react-faux-dom.js"></script>
<script type="text/javascript" src="../node_modules/react/dist/react.js"></script>
<script type="text/javascript" src="../node_modules/react-dom/dist/react-dom.js"></script>
<script>
const main = document.querySelector('main');

class Container extends React.Component {
class HyperListReact extends React.Component {
render() {
return React.createElement('div', this.state.element,
this.state.fragment
);
}

constructor(props) {
super(props);

this.container = ReactFauxDOM.createElement('div');
this.handleRef = this.handleRef.bind(this);

this.state = {
// Actual state.
children: React.createElement('div'),

// Configuration for HyperList.
config: {
// User configurable via props.
height: props.height,
itemHeight: props.itemHeight,
total: props.total,
reverse: props.reverse,

useFragment: false,
scroller: ReactFauxDOM.createElement('div'),

// Required to override since React Faux DOM doesn't have scrollTop.
overrideScrollPosition() {
return main.firstChild.scrollTop;
},

applyPatch(element, fragment) {
element.childNodes.length = 0;
fragment.forEach(childNode => element.appendChild(childNode));
},

afterRender: () => {
this.state.children = this.container.toReact();
this.setState(this.state);
},
element: {
ref: this.handleRef
},
scroller: {
key: 'scroller',
style: {
position: 'relative'
}
},
fragment: [],
node: {}
};
}

generate(row) {
var el = ReactFauxDOM.createElement('div');
var p = ReactFauxDOM.createElement('p');
handleRef(node) {
this.setState({ node })
}

el.appendChild(p);
componentDidMount() {
const {
height = window.innerHeight,
itemHeight = 50,
total = 0,
reverse = false,
generate = () => {}
} = this.props;

const config = {
height,
itemHeight,
total,
generate,
scroller: React.createElement('div', this.state.scroller),
useFragment: false,
overrideScrollPosition: () => this.state.node.scrollTop || 0,
inspectElement: (element, key) => element.props[key === 'class' ? 'className' : key] || null,
transformElement: (element, values) => {
if (values.class) {
values.className = values.class
delete values.class
}

p.innerHTML = 'ITEM ' + row;
return React.cloneElement(element, values)
},
mergeStyle: (element, style, forceClone) => {
if (forceClone) {
return React.cloneElement(element, { style })
}

return el;
for (let i in style) {
if (element.props.style[i] !== style[i]) {
element.props.style[i] = style[i]
}
}
}
};
}

componentDidMount() {
const config = this.state.config;
return element
},
applyPatch: (element, fragment) => {
this.setState({
element: Object.assign({}, this.state.element, {
style: Object.assign({}, this.state.element.style, element.props.style)
}),
fragment
});
},
};

// Create the HyperList once and refresh it whenever the resize event
// triggers.
this.list = HyperList.create(this.container, config);
this.list = HyperList.create(this, config);

// Bind to the resize event, and since you should only ever have one
// handler bound to this, we pave over whatever you had set before.
window.onresize = e => {
config.height = window.innerHeight;
this.list.refresh(this.container, config);
this.list.refresh(this, config);
};

this.container.setAttribute('class', 'container');
}

componentWillUnmount() {
window.onresize = null;
this.list.destroy();
}
}

HyperListReact.defaultProps = {
style: {}
}

class MyComponent extends React.Component {
render() {
return this.state.children;
return React.createElement(HyperListReact, {
itemHeight: 30,
total: 100000,
generate: this.generate
})
}

generate(row) {
return React.createElement('div', {}, 'Item ' + row);
}
}

ReactDOM.render(React.createElement(Container, {
height: window.innerHeight,
itemHeight: 50,
total: 100000,
reverse: false,
}), main);
ReactDOM.render(React.createElement(MyComponent), main);
</script>
</body>
</html>
Loading