{"id":13630795,"url":"https://github.com/winkerVSbecks/tachyons-measured","last_synced_at":"2025-04-17T17:31:46.143Z","repository":{"id":57141619,"uuid":"86024501","full_name":"winkerVSbecks/tachyons-measured","owner":"winkerVSbecks","description":"📏 📐 A set of higher order components for creating stateless functional UI components using tachyons.","archived":false,"fork":false,"pushed_at":"2018-05-09T19:42:22.000Z","size":118,"stargazers_count":67,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-02T05:41:20.568Z","etag":null,"topics":["css","higher-order-component","tachyons"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/winkerVSbecks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-24T03:46:44.000Z","updated_at":"2025-02-14T15:52:29.000Z","dependencies_parsed_at":"2022-09-03T07:00:18.992Z","dependency_job_id":null,"html_url":"https://github.com/winkerVSbecks/tachyons-measured","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winkerVSbecks%2Ftachyons-measured","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winkerVSbecks%2Ftachyons-measured/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winkerVSbecks%2Ftachyons-measured/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/winkerVSbecks%2Ftachyons-measured/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/winkerVSbecks","download_url":"https://codeload.github.com/winkerVSbecks/tachyons-measured/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249360009,"owners_count":21257149,"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":["css","higher-order-component","tachyons"],"created_at":"2024-08-01T22:01:59.509Z","updated_at":"2025-04-17T17:31:45.805Z","avatar_url":"https://github.com/winkerVSbecks.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"![Not Maintained](https://img.shields.io/badge/status-not%20maintained-red.svg?longCache=true\u0026style=for-the-badge)\n\nNo longer maintained. Consider using [tachyons-components](https://github.com/jxnblk/tachyons-components) or better yet [jxnblk/styled-system](https://github.com/jxnblk/styled-system) which has a similar API and is not constrained to tachyons.\n\n---\n\n[![CircleCI](https://circleci.com/gh/winkerVSbecks/tachyons-measured/tree/master.svg?style=svg)](https://circleci.com/gh/winkerVSbecks/tachyons-measured/tree/master)\n\n# 📏 📐 tachyons-measured\n\nA set of higher order components (HOC) for creating stateless functional UI components using tachyons.\n\n**🎏 Usage Demo:** [App](https://pushy-spirit.glitch.me) \u0026 [Code](https://glitch.com/edit/#!/pushy-spirit)\n\n```shell\n$ npm install tachyons-measured --save\n```\n\n---\n\n- [API](#api)\n  - [Media Query Support](#media-query-support)\n  - [Higher Order Components](#higher-order-components)\n  - [Compose](#compose)\n  - [Performance](#performance)\n- [Example](#example)\n- [Why?](#why)\n- [Inspired by and Related to](#inspired-by-and-related-to)\n\n\n## API\n\n### Media Query (MQ) Support\nThe following properties support the media query syntax:\n- `r`, `rounded`, `bw`\n- `f`, `lh`\n- `h`, `w`\n- `pa`, `pl`, `pr`, `pb`, `pt`, `pv`, `ph`\n- `ma`, `ml`, `mr`, `mb`, `mt`, `mv`, `mh`\n- `na`, `nl`, `nr`, `nb`, `nt`\n\nThis means that you can either provide regular values – such as a scale step number and literal values – or an object which specifies values by breakpoints.\n\nFor example: `\u003cText f={1} /\u003e` or `\u003cText f={{ all: 3, ns: 2, m: 1, l: 'headline' }} /\u003e`\n\n`all`: All breakpoints (unless otherwise specified with another breakpoint)\n`ns`: Not small\n`m`: Medium\n`l`: Large\n\n### Higher Order Components\n\n- [`withBaseStyles`](#withbasestyles)\n- [`withSpacing`](#withspacing)\n- [`withBackgroundColor`](#withbackgroundcolor)\n- [`withColor`](#withcolor)\n- [`withSize`](#withsize)\n- [`withTypography`](#withtypography)\n- [`withBorder`](#withborder)\n- [`withDefaults`](#withdefaults)\n- [`withMeasured`](#withMeasured)\n\n#### `withBaseStyles`\n```js\nwithBaseStyles(\n  baseStyles: Array\u003cstring\u003e or string\n): HigherOrderComponent\n```\nHOC for creating a styled component with a set of classNames applied to it.\n\n```js\nconst ButtonLink = compose('f6 link dim br1 ph3 pv2 mb2 dib white bg-black')('a');\n\n\u003cButtonLink\u003eLink Text\u003c/ButtonLink\u003e\n```\n\n\n#### `withSpacing`\n```js\nwithSpacing(): HigherOrderComponent\n```\nExposes the [spacing scale](http://tachyons.io/docs/layout/spacing) as props.\n\n```js\nconst Div = withSpacing('div');\n\n\u003cDiv\n  mh={3} mv={{ l: 4, m: 3, ns: 2, all: 1 }}\n  nl={{ l: 3, m: 2, ns: 4, all: 1 }}\n  pr={4} pl={4} pv={2}\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `ma` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `mt` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `ml` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `mr` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `mb` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `mv` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `mh` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `na` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `nt` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `nl` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `nr` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `nb` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pa` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pt` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pl` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pr` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pb` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `pv` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n| `ph` | `oneOf([0, 1, 2, 3, 4, 5, 6, 7])` | 🚫 |\n\n\n#### `withBackgroundColor`\n```js\nwithBackgroundColor(\n  colors: Array\u003cstring\u003e\n): HigherOrderComponent\n```\nAllows you to set the background color using the `bg` prop. You will have to provide it a list of colour names that you are using in your project.\n\n```js\nconst clrs = ['red', 'green', 'blue', 'washed-yellow'];\nconst Div = withBackgroundColor(clrs)('div');\n\n\u003cDiv\n  bg=\"washed-yellow\"\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `bg` | `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n\n\n#### `withColor`\n```js\nwithColor(\n  colors: Array\u003cstring\u003e\n): HigherOrderComponent\n```\nAllows you to set the font color using the `color` prop. You will have to provide it a list of colour names that you are using in your project.\n\n```js\nconst clrs = ['medium-gray', 'red', 'green', 'blue'];\nconst Text = withColor(clrs)('p');\n\n\u003cText\n  color=\"medium-gray\"\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `color` | `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n\n\n#### `withSize`\n```js\nwithSize(): HigherOrderComponent\n```\nExposes [widths](http://tachyons.io/docs/layout/widths/) \u0026 [heights](http://tachyons.io/docs/layout/heights/) as props.\n\n```js\nconst Div = withSize('div');;\n\n\u003cDiv\n  w={{ l: 5, m: 4, ns: 'third', all: 3 }}\n  h={5}\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `w` | `oneOf([1, 2, 3, 4, 5, 10, 20, 25, 30, 33, 34, 40, 50, 60, 70, 75, 80, 90, 100, 'third', 'two-thirds', 'auto'])` | ✅ |\n| `h` | `oneOf([1, 2, 3, 4, 5, 25, 50, 75, 100, 'auto'])` | ✅ |\n\n\n#### `withTypography`\n```js\nwithTypography(): HigherOrderComponent\n```\nAllows you to set the [font size](http://tachyons.io/docs/typography/scale) and [line-height](http://tachyons.io/docs/typography/line-height) using the `f` and `lh` props respectively.\n\n```js\nconst Text = withTypography('p');;\n\n\u003cText\n  f={{ l: 4, m: 3, ns: 2, all: 1 }}\n  lh=\"copy\"\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `f` | `oneOf([1, 2, 3, 4, 5, 6, 7, 'headline', 'subheadline'])` | ✅ |\n| `lh` | `oneOf(['solid', 'title', 'copy'])` | ✅ |\n\n\n#### `withBorder`\n```js\nwithBorder(\n  colors: Array\u003cstring\u003e\n): HigherOrderComponent\n```\nAllows you to set border styles using props. You will have to provide it a list of colour names that you are using in your project.\n\n```js\nconst clrs = ['medium-gray', 'red', 'green', 'blue'];\nconst Div = withBorder(clrs)('div');\n\n\u003cDiv\n  ba=\"gray\" bw={2}\n  radius={{ l: 1, m: 2, ns: 100, all: 4 }}\n  rounded={{ l: 'bottom', m: 'top', ns: 'right', all: 'left' }}\n  className=\"myClass my-other-class\"\n/\u003e\n```\n\n| Prop | Type | MQ Support |\n|---|---|---|\n| `ba` | boolean or `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n| `bl` | boolean or `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n| `br` | boolean or `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n| `bt` | boolean or `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n| `bb` | boolean or `oneOf([...\u003clist of colors provided\u003e])` | 🚫 |\n| `bn` | boolean | 🚫 |\n| `bw`  | `oneOf([[0, 1, 2, 3, 4, 5]])` | ✅ |\n| `radius` | `oneOf([0, 1, 2, 3, 4, 100, 'pill'])` | ✅ |\n| `rounded` | `oneOf(['bottom', 'top', 'right', 'left'])` | ✅ |\n\n\n#### `withDefaults`\n```js\nwithDefaults(\n  defaultsForProps: Object\n): HigherOrderComponent\n```\nAllows you to provide default values for any props.\n\n```js\nconst Title = compose(\n  withTypography,\n  withDefaults({ f: 1, lh: 'title' }),\n)('h1');\n\n// Will receive f as 1 and lh as 'title'\n\u003cTitle className=\"myClass my-other-class\" /\u003e\n// Will receive f as 2 and lh as 'title'\n\u003cTitle f={2} className=\"myClass my-other-class\" /\u003e\n```\n\n\n#### `withMeasured`\n```js\nwithMeasured(\n  colors: Array\u003cstring\u003e\n): HigherOrderComponent\n```\nA composition of `withSpacing`, `withBackgroundColor(colors)`, `withColor(colors)`, `withSize`, `withBorder(colors)` and `withTypography`.\n\n```js\nconst clrs = ['white', 'red', 'green', 'blue'];\nexport const Block = withMeasured(clrs)('div');\n\n\u003cBlock\n  f={{ l: 4, m: 3, ns: 2, all: 1 }}\n  lh=\"copy\"\n  mh={3} mv={2} mt={4} nl={3}\n  pa={{ l: 4, m: 4, ns: 3, all: 2 }}\n  bg=\"blue\"\n  color=\"white\"\n  w={5}\n  h={{ l: 50, m: 4, ns: 3, all: 2 }}\n  bb=\"gray\" bw={{ l: 1, m: 2, ns: 3, all: 4 }}\n  radius=\"pill\"\n  rounded=\"top\"\n/\u003e\n```\n\n### Compose\ntachyons-measured provides the [ramda](http://ramdajs.com/docs/#compose) `compose` function. However, should be able to use any `compose` function. Such as the one provided by [underscore](http://underscorejs.org/#compose) or [recompose](https://github.com/acdlite/recompose/blob/master/docs/API.md#compose), etc.\n\n```js\nimport { compose } from 'tachyons-measured';\n```\n\n\n### Performance\nAll the HOC provided by this library are stateless and mostly just responsible for mapping or generating props. Therefore, they have been setup to be eagerly evaluated. This is based on the [createEagerElement](https://github.com/acdlite/recompose/blob/master/src/packages/recompose/utils/createEagerElementUtil.js) pattern from [recompose](https://github.com/acdlite/recompose).\n\nWithout eager evaluation the component tree would look something like this:\n\n```js\n\u003cwithSpacing\u003e\n  \u003cwithBackgroundColor\u003e\n    \u003cwithColor\u003e\n      \u003cwithSize\u003e\n        \u003cwithBorder\u003e\n          \u003cdiv\u003e\n            Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n          \u003cdiv\u003e\n        \u003cwithBorder\u003e\n      \u003cwithSize\u003e\n    \u003cwithColor\u003e\n  \u003cwithBackgroundColor\u003e\n\u003c/withSpacing\u003e\n```\n\nWith eager evaluation all the HOC are collapsed into one component instance. This helps achieve better performance since a fewer component instances are created. Also, it should help with debugging since the component tree is much flatter.\n\n```js\n\u003cwithSpacing(withBackgroundColor(withColor(withSize(withBorder(div)))))\u003e\n  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\u003c/withSpacing(withBackgroundColor(withColor(withSize(withBorder(div)))))\u003e\n```\n\nFor more info see this [talk by Andrew Clark](https://youtu.be/zD_judE-bXk?t=19m10s)\n\n\n\n## Example\n\nWe are going to replicate this [Product Card](http://tachyons.io/components/cards/product-card/index.html). We start by creating some base components by enhancing HTML elements using tachyons-measured HOCs.\n\n```js\nexport const Block = withMeasured(clrs)('div');\nexport const Article = withMeasured(clrs)('article');\nexport const Heading = withMeasured(clrs)('h1');\n\nexport const Text = compose(\n  withDefaults({ f: 5, lh: 'copy' }),\n  withMeasured(clrs),\n)('p');\n\nexport const Media = compose(\n  withBorder(clrs),\n  withSize,\n  withSpacing,\n  withBaseStyles('db'),\n)('img');\n```\n\nThe `\u003cProductCard\u003e` component is simply the `\u003cArticle\u003e` component with some default styles applied to it. Therefore, we can create the `\u003cProductCard\u003e` by wrapping `\u003cArticle\u003e` with the `withDefaults` HOC.\n\n```js\nexport const ProductCard = withDefaults({\n  ba: 'black-10',\n  radius: 2,\n  bg: 'white',\n  color: 'dark-gray',\n})(Article);\n```\n\nFinally, we combine them all together to create the `\u003cCatProductCard\u003e`.\n\n```js\nexport const CatProductCard = props =\u003e (\n  \u003cProductCard {...props}\u003e\n\n    \u003cMedia\n      src=\"http://placekitten.com/g/600/300\"\n      w={100}\n      radius={2} rounded=\"top\"\n      alt=\"kitten looking menacing.\"\n    /\u003e\n\n    \u003cBlock pa={2} ph={{ ns: 3 }} pb={{ ns: 3 }}\u003e\n\n      \u003cBlock w={100} mt={1} className=\"flex items-center\"\u003e\n        \u003cHeading\n          f={{ all: 5, ns: 4 }} mv={0}\n          className=\"flex-auto\"\n        \u003e\n          Cat\n        \u003c/Heading\u003e\n        \u003cHeading f={5} mv={0}\u003e$1,000\u003c/Heading\u003e\n      \u003c/Block\u003e\n\n      \u003cText\n        mt={2}\n        f={6} lh=\"copy\" color=\"mid-gray\"\n        className=\"measure\"\n      \u003e\n        If it fits, i sits burrow under covers. Destroy couch leave hair\n        everywhere, and touch water with paw then recoil in horror.\n      \u003c/Text\u003e\n\n    \u003c/Block\u003e\n  \u003c/ProductCard\u003e\n);\n```\n\nWe are passing all `props` from `\u003cCatProductCard\u003e` to `\u003cProductCard\u003e`. This means when we are using `\u003cCatProductCard\u003e` we can use props to control the styles for a specific instance. For example:\n\n```js\n\u003cCatProductCard\n  w={{ all: 100, m: 5, l: 5 }}\n  className=\"center\"\n/\u003e\n```\n\n🎏 See the full code for the example here [tachyons-measured demo](https://pushy-spirit.glitch.me)\n\n🚨 For more examples see the `examples` directory.\n\n\n## Why?\n\n1. It allows you to quickly create styled and/or stateless functional UI components which use tachyons for styling.\n\n2. It helps break up the styles into multiple props. This avoids `className` from becoming long and hard to read.\n\n    ```js\n    \u003cButton\n      f={4} lh=\"solid\"\n      bg=\"near-white\" color=\"black-60\"\n      br=\"3\" rounded=\"top\"\n      mv={0} pv={2} ph={3}\n    /\u003e\n    ```\n\n3. It enforces typechecking using `propTypes`. This helps catch values not supported by tachyons.\n\n4. It makes it easier to provide defaults (see the explanation below).\n\nWhen building components we often want to provide some base styling and then allow the user to override some of that styling. This can be challenging to achieve by providing all the overriding-styles through one prop. For example:\n\n```js\nconst Button = ({ className, ...props}) =\u003e {\n  const styles = classNames('f6', 'link', 'dim', 'br1', 'bn',\n    'ph3', 'pv2', 'mb2', 'dib', 'bg-green', 'white', className);\n\n  return (\n    \u003ca className={styles} {...props} /\u003e\n  );\n};\n```\n\nThis component provides all the base-styles. Including the default background and text colours. There are many ways to do this however, for this particular example I'm using `classNames`.\n\n```js\n// Will render with green background and white text\n\u003cButton className=\"mr3\"\u003eButton Text\u003c/Button\u003e\n// Will render with blue background and white text\n\u003cButton className=\"bg-blue mr3\"\u003eButton Text\u003c/Button\u003e\n// Will render with green background and white text\n\u003cButton className=\"bg-red\"\u003eButton Text\u003c/Button\u003e\n```\n\nYou might notice a problem with the above scenario. The first two buttons will render as expected however, the third one will not. This is because in tachyons CSS `.bg-green` is defined after `.bg-red` so it will take precedence.\n\n```css\n/* Background colors */\n.bg-red { background-color: #ff4136; }\n  ...\n.bg-green { background-color: #19a974; }\n  ...\n.bg-blue { background-color: #357edd; }\n```\n\nIn order to get around this we can expose `background` and `color` as props.\n\n```js\nconst Button = ({\n  bgColor = 'bg-green',\n  color = 'white',\n  className,\n  ...props\n}) =\u003e {\n  const styles = classNames('f6', 'link', 'dim', 'br1', 'bn',\n    'ph3', 'pv2', 'mb2', 'dib', bgColor, color, className);\n\n  return (\n    \u003ca className={styles} {...props} /\u003e\n  );\n};\n```\n\nfull example: [codepen.io/winkerVSbecks/pen/LWBLYb](http://codepen.io/winkerVSbecks/pen/LWBLYb?editors=0010)\n\n\n## Inspired by and Related to\n\n+ [tachyons-react](https://github.com/tachyons-react/tachyons-react)\n+ [tachyons](https://github.com/tachyons-css/tachyons)\n+ [github.com/jxnblk/rebass](https://github.com/jxnblk/rebass)\n+ [github.com/acdlite/recompose](https://github.com/acdlite/recompose)\n\n\n## Feedback\nThis is still in the early stages. Any feedback and bug reports are much appreciated. Please submit them [here](https://github.com/winkerVSbecks/tachyons-measured/issues) or reach out to me on [twitter](https://twitter.com/winkerVSbecks).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FwinkerVSbecks%2Ftachyons-measured","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FwinkerVSbecks%2Ftachyons-measured","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FwinkerVSbecks%2Ftachyons-measured/lists"}