{"id":13627997,"url":"https://github.com/ArthurClemens/mithril-infinite","last_synced_at":"2025-04-17T00:33:02.066Z","repository":{"id":33345714,"uuid":"36990514","full_name":"ArthurClemens/mithril-infinite","owner":"ArthurClemens","description":"Infinite scroll for Mithril","archived":true,"fork":false,"pushed_at":"2022-07-20T13:47:03.000Z","size":13717,"stargazers_count":84,"open_issues_count":13,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-13T12:43:58.081Z","etag":null,"topics":["infinite-scroll","mithril"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArthurClemens.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-06T18:21:14.000Z","updated_at":"2024-06-02T08:51:47.000Z","dependencies_parsed_at":"2022-08-07T20:30:43.708Z","dependency_job_id":null,"html_url":"https://github.com/ArthurClemens/mithril-infinite","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArthurClemens%2Fmithril-infinite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArthurClemens%2Fmithril-infinite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArthurClemens%2Fmithril-infinite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArthurClemens%2Fmithril-infinite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArthurClemens","download_url":"https://codeload.github.com/ArthurClemens/mithril-infinite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249293151,"owners_count":21245687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["infinite-scroll","mithril"],"created_at":"2024-08-01T22:00:42.468Z","updated_at":"2025-04-17T00:33:01.423Z","avatar_url":"https://github.com/ArthurClemens.png","language":"JavaScript","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# Infinite Scroll for Mithril\n\nA component to handle scrolling of an \"infinite\" list or grid, while only drawing what is on screen (plus a bit of pre-fetching), so safe to use on mobiles.\n\nCompatible with Mithril 1.x.\n\n\u003c!-- MarkdownTOC autolink=\"true\" autoanchor=\"true\" bracket=\"round\" --\u003e\n\n- [Examples](#examples)\n- [Features](#features)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Handling data](#handling-data)\n    - [Using `pageUrl` for referencing URLs](#using-pageurl-for-referencing-urls)\n    - [Data file structure](#data-file-structure)\n    - [Using `pageData` for server requests](#using-pagedata-for-server-requests)\n      - [With m.request](#with-mrequest)\n      - [With `async`](#with-async)\n      - [Returning data directly](#returning-data-directly)\n      - [Returning data as a Promise](#returning-data-as-a-promise)\n  - [Handling dynamic data](#handling-dynamic-data)\n  - [Advanced item function example](#advanced-item-function-example)\n  - [Getting the total page count](#getting-the-total-page-count)\n  - [Using images](#using-images)\n  - [Using table data](#using-table-data)\n  - [Pagination](#pagination)\n  - [Custom page wrapper](#custom-page-wrapper)\n- [Configuration options](#configuration-options)\n  - [Appearance options](#appearance-options)\n  - [Callback functions](#callback-functions)\n  - [Paging options](#paging-options)\n  - [Options for infinite.isElementInViewport](#options-for-infiniteiselementinviewport)\n- [Styling](#styling)\n  - [CSS classes](#css-classes)\n  - [Fixed scroll and `overflow-anchor`](#fixed-scroll-and-overflow-anchor)\n- [Size](#size)\n- [Dependencies](#dependencies)\n- [Licence](#licence)\n\n\u003c!-- /MarkdownTOC --\u003e\n\n\u003ca name=\"examples\"\u003e\u003c/a\u003e\n\u003ca id=\"examples\"\u003e\u003c/a\u003e\n## Examples\n\n[Examples](https://github.com/ArthurClemens/mithril-infinite/tree/master/packages/examples)\n\n\n\u003ca name=\"features\"\u003e\u003c/a\u003e\n\u003ca id=\"features\"\u003e\u003c/a\u003e\n## Features\n\n* Natural scrolling using browser defaults.\n* Fast and fluent (on desktop and modern mobiles).\n* Can be used for lists, grids and table-like data.\n* Items that are out of sight are removed, so only a fraction of the total content is drawn on the screen. This is good for speed and memory consumption.\n* Support for unequal content heights and dynamic resizing of content elements.\n* As more data is loaded, the scroll view increases in size, so that the scrollbar can be used to go back to a specific point on the page.\n* Items are handled per \"page\", which is a normal way of handling batches of search results from the server.\n* Pages can contain an arbitrary and unequal amount of items.\n* Pre-fetches data of the current page, the page before and after (or n pages ahead).\n* When there is room on the page to show more data: automatic detection of \"loadable space\" (so no loading area detection div is needed).\n* Optionally use previous/next paging buttons.\n* Supports dynamic content (for instance when filtering results).\n\nNot included (by design):\n\n* Special support for older mobile browsers: no touch layer, requestAnimationFrame, absolute positioning or speed/deceleration calculations.\n\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n\u003ca id=\"installation\"\u003e\u003c/a\u003e\n## Installation\n\nUse as npm module:\n\n~~~bash\nnpm install --save mithril-infinite\n~~~\n\nor download/clone from Github.\n\nFor working with the examples, see the [examples documentation](https://github.com/ArthurClemens/mithril-infinite/tree/master/packages/examples).\n\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\u003ca id=\"usage\"\u003e\u003c/a\u003e\n## Usage\n\n**Note:** The parent of \"scroll-view\" must have a height. Also make sure that `html` has a height (typically set to `100%`).\n\n\u003ca name=\"handling-data\"\u003e\u003c/a\u003e\n\u003ca id=\"handling-data\"\u003e\u003c/a\u003e\n### Handling data\n\nData can be provided:\n\n* With `pageUrl` for referencing URLs\n* With `pageData` for server requests\n\n\n\u003ca id=\"using-pageurl-for-referencing-urls\"\u003e\u003c/a\u003e\n#### Using `pageUrl` for referencing URLs\n\nAn example using data files:\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\n\nm(infinite, {\n  maxPages: 16,\n  pageUrl: pageNum =\u003e `data/page-${pageNum}.json`,\n  item\n})\n~~~\n\nWith these options we are:\n\n* limiting the number of pages to 16\n* passing a function to generate a JSON data URL\n* passing a function that should return a Mithril element\n\nA simple item function:\n\n~~~javascript\nconst item = (data, opts, index) =\u003e \n  m(\".item\", [\n    m(\"h2\", data.title),\n    m(\"div\", data.body)\n  ])\n~~~\n\nThe `item` function passes 3 parameters:\n\n1. `data` contains the loaded data from `pageUrl`.\n2. `opts` contains: `isScrolling: Bool`, `pageId: String`, `pageNum: Number`, `pageSize: Number`\n3. `index`: the item index\n\n\n\u003ca id=\"data-file-structure\"\u003e\u003c/a\u003e\n#### Data file structure\n\nData is handled per \"results\" page. You are free to use any data format.\n\nYou could use a JSON data object for each page, containing a list of items. For example:\n\n~~~json\n[\n  {\n    \"src\": \"cat.jpg\",\n    \"width\": 500,\n    \"height\": 375\n  }\n]\n~~~\n\nOr:\n\n~~~json\n[\n  [\"red\", \"#ff0000\"],\n]\n~~~\n\n\n\u003ca id=\"using-pagedata-for-server-requests\"\u003e\u003c/a\u003e\n#### Using `pageData` for server requests\n \nIn most real world situations an API server will provide the data. So while passing file URLs with `pageUrl` is a handy shortcut, we preferably use data requests.\n\n\n\u003ca id=\"with-mrequest\"\u003e\u003c/a\u003e\n##### With m.request\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\n\nconst pageData = pageNum =\u003e \n  m.request({\n    method: \"GET\",\n    dataType: \"jsonp\",\n    url: dataUrl(pageNum)\n  })\n\nm(infinite, {\n  pageData,\n  item\n})\n~~~\n\nDemo tip: in the example \"Grid\" we use `jsonplaceholder.typicode.com` to fetch our images:\n\n~~~javascript\nconst PAGE_ITEMS = 10\n\nconst dataUrl = pageNum =\u003e\n  `http://jsonplaceholder.typicode.com/photos?_start=${(pageNum - 1) * PAGE_ITEMS}\u0026_end=${pageNum * PAGE_ITEMS}`\n~~~\n\n\n\u003ca id=\"with-async\"\u003e\u003c/a\u003e\n##### With `async`\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\n\nconst asyncPageData = async function(pageNum) {\n  try {\n    const response = await fetch(dataUrl(pageNum))\n    return response.json()\n  } catch (ex) {\n    //console.log('parsing failed', ex)\n  }\n}\n\nm(infinite, {\n  pageData: asyncPageData,\n  item\n})\n~~~\n\n\u003ca id=\"returning-data-directly\"\u003e\u003c/a\u003e\n##### Returning data directly\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\n\nconst returnData = () =\u003e\n  [{ /* some data */ }]\n\nm(infinite, {\n  pageData: returnData,\n  item\n})\n~~~\n\n\u003ca id=\"returning-data-as-a-promise\"\u003e\u003c/a\u003e\n##### Returning data as a Promise\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\n\nconst returnDelayedData = () =\u003e\n  new Promise(resolve =\u003e\n    setTimeout(() =\u003e\n      resolve(data)\n    , 1000)\n  )\n\nm(infinite, {\n  pageData: returnDelayedData,\n  item\n})\n~~~\n\n\u003ca name=\"handling-dynamic-data\"\u003e\u003c/a\u003e\n\u003ca id=\"handling-dynamic-data\"\u003e\u003c/a\u003e\n### Handling dynamic data\n\nIn situations where the Infinite component needs to show different items - for instance when filtering or sorting search results - we must provide a unique key for each page. The key will enable Mithril to properly distinguish the pages.\n\nUse option `pageKey` to provide a function that returns a unique identifying string. For example:\n\n~~~javascript\nimport infinite from \"mithril-infinite\"\nimport stream from \"mithril/stream\"\n\nconst query = stream(\"\")\n\nconst Search = {\n  view: () =\u003e\n    m(\"div\", \n      m(\"input\", {\n        oninput: e =\u003e query(e.target.value),\n        value: query()\n      })\n    )\n}\n\nconst MyComponent = {\n  view: () =\u003e {\n    const queryStr = query()\n    return m(infinite, {\n      before: m(Search),\n      pageKey: pageNum =\u003e `${pageNum}-${queryString}`,\n      // other options\n    })\n  }\n}\n~~~\n\n\n\u003ca name=\"advanced-item-function-example\"\u003e\u003c/a\u003e\n\u003ca id=\"advanced-item-function-example\"\u003e\u003c/a\u003e\n### Advanced item function example\n\nTo enhance the current loading behavior, we:\n\n* Load images when they are visible in the viewport\n* Stop loading images when the page is scrolling. This makes a big difference in performance, but it will not always result in a good user experience - the page will seem \"dead\" when during the scrolling. So use with consideration.\n\nThe `item` function can now look like this:\n\n~~~javascript\nconst item = (data, opts) =\u003e\n  m(\"a.grid-item\",\n    m(\".image-holder\",\n      m(\".image\", {\n        oncreate: vnode =\u003e maybeShowImage(vnode, data, opts.isScrolling),\n        onupdate: vnode =\u003e maybeShowImage(vnode, data, opts.isScrolling)\n      })\n    )\n  )\n\n// Don't load the image if the page is scrolling\nconst maybeShowImage = (vnode, data, isScrolling) =\u003e {\n  if (isScrolling || vnode.state.inited) {\n    return\n  }\n  // Only load the image when visible in the viewport\n  if (infinite.isElementInViewport({ el: vnode.dom })) {\n    showImage(vnode.dom, data.thumbnailUrl)\n    vnode.state.inited = true\n  }\nel.style.backgroundImage = `url(${url})`\n~~~\n\n\n\u003ca name=\"getting-the-total-page-count\"\u003e\u003c/a\u003e\n\u003ca id=\"getting-the-total-page-count\"\u003e\u003c/a\u003e\n### Getting the total page count\n\nHow the total page count is delivered will differ per server. `jsonplaceholder.typicode.com` passes the info in the request header.\n\nExample \"Fixed\" shows how to get the total page count from the request, and use that to calculate the total content height.\n\nWe place the `pageData` function in the `oninit` function so that we have easy access to the `state.pageCount` variable:\n\n~~~javascript\nconst state = vnode.state\nstate.pageCount = 1\n\nstate.pageData = pageNum =\u003e \n  m.request({\n    method: \"GET\",\n    dataType: \"jsonp\",\n    url: dataUrl(pageNum),\n    extract: xhr =\u003e (\n      // Read the total count from the header\n      state.pageCount = Math.ceil(parseInt(xhr.getResponseHeader(\"X-Total-Count\"), 10) / PAGE_ITEMS),\n      JSON.parse(xhr.responseText)\n    )\n  })\n~~~\n\nThen pass `state.pageData` to `infinite`:\n\n~~~javascript\nm(infinite, {\n  pageData: state.pageData,\n  maxPages: state.pageCount,\n  ...\n})\n~~~\n\n\n\u003ca name=\"using-images\"\u003e\u003c/a\u003e\n\u003ca id=\"using-images\"\u003e\u003c/a\u003e\n### Using images\n\nFor a better loading experience (and data usage), images should be loaded only when they appear on the screen. To check if the image is in the viewport, you can use the function `infinite.isElementInViewport({ el })`. For example:\n\n~~~javascript\nif (infinite.isElementInViewport({ el: vnode.dom })) {\n  loadImage(vnode.dom, data.thumbnailUrl)\n}\n~~~\n\nImages should not be shown with the `\u003cimg/\u003e` tag: while this works fine on desktop browsers, this causes redrawing glitches on iOS Safari. The solution is to use `background-image`. For example:\n\n~~~javascript\nel.style.backgroundImage = `url(${url})`\n~~~\n\n\n\n\u003ca name=\"using-table-data\"\u003e\u003c/a\u003e\n\u003ca id=\"using-table-data\"\u003e\u003c/a\u003e\n### Using table data\n\nUsing `\u003ctable\u003e` tags causes reflow problems. Use divs instead, with CSS styling for table features. For example:\n\n~~~css\n.page {\n  display: table;\n  width: 100%;\n}\n.list-item {\n  width: 100%;\n  display: table-row;\n}\n.list-item \u003e div {\n  display: table-cell;\n}\n~~~\n\n\n\n\u003ca name=\"pagination\"\u003e\u003c/a\u003e\n\u003ca id=\"pagination\"\u003e\u003c/a\u003e\n### Pagination\n\nSee the \"Paging\" example.\n\n\n### Custom page wrapper\n\nUse `processPageData` to either:\n\n* Process content data before passing to `item`\n* Wrap in a custom element wrapper\n* Use a custom item function\n\nSimple example with a wrapper:\n\n```js\nm(infinite, {\n  processPageData: (content, options)  =\u003e {\n    return m(\".my-page\", content.map((data, index) =\u003e item(data, options, index)));\n  },\n  ...\n});\n```\n\n\n\u003ca name=\"configuration-options\"\u003e\u003c/a\u003e\n\u003ca id=\"configuration-options\"\u003e\u003c/a\u003e\n## Configuration options\n\n\u003ca name=\"appearance-options\"\u003e\u003c/a\u003e\n\u003ca id=\"appearance-options\"\u003e\u003c/a\u003e\n### Appearance options\n\n| **Parameter** |  **Mandatory** | **Type** | **Default** | **Description** |\n| ------------- | -------------- | -------- | ----------- | --------------- |\n| **scrollView** | optional | Selector String | | Pass an element's selector to assign another element as scrollView |\n| **class** | optional | String |  | Extra CSS class appended to `mithril-infinite__scroll-view` |\n| **contentTag** | optional | String | \"div\" | HTML tag for the content element |\n| **pageTag** | optional | String | \"div\" | HTML tag for the page element; note that pages have class `mithril-infinite__page` plus either `mithril-infinite__page--odd` or `mithril-infinite__page--even` |\n| **maxPages** | optional | Number | `Number.MAX_VALUE` | Maximum number of pages to draw |\n| **preloadPages** | optional | Number | 1 | Number of pages to preload when the app starts; if room is available, this number will increase automatically |\n| **axis** | optional | String | \"y\" | The scroll axis, either \"y\" or \"x\" |\n| **autoSize** | optional | Boolean | true | Set to `false` to not set the width or height in CSS |\n| **before** | optional | Mithril template or component | | Content shown before the pages; has class `mithril-infinite__before` |\n| **after** | optional | Mithril template or component | | Content shown after the pages; has class `mithril-infinite__after`; will be shown only when content exists and the last page is in view (when `maxPages` is defined) |\n| **contentSize** | optional | Number (pixels) |  | Use when you know the number of items to display and the height of the content, and when predictable scrollbar behaviour is desired (without jumps when content is loaded); pass a pixel value to set the size (height or width) of the scroll content, thereby overriding the dynamically calculated height; use together with `pageSize`  |\n| **setDimensions** | optional | Function ({scrolled: Number, size: Number}) | | Sets the initial size and scroll position of `scrollView`; this function is called once |\n\n\u003ca name=\"callback-functions\"\u003e\u003c/a\u003e\n\u003ca id=\"callback-functions\"\u003e\u003c/a\u003e\n### Callback functions\n\n| **Parameter** |  **Mandatory** | **Type** | **Default** | **Description** |\n| ------------- | -------------- | -------- | ----------- | --------------- |\n| **pageUrl** | either `pageData` or `pageUrl` | Function `(page: Number) =\u003e String` | | Function that accepts a page number and returns a URL String |\n| **pageData** | either `pageData` or `pageUrl` | Function `(page: Number) =\u003e Promise` | | Function that fetches data; accepts a page number and returns a promise |\n| **item** | required: either `item` or `processPageData` | Function `(data: Array, options: Object, index: Number) =\u003e Mithril Template` | | Function that creates a Mithril element from received data |\n| **pageSize** | optional | Function `(content: Array) =\u003e Number` | Pass a pixel value to set the size (height or width) of each page; the function accepts the page content and returns the size |\n| **pageChange** | optional | Function `(page: Number)` | | Get notified when a new page is shown |\n| **processPageData** | required: either `item` or `processPageData` | Function `(data: Array, options: Object) =\u003e Array` | | Function that maps over the page data and returns an item for each |\n| **getDimensions** | optional | Function `() =\u003e {scrolled: Number, size: Number}` | | Returns an object with state dimensions of `scrollView`: `scrolled` (either scrollTop or scrollLeft) and `size` (either height or width); this function is called on each view update | \n| **pageKey** | optional | Function `(page: Number) =\u003e String` | key is based on page number | Function to provide a unique key for each Page component; use this when showing dynamic page data, for instance based on sorting or filtering |\n\n\u003ca name=\"paging-options\"\u003e\u003c/a\u003e\n\u003ca id=\"paging-options\"\u003e\u003c/a\u003e\n### Paging options\n\n| **Parameter** |  **Mandatory** | **Type** | **Default** | **Description** |\n| ------------- | -------------- | -------- | ----------- | --------------- |\n| **currentPage**  | optional | Number | | Sets the current page |\n| **from** | optional | Number | | Not needed when only one page is shown (use `currentPage`); use page data from this number and higher |\n| **to** | optional | Number | | Not needed when only one page is shown (use `currentPage`); Use page data to this number and lower |\n\n\u003ca name=\"options-for-infiniteiselementinviewport\"\u003e\u003c/a\u003e\n\u003ca id=\"options-for-infiniteiselementinviewport\"\u003e\u003c/a\u003e\n### Options for infinite.isElementInViewport\n\nAll options are passed in an options object: `infinite.isElementInViewport({ el, leeway })`\n\n| **Parameter** |  **Mandatory** | **Type** | **Default** | **Description** |\n| ------------- | -------------- | -------- | ----------- | --------------- |\n| **el** | required | HTML Element | | The element to check |\n| **axis** | optional | String | \"y\" | The scroll axis, either \"y\" or \"x\" |\n| **leeway** | optional | Number | 300 | The extended area; by default the image is already fetched when it is 100px outside of the viewport; both bottom and top leeway are calculated |\n\n\n\n\u003ca name=\"styling\"\u003e\u003c/a\u003e\n\u003ca id=\"styling\"\u003e\u003c/a\u003e\n## Styling\n\nNote: The parent of \"scroll-view\" must have a height. Also make sure that `html` has a height (typically set to `100%`).\n\nStyles are added using [j2c](https://github.com/pygy/j2c). This library is also used in the examples.\n\n\n\u003ca name=\"css-classes\"\u003e\u003c/a\u003e\n\u003ca id=\"css-classes\"\u003e\u003c/a\u003e\n### CSS classes\n\n| **Element**           | **Key**       |  **Class** |\n| --------------------- | ------------- | --------------- |\n| Scroll view           | scrollView    | `mithril-infinite__scroll-view` |\n| Scroll content        | scrollContent | `mithril-infinite__scroll-content` |\n| Content container     | content       | `mithril-infinite__content` |\n| Pages container       | pages         | `mithril-infinite__pages` |\n| Page                  | page          | `mithril-infinite__page` |\n| Content before        | before        | `mithril-infinite__before` |\n| Content after         | after         | `mithril-infinite__after` |\n\n| **State**             | **Key**     |  **Class** |\n| --------------------- | ----------- | --------------- |\n| Scroll view, x axis   | scrollViewX | `mithril-infinite__scroll-view--x` |\n| Scroll view, y axis   | scrollViewY | `mithril-infinite__scroll-view--y` |\n| Even numbered page    | pageEven    | `mithril-infinite__page--even` |\n| Odd numbered page     | pageOdd     | `mithril-infinite__page--odd` |\n| Page, now placeholder | placeholder | `mithril-infinite__page--placeholder` |\n\n\n\u003ca name=\"fixed-scroll-and-overflow-anchor\"\u003e\u003c/a\u003e\n\u003ca id=\"fixed-scroll-and-overflow-anchor\"\u003e\u003c/a\u003e\n### Fixed scroll and `overflow-anchor`\n\nSome browsers use [overflow-anchor](https://css-tricks.com/almanac/properties/o/overflow-anchor/) to prevent content from jumping as the page loads more data above the viewport. This may conflict how Infinite inserts content in \"placeholder slots\". \n\nTo prevent miscalculations of content size, the \"scroll content\" element has style `overflow-anchor: none`.\n\n\n\u003ca name=\"size\"\u003e\u003c/a\u003e\n\u003ca id=\"size\"\u003e\u003c/a\u003e\n## Size\n\nMinified and gzipped: ~ 3.9 Kb\n\n\n\n\u003ca name=\"dependencies\"\u003e\u003c/a\u003e\n\u003ca id=\"dependencies\"\u003e\u003c/a\u003e\n## Dependencies\n\n* [j2c](https://github.com/pygy/j2c) - for creating js stylesheets\n* [Mithril 1.0](https://www.npmjs.com/package/mithril)\n* [resize-observer-polyfill](https://github.com/que-etc/resize-observer-polyfill)\n* [Verge](https://www.npmjs.com/package/verge) - for measuring the viewport\n\n\n\u003ca name=\"licence\"\u003e\u003c/a\u003e\n\u003ca id=\"licence\"\u003e\u003c/a\u003e\n## Licence\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArthurClemens%2Fmithril-infinite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FArthurClemens%2Fmithril-infinite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArthurClemens%2Fmithril-infinite/lists"}