├── .editorconfig ├── .eslintignore ├── .eslintrc-base ├── .eslintrc-node ├── .eslintrc-react ├── .eslintrc-react-test ├── .gitignore ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── LICENSE.txt ├── README.md ├── demo ├── app.css ├── app.jsx ├── components │ ├── book.jsx │ ├── class-based-layout.jsx │ ├── column-based-layout.jsx │ └── style-based-layout.jsx ├── images │ ├── ChapterhouseDune.jpg │ ├── ChildrenOfDune.jpg │ ├── Dune.jpg │ ├── DuneMessiah.jpg │ ├── GodEmperorOfDune.jpg │ └── HereticsOfDune.jpg ├── index.html ├── webpack.config.dev.js └── webpack.config.hot.js ├── dist ├── boilerplate-component.js ├── boilerplate-component.js.map ├── boilerplate-component.min.js └── boilerplate-component.min.js.map ├── karma.conf.coverage.js ├── karma.conf.dev.js ├── karma.conf.js ├── package.json ├── src ├── components │ ├── container-query-columns.jsx │ └── container-query.jsx └── index.js ├── test └── client │ ├── main.js │ ├── spec │ └── components │ │ ├── container-query-columns.spec.jsx │ │ └── container-query.spec.jsx │ └── test.html ├── webpack.config.coverage.js ├── webpack.config.dev.js ├── webpack.config.js └── webpack.config.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 100 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | node_modules/* 3 | -------------------------------------------------------------------------------- /.eslintrc-base: -------------------------------------------------------------------------------- 1 | --- 2 | plugins: 3 | - "filenames" 4 | 5 | rules: 6 | "filenames/filenames": [2, "^[a-z0-9\\-\\.]+$"] # dash-cased filenames. 7 | -------------------------------------------------------------------------------- /.eslintrc-node: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - "defaults/configurations/walmart/es5-node" 4 | - ".eslintrc-base" 5 | -------------------------------------------------------------------------------- /.eslintrc-react: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - "defaults/configurations/walmart/es6-react" 4 | - ".eslintrc-base" 5 | -------------------------------------------------------------------------------- /.eslintrc-react-test: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - "defaults/configurations/walmart/es6-react" 4 | - "defaults/environments/test" 5 | - ".eslintrc-base" 6 | 7 | globals: 8 | expect: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### SublimeText ### 2 | *.sublime-workspace 3 | 4 | ### OSX ### 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear on external disk 14 | .Spotlight-V100 15 | .Trashes 16 | 17 | ### Windows ### 18 | # Windows image file caches 19 | Thumbs.db 20 | ehthumbs.db 21 | 22 | # Folder config file 23 | Desktop.ini 24 | 25 | # Recycle Bin used on file shares 26 | $RECYCLE.BIN/ 27 | 28 | # App specific 29 | 30 | coverage 31 | node_modules 32 | bower_components 33 | .tmp 34 | lib 35 | npm-debug.log 36 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Cruft 2 | *.sublime-workspace 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | Icon 7 | ._* 8 | .Spotlight-V100 9 | .Trashes 10 | Thumbs.db 11 | ehthumbs.db 12 | Desktop.ini 13 | $RECYCLE.BIN/ 14 | .tmp 15 | npm-debug.log 16 | 17 | # Code / build 18 | coverage 19 | node_modules 20 | bower_components 21 | demo 22 | test 23 | karma* 24 | webpack* 25 | .eslint* 26 | .editor* 27 | .travis* 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 0.10 5 | - 0.12 6 | 7 | # Use container-based Travis infrastructure. 8 | sudo: false 9 | 10 | branches: 11 | only: 12 | - master 13 | 14 | before_install: 15 | # GUI for real browsers. 16 | - export DISPLAY=:99.0 17 | - sh -e /etc/init.d/xvfb start 18 | 19 | script: 20 | - npm run check-ci 21 | 22 | # Prune deps to just production and ensure we can still build 23 | - npm prune --production 24 | - npm install --production 25 | - npm run build 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | Thanks for helping out! 5 | 6 | ## Development 7 | 8 | Run `npm run dev` to run a webpack dev server with component examples. 9 | 10 | ## Checks, Tests 11 | 12 | Run `npm run check` before committing. 13 | 14 | ## Dist 15 | 16 | Please do not commit changes to files in `dist`. 17 | These files are only committed when we tag releases. 18 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | ## Build 5 | 6 | Build for production use (NPM, bower, etc) and create `dist` UMD bundles 7 | (min'ed, non-min'ed) 8 | 9 | ``` 10 | $ npm run build 11 | ``` 12 | 13 | Note that `dist/` files are only updated and committed on **tagged releases**. 14 | 15 | 16 | ## Development 17 | 18 | All development tasks consist of watching the demo bundle, the test bundle 19 | and launching a browser pointed to the demo page. 20 | 21 | Run the `demo` application with watched rebuilds: 22 | 23 | ``` 24 | $ npm run dev # dev test/app server (OR) 25 | $ npm run open-dev # dev servers _and a browser window opens!_ 26 | ``` 27 | 28 | From there you can see: 29 | 30 | * Demo app: [127.0.0.1:3000](http://127.0.0.1:3000/) 31 | * Client tests: [127.0.0.1:3001/test/client/test.html](http://127.0.0.1:3001/test/client/test.html) 32 | 33 | 34 | ## Programming Guide 35 | 36 | ### Logging 37 | 38 | We use the following basic pattern for logging: 39 | 40 | ```js 41 | if (process.env.NODE_ENV !== "production") { 42 | /* eslint-disable no-console */ 43 | if (typeof console !== "undefined" && console.warn) { 44 | console.warn("Oh noes! bad things happened."); 45 | } 46 | /* eslint-enable no-console */ 47 | } 48 | ``` 49 | 50 | Replace `console.warn` in the condtional + method call as appropriate. 51 | 52 | Breaking this down: 53 | 54 | * `process.env.NODE_ENV !== "production"` - This part removes all traces of 55 | the code in the production bundle, to save on file size. This _also_ means 56 | that no warnings will be displayed in production. 57 | * `typeof console !== "undefined" && console.METHOD` - A permissive check to 58 | make sure the `console` object exists and can use the appropriate `METHOD` - 59 | `warn`, `info`, etc. 60 | 61 | To signal production mode to the webpack build, declare the `NODE_ENV` variable: 62 | 63 | ```js 64 | new webpack.DefinePlugin({ 65 | "process.env.NODE_ENV": JSON.stringify("production") 66 | }) 67 | ``` 68 | 69 | Unfortunately, we need to do _all_ of this every time to have Uglify properly 70 | drop the code, but with this trick, the production bundle has no change in code 71 | size. 72 | 73 | 74 | ## Quality 75 | 76 | ### In Development 77 | 78 | During development, you are expected to be running either: 79 | 80 | ``` 81 | $ npm run dev 82 | ``` 83 | 84 | to build the lib and test files. With these running, you can run the faster 85 | 86 | ``` 87 | $ npm run check-dev 88 | ``` 89 | 90 | Command. It is comprised of: 91 | 92 | ``` 93 | $ npm run lint 94 | $ npm run test-dev 95 | ``` 96 | 97 | Note that the tests here are not instrumented for code coverage and are thus 98 | more development / debugging friendly. 99 | 100 | ### Continuous Integration 101 | 102 | CI doesn't have source / test file watchers, so has to _build_ the test files 103 | via the commands: 104 | 105 | ``` 106 | $ npm run check # PhantomJS only 107 | $ npm run check-cov # (OR) PhantomJS w/ coverage 108 | $ npm run check-ci # (OR) PhantomJS,Firefox + coverage - available on Travis. 109 | ``` 110 | 111 | Which is currently comprised of: 112 | 113 | ``` 114 | $ npm run lint # AND ... 115 | 116 | $ npm run test # PhantomJS only 117 | $ npm run test-cov # (OR) PhantomJS w/ coverage 118 | $ npm run test-ci # (OR) PhantomJS,Firefox + coverage 119 | ``` 120 | 121 | Note that `(test|check)-(cov|ci)` run code coverage and thus the 122 | test code may be harder to debug because it is instrumented. 123 | 124 | ### Client Tests 125 | 126 | The client tests rely on webpack dev server to create and serve the bundle 127 | of the app/test code at: http://127.0.0.1:3001/assets/main.js which is done 128 | with the task `npm run server-test` (part of `npm dev`). 129 | 130 | #### Code Coverage 131 | 132 | Code coverage reports are outputted to: 133 | 134 | ``` 135 | coverage/ 136 | client/ 137 | BROWSER_STRING/ 138 | lcov-report/index.html # Viewable web report. 139 | ``` 140 | 141 | ## Releases 142 | 143 | **IMPORTANT - NPM**: To correctly run `preversion` your first step is to make 144 | sure that you have a very modern `npm` binary: 145 | 146 | ``` 147 | $ npm install -g npm 148 | ``` 149 | 150 | Built files in `dist/` should **not** be committeed during development or PRs. 151 | Instead we _only_ build and commit them for published, tagged releases. So 152 | the basic workflow is: 153 | 154 | ``` 155 | # Make sure you have a clean, up-to-date `master` 156 | $ git pull 157 | $ git status # (should be no changes) 158 | 159 | # Choose a semantic update for the new version. 160 | # If you're unsure, read about semantic versioning at http://semver.org/ 161 | $ npm version major|minor|patch -m "Version %s - INSERT_REASONS" 162 | 163 | # ... the `dist/` and `lib/` directories are now built, `package.json` is 164 | # updated, and the appropriate files are committed to git (but unpushed). 165 | # 166 | # *Note*: `lib/` is uncommitted, but built and must be present to push to npm. 167 | 168 | # Check that everything looks good in last commit and push. 169 | $ git diff HEAD^ HEAD 170 | $ git push && git push --tags 171 | # ... the project is now pushed to GitHub and available to `bower`. 172 | 173 | # And finally publish to `npm`! 174 | $ npm publish 175 | ``` 176 | 177 | And you've published! 178 | 179 | For additional information on the underlying NPM technologies and approaches, 180 | please review: 181 | 182 | * [`npm version`](https://docs.npmjs.com/cli/version): Runs verification, 183 | builds `dist/` and `lib/` via `scripts` commands. 184 | * Our scripts also run the applicable `git` commands, so be very careful 185 | when running out `version` commands. 186 | * [`npm publish`](https://docs.npmjs.com/cli/publish): Uploads to NPM. 187 | * **NOTE**: We don't _build_ in `prepublish` because of the 188 | [`npm install` runs `npm prepublish` bug](https://github.com/npm/npm/issues/3059) 189 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Formidable Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *** 2 | # NOTICE: 3 | 4 | ## This repository has been archived and is not supported. 5 | 6 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 7 | *** 8 | NOTICE: SUPPORT FOR THIS PROJECT HAS ENDED 9 | 10 | This projected was owned and maintained by Walmart. This project has reached its end of life and Walmart no longer supports this project. 11 | 12 | We will no longer be monitoring the issues for this project or reviewing pull requests. You are free to continue using this project under the license terms or forks of this project at your own risk. This project is no longer subject to Walmart's bug bounty program or other security monitoring. 13 | 14 | 15 | ## Actions you can take 16 | 17 | We recommend you take the following action: 18 | 19 | * Review any configuration files used for build automation and make appropriate updates to remove or replace this project 20 | * Notify other members of your team and/or organization of this change 21 | * Notify your security team to help you evaluate alternative options 22 | 23 | ## Forking and transition of ownership 24 | 25 | For [security reasons](https://www.theregister.co.uk/2018/11/26/npm_repo_bitcoin_stealer/), Walmart does not transfer the ownership of our primary repos on Github or other platforms to other individuals/organizations. Further, we do not transfer ownership of packages for public package management systems. 26 | 27 | If you would like to fork this package and continue development, you should choose a new name for the project and create your own packages, build automation, etc. 28 | 29 | Please review the licensing terms of this project, which continue to be in effect even after decommission. 30 | 31 | ContainerQuery 32 | ============== 33 | 34 | A common problem in responsive design is the layout being depedent on the width 35 | of the media (i.e. a media query) as opposed to the width of the host container 36 | (i.e. a container query). 37 | 38 | For example, let's say you have a book list, and you want it to be one column in 39 | a small width, then two, then four columns as the width of the content area grows. 40 | Great, if you control the entire screen. But what if the list is put into the sidebar. 41 | Now, even though the screen maybe large, the width for the book list is small. 42 | 43 | So we need a tool to be able to define breakpoints relative to the container 44 | and not to the screen. 45 | 46 | Introducing, `ContainerQuery`, where you can define breakpoint names on a container 47 | and then apply `style`, `props` or `className` depending on the current width of the 48 | container. For example: 49 | 50 | ```jsx 51 | 52 | 58 | 64 | ... 65 | 66 | ``` 67 | 68 | Will check to see how much space it's given, turn that into a breakpoint name (e.g. `small`, 69 | `medium` or `large`) and then set the `className` of the children of the component 70 | based on that value. 71 | 72 | You can also set styles: 73 | 74 | ```jsx 75 | 77 | 83 | 89 | 90 | ``` 91 | 92 | In this case we are setting the `width` as a `style` based on the current breakpoint 93 | as defined by the `breakpoints` object. 94 | 95 | You can also set properties: 96 | 97 | ```jsx 98 | 100 | 106 | 107 | ``` 108 | 109 | If your component, in this case, knows how to interpret `size` in some meaningful way. 110 | 111 | And, of course, you can use any combination of these. 112 | 113 | You are also free to name the breakpoints however you choose. 114 | 115 | For something even easier you can use a columns-based helper class like so: 116 | 117 | ```jsx 118 | 121 | 124 | 127 | 128 | ``` 129 | 130 | Which sets `width` in the `style` of all of the children using the number of columns 131 | defined in the `at-{breakpoint}` props in the `ContainerQuery.Columns` component. 132 | 133 | ## Development 134 | 135 | Please see [DEVELOPMENT](DEVELOPMENT.md) 136 | 137 | ## Contributing 138 | 139 | Please see [CONTRIBUTING](CONTRIBUTING.md) 140 | -------------------------------------------------------------------------------- /demo/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: arial, verdana, sans-serif; 3 | margin: 2em; 4 | } 5 | 6 | h4 { 7 | border-bottom: 2px solid black; 8 | } 9 | 10 | .main .left { 11 | float: left; 12 | width: 500px; 13 | } 14 | 15 | .main .right { 16 | float: left; 17 | width: 150px; 18 | } 19 | 20 | .book { 21 | float: left; 22 | text-align: center; 23 | font-weight: bold; 24 | padding: 0.5em; 25 | } 26 | 27 | .book .image img { 28 | width: 100px; 29 | } 30 | 31 | .book .title { 32 | font-size: xx-small; 33 | } 34 | 35 | .col-12 { 36 | width: 90%; 37 | } 38 | .col-6 { 39 | width: 50%; 40 | } 41 | .col-3 { 42 | width: 25%; 43 | } 44 | -------------------------------------------------------------------------------- /demo/app.jsx: -------------------------------------------------------------------------------- 1 | /*global document:false*/ 2 | import React from "react/addons"; 3 | 4 | import "./app.css"; 5 | 6 | import ClassBasedLayout from "./components/class-based-layout"; 7 | import ColumnBasedLayout from "./components/column-based-layout"; 8 | import StyleBasedLayout from "./components/style-based-layout"; 9 | 10 | class App extends React.Component { 11 | render() { 12 | return ( 13 |
14 | 15 | 19 | 23 |
16 |

Container fixed at 500px

17 | 18 |
20 |

Container fixed at 300px

21 | 22 |
24 | 25 |

Test of columns dynamic generated

26 | 27 |
28 | ); 29 | } 30 | } 31 | 32 | const content = document.getElementById("content"); 33 | 34 | React.render(, content); 35 | -------------------------------------------------------------------------------- /demo/components/book.jsx: -------------------------------------------------------------------------------- 1 | import React from "react/addons"; 2 | 3 | export default class Book extends React.Component { 4 | render() { 5 | return ( 6 |
7 |
8 | 9 |
10 |
11 | {this.props.title} 12 |
13 |
14 | ) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo/components/class-based-layout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react/addons"; 2 | 3 | import {ContainerQuery} from "../../src/index"; 4 | 5 | import Book from "./book"; 6 | 7 | export default class ClassBasedLayout extends React.Component { 8 | render() { 9 | return ( 10 | 11 | 17 | 23 | 29 | 35 | 41 | 47 | 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /demo/components/column-based-layout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react/addons"; 2 | 3 | import {ContainerQuery} from "../../src/index"; 4 | 5 | import Book from "./book"; 6 | 7 | export default class ColumnBasedLayout extends React.Component { 8 | render() { 9 | return ( 10 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demo/components/style-based-layout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react/addons"; 2 | 3 | import {ContainerQuery} from "../../src/index"; 4 | 5 | import Book from "./book"; 6 | 7 | export default class StyleBasedLayout extends React.Component { 8 | render() { 9 | return ( 10 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /demo/images/ChapterhouseDune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/ChapterhouseDune.jpg -------------------------------------------------------------------------------- /demo/images/ChildrenOfDune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/ChildrenOfDune.jpg -------------------------------------------------------------------------------- /demo/images/Dune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/Dune.jpg -------------------------------------------------------------------------------- /demo/images/DuneMessiah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/DuneMessiah.jpg -------------------------------------------------------------------------------- /demo/images/GodEmperorOfDune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/GodEmperorOfDune.jpg -------------------------------------------------------------------------------- /demo/images/HereticsOfDune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/walmartlabs/container-query/bc2d60f99f80588916f9c65ee5d231f5cc212742/demo/images/HereticsOfDune.jpg -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | Demo 10 | 11 | 12 | 34 | 35 | 36 | 39 |
40 |

If you can see this, something is broken (or JS is not enabled)!!.

41 |
42 | 43 | 44 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /demo/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /*globals __dirname:false */ 2 | "use strict"; 3 | 4 | var webpack = require("webpack"); 5 | 6 | module.exports = { 7 | 8 | devServer: { 9 | contentBase: __dirname, 10 | noInfo: false 11 | }, 12 | 13 | output: { 14 | path: __dirname, 15 | filename: "main.js", 16 | publicPath: "/assets/" 17 | }, 18 | 19 | cache: true, 20 | devtool: "source-map", 21 | entry: { 22 | app: ["./demo/app.jsx"] 23 | }, 24 | stats: { 25 | colors: true, 26 | reasons: true 27 | }, 28 | resolve: { 29 | extensions: ["", ".js", ".jsx"] 30 | }, 31 | module: { 32 | loaders: [ 33 | { 34 | test: /\.jsx?$/, 35 | exclude: [/node_modules/], 36 | loaders: ["babel-loader?stage=0"] 37 | }, { 38 | test: /\.css$/, 39 | loader: "style-loader!css-loader" 40 | }, { 41 | test: /\.(png|jpg)$/, 42 | loader: "url-loader?limit=32767" 43 | } 44 | ] 45 | }, 46 | plugins: [ 47 | new webpack.NoErrorsPlugin() 48 | ] 49 | }; 50 | -------------------------------------------------------------------------------- /demo/webpack.config.hot.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _ = require("lodash"); 4 | var base = require("./webpack.config.dev"); 5 | 6 | // Update our own module version. 7 | var mod = _.cloneDeep(base.module); 8 | // First loader needs react hot. 9 | mod.loaders[0].loaders = ["react-hot"].concat(mod.loaders[0].loaders); 10 | 11 | module.exports = _.merge({}, _.omit(base, "entry", "module"), { 12 | entry: { 13 | app: ["webpack/hot/dev-server", "./demo/app.jsx"] 14 | }, 15 | 16 | module: mod 17 | }); 18 | -------------------------------------------------------------------------------- /dist/boilerplate-component.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("react")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["react"], factory); 6 | else if(typeof exports === 'object') 7 | exports["ContainerQuery"] = factory(require("react")); 8 | else 9 | root["ContainerQuery"] = factory(root["React"]); 10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_2__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ exports: {}, 25 | /******/ id: moduleId, 26 | /******/ loaded: false 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.loaded = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // __webpack_public_path__ 47 | /******/ __webpack_require__.p = ""; 48 | /******/ 49 | /******/ // Load entry module and return exports 50 | /******/ return __webpack_require__(0); 51 | /******/ }) 52 | /************************************************************************/ 53 | /******/ ([ 54 | /* 0 */ 55 | /***/ function(module, exports, __webpack_require__) { 56 | 57 | "use strict"; 58 | 59 | module.exports = { 60 | ContainerQuery: __webpack_require__(1) 61 | }; 62 | 63 | /***/ }, 64 | /* 1 */ 65 | /***/ function(module, exports, __webpack_require__) { 66 | 67 | "use strict"; 68 | 69 | Object.defineProperty(exports, "__esModule", { 70 | value: true 71 | }); 72 | 73 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 74 | 75 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 76 | 77 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 78 | 79 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 80 | 81 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; } 82 | 83 | var _react = __webpack_require__(2); 84 | 85 | var _react2 = _interopRequireDefault(_react); 86 | 87 | var ContainerQuery = (function (_React$Component) { 88 | _inherits(ContainerQuery, _React$Component); 89 | 90 | function ContainerQuery() { 91 | _classCallCheck(this, ContainerQuery); 92 | 93 | _get(Object.getPrototypeOf(ContainerQuery.prototype), "constructor", this).apply(this, arguments); 94 | } 95 | 96 | _createClass(ContainerQuery, [{ 97 | key: "render", 98 | value: function render() { 99 | return _react2["default"].createElement( 100 | "div", 101 | null, 102 | "Edit me!" 103 | ); 104 | } 105 | }]); 106 | 107 | return ContainerQuery; 108 | })(_react2["default"].Component); 109 | 110 | exports["default"] = ContainerQuery; 111 | module.exports = exports["default"]; 112 | 113 | /***/ }, 114 | /* 2 */ 115 | /***/ function(module, exports) { 116 | 117 | module.exports = __WEBPACK_EXTERNAL_MODULE_2__; 118 | 119 | /***/ } 120 | /******/ ]) 121 | }); 122 | ; 123 | //# sourceMappingURL=container-query.js.map -------------------------------------------------------------------------------- /dist/boilerplate-component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap ad185fd8a0644f1374aa","webpack:///./src/index.js","webpack:///./src/components/container-query.jsx","webpack:///external {\"root\":\"React\",\"commonjs2\":\"react\",\"commonjs\":\"react\",\"amd\":\"react\"}"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;ACtCA,OAAM,CAAC,OAAO,GAAG;AACf,uBAAoB,EAAE,mBAAO,CAAC,CAAoC,CAAC;EACpE,C;;;;;;;;;;;;;;;;;;;;;;kCCFiB,CAAO;;;;KAEJ,oBAAoB;aAApB,oBAAoB;;YAApB,oBAAoB;2BAApB,oBAAoB;;gCAApB,oBAAoB;;;gBAApB,oBAAoB;;YACjC,kBAAG;AACP,cAAO;;;;QAAmB,CAAC;MAC5B;;;UAHkB,oBAAoB;IAAS,mBAAM,SAAS;;sBAA5C,oBAAoB;;;;;;;ACFzC,gD","file":"container-query.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"react\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ContainerQuery\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"ContainerQuery\"] = factory(root[\"React\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {\nreturn \n\n\n/** WEBPACK FOOTER **\n ** webpack/universalModuleDefinition\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap ad185fd8a0644f1374aa\n **/","module.exports = {\n ContainerQuery: require(\"./components/container-query\")\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/index.js\n **/","import React from \"react\";\n\nexport default class ContainerQuery extends React.Component {\n render() {\n return
Edit me!
;\n }\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/components/container-query.jsx\n **/","module.exports = __WEBPACK_EXTERNAL_MODULE_2__;\n\n\n/*****************\n ** WEBPACK FOOTER\n ** external {\"root\":\"React\",\"commonjs2\":\"react\",\"commonjs\":\"react\",\"amd\":\"react\"}\n ** module id = 2\n ** module chunks = 0\n **/"],"sourceRoot":""} -------------------------------------------------------------------------------- /dist/boilerplate-component.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ContainerQuery=t(require("react")):e.ContainerQuery=t(e.React)}(this,function(e){return function(e){function t(o){if(r[o])return r[o].exports;var n=r[o]={exports:{},id:o,loaded:!1};return e[o].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){"use strict";e.exports={ContainerQuery:r(1)}},function(e,t,r){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function u(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var r=0;rEdit me!;\n }\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/components/container-query.jsx\n **/","module.exports = __WEBPACK_EXTERNAL_MODULE_2__;\n\n\n/*****************\n ** WEBPACK FOOTER\n ** external {\"root\":\"React\",\"commonjs2\":\"react\",\"commonjs\":\"react\",\"amd\":\"react\"}\n ** module id = 2\n ** module chunks = 0\n **/"],"sourceRoot":""} -------------------------------------------------------------------------------- /karma.conf.coverage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | * Karma Configuration: "coverage" version. 4 | * 5 | * This configuration is the same as basic one-shot version, just with coverage. 6 | */ 7 | var webpackCovCfg = require("./webpack.config.coverage"); 8 | 9 | module.exports = function (config) { 10 | require("./karma.conf")(config); 11 | config.set({ 12 | reporters: ["spec", "coverage"], 13 | webpack: webpackCovCfg, 14 | coverageReporter: { 15 | reporters: [ 16 | { type: "json", file: "coverage.json" }, 17 | { type: "lcov" }, 18 | { type: "text" } 19 | ], 20 | dir: "coverage/client" 21 | } 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /karma.conf.dev.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | * Karma Configuration: "dev" version. 4 | * 5 | * This configuration relies on a `webpack-dev-server` already running and 6 | * bundling `webpack.config.test.js` on port 3001. If this is not running, 7 | * then the alternate `karma.conf.js` file will _also_ run the webpack dev 8 | * server during the test run. 9 | */ 10 | module.exports = function (config) { 11 | config.set({ 12 | frameworks: ["mocha", "phantomjs-shim"], 13 | reporters: ["spec"], 14 | browsers: ["PhantomJS"], 15 | basePath: ".", // repository root. 16 | files: [ 17 | // Sinon has issues with webpack. Do global include. 18 | "node_modules/sinon/pkg/sinon.js", 19 | 20 | // Test bundle (must be created via `npm run dev|hot|server-test`) 21 | "http://127.0.0.1:3001/assets/main.js" 22 | ], 23 | port: 9999, 24 | singleRun: true, 25 | client: { 26 | mocha: { 27 | ui: "bdd" 28 | } 29 | } 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | * Karma Configuration: "full" version. 4 | * 5 | * This configuration runs a temporary `webpack-dev-server` and builds 6 | * the test files one-off for just a single run. This is appropriate for a 7 | * CI environment or if you're not otherwise running `npm run dev|hot`. 8 | */ 9 | var webpackCfg = require("./webpack.config.test"); 10 | 11 | // BUG: Karma 0.13 is broken for circular imports 12 | // TODO: Upgrade Karma to 0.13 when upstream bug is fixed. 13 | // https://github.com/FormidableLabs/ 14 | // formidable-react-component-boilerplate/issues/25 15 | 16 | module.exports = function (config) { 17 | // Start with the "dev" (webpack-dev-server is already running) config 18 | // and add in the webpack stuff. 19 | require("./karma.conf.dev")(config); 20 | 21 | // Overrides. 22 | config.set({ 23 | preprocessors: { 24 | "test/client/main.js": ["webpack"] 25 | }, 26 | files: [ 27 | // Sinon has issues with webpack. Do global include. 28 | "node_modules/sinon/pkg/sinon.js", 29 | 30 | // Test bundle (created via local webpack-dev-server in this config). 31 | "test/client/main.js" 32 | ], 33 | webpack: webpackCfg, 34 | browsers: ["PhantomJS"], 35 | webpackServer: { 36 | port: 3002, // Choose a non-conflicting port (3000 app, 3001 test dev) 37 | quiet: false, 38 | noInfo: true, 39 | stats: { 40 | assets: false, 41 | colors: true, 42 | version: false, 43 | hash: false, 44 | timings: false, 45 | chunks: false, 46 | chunkModules: false 47 | } 48 | } 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "container-query", 3 | "version": "0.0.1", 4 | "description": "React Component", 5 | "main": "lib/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/jherr/container-query.git" 9 | }, 10 | "author": "Jack Herrington", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/jherr/container-query/issues" 14 | }, 15 | "homepage": "https://github.com/jherr/container-query", 16 | "scripts": { 17 | "postinstall": "npm run build-lib", 18 | "preversion": "npm run check", 19 | "version": "npm run clean && npm run build && git add -A dist", 20 | "clean-dist": "rimraf dist", 21 | "build-dist-min": "webpack --config webpack.config.js", 22 | "build-dist-dev": "webpack --config webpack.config.dev.js", 23 | "build-dist": "npm run clean-dist && npm run build-dist-min && npm run build-dist-dev", 24 | "clean-lib": "rimraf lib", 25 | "build-lib": "npm run clean-lib && babel --stage 0 src -d lib", 26 | "clean": "npm run clean-lib && npm run clean-dist", 27 | "build": "npm run build-lib && npm run build-dist", 28 | "server-dev": "webpack-dev-server --port 3000 --config demo/webpack.config.dev.js --content-base demo", 29 | "server-hot": "webpack-dev-server --port 3000 --config demo/webpack.config.hot.js --hot --content-base demo", 30 | "server-test": "webpack-dev-server --port 3001 --config webpack.config.test.js", 31 | "dev": "npm run server-dev & npm run server-test", 32 | "hot": "npm run server-hot & npm run server-test", 33 | "open-demo": "opener http://127.0.0.1:3000", 34 | "open-dev": "npm run dev & npm run open-demo", 35 | "open-hot": "npm run hot & npm run open-demo", 36 | "lint-node": "eslint -c .eslintrc-node *.js demo/webpack.*.js", 37 | "lint-react": "eslint --ext .js,.jsx -c .eslintrc-react src demo/*.jsx", 38 | "lint-react-test": "eslint --ext .js,.jsx -c .eslintrc-react-test src test/client", 39 | "lint": "npm run lint-node && npm run lint-react && npm run lint-react-test", 40 | "test-frontend": "node node_modules/karma/bin/karma start karma.conf.js", 41 | "test-frontend-ci": "node node_modules/karma/bin/karma start --browsers PhantomJS,Firefox karma.conf.coverage.js", 42 | "test-frontend-cov": "node node_modules/karma/bin/karma start karma.conf.coverage.js", 43 | "test-frontend-dev": "node node_modules/karma/bin/karma start karma.conf.dev.js", 44 | "test": "npm run test-frontend", 45 | "test-ci": "npm run test-frontend-ci", 46 | "test-cov": "npm run test-frontend-cov", 47 | "test-dev": "npm run test-frontend-dev", 48 | "check": "npm run lint && npm run test", 49 | "check-ci": "npm run lint && npm run test-ci", 50 | "check-cov": "npm run lint && npm run test-cov", 51 | "check-dev": "npm run lint && npm run test-dev" 52 | }, 53 | "dependencies": { 54 | "babel": "^5.5.8", 55 | "babel-core": "^5.5.8", 56 | "babel-loader": "^5.3.2", 57 | "classnames": "^2.1.3", 58 | "css-loader": "~0.9.0", 59 | "object.assign": "^4.0.1", 60 | "react-component-resizable": "^0.2.3", 61 | "rimraf": "^2.4.0", 62 | "style-loader": "~0.8.0", 63 | "url-loader": "~0.5.5", 64 | "webpack": "^1.10.0" 65 | }, 66 | "devDependencies": { 67 | "babel-eslint": "^3.1.25", 68 | "chai": "^3.2.0", 69 | "eslint": "^0.24.1", 70 | "eslint-config-defaults": "^3.0.3", 71 | "eslint-plugin-filenames": "^0.1.1", 72 | "eslint-plugin-react": "^2.6.4", 73 | "isparta-loader": "^0.2.0", 74 | "karma": "^0.13.7", 75 | "karma-chrome-launcher": "^0.2.0", 76 | "karma-coverage": "^0.4.2", 77 | "karma-firefox-launcher": "^0.1.6", 78 | "karma-ie-launcher": "^0.2.0", 79 | "karma-mocha": "^0.2.0", 80 | "karma-phantomjs-launcher": "^0.2.0", 81 | "karma-phantomjs-shim": "^1.0.0", 82 | "karma-safari-launcher": "^0.1.1", 83 | "karma-sauce-launcher": "^0.2.14", 84 | "karma-spec-reporter": "0.0.20", 85 | "karma-webpack": "^1.6.0", 86 | "lodash": "^3.9.3", 87 | "mocha": "^2.2.5", 88 | "opener": "^1.4.1", 89 | "phantomjs": "^1.9.17", 90 | "react": "0.13.x", 91 | "react-hot-loader": "^1.2.8", 92 | "sinon": "^1.15.4", 93 | "sinon-chai": "^2.8.0", 94 | "webpack-dev-server": "^1.10.0" 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/components/container-query-columns.jsx: -------------------------------------------------------------------------------- 1 | /* eslint prefer-const:0, no-var:0, react/prop-types:0, space-infix-ops:0 */ 2 | import React from "react/addons"; 3 | 4 | const cloneElement = React.cloneElement; 5 | 6 | import ContainerQuery from "./container-query"; 7 | 8 | export default class ContainerQueryColumns extends React.Component { 9 | render() { 10 | let childProps = {}; 11 | for (var b in this.props.breakpoints) { 12 | if (this.props[`at-${b}`]) { 13 | const columns = this.props[`at-${b}`]; 14 | childProps[`style-${b}`] = { 15 | width: `${Math.round(100/columns)}%` 16 | }; 17 | } 18 | } 19 | return ( 20 | 21 | {React.Children.map(this.props.children, (child, index) => { 22 | childProps.key = index; 23 | return cloneElement(child, childProps); 24 | })} 25 | 26 | ); 27 | } 28 | } 29 | 30 | ContainerQuery.Columns = ContainerQueryColumns; 31 | -------------------------------------------------------------------------------- /src/components/container-query.jsx: -------------------------------------------------------------------------------- 1 | /* eslint prefer-const:0, no-var:0, react/prop-types:0, space-infix-ops:0 */ 2 | import React from "react/addons"; 3 | 4 | const cloneElement = React.cloneElement; 5 | 6 | import Resizable from "react-component-resizable"; 7 | 8 | import classNames from "classnames"; 9 | import assign from "object.assign"; 10 | 11 | export default class ContainerQuery extends React.Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | width: 0 16 | }; 17 | this._updateWidth = this._updateWidth.bind(this); 18 | this._getBreakpoint = this._getBreakpoint.bind(this); 19 | } 20 | _updateWidth(dim) { 21 | this.setState({ 22 | width: dim.width 23 | }); 24 | if (this.refs.resizable.resetTriggers) { 25 | this.refs.resizable.resetTriggers(); 26 | } 27 | } 28 | _getBreakpoint() { 29 | let breakpoint = ""; 30 | let curBp = -1; 31 | for (var b in this.props.breakpoints) { 32 | let bp = this.props.breakpoints[b]; 33 | if (this.state.width > bp) { 34 | if (bp > curBp) { 35 | breakpoint = b; 36 | curBp = bp; 37 | } 38 | } 39 | } 40 | return breakpoint; 41 | } 42 | _renderChild(breakpoint, child, index) { 43 | if (!child.props) { 44 | return child; 45 | } 46 | 47 | let props = { 48 | key: index 49 | }; 50 | 51 | if (child.props[`style-${breakpoint}`]) { 52 | props.style = assign(child.props.style || {}, 53 | child.props[`style-${breakpoint}`]); 54 | } 55 | 56 | if (child.props[`className-${breakpoint}`]) { 57 | props.className = classNames(child.props.className, 58 | child.props[`className-${breakpoint}`]); 59 | } 60 | 61 | if (child.props[`props-${breakpoint}`]) { 62 | props = assign(props, child.props[`props-${breakpoint}`]); 63 | } 64 | 65 | return cloneElement(child, props); 66 | } 67 | render() { 68 | const breakpoint = this._getBreakpoint(); 69 | const ResizableComp = this.props.resizableContainer; 70 | return ( 71 | 76 | {React.Children.map(this.props.children, (child, index) => { 77 | return this._renderChild(breakpoint, child, index); 78 | })} 79 | 80 | ); 81 | } 82 | } 83 | 84 | ContainerQuery.PropTypes = { 85 | breakpoints: React.PropTypes.object.isRequired, 86 | resizableContainer: React.PropTypes.component 87 | }; 88 | 89 | ContainerQuery.defaultProps = { 90 | resizableContainer: Resizable 91 | }; 92 | 93 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ContainerQuery: require("./components/container-query"), 3 | ContainerQueryColumns: require("./components/container-query-columns") 4 | }; 5 | -------------------------------------------------------------------------------- /test/client/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test setup for client-side tests. 3 | * 4 | * Intended for: 5 | * - Karma tests: `npm run test-client` 6 | * - Browser tests: `http://localhost:3000/test/client/test.html` 7 | */ 8 | /*globals window:false*/ 9 | const chai = require("chai"); 10 | const sinonChai = require("sinon-chai"); 11 | 12 | // -------------------------------------------------------------------------- 13 | // Chai / Sinon / Mocha configuration. 14 | // -------------------------------------------------------------------------- 15 | // Exports 16 | window.expect = chai.expect; 17 | 18 | // Plugins 19 | chai.use(sinonChai); 20 | 21 | // Mocha (part of static include). 22 | window.mocha.setup({ 23 | ui: "bdd", 24 | bail: false 25 | }); 26 | 27 | // -------------------------------------------------------------------------- 28 | // Bootstrap 29 | // -------------------------------------------------------------------------- 30 | // Use webpack to include all app code _except_ the entry point so we can get 31 | // code coverage in the bundle, whether tested or not. 32 | const srcReq = require.context("src", true, /\.jsx?$/); 33 | srcReq.keys().map(srcReq); 34 | 35 | // Use webpack to infer and `require` tests automatically. 36 | const testsReq = require.context(".", true, /\.spec.jsx?$/); 37 | testsReq.keys().map(testsReq); 38 | 39 | // Only start mocha in browser. 40 | if (!window.__karma__) { 41 | window.mocha.run(); 42 | } 43 | -------------------------------------------------------------------------------- /test/client/spec/components/container-query-columns.spec.jsx: -------------------------------------------------------------------------------- 1 | /* eslint no-undef:0, no-unused-expressions:0, prefer-const:0 */ 2 | import React from "react/addons"; 3 | import ContainerQueryColumns from "src/components/container-query-columns"; 4 | 5 | const TestUtils = React.addons.TestUtils; 6 | 7 | describe("components/container-query-columns", function () { 8 | let component; 9 | let container; 10 | 11 | beforeEach(function () { 12 | container = document.createElement("div"); 13 | component = React.render( 14 | 20 |
21 | Hello. 22 |
23 |
, 24 | container 25 | ); 26 | }); 27 | 28 | it("should render to small", function () { 29 | expect(component).to.not.be.false; 30 | component.refs.container._updateWidth({width: 100}); 31 | let foundClass = TestUtils.scryRenderedDOMComponentsWithClass( 32 | component, 33 | "foo" 34 | ); 35 | expect(foundClass.length).to.equal(1); 36 | expect(foundClass[0].props.style.width).to.equal("100%"); 37 | }); 38 | 39 | it("should render to small", function () { 40 | expect(component).to.not.be.false; 41 | component.refs.container._updateWidth({width: 250}); 42 | let foundClass = TestUtils.scryRenderedDOMComponentsWithClass( 43 | component, 44 | "foo" 45 | ); 46 | expect(foundClass.length).to.equal(1); 47 | expect(foundClass[0].props.style.width).to.equal("50%"); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /test/client/spec/components/container-query.spec.jsx: -------------------------------------------------------------------------------- 1 | /* eslint no-undef:0, no-unused-expressions:0, prefer-const:0 */ 2 | import React from "react/addons"; 3 | import ContainerQuery from "src/components/container-query"; 4 | 5 | const TestUtils = React.addons.TestUtils; 6 | 7 | describe("components/container-query", function () { 8 | let component; 9 | let container; 10 | 11 | beforeEach(function () { 12 | container = document.createElement("div"); 13 | component = React.render( 14 | 15 |
26 | Hello. 27 |
28 |
, 29 | container 30 | ); 31 | }); 32 | 33 | it("should render to small", function () { 34 | expect(component).to.not.be.false; 35 | component._updateWidth({width: 100}); 36 | let foundClass = TestUtils.scryRenderedDOMComponentsWithClass( 37 | component, 38 | "small" 39 | ); 40 | expect(foundClass.length).to.equal(1); 41 | expect(foundClass[0].props.foo).to.equal("small"); 42 | expect(foundClass[0].props.style.fontSize).to.equal("small"); 43 | }); 44 | 45 | it("should render to medium", function () { 46 | expect(component).to.not.be.false; 47 | component._updateWidth({width: 250}); 48 | let foundClass = TestUtils.scryRenderedDOMComponentsWithClass( 49 | component, 50 | "medium" 51 | ); 52 | expect(foundClass.length).to.equal(1); 53 | expect(foundClass[0].props.foo).to.equal("medium"); 54 | expect(foundClass[0].props.style.fontSize).to.equal("medium"); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/client/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Frontend Tests 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /webpack.config.coverage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * Webpack frontend test (w/ coverage) configuration. 4 | */ 5 | var _ = require("lodash"); 6 | var testCfg = require("./webpack.config.test"); 7 | 8 | module.exports = _.merge({}, testCfg, { 9 | module: { 10 | preLoaders: [ 11 | // Manually instrument client code for code coverage. 12 | // https://github.com/deepsweet/isparta-loader handles ES6 + normal JS. 13 | { 14 | test: /src\/.*\.jsx?$/, 15 | exclude: /(test|node_modules)\//, 16 | loader: "isparta?{ babel: { stage: 1 } }" 17 | } 18 | ] 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var webpack = require("webpack"); 4 | var config = require("./webpack.config"); 5 | 6 | // **WARNING**: Mutates base configuration. 7 | // We do this because lodash isn't available in `production` mode. 8 | config.output.filename = "container-query.js"; 9 | config.plugins = [ 10 | new webpack.SourceMapDevToolPlugin("[file].map") 11 | ]; 12 | 13 | // Export mutated base. 14 | module.exports = config; 15 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var webpack = require("webpack"); 4 | var path = require("path"); 5 | 6 | module.exports = { 7 | cache: true, 8 | entry: path.join(__dirname, "src/index.js"), 9 | externals: [ 10 | { 11 | "react": { 12 | root: "React", 13 | commonjs2: "react", 14 | commonjs: "react", 15 | amd: "react" 16 | } 17 | } 18 | ], 19 | output: { 20 | path: path.join(__dirname, "dist"), 21 | filename: "container-query.min.js", 22 | library: "ContainerQuery", 23 | libraryTarget: "umd" 24 | }, 25 | resolve: { 26 | extensions: ["", ".js", ".jsx"] 27 | }, 28 | module: { 29 | loaders: [ 30 | { 31 | test: /\.jsx?$/, 32 | exclude: [/node_modules/], 33 | loader: "babel-loader?stage=0" 34 | }, { 35 | test: /\.css$/, 36 | loader: "style-loader!css-loader" 37 | }, { 38 | test: /\.(png|jpg)$/, 39 | loader: "url-loader?limit=8192" 40 | } 41 | ] 42 | }, 43 | plugins: [ 44 | new webpack.optimize.DedupePlugin(), 45 | new webpack.optimize.UglifyJsPlugin({ 46 | compress: { 47 | warnings: false 48 | } 49 | }), 50 | new webpack.DefinePlugin({ 51 | // Signal production, so that webpack removes non-production code that 52 | // is in condtionals like: `if (process.env.NODE_ENV === "production")` 53 | "process.env.NODE_ENV": JSON.stringify("production") 54 | }), 55 | new webpack.SourceMapDevToolPlugin("[file].map") 56 | ] 57 | }; 58 | -------------------------------------------------------------------------------- /webpack.config.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * Webpack frontend test configuration. 4 | */ 5 | var path = require("path"); 6 | var _ = require("lodash"); 7 | var prodCfg = require("./webpack.config"); 8 | 9 | module.exports = { 10 | cache: true, 11 | context: path.join(__dirname, "test/client"), 12 | entry: "./main", 13 | output: { 14 | path: __dirname, 15 | filename: "main.js", 16 | publicPath: "/assets/" 17 | }, 18 | resolve: _.merge({}, prodCfg.resolve, { 19 | alias: { 20 | // Allow root import of `src/FOO` from ROOT/src. 21 | src: path.join(__dirname, "src") 22 | } 23 | }), 24 | module: prodCfg.module, 25 | devtool: "#source-map" 26 | }; 27 | --------------------------------------------------------------------------------