{"_id":"@asemirsk/fclasses","_rev":"28-69fe96ea58e0b1e06143e97ef2ff6698","time":{"created":"2022-04-04T11:44:54.503Z","1.0.0-alpha-3.9.0":"2022-03-15T12:56:36.330Z","modified":"2022-05-25T09:17:50.200Z","1.0.0-alpha-3.1.0":"2022-03-15T13:54:14.310Z","1.0.0-beta.2":"2022-03-15T14:25:09.125Z","1.0.0-beta.3":"2022-03-15T14:37:38.366Z","1.0.0":"2022-03-15T14:40:36.088Z","1.0.1-beta.0":"2022-03-15T14:44:43.878Z","1.0.0-alpha-5.3.0":"2022-03-15T16:03:36.866Z","1.0.0-alpha.0":"2022-04-04T11:44:54.750Z","1.0.0-beta.5":"2022-04-04T13:57:36.973Z","1.0.0-beta.6":"2022-04-08T20:00:50.129Z","1.0.1-beta.6":"2022-04-08T20:05:01.861Z","1.0.1":"2022-04-08T20:09:42.887Z","1.0.2-beta.0":"2022-04-08T20:19:10.983Z","1.0.2":"2022-04-08T20:22:20.972Z","1.0.3":"2022-04-08T20:26:21.074Z","1.1.0":"2022-04-19T15:07:10.650Z","2.0.1-beta.0":"2022-04-29T14:35:15.817Z","2.0.1-beta.1":"2022-04-29T14:41:37.071Z","2.0.3-beta.0":"2022-04-29T14:49:46.097Z","2.0.3-beta.1":"2022-04-29T14:51:39.816Z","2.0.5-beta.0":"2022-04-29T15:06:47.768Z","2.0.6-beta.0":"2022-05-02T10:08:13.473Z","3.0.0":"2022-05-02T10:21:42.907Z","1.0.0-beta.16":"2022-05-06T09:17:12.437Z","1.0.0-canary-24-22.0":"2022-05-25T08:46:20.843Z","1.0.0-canary-24-23.0":"2022-05-25T09:07:53.972Z","1.0.0-canary-24-24.0":"2022-05-25T09:17:50.133Z"},"name":"@asemirsk/fclasses","dist-tags":{"alpha":"1.0.0-alpha.0","latest":"3.0.0","next":"1.0.0-beta.16","canary-24":"1.0.0-canary-24-24.0"},"versions":{"1.0.0-alpha.0":{"name":"@asemirsk/fclasses","version":"1.0.0-alpha.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"28ce15a6b1c49e6f984d59ff1db29bac050fe78d","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-alpha.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-+K+Tj9mvcCvn0HJ6KJYlzaieQ621mbE/2Kh1JObDMv8BTbpQvhTwtLzKP5tUBSQkjqlskOTvxFLIc0ZKI8NRcQ==","shasum":"79f1e91c98072be9289c0beaca3ef304e94c5106","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-alpha.0.tgz","fileCount":65,"unpackedSize":346907,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDVG/N935Rmdz6kNiK+Rwsi1x0WMmqJQ6i72TFcSBjiVAIgIoqPfqqX4mNEdqFhYF8dtVX6VCM5zvoLzOnbpzlBebo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiSto2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo98Q/7BAmrRDpZm6mGibiMTz+hOOJOa6B+a4UrwdLVnf9ZsAZuV3Nn\r\nqapjQX5cYyiZRSK4yxrpW0TiE7BmVbXrkfZ7baZhamYwfrmust/FlZoSmCou\r\nR2HLHmdkJg1jZZbJgfaaZyke6GRKfClQi3/GkdmGEdXSaxXzUv5IjQrFSHoK\r\nD5yEyR7ykvMmLkPJqHxNDrA6lM2tFrD5kErHTmP5B19fWTof2zYxltE5NYHD\r\nT4n/NMq6vxSlWk+6GeVuZJcRHcZmj9ApiOh1qBAKwXb8mO/I2n8V+FFDZPFp\r\nUayKKrav4wzAab92BhzSmiJsWHrYdbDR6FRecdsbe4hvbBsprMIHefiHBOM2\r\nlg18nvFL1BtNL++JrK0/Y2wNCDA4jemfC/Rb4vZYJWlTc1DIcO01CxPN5Rqa\r\nbTpsLP84Zjh8JEfVcGabV5mPjhuBLBCMPU8Por8hIPkwc1MlDnlIH7PLqkEE\r\nG0PU6pZtQxLIVYjdzJ7HvBftyVhZdfyUQrSovM17KQh0xV6AQKBvVIxdmfUk\r\nWQSDYBKRZnAwaMhtj2iuzKe/f8g0L5oZi9XNOy0nNBr/9KERbaUHXm7mUgD0\r\n2hutVBMG+MUnPXFr7os8TE5YBX9GQuHMEubcxGwbN62iG46RF9ucvPx6HCOj\r\nZLHupYB5J0eeoSvHGBv5g+MRtsWRidMbq5c=\r\n=947Y\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-alpha.0_1649072694557_0.36184458734146907"},"_hasShrinkwrap":false},"1.0.0-beta.5":{"name":"@asemirsk/fclasses","version":"1.0.0-beta.5","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"e6beb3c3e2c8fcff324e0e741ec5746fc55ec312","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-beta.5","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-1p5eAAhSeyQq20XJfBldUf+rMdV+AIVLvJaeoWRB4CwNdPHQGnipp3dhUbMFrJjc71aMjahAPiWcVc9eTDcB8Q==","shasum":"c48dce0acd1d73740a148fc60c686eae4222a420","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-beta.5.tgz","fileCount":65,"unpackedSize":347082,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGf+uD7dJ8lfKKixyg0z9/nuGDDVv30KsSKFV4V9vDOPAiAd5G8OwVAiqjPUKmfT5HtcVbB8hCr+Rx91ugc2pY7slQ=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiSvlQACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmre2Q//QXiHlEJfgoSxv/d4S8jR06P29+4xhygh26KUvuiHnOlfTjG5\r\n96h/S6ELefDhq+C0TyITjhCY1lwp+hQyaX/RAG+u+kB2gnbvEaKYmi9johu6\r\nNBiK6fPUiOkhP9n4gsQZo/yEG4Xt1Fqm0MZS/WPPoSuqQ5YO5xTckafeEL7i\r\ne5HGQHN5clFdVudARRZW0HXNq36eoTfXvl1m7Qe66nbv3e+GGRb2t4eNLIHm\r\nhSVhpxK+Sh/fOhgmC2AU2cbsq7xa9YDORRmDHJnS5rIHCzS9ssuH3eoi9W/r\r\nO4S8ijklwyplrek+98cneZJesGKoGPWgEyvgnVNY1RIAj2Q9u1uNiOQ5KFAJ\r\nYoRPaDi+CFHVpaPQIjA8CMcW9imtM9EGY8m8ksaQLWtEM2DGWMpqYsXVLUef\r\nGYC/yoTDnLK+wj8tgEGqyxjcB8lub/OyQuVoUTLb+AxFL9pETVA8PzPHDOLg\r\nXOPQCulFVOC5A1BS2Q1rr87yZkM3MAq23mNtLs9e+KimJNkC/e+mmojNOCRw\r\nVZAP8O5CDtQS3FSZI5o5Y7rmSXK+TmMqHW93DpzWj0rtJi/ht+gajVRUaxs3\r\nQX6jqJkV3UhbjqQDAnvhqx8Ezy7AqunZDNYtP6Qai6tXrtVnTtRpe9g0clr4\r\nB6BlIWtseMiQ4u96Oucbo40luStjLBk3CYQ=\r\n=4GFh\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-beta.5_1649080656797_0.05937483742007954"},"_hasShrinkwrap":false},"1.0.0-beta.6":{"name":"@asemirsk/fclasses","version":"1.0.0-beta.6","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"cbd97725152f2362bb86e6d4bba02043e3c4570e","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-beta.6","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-7o4EMNy3QyT++D9/RTgcjfH8ouEZz8jqNiZm5zUgyLPbBrbUWtX5zLIoFyMOZ9V3vOe3PIuqZoQnUDFDXjGRqA==","shasum":"f6cd0043ef0e7d1cece9c7ee6f2d690924e85975","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-beta.6.tgz","fileCount":90,"unpackedSize":374556,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDX+eWRu+N7aAxs7stf9x6AZdnNLbLPXXKhJO4qncuydwIgMjLhuRzzMJ+rV3kXKbzMc6R0/mx5NmAFqZU8XLycOw0="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJRyACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoj1Q//R1y8FNigfxGxzhrbnjcqvk7ECkn3KWeDit4Plfjac7pHoIVt\r\nBEsj14v2exkaQi4fwVPNzk585xn/YTXvsI4TUPsiY/fUSQ8S2Wty9KheQP1K\r\noI2ZyhEYZGtfZW5so9Fq/0QAz4KH599LlQ8PnVJOiZruOhJADu/5il7Ezv6R\r\nQ9CJaedLxHrjJqgwFwshLM0XhprPKO4hlnFwfQO8FOmR2ERuC1dwEyIack92\r\nENvdoE5p4bRDh9O4z+hhx4NkFqrAnQZenczRlHpszRg0cwmZIyH45wKtZp00\r\nsPJAkDzOYHdCQXEC4J20kBNCKTHodRc98xz2SmDQH6d16Ni6aqqcF6v5kCu3\r\nbMaetE2LUO8fFowzHQ8Lv+TlXDZsBUanxYMCqmT6mrji/XTJEg4zQBjJ9YHH\r\nPXToR+6nbjoGKp3Eci3B6ozRuct0yWt0XenbAUHVhyCjICZpgVDwbPaCTeax\r\nHQJ4sOUNha/aE4xs9T5EkUHgcFj+g963fhMFMMCVwx2PWBRh+EtuMaS+Kv06\r\nnP7Weu9Yr9NHnalSB3JtimGZbFHfPU0ujEAiKmHdPQDrMZKKX3dPdUinYzhB\r\nAiyHpMBvx4CK+eiExjKV/px/x08NhycMU5/CZqv1IsfSdYZOvm1G5Uuiezhq\r\nDT0MY4pFTLtdsPSh03PjoeCgLj5JjcYAq50=\r\n=Z4AE\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-beta.6_1649448049950_0.7776540421858482"},"_hasShrinkwrap":false},"1.0.1-beta.6":{"name":"@asemirsk/fclasses","version":"1.0.1-beta.6","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.1-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"dfbcb3dab592c76bd48c138c275c1e27fbd9ca1d","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.1-beta.6","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-gNmqrtCuqg3zRicDrI/MaLUErOfJMMVzNLddr/hE+/PJwCRtl6mZVN3xhAYJR3SdSHSTNEDwAVnPuyS1yWlfBA==","shasum":"fb18f15407551b710abf443f7bc7f9bdbddbd4ff","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.1-beta.6.tgz","fileCount":90,"unpackedSize":374556,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBaRGxznpP+eGRCZ5gkFUGmRwqPsmpRc2G7/a5fmvg2zAiAFVnlW5z6pQm9eW+OpaD4mwi3HPYWY5nsyytGSPnT0ng=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJVtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq/HRAAmooJ/Qhgvn2XFD/0As/DKweg8PJAYibL/dIYhbk41qwudDdL\r\nOLVXomurFDIs5kAgCAfUYNiSxhZKy8+7ZwWggUMCd4BCtrtyfLgc8NdDTtsZ\r\nBSz5N3CCdDWEYhV/sKQgJ0YVtjZ3R2Yqe0S7X7+jnRgGpxie0IH98jVk/6WI\r\ntfxh+jo7H/X5j+wivuOGRS8si9OagKdl12I5Ru1DoRt1u8aNxzx0lX/gI+Qj\r\nMXNs5XFfvGqKz2wmT/5LKzm38/bOuecr0WXjT+sRscREfdMPUgzGDkZzsra6\r\nw1vw8jlX5P4zXFSBvNHZXoF6fWLpVgd9NEvT1tXa7fq468tBcsRTXsNCOgNR\r\n7jbeH8uHpisSEk8/exyhjuNtOESti0YwM5/JomsuVF392rzgFbT30U7LPXeP\r\nCtFePZC2dPUmD+voXSKHI7K8S4WLRKnQb97KZqRbQc1j73QSVcw5PkEVPHbe\r\nDxVYlPBwKSYfQOxF8C+DeT+v89YxXYTFqz7tiyPiJKLkPq0J68LrSUzD8Huw\r\nevoBMD4TmXHCYdUFhZSi7mqGhzQs91XPnDXaqYNHH0sYLOx+VL5tOoQX6g8W\r\nNS2BF8znXZ4FwJkTlI4aWVfjU2dUnef7ONmcQJG7Wbj7dF+z4sDckKv2gtr9\r\nfleZradJ1acwdx5SG4lAj/WqTEcGGaE/baA=\r\n=ROYN\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.1-beta.6_1649448301536_0.38519048411258217"},"_hasShrinkwrap":false},"1.0.1":{"name":"@asemirsk/fclasses","version":"1.0.1","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.1","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"b943f745d8dc223a872b770f79f3e0db78f43486","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.1","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-qhs+CifgGwuAIUKlDxht/lMkBHhomP3MMiJ8kidD0F8IT/Ha7R9mHT6QjCwzNnIHngZKr2Az2e79Lwken/n+gA==","shasum":"6a848b866728671f6aab465d4f552f7ab2192380","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.1.tgz","fileCount":90,"unpackedSize":374734,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEMqaoBotahqh+EGrYPoeuurohljFayzEryQIkQFfg5FAiEAuksBAklA4rroaRCnwWzTCH7VuChATSqk5+4ypg9EBwo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJaGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrETRAAhL27HfvaMyh3H4B5PanEA51QTop2g40yiP0DICV+vgidRxQZ\r\nWovrOZ40VOXk30PCP773+t/uZV3FCqKJtcN1Ho5MZyI7JnctSx/c49jjrAgL\r\nlmBDRa2w74ztEmxoq6VgJJIbC9j+VuaV67zGJ6kCpje8XZMRWE8oY28wwuMe\r\nYj439vpDLyeFpKXzhdB7a/VDGGX5IhS7meORNWfLI1fZXkBGlxq6fyMLAh5g\r\nboMyYq42BE54kabc1RivpMQzRGLFEKwEAvxPpLV2TuV/mDvt4S0bgJ+o+4WF\r\nXognmhNxcBQZBSFpF6y7pJ4+vwGcWkv/HLV8G1mb9DsRYx0Y81mUSZY+F2Kn\r\nK7ld0KFb1XNdS6dUjaohD0e2noVy0MRyRTkHtmwH+npHjsMmsF+vjQP3hSIw\r\nKoPXReDAqoybDrVRc8C0QgbQ8l+0DT6/Kt3roRJFMluqxKmDCuZEkF+w6muD\r\nlVZm2KapuTD6aS+c+/qqXm7dtnsqb0WzZZ4zzFgs7nr2xZhNh4hosC1D4Pc8\r\nYx/ww/d6QWyNiJ56PTGiIJAG91uPA3I3tdpMSJUxHs2QkqYq7G0HGZmkO+Qm\r\n1nxniddyan7zXZKdOYkC+/yuI+/zxv/ynX14xxR+5enisAGH0INmgVF5gbnY\r\nEMxE51gHtnXXKd3R8akXlAFAB3v2XmflvRc=\r\n=0zZ5\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.1_1649448582727_0.5226331347100726"},"_hasShrinkwrap":false},"1.0.2-beta.0":{"name":"@asemirsk/fclasses","version":"1.0.2-beta.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"test":"test","build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.2-beta.0","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"da62659a8fb42aa89cdc8cae2f148c8dd8db5dcb","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.2-beta.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-bTfV9NTJ4KTxBoGX+wecZp6gQGxFddudwLoTfWJHcSIVIhxJ4GjTZxyXC4IONgA+02ozfJsvp7mTP6IINYxZwA==","shasum":"10dc97abc3ea07fad32fde4d9f8fd046fedbcc12","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.2-beta.0.tgz","fileCount":90,"unpackedSize":374576,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDoKf7oQwAIrPfIoFOlDIsbwwVHThQopLBF9qFpFYsWcgIhALEPmPim4y02hCVzvkWisxa31WQ01vtSOUxT3oTmUOwc"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJi/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoRvw//QPESAvihD6zQjfNunLfie73+SRqVFlV5+RzWgqXE6rp0gziC\r\nV9mMCu/UsgP1GR/LpCXoscIUBsI0IIcUiCXNgH11BS0MjeQvOd3BeIDzYqpq\r\ntj0sbZa6RtcOSgs1VZjz8ba+JnjAD2KbaIbiV6fMW0l4jdFVNFq9uLMiUFoD\r\nmUEurzx6RYA4L66feBOvD1MDHc2d505GC5/K8+vfdcdMyb9Xiem4chHpuzIG\r\nlUJS28FZvxqj7dBax4tFwAnv+/8SXRAgpe1ltsfCg1xHxQXuQ9FkFLC0pzNY\r\nq6aUEgjq+gIG9bVmlcHd4yj5ECdztSVgFvYYK3QJBlX4p0keosA0GiKVGbAh\r\nIyWikwyMyvrT9cGtqe1nfMP14yqo7m8Q1AXam0eE/D95VIytZc1i2KblLO9A\r\nIoOTS1y2b1/6upWmBEHfFm8ixpV9GUddMUL1VNskUDHvkqV4XtVc3Mu1suFE\r\n1zs8tQezy9K9dO2Xd/CvNHRF4Stz8EYzUOP6FzEAo7eAKjjigsJ7n1mzD6Cz\r\nCSq3bLbl2KFprz0KbxLW0GUsun0VkvkR/i2ZPtq4PpC5Nc4f1tSnIM00ProZ\r\ndHsSzQCF9RNQx4X8aoGR+cwXHLEEX/UToBZ9toNBuP/+BRg0BZiYnLTvW2du\r\nN7zUNZSsVwy2MnpgDUfVCuKD6lU7JdLpuXg=\r\n=7PIm\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.2-beta.0_1649449150869_0.7226362076839443"},"_hasShrinkwrap":false},"1.0.2":{"name":"@asemirsk/fclasses","version":"1.0.2","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"test":"test","build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.2","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"19cad7cb078a3029c7b40248078ddfa4d413bdcc","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.2","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-K7IlHGgOezhrC7wmcQRbYgrh95SDBq4oFtXdOoamyvwweJ/3Ucle7vx/W4A1h7rhLlRFvDI3UQ7QMgA2qymzMQ==","shasum":"d3184093ae1c384222249f02576138d5831a25c8","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.2.tgz","fileCount":90,"unpackedSize":374754,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFXA+Bl85cve+cEI000xInpeoR2JTyeCQynYets/HUtgAiEA1kJqLJ+88a8kGFGDozeCdmF9kHnkrdb2FryCswiopwc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJl9ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpMIxAAjtInA89O8gcuIH/mj+vBih+Sfb1BFhHsnlRU4FlZHxp0LgtJ\r\n3TNCrvAEr7miZieEaVroJ4oHRZkwvmTOZCeUxVSwfe9786Kz04Bsg3ow0+8I\r\nL0E2NkRpod9AzY8aFDE4W6Zy6QfaJFsrxu2cCfAh2KjDowB0DVow1Hbbi+i/\r\nvwQnVsfz0hIHk8hrfzrCXZOFws+6wKy47mmUBXfMiSBZVv5aZtd63Plyx7M3\r\n9GXyqI0rOyRmEbirnOaBeigXVH+7RLJPWwBiPyXVHVedfyaMs3teS7KQ9mWJ\r\ncBQxGhMMRRf/ZeNQa+Q+SWoreOCeEy8UpB7GJ9Vhf671m6Q9WS/eTNY6uc41\r\nB+m/GWL3MpDZ4eP45usj7Wy/NqK7Td2BHXDFUkQgraGHala7eC9TII4cUjzh\r\nPPhou+Qkadgs6EjrGugSFH9Qwog1g6CpS07AVr+w2aMY0jpCIM3RbN0z476s\r\n3AYuMkXxuSpVT1uyQMQWbs15NvJpaO9zgCHVVrRU0xYUfWtSAbdY8IBQdr58\r\n3kFZuHbTeGPbYVP64/euu2gTafsH3vNTo5ORKcTHvs4PZMRAn17zqYoZhebV\r\nAnYVL54cMKFOnMdFMwoUXjQnG1gvOxza4040qADJpjbZRdMS95Uj1RHmgXsY\r\nKCiA1tIzEe+wsatXagigiSceTtle2QjQCjA=\r\n=AZCe\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.2_1649449340798_0.16808368121857464"},"_hasShrinkwrap":false},"1.0.3":{"name":"@asemirsk/fclasses","version":"1.0.3","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.0.2","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"b46d91ae36b8631daaeaf0e17b4197086a98c2f9","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.3","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-DqIlZQjOsWNxQecr56psa1oKRDHuT3q11o5vmmuvHzl7QGGOEIw0froauZBxlQSqpJS0bIAPEuGEZwpC1V1oOw==","shasum":"39215892b923538558711b8cfbddfda2807d4d82","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.3.tgz","fileCount":90,"unpackedSize":374734,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFQcl0e+I8V3JHA50h8b9wH4LLECsGNj+SaXvX4h835GAiEA2067h8dj7QdJ+u5iS8+EwnMlbD//QQKL+GZshBMc7U0="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUJptACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmocsg//VF4Pbd5sqn1eMvXIq3cL0pkgDwRTyVyv0pWyrJW+xtJXgnAY\r\n9ANTI809zIOuH9XF73nprhvF3KL4M3FGx3NL6NmHXid7Hgs/xSN+Ov8DTfpS\r\nTj3mU7MgEYAZ+H5gBl8HfjCCQSAHojDe/R6CXRD7pkqnzLF1LzBSp/hR3Q1E\r\np64mjDD4+L7qrHug0hYzmq+vNyuvoJ9ZlNXpj1hBmw/yRJ7EcQkdzPtCCmVm\r\nF7dD5JX8DdpyJtWpIHs7Vq8KKcFBybV4jK8CVOjmE7Piv0/aa8/2P+fCNih8\r\nkp42KenLUDVd38AddXBPMj2nlnuDUTCkt1EAm49eqrSA4uWMSYqyx7ITBySi\r\niOfGnxNX3fUSDwfZZVPIXJBGdo4Bs/e6IfCqx1MtbbVTZZfuk4PEHSKNAZBY\r\nhG1lDMS9TtKl2QIPfF2OX/cGMD4BjWPxV6aVfVjsu/Jvg2r2QfPeTSVkUF3W\r\n885TYp92Et5eUUo9vfwrC3sWp1cD3B5AtaNY2c3irn3hlnSaYK9P2N/ue+i5\r\nyYSR9fscJGP6Ghs72z0bseWI62gQRt0deEL4FlnHyHPcr12p8/POe0gJ5jGU\r\n9ADQBLCAgCSHPakuwh9jBK79I95oCs5SLUV92/sP9ym40hHdDZ2JWujZgPB8\r\noTX8hgkok1JlMkTKYEiyaUDWgAAmvIPlf9s=\r\n=3vXO\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.3_1649449580892_0.025770898030908818"},"_hasShrinkwrap":false},"1.1.0":{"name":"@asemirsk/fclasses","version":"1.1.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","test":"test","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"@asemirsk/cli":"^1.1.0","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"e767bae774cc17eba5d92b638b7628cdc9236086","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.1.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-4LBCBfrdyny+jPaYLMiN59hsqiiMQReumMoN3292/tPA5sAD09xiCANKJDCM/q6uUQ8ZTVa/2e6cht2PbX+scw==","shasum":"45e8f08b2c960f89a1e78359d66ca4d668868c79","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.1.0.tgz","fileCount":91,"unpackedSize":375874,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCWMSqx9Fw4wpEhQFr8RjDBHCWWtBA6y2Z5BDyydlv+5QIhAOuyQqD9YLO4y7Fw2R+6ChPvkpi9/DLazuZxUTcRNIU4"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiXtAeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr6gA//eIa5ZTNf8mpHUDJ7M9xt4Q9nTizwMsbdJhrUVfmv3M9T6Brx\r\nsmTGIR7rZlHYL+/iieYOXY5POcbPiaxdNKW0LGnWzkJwMDVfclC04Ey//Grm\r\nJ8jV8dftSNaloJOb/Ol7y5W7mVXlNk3tOyQOGG1Z/yElllRAsB/0JszGGVod\r\na6i+tSuSVmJUQrKhPTYAohSX8zskfortNQq8bB5uAGe/ui7A4h7phwiGjs+z\r\n9t1gqU0+joUU+UoL76TBlHxRVqQgEunH1Qt9zEAj8cArP1DSdfXp2c1YpFib\r\nRd+snFeP7E9+m2gq5nlhm8ZFe2T2mW9yLBKB8bGtiMZHveu4IyEcFFDQV6gf\r\nTQN59cyFDOFcj2HnBkr+WetyTCMId/qm61oK+vWI0Gc6IRUxluWcDSUnM/dv\r\nB2PNomw+pMiWcVb0CsIUhqE9iesvawegFVbjwUNKRBjLpLSDjlyu90ua38zP\r\nbmPCFk1VoLIdcmvX7pVDw+y5GpU09LUtX21XSB4pnYpi8twxltO1emwGLySF\r\n67P9WxLqTv2aiyzS54C1g41hHYL1kF8FOEFXid1KfEHobzgAURTnI7HJHWX2\r\n8/LhM4Ez76TM9z2U5bfi77Sqv9Z/9ihi6nLHwmNUqnsO0Mph4zyBU5BPTMjV\r\nLyckvn+Gs1z437nCW4uMm+Qb9MujCzTaGSU=\r\n=Rxs5\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.1.0_1650380830486_0.08013507123242203"},"_hasShrinkwrap":false},"2.0.1-beta.0":{"name":"@asemirsk/fclasses","version":"2.0.1-beta.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"2aebb64eab582696b080b48c5f3475c2759f6408","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.1-beta.0","_nodeVersion":"16.9.1","_npmVersion":"lerna/4.0.0/node@v16.9.1+x64 (linux)","dist":{"integrity":"sha512-qF8dn2J9zGvZWScEyZyusCCQ37ZVsOEKSbFDHJV1ua7CwQX/saXEVtmTQKwY1CT/SCvOzoZVDP06itnwwqLmUQ==","shasum":"f8c91a8c3a918aa6b9bb020ff963734dc1b6fb50","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.1-beta.0.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDM6HSo/A4OCmPurc+6hrd5/8QgVhqwNRGPiyfzMi3mYAIhAOg+8g6n9nObeVJSnhOFByrxvLk7zS9Bk/3qkMC7BzE2"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJia/ejACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoFpA/+KZSnc/lt3UjlwhJOIdH6ZaKxqWqIAFFa22c40XLsi8YimFqj\r\nNXWJIGeRF983QtkkbbL+/I+NY0e8fvLKH4MASav2otBFYmIcVTn6ZBGR7DeS\r\nkh7LUcXoez5L5nqTfdMnKTI+qiwXuJYrNVURDXItgk08KGNvHyX0xEOwVFFb\r\nNRy4aYZFZeO+/nf3EXv1nT7XKpPOJLWVu/08UFVR7bRoouPrfqSBtnJG6ptq\r\nq3coIzm82+CSBMj+/GOxQ0mnIdaEsEWapYV6PwmpBvAKzjbI8N6ekyNzZMNy\r\n4sipBV9mpPacTPmFMETUlTU1+dqhhL/37/HXqM0unNoIsjC0iHWxVVEaMPq9\r\nfQNtsWM4LDy/mqX4HD/foXNsaoY+CQjiEW0+83KlTiakm6PvCl+hRDQenPSf\r\ndv/WiiaYNtfowgNv1muRtStnRkviEjtbEaUqyZq8Hp5c2lU2Wa+JxFR3mJ3f\r\nKdCCBH0h38NluvYb5uTCYcjJqPJc55Ac01m6232cdjNcN2QKmffGwOhxsVP+\r\n5aibCH3HNqI52R/QS98icpqa9nOEBwkSRWue4szUxvcL8y3xwYEBIobcImGO\r\n54HCSbzfhoysxNIZ1E3Ey+LpacgzNZmWrhbQBq4zRxCuzjZNugHAGa+5rNFO\r\niqnUO9oDRSTyOCY3xqCn8sW6gwk+b/358Js=\r\n=QWJQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.1-beta.0_1651242915555_0.8720555368425935"},"_hasShrinkwrap":false},"2.0.1-beta.1":{"name":"@asemirsk/fclasses","version":"2.0.1-beta.1","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"8651151ffab8ce28ac9424085c9325e3485ba177","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.1-beta.1","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-rUw376OYCG23dgdf9l6u1k+MpfbfHN/rAG5w50mPBlAN16Id6oTTD+1YIJHlhsekXEmnqTF8eOtsgQF/gVCN0g==","shasum":"7c4b9e05eadecd103bd37e85abaed76036935293","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.1-beta.1.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDISBDO9rg/LlzKoA/rwBuHIBme2Myw9ACi2tVcuIH88AiEAlZoCmANAnGRJCOhvixo+JXk8ceZQeo3gOsw0JgARqII="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJia/khACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqvLhAAnPvALLn4Yfncm5yXi98rsF6y9UW5C+FfUokVwoPJicgpfLDy\r\n+DqvG727ivsGoZeDHf83BcP1/50CuepUyTWXop11WwDVh4n0PlQ3ULJocQCt\r\nnyZu8Ec+iASD+vSEcgSODQJk/6UT+OlZZZEbGHXQe6uguBJCcAIpcFTBlUiU\r\nX41kafOTxuGv/Z85EaF55fy90omob7x9bfqW/Pv52u8H9twBpckBzeWK06DB\r\nFZxBv6iU5VzMNCQxiBLiIVZtJMaC5r2FihRSA4Ja32o3NW40GvDIeXg562/F\r\nr/4OQEG8yg+fhcPqWryuUjLPUJcGLb47IWvgE1+LX3HV8JCU0wFTokzPqsUF\r\nvQi169DHo7T1FokizNHvUW/xA5u3jofKapyJIkyj/t/tkCSfC1oSkUgVA784\r\n5+DnSh569DjhjjxocnJbrMmyXbSvuNq+CiKy0kS8z0KPA14RcqSlFdOAa4ii\r\n5klRzfeHUwPUnUzfuN8FTrFNaLu7AYanQTetfjqQC2rgw3da1f4m+Fhh528f\r\napst0tAzhRYjTIzxRJkTn7fUDDggoA2V/JgXxAJgbhx6bpFfBykT0C6WibCE\r\nT3HqU8qgFIuvgUd6gG2hvpXR6bqiKkjEaLdA4mXeUTUz2XVE8sstKDHE/LYw\r\n1oTSGGLXNlJKeEqj45KuawtacZ/cfNwaJVg=\r\n=OMTy\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.1-beta.1_1651243296936_0.2828185473633915"},"_hasShrinkwrap":false},"2.0.3-beta.0":{"name":"@asemirsk/fclasses","version":"2.0.3-beta.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"95b0d427717d1ca0bfedc22f3f23323acc223e94","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.3-beta.0","_nodeVersion":"16.9.1","_npmVersion":"lerna/4.0.0/node@v16.9.1+x64 (linux)","dist":{"integrity":"sha512-FiwaxrS680gUJJgigHtEng7E2ajz0PZ6xzDICj7DZMhbQ+FVSp12pIg24hsyXEQtzw7Ij1n85JAthPrlPP4+Rg==","shasum":"a74bb362d8a45e9054ee372cf52a1b7357e49004","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.3-beta.0.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC7LlSxCwaCciHRvm2i6vK+1ehB4rNyoPAMTRuuBN2hIQIgbcxfISRwt2w+bCTCJj6CgCkhLnZ7IzK6JEEWU5+ln10="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJia/sKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqMxA//ZwoZN8sIJWQq7UR3esjKhhFpdAVeLQAVo4ljkybcoxO18DRO\r\nRjYMzyqXKIOikXSJauDXWiSyzTkEy6maY5HfSZKO42Z4TIXO5HXBw5T18slM\r\n0mV6BG2LVzGbsRmgxCCJNF4ik9x7JmwKoRLbPsWtu2B0ccBBGWaEkqh5P+KI\r\n5pZWxl78y7q8kXxdab32muVo23qasChnIwNX6D7SW1W5NH+4Y5L5YbdjVn0B\r\n/J/qgQFo1OYB8QjPzwQRy2aTbpSML5vW6MkM8BG32HFqA2de+ovzDoymLbd6\r\nbdG8dsdt8RoCf/pj8RUeSjKg7B163N3sS1txf4vIgOP52TMqqKzKT1G9KnMN\r\nll857LWR89SGCo6SmCPlaCp5XGw9uowWd8KwQq/N0x00gxHQxe4uCOxLODiM\r\nf/X55arNXyOoEn0p+UHaIs7//KumBMv5/0dXnvWbkgCe9A2UBjJyvc2iaUZE\r\nd8bJb4HLpnh9gernOXfpdaqngfWR+lPGZnNbW9VyLQ+COSCz14hYj079k3l7\r\nagya5N13+CA0fL1/fWniFXffgpiSnwWu1t9fVfO/2fKRASueeC1j1dp+8yqZ\r\nxWvyjRMyLvWFFd5/TatLRwT2FtGUmwbcZepArobmwEFxxjAfQjOcKGF6Db1s\r\nUgyKnJq3i4QcQmDQc1K71gozawd2xAlrjaY=\r\n=ywO6\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.3-beta.0_1651243785855_0.7190873533907123"},"_hasShrinkwrap":false},"2.0.3-beta.1":{"name":"@asemirsk/fclasses","version":"2.0.3-beta.1","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"1be4d3bb997d192b34b946c04f840a2a82b34a5b","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-green-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-green-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-green-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-green-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.3-beta.1","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-42cObKhw3Gt0r/QLhsF3NBHgDQRIqGF7OrKFzlCr8yP0qDR5KCWdh5e8HZfaSVgYKkCoQ7OvZTuQR1ZgAyiZJQ==","shasum":"5470ec7a101e3246cc58484a0f7c7f77795958a7","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.3-beta.1.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCFOtI3ROh3/ROPEUUAY9WSvgWNLgPhXK/5iXRT68D6RQIgHm/jW2qLfMMIvuFPVrnw6/EOIcjNRSy24NBJh8Gcp3U="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJia/t7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr7KQ//doa0Oa2G5BhnL6656MQ4Nmc/jXcF3pk0igpptlxPMUSdVdpY\r\nY4gKmqIUlOdiuisrswmoR8JDoMkxsAbh2OxAfmJiIBJJpNRxv3pa9GZUkQAw\r\nM6u/umhoUq0wfncDPyTHJWjGKKnFWYxQTsnuoLRo5dpGb45qKI0LKUvkt6os\r\nek10/HB3BwSQquvfqs9qOkvfgkQCVmwkH7zSHCrO5Yty6Xd6FHGRPGndcnL0\r\nVv6zerEVdA17sTFd5qfFOwyrojGrKI9TtZ2gzcZknFPDH+ntwwsNRlFG4WJo\r\nxftn8ZRnzp4q+2qqrFIiKcLR5xcorHOWR/ypwTWUTom2yYHXTS/a67hxdRvg\r\nd2KqXgsxxm4od/4bCH+0r3VPowOg6oN6I7DLXoV8/g5DCnI5zu1eMKUr4gha\r\nJo62o3Ih5Iw3qVUN2VfGAnbpVonuIzVla4Z4lKmm175YeiH5gqrQW3fYKM8a\r\n+88pRkM/gFQ3HSL9wfOF9znbQnEoQK4yhqEeCuXJG3spcF61zzOK/sipLKot\r\n7Sl69UdJom8+HMxzL1nO4vHnP0cf4CSmq6kHqCvlfuTJQf1nrw9miNrrouFi\r\n9OU1dEHpmd+Wh5oKj8rV6Y1Rd7jdPoCMn0Yu7CD1IxYKqjWmxqcYMTn8ZiYW\r\nIYs11Z7C82c4q/AonPlhZeK2OdKmdq+E+38=\r\n=yLyX\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.3-beta.1_1651243899651_0.07065186430449155"},"_hasShrinkwrap":false},"2.0.5-beta.0":{"name":"@asemirsk/fclasses","version":"2.0.5-beta.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"9b047b3a72ac828e21a6e31cb9a8e77e5225f5c9","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.5-beta.0","_nodeVersion":"16.9.1","_npmVersion":"lerna/4.0.0/node@v16.9.1+x64 (linux)","dist":{"integrity":"sha512-aEB2cMByYr/W+p0Hc3J1B+RWOoE+cHtzTi27Msj29B15r9AKoPf0fYARk9c3aoDW+Lk1iNJpCwta+qqkmMD4xA==","shasum":"648c8407d2cc24bddd0795ad5d4ac5f183f948a6","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.5-beta.0.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCuJkX94Mn+z697AdAOkssCePYobBjUqUv1vIPKrnyCrAIhAPFMVOCgzYmXTuonF0tOlxcR74sIsK8AiQW5j33f+La+"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJia/8HACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqEEg//fIR9+KjDqktdrIROoIIuF5NgNi1GtbtBZ5J2bBUmDAvEEhfD\r\nQ/d1Stc/bbfiMp+KPp4iGcnfs91nqFT3YqNsQWHDNZMi2hPIuMD72S0pYtRJ\r\nAOEek2zjUlp4yatOulHmmVu15XNRsvv5ZD6QjUKHjcOAaVCrjX1Rjzp126Ma\r\nphtIfZZTF4mORSTr2lydvjEVLchsA/QY0CyYrGYNjO4rkhLQ6xxJ/t3c/7xx\r\new1hMfRUiqKyGIblgMYBYXlhCowcMD/53+FJyF4aMbvIXOF2iyNqEFRjIu3o\r\nPX85rAYqixmo0625TxIJd38f2oIx6c9RIG4vfR1jq/YfSx8OMYqLn2BbOW9G\r\nyZeeVHdsMr0sOmrzNdxw4Z1Xp0TSO7HlfWcYnm2Ukz7gbHxyq2X2lSdHi3yu\r\nu3j90Orz+HxR37CSxbCZ7AXfGTTj4uQUWbtM9UsoRiutbsrXnEr92EerdAvF\r\nvN+wLkKhcQleJ8Nm9gU4i4pJNFaMFzG9gMZxfnO2NLzdgickIy82aIO2//3W\r\nsjOoY0uR9Tr/jmxe/lYxsFduz9ktwhkoQbiPNTjKO5vTVDKbO5SmDpVxFGpL\r\nX7Aqr9X4X1zNxFDBXcUl8ejAqnNFkTACkR9BaLfzj7k66HfBRf455zvrHSsZ\r\nKdcXEOLT0mFqTUWYgwzfGaG50jrXnRxqqKw=\r\n=/Dg9\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.5-beta.0_1651244807551_0.4730672849854174"},"_hasShrinkwrap":false},"2.0.6-beta.0":{"name":"@asemirsk/fclasses","version":"2.0.6-beta.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"e98b014aabae41353460b67b25ad4d50f0133fca","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@2.0.6-beta.0","_nodeVersion":"16.9.1","_npmVersion":"lerna/4.0.0/node@v16.9.1+x64 (linux)","dist":{"integrity":"sha512-grOcK8PvXNAA5t+WpzySYfWftbv65V0zXSlgwK3T0sGfMN06kZQPRJxSZQj6TnNuswQb9uCo4sQCM9wRET1+Dg==","shasum":"cd2f68bd3c2bd3dba15febae94b0fd1dd85d6954","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-2.0.6-beta.0.tgz","fileCount":7,"unpackedSize":48645,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF6EoYoX5Oekvm8MbEtbjznGRgrlenanBufELLBmWDLjAiEApRIDWWCuudKJ29VejTvZtV97OD+KbM286Rsk46p7tFg="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJib62NACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoe7g/+PeAKYEuOR6gCmHECtJterHvKP+0HM/0gNWx89buWHaM16Dcl\r\n5qKYMzjUQEecFUZ68IndYIvmWmCp1NKYfRLPaLCo8zD/m+QAFWvweCY2L0Rn\r\n/IIwvePaCtv3M/5jafeBTSRh3KZONEpFy9b39/nnmo3onthZVCy0E2cXBQB0\r\nF5n2rjXZgwtxdA0Rb+K9FiYt65/M03oX3Ugtok3IE9kcBwAbCL8kGBYre8Op\r\nYFCqrZLILhmJzODPhLcT4oJ/d4G5oD6kW+/gHGnHfXwQwbPDWtgAs5LLvuUB\r\nzjFKP7B+LAtsxVDHwSFYTAbmhiGSnW+/Ue292zCBXSTB9LVMQuFV+M94zYjT\r\nukPYCmI117dZgWM3QmGmXh7kHWoIlbMkdvEzgkrwszn3pTkRa6CwoDjYsbAk\r\nru+7uJ5cO4FPgt1Yi9oZa/eP4H7eQniGiHXJ2A06v2jxK05qSl0XQYywb0PS\r\nMcrnL4cQYwv/gJgB41fIc/EaMZ6r0sEfebmEUzi0wN4ff1/ebGrGCV8Jq+av\r\nPZ9y+cT/8d78Ozan0Ik7m2AifKRr08Y1SE3tVcPAOv0kA4R28LPNaKQDvNFy\r\ni1F76/2G483S3tcN+TvFukOEmzWtcLFqF41FumV3Igd51SOg46uD902iV8R7\r\n5QsRLsDDDCRC7NFIkPOLHoLvdAClZ8iCc2k=\r\n=ViLQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_2.0.6-beta.0_1651486093262_0.05962935441558148"},"_hasShrinkwrap":false},"3.0.0":{"name":"@asemirsk/fclasses","version":"3.0.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"tsc --version && tsc -p ./tsconfig.json && npm run build:api-doc","build:watch":"npm run build -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","change":"change"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.6","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"6cf8b4df75f61c7e648a17bd5eafcd3965785c77","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@3.0.0","_nodeVersion":"16.9.1","_npmVersion":"lerna/4.0.0/node@v16.9.1+x64 (linux)","dist":{"integrity":"sha512-iLdoQ/dHFKhJWpSixLQaCJoYXBVZAfGpOKgZe+3W1lRE7JhTk/VLa8/NwkGE2HKv++fMBu35mv+OknVPgK1RUw==","shasum":"7f588bf1f6ec11b4da3cf554b3ebac050a92d797","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-3.0.0.tgz","fileCount":7,"unpackedSize":48638,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDGfJ0poL0FR/q072+zLVuAWCjK8C4JT92gnBpw5iaBWQIhAOjMHF6dF/ggL6yQMil1eRsMlh5HHb0sqU+74KOm015a"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJib7C2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrd8Q//ZA9A2YXEC1yxtkQwSINIex1qz5rwyAcayEoVdTLykM1POZz/\r\nPrRHJYytS+ykrpGcqXB2XPnrkVyNyPMFRAU1ipLR5v4bH1JeJD8ZuW4qhI9V\r\nvV7nk76J5/P5fN1yJzoSyw5/cjRgcQRKFFLObOUXnuTqdje+AwqHWycYH4ZN\r\n5eWZiz4bbAD2FF8dP1qrvcs/NiPNPeo/HAa6yadKti65MjT2cPUREt6NW+Yt\r\nkuYe2AZnCAJjOhWnQwAtdEBxhBiVBp5AH5Ok2SMAWFhEYksRQkRMiDU+WfEo\r\n4r8CoxvvvtxHmaKf5OQq6UFHjNIPho2qPfinIndSuwVj7zsZ+Ophyn2ZKChz\r\nnPnpbafQ24G++hMjGSjeOFqAtyW8M/Q/dhgdTWXDc7zbQ1Zd+9JAP9PcCIe7\r\nfE+UN95D+eLgYe3sn4VgFgJEFFtO1rR6idEjpLatT19duid1IF5/i/ribTUx\r\neVtghIX7KSfby7LTERQ6MZ8jswPTbcuD0O1xSR7fj4Xl6qKjtyT4dYKSbNSW\r\nVnGQzOx42ThT1JoE7IZbJgrd7HnVJNyjl5oWECex4tIV2dY5RcZCoOXHOhWS\r\nwTLeaYNjfnsVt70g8O1yddMJbzHXpX4UooJo0eAwIw/HiawINLfQxDVZBl8J\r\nz81cArX3tFYMsW36ipX5xQYN191L2zUEdu0=\r\n=OFUR\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_3.0.0_1651486902723_0.669743645149093"},"_hasShrinkwrap":false},"1.0.0-beta.16":{"name":"@asemirsk/fclasses","version":"1.0.0-beta.16","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"npm run build:lib && npm run build:api-doc","build:lib":"tsc --version && tsc -p ./tsconfig.json","build:watch":"npm run build:lib -- --watch","build:api-doc":"typedoc --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\"","test":"npm -v"},"dependencies":{"@asemirsk/cli":"^1.0.0-beta.15","babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"gitHead":"0ff46789373c0ccb710fa463d6cbd035aeb8eb1f","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-emerald-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-emerald-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-emerald-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-beta.16","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-LUyHgsb2mmZ0Xtvbv6S3Tx802UX3U/VQWqFYahGwNXh4mzEHSgtK6yuxZ5E6bpNziPoCFQJcemnCUyRCT0s4oA==","shasum":"7ccc042df78789e0c6551f91f812c3f00cacf4fb","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-beta.16.tgz","fileCount":7,"unpackedSize":48697,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCxDvL0bUuCldZb8YtZgp6eaz4TdbbZ+6da/8HJoRpLawIhAPMfX89RjcahibmRG2vwPrNRgfNrl6L10u0l0QcY6s7N"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJidOeYACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmro9A//TSnKX7QwJgZORqOXG2yozAjFZO7I3dp50t2JXR5uX9wwWivH\r\ntP3e9/OjLZtC8WrWcI+AwVb+QUKIgBqf1o4AKf6NGlNMYupJ8gTgB2BFRuFL\r\ngIny+QvGFxiW/qsqoihHMpdeWfQJPRKmVIHeYXT30gW5GGRHAmMC5CrgG4Dc\r\nZu4UpQ9unXPhcV/T0zgDq0uaGbdfQPv9hfPV7Jc8gGH/Ex8bTRaRIxnLI813\r\nL/GYRRsrfEPpWSrft6jXOf3osyOZGH+6Ccqffc6YlI9CmMS76zQJmjrP9VKi\r\nzZHp403PIqOaA4jEhxJR9fo299U0Uy0JkRypixXY4oM3tAJgPdbAocMDlsoS\r\nC9iedP4Kxthp0vPVR5VHaXgKPM4+LrhvZoI2Ue1aQyZ+ZNTMDJPtqolBig3a\r\nmZR4rN1V3CQFS+CRh4i3OsNUOOStoYYvtwSu+VugqmR3+iFyIiIkONUNK2TI\r\nMUpEgmnheAYE9dL2253JovBV3XSRCAVFFJg1J94MALwbmgZOV891yWayWMtB\r\nFuTTswZcsBcE3iVqqUVgwyAH72AYgIGsvSteFKUbEqyz4PodZaOwTQALjEOa\r\nlJo3GBknCNS8DjElr9c/srAI+MAoh6c5PpmfhHcpbof4uluHLvUl3PT7xY2+\r\nZvcCil0c+nI9nx69sCde+SpwaCZf9u/T6k8=\r\n=soIK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-beta.16_1651828631987_0.05804226962025982"},"_hasShrinkwrap":false},"1.0.0-canary-24-22.0":{"name":"@asemirsk/fclasses","version":"1.0.0-canary-24-22.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"npm run build:lib && npm run build:api-doc","build:lib":"tsc --version && tsc -p ./tsconfig.json","build:watch":"npm run build:lib -- --watch","build:api-doc":"typedoc --options ../../typedoc.js --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"devDependencies":{"@types/tailwindcss":"^3.0.10"},"gitHead":"a48e91c77704024ccd08e24d4f85d1cd6971ccb1","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-emerald-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-emerald-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-emerald-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@bodiless/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@bodiless/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-canary-24-22.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-5auYLQgaKQDkvlXpMt94i72Pn+gilvwZg7iZqcEGjZLb70FmyOnQlUt1+MKUh6SLXgCnNskQykjkDkamCSVYUw==","shasum":"1734b8cce7e5a275408def422399af93d9a413f0","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-canary-24-22.0.tgz","fileCount":7,"unpackedSize":48742,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCSvSt8f7JdvIiLFR2NgwhXNuekJLIxBxuEgsz0hY4skQIhAMx+Zmk4Ox+i412+qLUmoXEM9zz3Ll6u2rJj7TGNt611"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJijezcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpAZw/9FoRh9VCpdVwYuNNroXdNQzjl4pe4k0XstBPlmuqPt/pqMTbs\r\nuui7Had3gUrhId7NnzlZ5DVxN3CnREeOylraEzOwhMcbsIC69U+JGuc3iIVC\r\n0HOgjOMznVIOrImJzhEisNhfVWeaOyA43fK11MmllbHXqPiiLGUbKXKyFRCN\r\nvvsXDoKf9mJ7yn30RigdVQwnGx0a47wz5xapsVYmWCsQit/UZWkbz3KOf66u\r\nI0YJ8m+boMVDFunGWyi4aazViUnpumCCJ8xovviaGHIzj3B0PEL62GoLhdja\r\nxa2gkXa/w+zsPlruv1gnT3BdULb7olyRBBt5ZFazaI1LaCTfKxiEf3e6PxnL\r\nCd6T2rukrB43icPmGMw96egPpwh33efgVXHVce12RqXYPPMPwDLy89WkZsak\r\n6oqSGb90NyH6KZYzPZvOT2xYwzi3+FHbNqkcwClh+Z4kmZtTJuLZ1iYAUuLS\r\nFbpWY7PuN1w5oFzjn/DDpwJPKrdBCqTbD8HyBB/0niP391X+umD9r12bNwTO\r\nFCbdEMXbcDMOZc8abJqHhIy+xq31fvXWm5HaP7f80wakzAd+ezYCrlnljXO9\r\nN0JSPobqNxDR8PxdvqsVzpO24WxPQETdV7IiIxSGAiaDq0ENz3kYRKTOAHzq\r\nyG/zq5WVGZY97Xg1yvdnqcDwfrkj1IGCizc=\r\n=GOKV\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-canary-24-22.0_1653468380602_0.21091852816895318"},"_hasShrinkwrap":false},"1.0.0-canary-24-23.0":{"name":"@asemirsk/fclasses","version":"1.0.0-canary-24-23.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"npm run build:lib && npm run build:api-doc","build:lib":"tsc --version && tsc -p ./tsconfig.json","build:watch":"npm run build:lib -- --watch","build:api-doc":"typedoc --options ../../typedoc.js --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"devDependencies":{"@types/tailwindcss":"^3.0.10"},"gitHead":"2cab1eaf4ac4d1a8ef3ef53ba3228ff16f7504eb","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-emerald-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-emerald-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-emerald-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@asemirsk/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@asemirsk/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-canary-24-23.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-+hlyZZjyK/FlEzpXQS9Ge+4gvv2aF+CJA2mnMivFKLhfKlVQoo5CK7X14CXZ75D0zuZOttzLuCgZUV60QhF3vg==","shasum":"fb3b9accb18ed6472cd4132622f8fb663cd45148","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-canary-24-23.0.tgz","fileCount":90,"unpackedSize":381280,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID/syQAveQPOfiSUr1m3gNsfNPKTdjs5l5dCfBhXBqXeAiEAiYcqGSwmHXeOkrm5wAR63pORuTbLMF41BXazbLK2dMM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJijfHqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqpow//bsbR86YA0AxJ5cdlkQiPPAJCyiXkAfkL4y/VhI/E69k3zxy8\r\n1dDAEi+1a874LOoOWgbxdWUFgddZ9Ga7+sCKwMV8oSgnyXJoLRkMPVFAr3aR\r\nF+IIrst8u+rKLdflJg68hDSfAY2Mp14Xy7tyGWTEQ7+wSDcEK8hTk7Bi3/MN\r\niHwh8cfWeG6cDsV7DkODwfDYtHeIv8wOF38VEd83PNBttEhzXH3itQMyFbMt\r\nj4A/pEpxbdFFU/UtO8oCRXyUVLk97b0CDyKq/WntKSwfWd1Kca44IgfgGIcP\r\nZ7naxnaVpvayBb0PrIK+ZrSmHsupHflohY2PFK14oL9+VAf13n9BE+mmN/Vx\r\ng3z5+EsUUeC7aZcLDHJ5fWF5UfhYMgO1gY4Bk/xg+TAfDNF8kRdsakJaj2GU\r\nBuf3udE5KhR0ysSWnn8jcjSECzuDSYHMYVOwZsXiamcoSRnf5cAp9Dg6OIyg\r\npxic4eF+rZJ2BNK51PnmrAcjLHVDgmRmG3t2ZSxL/BPdt7QyGewF6TgWO/RV\r\nlJn1QNCr5wYHrXMZkuX2X7yvol0HQSP3ZOdfPWlRRTc0TdSG6FRu3q+6M/5u\r\nbW9R+3eb6k3lG78q217c7jDRwsWE6RcwFpDD9hnrvPJ8Ed20f1ZegUyA0hnD\r\n85zc2QCvTNzv0c5Alw3YzeCBsDXkWsJA4lM=\r\n=LoPP\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-canary-24-23.0_1653469673805_0.3914378885128007"},"_hasShrinkwrap":false},"1.0.0-canary-24-24.0":{"name":"@asemirsk/fclasses","version":"1.0.0-canary-24-24.0","description":"Allows for the injection of functional class into components.","author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","license":"Apache-2.0","main":"lib/index.js","sideEffects":false,"typings":"lib/index.d.ts","directories":{"lib":"lib","test":"__tests__"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"scripts":{"build":"npm run build:lib && npm run build:api-doc","build:lib":"tsc --version && tsc -p ./tsconfig.json","build:watch":"npm run build:lib -- --watch","build:api-doc":"typedoc --options ../../typedoc.js --out doc/api src","clean":"rimraf \"lib/*\" && rimraf tsconfig.tsbuildinfo && rimraf \"doc/api\""},"dependencies":{"babel-plugin-preval":"5.0.0","lodash":"^4.17.19","uuid":"^3.3.2"},"peerDependencies":{"react":"^17.0.2"},"devDependencies":{"@types/tailwindcss":"^3.0.10"},"gitHead":"af2c8ace172b3dc3a1f237c51eb55be1e21978bb","readme":"# FClasses Design API\n\n## Introduction\n\nThe Bodiless FClasses Design API is designed to facilitate the implementation of\na *Design System* in a React application. Before diving into the technical\ndetails below, it might make sense to read our\n[high level overview of Design Systems in Bodiless](../../Design/DesignSystem) to\nbetter understand the general patterns at work.\n\nAt a high level, this API expresses *Design Tokens* as React higher-order\ncomponents, and provides utilities which allow you to apply them to both simple\nelements and compound components. In most cases, the design token HOC's leverage\n\"atomic\" or \"functional\" CSS, defining units of design as collections of utility\nclasses.\n\nA compound component using this API will expose a styling API (a `design` prop) which\ndescribes the UI elements of which it is composed. Consumers then supply a\nlist of higher-order components which should be applied to each element to modify\nits appearence or behavior. The framework allows nested wrapping of components\nto selectively extend or override individual elements. It also provides a tool\nfor adding and removing classes to/from individual elements.\n\nUse of this API allows composed components to expose a\nstyling API which remains consistent even when the internal markup of the\ncomponent changes. Consumers of those components can then sustainably extend and\nre-extend their look and feel, with less danger of breakage when the underlying\ncomponent changes.\n\n## Tokens\n\nIn Bodiless, you implement design tokens as React higher-order components (HOC).\nApplying the HOC to a component is equivalent to styling that component with a\ntoken:\n\n```js\nconst ComponentWithStyles = withMyStyles(Component);\n```\n\nThis pattern should be familiar to those who have worked with CSS-in-JS\nlibraries like [Styled Components](https://styled-components.com/) or\n[Emotion](https://emotion.sh/docs/introduction).\n\nAny HOC can be used as a token, and tokens can be composed using normal\nfunctional programming paradigms (eg Lodash flow):\n```js\nconst withComposedToken = flow(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, Bodiless provides a token composition utility which adds some\nadditional functionality:\n\n- The ability to attach metadata to a token.\n- The ability to selectively remove tokens from a composition based on\n  their metadata (or other criteria).\n- Better type inference of the resulting component.\n\nThis is intended to promote design-system thinking when defining\ntokens, by encouraging us to think about the structure and organization\nof tokens as we implement them.  It also facilitates implementation of\ntools which allow browsing the design system (eg StorybooK), and eases\nthe process of extending or customizing composed tokens without fully\nrecomposing them.\n\nIn general, you can use `flowHoc` to compose tokens the same way you\nwould use Lodash flow, eg:\n\n```js\nconst withComposedToken = flowHoc(\n  withToken1,\n  withToken2,\n);\n```\n\nHowever, there are a few key differences:\n\n- Metadata (static properties) attached to a component are prppagated through\n  the chain of HOC's.\n- If you are using Typescript, the type of the parameters is constrained to be an\n  HOC (or an object specifying metadata, see below).\n- There is an optional overload to accept a \"TokenMeta\" object which consists of\n  metadata which should be attached to the token.\n- We intruduce a special kind of Token known as a \"Filter\". See more\n  below.\n\n### Metadata and Filters\n\nToken metadata are properties which can be attached to tokens to help\norganize them and understand their structure. When a token is applied,\nits metadata will also be attached to the component to which it is applied.\nIf a composed token is applied, metadata from all constituents will be\naggregated and attached to the target component. See below for some examples.\n\nIn addition to a normal HOC, a Token can also be a \"filter\". A filter is a token\nwhich, when composed with other tokens, *removes* any which match certain\ncriteria. Filters are usually defined to test the metadata attached to other\ntokens. So, for exmple, you can compose a token which removes all 'Color' tokens\nand adds a new one.\n\n> Note that while metadata from all constituent tokens are aggregated and attached\n> to the component to which a composed token is applied, the composed token\n> itself does not have the metadata of its constituents; if it did, it would be\n> much harder to filter. Think of the metadata attached to a Token as that portion\n> of the final metadata which it will contribute.\n>\n> It's easy enough to get the aggregated metadata, eg:\n> ```\n> const finalMeta = pick(myToken(Fragment), 'categories', 'title', ...);\n> ```\n\n### Examples\n\nGiven\n\n```js\nconst asBold = flowHoc(\n  addClasses('font-bold'),\n  { categories: { Style: ['Bold'] } },\n);\n\nconst asTextBlue = flowHoc(\n  addClasses('text-blue-500'),\n  { categories: { TextColor: ['Blue'] } },\n);\n\nconst asTextRed = flowHoc(\n  addClasses('text-red-500'),\n  { categories: { TextColor: ['Red'] } },\n);\n// Same as:\n// const asTextRed = flowHoc(addClasses('text-red-500'));\n// asTextRed.meta = { categories: { TextColor: ['Red'] } };\n\nconst asBgYellow = flowHoc(\n  addClasses('bg-yellow-500'),\n  { categories: { BgColor: ['Yellow'] } },\n)\n\nconst asHeader1 = flowHoc(\n  asTextBlue,\n  asBold,\n  asBgYellow,\n  { categories: { Header: ['H1'] } },\n);\n\nconst Header1 = asHeader1(H1);  // `H1` is a version of 'h1' stylable with fclasses, see below.\n```\n\nThen\n\n```js\n\n<Header1 /> === <h1 className=\"text-blue bg-yellow-500 font-bold\" />\n\n// The component itself includes aggregated metadata from all composed tokens...\nHeader1.categories === {\n  TextColor: ['Blue'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n\n// ... but the token itself does not.\nasHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  }\n}\n```\n\nAnd given\n\n```js\nconst asRedHeader1 = flowHoc(\n  asHeader1,\n  asHeader1.meta, // We are creating a variant of asHeader1, so propagate its meta.\n  // The following creates a \"filter\" token. Note this must be applied after asHeader1\n  withTokenFilter(t => !t.meta.categories.includes('TextColor')),\n  // Replace the color with red.  Note this must be applied after the filter.\n  asTextRed,\n);\n\nconst RedHeader1 = asRedHeader1(H1);\n```\n\nthen\n\n```jsx\n<RedHeader1 /> === <h1 className=\"font-bold text-red-500 bg-yellow-500\" />\n\n// Our new token has the metadata of `asHeader1` only because we propagated it explicitly.\nasRedHeader1.meta === {\n  categories: {\n    Header: ['H1'],\n  },\n};\n\nRedHeader1.categories === {\n  TextColor: ['Red'],\n  BgColor: ['Yellow'],\n  TextStyle: ['Bold'],\n  Header: ['H1'],\n};\n```\n\n> **Order is important**\n>\n> As you can see from the examples above, the order in\n> which you compose tokens can be significant, especially when applying filters.\n> `flowHoc` composes tokens in left-to-right order (Lodash `flow` as opposed to\n> `flowRight`).\n\n## Styling Elements with FClasses\n\n### Functional CSS\n\nThis library was developed to support a styling paradigm known as \"atomic\" or\n\"functional\" CSS.  There are many excellent web resources describing the goals\nand methodology of this pattern, but in its most basic form, it uses simple,\nsingle-purpose utility classes in lieu of complex CSS selectors. Thus, for example,\ninstead of\n\n```html\n<div class=\"my-wrapper\">Foo</div>\n```\n\n```css\n.my-wrapper {\n  background-color: blue;\n  color: white;\n}\n```\n\nthe functional css paradigm favors\n\n```html\n<div class=\"bg-blue text-white\">Foo</div>\n```\n\n```css\n.bg-blue {\n  background-color: blue;\n}\n.text-white {\n  color: white;\n}\n```\n\nUsually, a framework is used to generate the utility classes programmatically.\n[Tachyons](https://tachyons.io/) and [Tailwind](https://tailwindcss.com/) are\ntwo such frameworks. All the examples below use classes generated by Tailwind.\n\n\n\n## FClasses\n\nThe `FClasses` API in this library provides higher-order components which can be\nused to add and remove classes from an element. They allow a single element\nstyled using functional utilty classes to be fully or partially restyled --\nprserving some of its styles while adding or removing others. For example:\n\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst Callout = addClasses('bg-blue text-white p-2 border border-yellow')(Div);\nconst SpecialGreenCallout = flow(\n  addClasses('bg-green'),\n  removeClasses('bg-blue'),\n)(Callout);\n```\n\nThe higher order components are reusable, so for example:\n\n```\nconst withRedCalloutBorder = flow(\n  addClasses('border-red'),\n  removeClasses('border-yellow),\n);\nconst RedBorderedCallout = withRedCalloutBorder(Callout);\nconst ChristmasCallout = withRedCalloutBorder(SpecialGreenCallout);\n```\n\nand they can be composed using standard functional programming techniques:\n\n```javascript\nconst ChristmasCallout = flowRight(\n  withRedCalloutBorder,\n  asSpecialGreenCallout,\n  asCallout,\n)('div');\n```\n\n### Some important things to remember about FClasses.\n\n#### Always use `stylable()`\n\nIn order to use `addClasses()` or `removeClasses()`, the target component must\nfirst be made stylable. That is:\n```javascript\nconst BlueDiv = addClasses('bg-blue')('div');\n```\nwill not work (and will raise a type error if using Typescript).  Instead, you must write:\n```javascript\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst BlueDiv = addClasses('bg-blue')(Div);\n```\nor, if you prefer:\n```\nconst BlueDiv = flowRight(\n  addClasses('bg-blue'),\n  stylable,\n)('div');\n```\n\n#### Explicitly type `stylable()` when applied to intrinsic elements.\n\nWhen using typescript in the above examples, we must explicitly\nspecify the type of our stylable `Div` because it cannot be inferred from the\nintrinsic element `'div'`.\n\n#### Don't add classes directly.\n\n`removeClasses()` can only remove classes which were originally added by\n`addClasses()`. Thus, for example:\n```javascript\nconst BlueDiv = ({ className, ...rest }) => <div className={`${classname} bg-blue`} {...rest} />;\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\nwill *not* work, because the `bg-blue` class is hidden inside `BlueDiv` and not\naccessible to the `removeClasses()` HOC. Instead, use:\n```\nconst BlueDiv = addClasses('bg-blue')(Stylable('div'));\nconst GreenDiv = removeClasses('bg-blue').addClasses('bg-green')(BlueDiv);\n```\n\n#### Use `removeClasses()` with no arguments to remove all classes\n```\nconst Button: FC<HTMLProps<HTMLButtonElement>> = props => <button onClick={specialClickHandler} type=\"button\" {...props} />;\nconst StylableButton = stylable(Button);\nconst OceanButton = withClasses('text-green bg-blue italic')(StylableButton);\nconst DesertButton = withoutClasses().withClasses('text-yellow bg-red bold')(OceanButton);\n```\nThis is useful when you don't have access to the original, unstyled variant of the component.\n\n\n## The Design API\n\nThe Design API provides a mechanism for applying higher order components (including those\nprovided by the FClasses API) to individual elements within a compound component.\n\n### Exposing the Design API\n\nConsider the following component:\n```javascript\nconst Card: FC<{}> = () => {\n  return (\n    <div className=\"wrapper\">\n      <h2 className=\"title\">This is the title</h2>\n      <div className=\"body\">This is the body</h2>\n      <a href=\"http://foo.com\" className=\"cta\">This is the CTA</a>\n    </div>\n  );\n)\n```\n\nWith the Design API, rather than providing classes which a consumer can style\nusing CSS, we provide a way for consumers to replace or modify the individual\ncomponents of which the Card is composed:\n\n```ts\nexport type CardComponents = {\n  Wrapper: ComponentType<StylableProps>,\n  ImageWrapper: ComponentType<StylableProps>,\n  ImageLink: ComponentType<StylableProps>,\n  Image: ComponentType<StylableProps>,\n  ContentWrapper: ComponentType<StylableProps>,\n  Title: ComponentType<StylableProps>,\n  Body: ComponentType<StylableProps>,\n  Link: ComponentType<StylableProps>,\n};\n\ntype Props = DesignableComponentsProps<CardComponents> & { };\n\nconst CardBase: FC<Props> = ({ components }) => {\n  const {\n    Wrapper,\n    ImageWrapper,\n    Image,\n    ImageLink,\n    ContentWrapper,\n    Title,\n    Body,\n    Link,\n  } = components;\n\n  return (\n    <Wrapper>\n      <ImageWrapper>\n        <ImageLink>\n          <Image />\n        </ImageLink>\n      </ImageWrapper>\n      <ContentWrapper>\n        <Title />\n        <Body />\n        <Link />\n      </ContentWrapper>\n    </Wrapper>\n  );\n};\n```\n\nHere we have defined a type of the components that we need, a starting point for\nthose components and then we have create a componant that accepts those\ncompoents. Next we will combine the Start point as well as the CardBase to make\na designable card that can take a Design prop.\n\n``` js\nconst cardComponents: CardComponents = {\n  Wrapper: Div,\n  ImageWrapper: Div,\n  ImageLink: A,\n  Image: Img,\n  ContentWrapper: Div,\n  Title: H2,\n  Body: Div,\n  Link: A,\n};\nconst CardDesignable = designable(cardComponents, 'Card')(CardBase);\n```\n\n### Design Key Annotations\n\nNote the second parameter to `designable` above; it is a label which will be used\nto identify the component and its design keys is in the markup.  This can make\nit easier to locate the specific design element to which styles should be\napplied, for example:\n\n```\n<div bl-design-key=\"Card:Wrapper\">\n  <div bl-design-key=\"Card:ImageWrapper\">\n  ...\n```\n\nGeneration of these attributes is disabled by default.  To enable it, wrap the section\nof code for which you want the attributes generated in the `withShowDesignKeys` HOC:\n\n```js\nconst CardWithDesignKeys = withShowDesignKeys()(CardDesignable);\n```\n\nor, to turn it on for a whole page, but only when not in production mode,\n\n```js\nconst PageWithDesignKeys = withDesignKeys(process.env.NODE_ENV !== 'production')(Fragment);\n<PageWithDesignKeys>\n  ...\n</PageWithDesignKeys>\n```\n\n## Consuming the Design API\n\nA consumer can now style our Card by employing the `withDesign()` API method to\npass a `Design` object as a prop value. This is simply a set of higher-order\ncomponents which will be applied to each element. For example:\n\n```js\nconst asBasicCard = withDesign({\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n});\n\nconst BasicCard = asBasicCard(Card);\n```\n\nIn ths example, we could simply have provided our design directly as a prop:\n\n```js\nconst BasicCard: FC = () => <Card design={{\n  Wrapper: addClasses('font-sans'),\n  Title: addClasses('text-sm text-green'),\n  Body: addClasses('my-10'),\n  Cta: addClasses('block w-full bg-blue text-yellow py-1'),\n}} />\n```\n\nHowever, by using `withDesign()` instead, our component itself will expose its own\ndesign prop, allowing other consumers to further extend it:\n\n```javascript\nconst asPinkCard = withDesign({\n  Cta: addClasses('bg-pink').removeClasses('bg-blue'),\n});\nconst PinkCard = asPinkCard(BasicCard);\n```\n\nIn these examples, we are *extending* the default components. If we wanted\ninstead to *replace* one, we could write our HOC to ignore its argument\n(or use the provided shortcut HOC `replaceWith()`):\n\n```ts\nconst StylableH2 = stylable<JSX.IntrinsicElements['h2']>('h2');\nconst StandardH2 = addClasses('text-xl text-blue')(StylableH2);\n\nconst StandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n})(BasicCard);\n```\n\nWe can also use the `startWith()` HOC, instead of replacing the whole component,\nit will only replace the base component but still use any hoc that might have\nwrapped it.\n\nAs with FClasses, HOC's created via `withDesign()` are themselves reusable, so\nwe can write:\n\n``` js\nconst asStandardCard = withDesign({\n  Title: replaceWith(StandardH2), // same as () => StandardH2\n});\nconst StandardCard = asStandardCard(Card);\nconst StandardPinkCard = asStandardCard(PinkCard);\nconst StandardRedCard = asStandardCard(RedCard);\n```\n\nAnd, also as with FClasses, the HOC's can be composed:\n\n``` js\nconst StandardPinkAndGreenCard = flowRight(\n  withGreenCtaText,\n  asStandardCard,\n  asPinkCard,\n)(BasicCard);\n```\n\n## Conditional Tokens\n\nIt is sometimes useful to apply classes conditionally, based on props passed to\na component and/or some enclosing state. The FClasses design API includes\nsome helper methods which make this easier.\n\n### Conditional styling based on passed props\n\nImagine we have a button which has different variants depending on whether it is\nactive and/or whether it is the first in a list of buttons. We can use the\n`addClassesIf()`, `removeClassesIf()`, `withoutProps()` and `hasProp()` helpers\nto accomplish this:\n\n``` js\ntype VariantProps = {\n  isActive?: boolean,\n  isFirst?: boolean,\n  isEnabled?: boolean,\n};\n\nconst Div = stylable<HTMLProps<HTMLDivElement>>('div');\nconst isActive = (props: any) => hasProp('isActive')(props);\nconst isFirst = (props: any) => hasProp('isFirst')(props);\n\nconst ContextMenuButton = flowHoc(\n  withoutProps<VariantProps>(['isActive', 'isFirst'),\n  addClasses('cursor-pointer pl-2 text-gray'),\n  addClassesIf(isActive)('text-white'),\n  removeClassesIf(isActive)('text-gray'),\n  removeClassesIf(isFirst)('pl-2'),\n)(Div);\n```\n> Note: Our innermost HOC is `withoutProps()`. This guarantees that the props used to\n> control styling won't be passed to the `div` element. We must explicitly type\n> the generic `withoutProps()`. This ensures that the type of the resulting\n> component will include these props.\n\n### Conditional styling based on context\n\nImagine we have a button which consume some state from a react context. We can\nuse `addClassesIf` and `removeClassesIf` helpers to add classes to the button\nconditionally:\n\n```js\nconst ToggleContext = React.createContext({\n  state: false,\n  toggleState: () => undefined,\n});\n\nconst useIsToggled = () => React.useContext(ToggleContext).state;\nconst useToggle = () => React.useContext(ToggleContext).toggleState;\n\nconst ToggleContextProvider: FC = ({ children }) => {\n  const [state, setState] = React.useState(false);\n  const value = {\n    state,\n    toggleState: React.useCallback(() => setState(s => !s), []),\n  };\n  return (\n    <ToggleContext.Provider value={value}>\n      {children}\n    </ToggleContext.Provider>\n  );\n};\n\nconst Toggle = ({ children, ...rest }) => <Button {...rest} onClick={useToggle()}>{children || 'Click Me'}</Button>;\n\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nHere we pass a custom hook (`useIsToggled`) to `addClassesIf`. This hook consumes\nthe toggle state from the context, and applies the classes only if toggled on.\n\n### Modifying props conditionally\n\nYou can use the similar `addPropsIf` hoc to add props as well as styles to a\ncomponent conditioonally:\n\n```js\nconst StyledToggle = flowHoc(\n  addClassesIf(useIsToggled)('bg-emerald-200'),\n  addPropsIf(useIsToggled)({ children: 'On' }),\n  addPropsIf(() => !useIsToggled())({ children: 'Off' }),\n);\n```\n  \n### Flow Toggles\n\nA more general version of the above pattern is provided by th `flowIf` utility.\nThis takes a condition hoo (like `addClassesIf`) and returns a version of\n`flowHoc` which applies only if the condition evaluates to true. The above\nexample could be rewritten using a flow toggle as:\n```js\nconst StyledToggle = flowHoc(\n  flowIf(useIsToggled)(\n    addClasses('bg-emerald-200'),\n    addProps({ children: 'On' }),\n  ),\n  flowIf(() => !useIsToggled)(\n    addProps({ children: 'Off' }),\n  ),\n)(Toggle);\n```\nThis is more powerful than `addClassesIf` since you can pass any collection of\ntokens to the function returned by `flowIf`. For example, we could use it\nto replace the component entirely:\n```js\nconst ReplacedToggle = flowIf(useIsToggled)(\n  replaceWith(SomeOtherComponent),\n)(Toggle);\n```\nNote howeer that unlike `addClassesIf` and `addPropsIf`, \nthis will cause the enhanced component to be recreated (and\nthus lose state) whenever the condition changes. For example, imagine\nour base Toggle kept a counter:\n\n```js\nconst Toggle = ({ children, ...rest }) => {\n  const [count, setCount] = React.useState(1);\n  const toggle = useToggle();\n  const onClick = React.useCallback(() => {\n    setCount(c => c + 1);\n    toggle();\n  }, [toggle]);\n  return <Button {...rest} onClick={onClick}>Count is {count}</Button>;\n}\n```\nNow compare\n```js\nconst StyledToggle = flowIf(useIsToggled)(addClasses('bg-emerald-200'))(Toggle);\n```\nwith\n```js\nconst StyledToggle = addClassesIf(useIsToggled)('bg-emerald-200')(Toggle);\n```\nThe first will lose the counter state every time the button is clicked, while\nthe second will properly retain it.\n\n#### Reusable flow toggles.\n\nFor convenience, Bodiless packages often export a reusable flow toggle which\nencapsulates its condition. One example is the `ifEditable` flow toggle\nexported by `@asemirsk/core`, which allows you to apply tokens only when\nin edit mode.\n\n## Design Variants\n\nOne of the most powerful features of the Design API is the ability to create\nmultiple variants of a component by composing different tokens onto it. These\nvariants can then be fed to component selectors like the\n[Flow Container](../../Components/FlowContainer/) or\n[Chameleon](../../Components/Chameleon)) to provide a content editor with a\nrange of options.\n\nSuch component selectors themselves accept a \"fluid\" or 'flexibe\" design; that\nis, a design which can accept any number of arbitrary keys, rather than one with\na fixed set of keys corresponding to fixed \"slots\" in the designable component.\nEach key in this flexible design represents one variant.\n\nYou can use th `varyDesigns` helper to simplify the process of creating a large\nnumber of variants. `varyDesigns` accepts any number of designs, and produces a\nnew design created by composing the keys of each design with each key of the\nother designs (essentially a matrix multiplication). It's easiest to explain\nwith an example:\n\n```js\nimport { varyDesigns } from '@asemirsk/fclasses';\nconst base = {\n  Box: flowHoc(startWith(Div), asBox),\n};\n\nconst borders = {\n  Rounded: asRounded,\n  Square: asSquare,\n};\n\nconst bgColors = {\n  Orange: asOrange,\n  Blue: asBlue,\n  Teal: asTeal,\n};\n\nconst variations = varyDesigns(\n  base,\n  borders,\n  bgColors,\n);\n```\nHere we first define a base design, which contains the tokens to be shared among\nall variants. Then we create a separate design for each dimension of variation.\nFinally, we combine them to produce our set of variations, which in this case\nwill be:\n```js\n{\n  BoxRoundedOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxRoundedBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxRoundedRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n  BoxSquareOrange: flowHoc(startWith(Box), asBox, asRounded, asOrange),\n  BoxSquareBlue: flowHoc(startWith(Box), asBox, asRounded, asBlue),\n  BoxSquareRed: flowHoc(startWith(Box), asBox, asRounded, asRed),\n}\n```\n\nIn some cases, you may want to restrict the options.  For example, if we\nintroduce border color into the mix, we may not want to allow certain\ncombinations of backgrounds and borders. This can be done by creating\nan intermediate design with the exact variations we want:\n```js\nimport pick from 'lodash/pick';\n\nconst borderColors = {\n  Blue: withBlueBorder,\n  Teal: withTealBorder,\n};\n\nconst colors = {\n  ...varyDesigns(\n    pick(bgColors, 'Orange'),\n    borderColors,\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Blue'),\n    pick(borderColors, 'Teal'),\n  ),\n  ...varyDesigns(\n    pick(bgColors, 'Teal'),\n    pick(borderColors, 'Blue'),\n  ),\n};\n```\nThis will produce\n```js\n{\n  OrangeBlue: flowHoc(asOrange, withBlueBorder),\n  OrangeTeal: flowHoc(asOrange, withTealBorder),\n  BlueTeal: flowHoc(asBlue, withTealBorder),\n  TealBlue: flowHoc(asTeal, withBlueBorder),\n}\n```\nwhich can then be composed with our border styles to produce the final\nset of variations:\n```js\nconst variations = varyDesigns<any>(\n  base,\n  borders,\n  colors,\n);\n```\nwhich produces\n```js\n{\n  BoxRoundedOrangeBlue: flowHoc(startWith(Box), asBox, asRounded, asOrange, withBlueBackground),\n  BoxRoundedOrangeTeal: flowHoc(startWith(Box), asBox, asRounded, asOrange, withTealBackground),\n  BoxRoundedBlueTeal: flowHoc(startWith(Box), asBox, asRounded, asBlue, withTealBackground),\n  BoxRoundedTealBlue: flowHoc(startWith(Box), asBox, asRounded, asTeal, withBlueBackground),\n  BoxSquareOrangeBlue: flowHoc(startWith(Box), asBox, asSquare, asOrange, withBlueBackground),\n  BoxSquareOrangeTeal: flowHoc(startWith(Box), asBox, asSquare , asOrange, withTealBackground),\n  BoxSquareBlueTeal: flowHoc(startWith(Box), asBox,  asSquare, asBlue, withTealBackground),\n  BoxSquareTealBlue: flowHoc(startWith(Box), asBox, asSquare, asTeal, withBlueBackground),\n}\n```\nNote in all the above examples, the design keys produced by `varyDesign` are\nconstructed simply by concatenating the keys of all the keys which are composed\nin each.\n\nNote also that all the tokens composed above could *themselves* be designs which\napply to on the base component which is being varied. For example, if\ninstead of\n```js\nconst base = flowHoc(startWith(Div), asBox);\n```\nwe had\n```js\nconst base = flowHoc(startWith(SomeDesignableComponentWithAWrapper), ...);\n```\nThen our individual style tokens might look like this:\n```js\nconst asOrange = withDesign({\n  Wrapper: addClasses('bg-orange'),\n});\n```\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"_id":"@asemirsk/fclasses@1.0.0-canary-24-24.0","_nodeVersion":"16.13.2","_npmVersion":"lerna/4.0.0/node@v16.13.2+x64 (linux)","dist":{"integrity":"sha512-pDKjty8hLoRb7e6BqI/cN7+XR3uaMcj1lioe/AamgNwRZRWb6BCDo3PjGOPNTbWZEF6EbA5aztV2Qvh0krq7Lg==","shasum":"73239c4104286c0a977785b2d0a8097acfa344f2","tarball":"https://registry.npmjs.org/@asemirsk/fclasses/-/fclasses-1.0.0-canary-24-24.0.tgz","fileCount":90,"unpackedSize":381280,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAys2+t29fuLM9olebXBpJleglkj/zRYGwA1bbelayOJAiAVLpQhZUs0mgR6wbBrBoXulN497O8cadV/GmaOPwU9pA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJijfQ+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqGFhAAnP0gr7HDh2D1ynTy8KLzA2i/rqLO1AuwyPuMFP6dtiCaPc2U\r\nVKlO5CYiU/fuy2f1HsvoOIjsafGB2h2omeU1V7B/vXlNiw8gU1fgWvP77kxp\r\nUssxLCpqzEL1mow87FZY4vxt64F6FuY80pVwcRO2vbEc7zJcsKb2Cn0dJVot\r\nUPVvwIUROtmaaPlZlgzq/jiELfgU3UyUHIndK7lf6X4Lx0masrtYd7uLQGQb\r\nttuMNnvvFNsEZJtamFadJiCEYXApf/8EBOcb+HATVLWjxqKpAQGwCnN5kIOm\r\n3kK9s1BO+KZDg4eo5dZsGGo2kYsDCMeg6YwTZCwGWzoDGbD6GUKsRdanoqV9\r\nOQa+PIKK6Mjo5n8ga51kjoGyMuGQ7gzPn+qFBM5lu4rueI4zCg36gNpiPeOy\r\nrPDUlqXUceMbRqLOzzSxK8y2mOe2aw5o35BBktD5hdVyv3FhjgSpAcLgk6Bv\r\nQWqNzHY5PlYLFqSizKan0LjRWbK2TpDdUIsyGmtURfSD9DLJ3pJe2PsTKsNI\r\nW3T22IpkeIDcVeFKEh3uIPlK/cv4nFtH6S6wJ2bpGMS0F73JI/d3r/vc/RRf\r\nszOcMsVWmbpYVNn4BuDfgAB19xDmtnx1ctlws/Z+J2CA/bWfmtDsHNgAUcok\r\nsiobNJ7zKI7axcAZr6BvQteUhkdq5DSAXe0=\r\n=Dxkq\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"asemirsk","email":"al.semirski@gmail.com"},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fclasses_1.0.0-canary-24-24.0_1653470270023_0.48907961605275885"},"_hasShrinkwrap":false}},"maintainers":[{"name":"asemirsk","email":"al.semirski@gmail.com"}],"description":"Allows for the injection of functional class into components.","homepage":"https://github.com/johnsonandjohnson/bodiless-js#readme","repository":{"type":"git","url":"git+https://github.com/johnsonandjohnson/bodiless-js.git"},"author":{"name":"Chris Oden","email":"coden@its.jnj.com"},"bugs":{"url":"https://github.com/johnsonandjohnson/bodiless-js/issues"},"license":"Apache-2.0","readme":"","readmeFilename":""}