<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by arfi720 on Medium]]></title>
        <description><![CDATA[Stories by arfi720 on Medium]]></description>
        <link>https://medium.com/@arfi720?source=rss-93b90d2ddd14------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*1SEz1RurIBF_veyn</url>
            <title>Stories by arfi720 on Medium</title>
            <link>https://medium.com/@arfi720?source=rss-93b90d2ddd14------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 28 May 2026 12:17:22 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@arfi720/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Positioning a toast component (reactjs, css/scss)]]></title>
            <link>https://medium.com/@arfi720/positioning-a-toast-component-reactjs-css-scss-bf3b2793e073?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/bf3b2793e073</guid>
            <category><![CDATA[react-components]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[toast]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Mon, 16 May 2022 14:14:56 GMT</pubDate>
            <atom:updated>2022-05-16T14:14:56.051Z</atom:updated>
            <content:encoded><![CDATA[<p>In a <a href="https://medium.com/@arfi720/lets-make-a-toast-4a9b87a785fc">previous</a> <a href="https://medium.com/@arfi720/custom-usestore-hook-6727d7b00ba3">articles</a>, we’ve been building a toast notification component library for use in reactjs projects. This article explores a solution for adding a position parameter to the toasts.</p><p>Get the finished code on <a href="https://github.com/aroomforimprovement/react-comp-pack/tree/4.3-positions">Github</a>.</p><p>Or, to code along from the previous article, clone <a href="https://github.com/aroomforimprovement/react-comp-pack/tree/4.2-useStore">this</a>.</p><p><strong>Step 1: It’s mostly about style, toast.scss</strong></p><p>First thing to do here is to define a class for each position we’d like to be able to display a toast in:</p><pre>.top-center {<br>  top: 1vh;<br>  left: 50%;<br>  margin-left: -10rem;<br>}</pre><pre>.top-left{<br>  top: 1vh;<br>  left:0px;<br>}</pre><pre>.top-right {<br>  top: 1vh;<br>  right:1vw;<br>}</pre><pre>.middle-left{<br>  top: 40vh;<br>}</pre><pre>.middle-center{<br>  top: 40vh;<br>  left: 50%;<br>  margin-left:-10rem;<br>}</pre><pre>.middle-right{<br>  top: 40vh;<br>  right:1vw;<br>}</pre><pre>.bottom-left {<br>  bottom: 1vh;<br>  left:0px;<br>}</pre><pre>.bottom-right{<br>  bottom: 1vh;<br>  right:1vw;<br>}</pre><pre>.bottom-center{<br>  bottom: 0px;<br>  left:50%;<br>  margin-left:-10rem;<br>}</pre><p>You can play around with the particulars of these but the point is that they define a position on the screen and nothing else — these will be added to the same component as the toast-slice class defined previously but we’ll come back to the other classes in a moment.</p><p><strong>Step 2: For consistency! types.js</strong></p><p>Just to make them easier to cycle through in the component package and any app that uses it, I define an array of positions in types.js</p><pre>export const POSITIONS = [<br>  &#39;top-left&#39;, &#39;top-center&#39;, &#39;top-right&#39;,<br>  &#39;middle-left&#39;, &#39;middle-center&#39;, &#39;middle-right&#39;,<br>  &#39;bottom-left&#39;, &#39;bottom-center&#39;, &#39;bottom-right&#39;<br>]</pre><p><strong>Step 3: Stay in your lane, Toast.js</strong></p><p>I designed my component code in such a way that the ToastRackcomponent that accesses the toastState from a custom useStore hook (<a href="https://medium.com/@arfi720/custom-usestore-hook-6727d7b00ba3">see previous article</a>) will now map the toasts that need to be indifferent positions into their own arrays, then map each of those arrays into a ToastSlot component which, in turn, maps it’s array into a number of ToastSlice components:</p><p>First the ToastRack component, mapping a new array for each position in the POSITIONS array above:</p><pre>export const ToastRack = () =&gt; {<br>  const [toastState, toastDispatch] = useStore();<br>  const positions = POSITIONS.map((pos, i) =&gt; {<br>    return [...toastState.toasts].filter((toast) =&gt; {<br>      if(toast.position === pos){<br>        return true;<br>      }<br>    })<br>  })</pre><pre>const slots = positions.map((pos, i) =&gt; {<br>    return(<br>      &lt;ToastSlots<br>        key={i}<br>        toasts={pos} /&gt;<br>    )<br>  })</pre><pre>return(<br>    &lt;div className={`toast-rack`}&gt;<br>      {slots ? slots : &#39;Nothing&#39;}<br>    &lt;/div&gt;<br>  )<br>}</pre><p>Then the new ToastSlots component sets it’s pos state based on the toasts it has received (or defaults to ‘top-center’) and maps an array of ToastSlice components:</p><pre>export const ToastSlots = ({toasts}) =&gt; {<br>  const [pos, setPos] = useState();<br>  <br>  useEffect(() =&gt; {<br>    setPos(toasts &amp;&amp; toasts[0] &amp;&amp; toasts[0].position<br>    ? toasts[0].position  : &#39;top-center&#39;);<br>  },[toasts])</pre><pre>const toastComps = toasts?.reverse().map((t) =&gt; {</pre><pre>return(<br>    &lt;ToastSlice<br>      key={t.id}<br>      t={t} /&gt;<br>    )<br>  })<br>  return &lt;div className={`toast-slots ${pos}`}&gt;{toastComps}&lt;/div&gt;<br>}</pre><p>Finally, the very simple ToastSlice component remains unchanged:</p><pre>const ToastSlice = ({t}) =&gt; {<br>  return(<br>    &lt;div className={`toast-slice `}&gt;<br>      {t.message}<br>    &lt;/div&gt;<br>  )<br>}</pre><p><strong>Step 4: Styling, toast.css</strong></p><p>I added the .toast-slots class and moved some of the previous content from .toast-rack . Importantly, I’ve removed position attributes, like left and top from both of these classes, now relying on the position classes above.</p><p>The rest of this, you can play around with to get a similar but different result:</p><pre>.toast-rack{<br>  position: fixed;<br>  min-width: 100vw;<br>  z-index: 1001;<br>}</pre><pre>.toast-slots{<br>  position:fixed;<br>  margin: 0px;<br>  padding: 0px;<br>  pointer-events: none;<br>  font-family: &#39;sans-serif&#39;;<br>  background-color: rgba(255, 255, 255, 0);<br>}</pre><pre>.toast-slice{<br>  pointer-events: all;<br>  position: relative;<br>  display: block;<br>  min-height: 50px;<br>  max-height: 30vh;<br>  width: 20rem;<br>  margin: 5px;<br>  padding: 10px;<br>  background-color: rgba(255, 255, 255, 0.9);<br>  border: 0px;<br>  border-radius: 0.5rem;<br>  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);<br>  color: rgba(40, 40, 40, 0.8);<br>}</pre><p><strong>Step 5: Action, App.js</strong></p><p>In the demo app, I’ve added a few buttons to demo two of the positions:</p><pre>import React from &quot;react&quot;;<br>import { Button, ToastRack, useToastRack } from &#39;./lib&#39;;</pre><pre>const App = () =&gt; {<br>  const toast = useToastRack();<br>  <br>  const handleAdd = (pos) =&gt; {<br>    const id = toast.fire({<br>      message: `Hi, I am ${pos}`,<br>      position: pos ? pos : &#39;top-center&#39;<br>    });<br>    console.log(id);<br>  }</pre><pre>const handleRemove = () =&gt; {<br>    toast.dismiss(toast?.toasts[0]?.id);<br>    console.dir(toast?.toasts);<br>  }</pre><pre>return(<br>    &lt;div&gt;<br>      &lt;Button btnText={&#39;Top right&#39;} onClick={() =&gt; handleAdd(&#39;top-right&#39;)}/&gt;<br>     &lt;Button btnText={&#39;Bottom left&#39;} onClick={() =&gt; handleAdd(&#39;bottom-left&#39;)}/&gt;<br>     &lt;Button btnText={&#39;Remove toast&#39;} type={&#39;alter&#39;} onClick={handleRemove}/&gt;<br>     &lt;ToastRack /&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>Give them a few clicks, and presto, you can take it from here:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/948/1*GfWSNcdnBd1jEbgu-yaWOA.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bf3b2793e073" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Custom useStore hook]]></title>
            <link>https://medium.com/@arfi720/custom-usestore-hook-6727d7b00ba3?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/6727d7b00ba3</guid>
            <category><![CDATA[react-hook]]></category>
            <category><![CDATA[react-components]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[react-js-tutorials]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Thu, 28 Apr 2022 19:09:40 GMT</pubDate>
            <atom:updated>2022-04-28T19:09:40.225Z</atom:updated>
            <content:encoded><![CDATA[<p>I wanted to add some similar functionality as provided by libraries like react-redux to a reactjs <a href="https://medium.com/@arfi720/package-react-components-for-npm-d22cd2f23b8">component library</a> I’m building but didn’t want to rely on so many dependencies. Hence the need to code my own useStore hook, to allow my library to benefit from a kind of “global” state so it can be used any where in app with a minimum of fuss.</p><p>I’ll be using the new hook with the simple toast component from a <a href="https://medium.com/@arfi720/lets-make-a-toast-4a9b87a785fc">previous article</a>.</p><p><em>Get the finished code for this article on </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/4.2-useStore"><em>Github</em></a><em>.</em></p><p><em>Or, to code along, </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/4.1-basic-toast"><em>clone this to start</em></a><em>.</em></p><p><strong>Step 1: To the core</strong></p><p>I added a new directory, /src/lib/core/ with two files, store.js and types.js</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/174/1*dUeezO_CCsftzqWnWQf97Q.png" /></figure><p>This is just a conventional place to put logical code that can be used by multiple components.</p><p><strong>Step 2: Just your type(s), types.js</strong></p><p>Very quickly, we’ll put an object called Actions in types.js, containing two constants, ADD_TOAST, and REMOVE_TOAST:</p><pre>export const Actions = {<br>  ADD_TOAST: &#39;ADD_TOAST&#39;,<br>  REMOVE_TOAST: &#39;REMOVE_TOAST&#39;<br>}</pre><p>These are the two actions I currently have my app driving for demo purposes and we want to bring that logic into the library.</p><p><strong>Step 3: Use the store, store.js</strong></p><p>We first want to create a variable at the top level of the file, where they won’t be affected by re-renders, for a global state object and another for an array of listeners that we’ll connect to the state.</p><pre>let globalToastState = {toasts: []}<br>const toastListeners = [];</pre><p>Next we’ll define a reducer function that takes a state object and an action object as parameters and returns the state after the action has been completed. In here, we’ll put functions to add and remove toasts from the array toasts inside the state object:</p><pre>const reducer = (state, action) =&gt; {<br>  switch(action.type){<br>    case Actions.ADD_TOAST:{<br>      const toasts = [...state.toasts];<br>      toasts.push(action.data);<br>      return({...state, toasts: toasts});<br>    }<br>    case Actions.REMOVE_TOAST:{<br>      let toasts = [...state.toasts];<br>      toasts = toasts.filter((e) =&gt; {<br>        return e.id !== action.data.id;<br>      });<br>      return({...state, toasts: toasts});<br>    }<br>    default:<br>      return(state);<br>  }<br>}</pre><p>Finally, we define the useStore hook itself. This does two things:</p><p>It uses useState(), initialised with the global state defined outside the hook function and, inside a useEffect hook, adds the useState’s setState() function to the toastListeners array defined at the top level whenever setState is changed.</p><p>It also defines a dispatch function that uses the reducer defined earlier to update the state with an action and updates the state of each listener.</p><pre>export const useStore = () =&gt; {<br>  const setState = useState(globalToastState)[1];<br>  useEffect(() =&gt; {<br>    toastListeners.push(setState);<br>    return() =&gt; {<br>      const index = toastListeners.indexOf(setState);<br>      if(index &gt; -1){<br>        toastListeners.splice(index, 1);<br>      }<br>    }<br>  },[setState]);</pre><pre>  const dispatch = (action) =&gt; {<br>    globalToastState = reducer(globalToastState, action);<br>    for(const listener of toastListeners){<br>      listener(globalToastState);<br>    }<br>    return globalToastState;<br>  }<br>  return [globalToastState, dispatch];<br>}</pre><p>We can use the listeners to update all kinds of info to do with each toast later on, but that falls outside the scope of this article.</p><p>Importantly, the useStore hook returns an array containing the global state object and the dispatch function. We can access these later in a similar way to the built in react hook useState.</p><p><strong>Step 4: Using useStore, Toast.js, index.js</strong></p><p>Previously, we’d passed an array of toast objects into the ToastRack components but now we can replace that with a call to useStore:</p><pre>export const ToastRack = () =&gt; {</pre><pre>  const [toastState, toastDispatch] = useStore();</pre><pre>  const toastComps = [...toastState.toasts]<br>    .map((t, i) =&gt; &lt;ToastSlice key={i} t={t}/&gt;)<br>    .reverse();<br>    <br>    return(<br>      &lt;div className={`toast-rack`}&gt;<br>       {toastComps}<br>      &lt;/div&gt;<br>    );</pre><pre>}</pre><p>Simple. We also need to expose some functions for an app to use the reducer actions ADD/REMOVE_TOAST. To do this, we’ll create another customer hook called useToastRack:</p><pre>export const useToastRack = () =&gt; {</pre><pre>  const [toastState, toastDispatch] = useStore();</pre><pre>  const fire = (params) =&gt; {<br>    params = params ? params : {};<br>    const toast = {<br>      id: params.toastId ? params.toastId : uuidv4(),<br>      message: params.message <br>               ? params.message <br>               : &#39;Things are happening&#39;,<br>    }<br>    toastDispatch({<br>      type: Actions.ADD_TOAST,<br>      data: toast<br>    });<br>    return toast.id;<br>  }</pre><pre>  const dismiss = (id) =&gt; {<br>     toastDispatch({<br>       type: Actions.REMOVE_TOAST,<br>       data: {id: id}<br>     });<br>  }</pre><pre>  return {<br>    &quot;fire&quot;: (params) =&gt; fire(params),<br>    &quot;dismiss&quot;: (id) =&gt; dismiss(id),<br>    &quot;toasts&quot;: {...toastState.toasts}<br>  }</pre><pre>}</pre><p>Here, we’ve defined the fire and dismiss function, which in turn call the toastDispatch returned by the useStore hook.</p><p>We then return an object containing both these functions and a property containing the array of toast objects from the state returned by useStore.</p><p>Notice that I’m using the function uuidv4() from the libary uuid. You can install this with npm install uuid then import it to your component file using import {v4 as uuidv4} from `uuid` . This is a small library for generating an essentially unique id in various formats.</p><p>We’ll also want to export the useToastRack function, updating the existing export in index.js</p><pre>export { ToastRack, useToastRack  } from &#39;./components/toast/Toast&#39;;</pre><p><strong>Step 5: Hooked on a… demonstration of basic functionality, App.js</strong></p><p>In our demo app, we can replace the array, the useState, and the content of the handler functions attached to our two buttons to instead allow the library to handle the toast state, while the app can call the fire and dismiss functions exposed by useToastRack:</p><pre>import React from &quot;react&quot;;<br>import { Button, ToastRack, useToastRack } from &#39;./lib&#39;;</pre><pre>const App = () =&gt; {<br>  const toast = useToastRack();<br>  const handleAdd = () =&gt; {<br>    const id = toast.fire({message: &quot;Hi. I am toast&quot;});<br>    console.log(id);<br>  }</pre><pre>  const handleRemove = () =&gt; {<br>    toast.dismiss(toast?.toasts[0]?.id);<br>    console.dir(toast?.toasts);<br>  }</pre><pre>  return(<br>    &lt;div&gt;<br>      &lt;Button btnText={&#39;Add toast&#39;} onClick={handleAdd}/&gt;<br>      &lt;Button btnText={&#39;Remove toast&#39;} type={&#39;alter&#39;} <br>        onClick={handleRemove}/&gt;<br>      &lt;ToastRack /&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>And like that, we can add and remove toasts, log out their ids on creation and log out the whole array from the app, while the library takes care of the logic:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mNHK2nRfjqmsBfOthcWaSA.png" /></figure><p>You sure are buddy, you sure are toast.</p><p><strong>Conclusion</strong></p><p>That’s about the most basic example of a custom useStore hook I could create and seems to be working for my purposes. Most importantly for the use case of a small component library, I’ve only added one little dependency.</p><p>In further articles, we’ll step through various way of giving the toasts their own lifecycles and add some parameterised visual variations.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6727d7b00ba3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Let’s make a toast]]></title>
            <link>https://medium.com/@arfi720/lets-make-a-toast-4a9b87a785fc?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/4a9b87a785fc</guid>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[reactjs-development]]></category>
            <category><![CDATA[react-js-tutorials]]></category>
            <category><![CDATA[react-components]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Sun, 24 Apr 2022 22:54:37 GMT</pubDate>
            <atom:updated>2022-04-28T19:10:49.028Z</atom:updated>
            <content:encoded><![CDATA[<p>In previous articles, I stepped through the boiler-plate code needed to create an <a href="https://medium.com/@arfi720/package-react-components-for-npm-d22cd2f23b8">npm package</a> for a react component library, as well as a <a href="https://medium.com/@arfi720/demo-app-for-development-of-react-component-library-8ec9f4a5531b">demo app</a> to test the components during development.</p><p>The component I want to make is a toast notification, largely because I found myself writing the same chunks of code into two different apps in order to adapt an <a href="https://react-hot-toast.com/">existing npm package</a> to my purposes.</p><p><em>Get the completed code on</em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/4.1-basic-toast"><em> Github</em></a><em>.</em></p><p><em>Or, to code along, clone this to </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/3.3-sass-loader"><em>start</em></a><em>.</em></p><p><strong>Before we start (if you’re coding along):</strong></p><p>In the existing Button component, I removed the nonsense onClick function and am instead passing an onClick prop into the button so that it can actually be used for something:</p><pre>export const Button = ({btnText, onClick, type}) =&gt; {<br>  return (<br>    &lt;button<br>      className={`butt shade ${type}`}<br>      onClick={onClick}<br>    &gt;<br>      {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p><strong>Step 1: A New Component, Toast.js</strong></p><figure><img alt="Screenshot of file structure with toast directory and Toast.js, toast.scss files" src="https://cdn-images-1.medium.com/max/171/1*R7BCxyLe6rsTkTcwOUJ3Kg.png" /></figure><p>I added a new directory at src/lib/components/toast/ with a component file and style sheet, Toast.js and toast.scss.</p><p>In Toast.js, I’m creating a component ToastSlice to represent the individual notifications and exporting a component ToastRack as a holder for all my toasts. For the moment, toasts will be js objects with the simple format {id: 0, message: &quot;text&quot;} and, for the moment, will be passed as props into the ToastRack component.</p><pre>import React from &#39;react&#39;;<br>import &#39;./toast.scss&#39;;</pre><pre>const ToastSlice = ({t}) =&gt; {<br>  return(<br>   &lt;div className={`toast-slice `}&gt;<br>     {t.message}<br>   &lt;/div&gt;<br>  )<br>}</pre><pre>export const ToastRack = ({toasts}) =&gt; {<br>  const toastComps = toasts.map((t, i) =&gt;<br>    &lt;ToastSlice key={i} t={t}/&gt;).reverse();<br>  <br>  return(<br>    &lt;div className={`toast-rack`}&gt;<br>      {toastComps}<br>    &lt;/div&gt;<br>  )<br>}</pre><p>Notice I’ve imported toast.scss and used some class names, toast-slice and toast-rack although these don’t exist yet.</p><p><strong>Step 2: Exporting from the component library, and taking a look in the demo app, /lib/index.js, App.js</strong></p><p>I only need to export the ToastRack component right now, but I’m also updating the export for my Button to be a bit more consistent as well.</p><p>So the whole code of /lib/index.js is now:</p><pre>export { Button } from &#39;./components/button/Button&#39;;<br>export { ToastRack } from &#39;./components/toast/Toast&#39;;</pre><p>To see what these will look like, I made up an array with three toast objects and pass them to a ToastRack component in our demo App.js (we can leave our useless buttons there for illustration purposes):</p><pre>import React from &quot;react&quot;;<br>import { Button, ToastRack } from &#39;./lib&#39;;</pre><pre>const dummyToasts = [<br>  {<br>    id: 0,<br>    message: &quot;The first toast&quot;<br>  },<br>  {<br>    id: 1,<br>    message: &quot;The second toast&quot;<br>  },<br>  {<br>    id: 2,<br>    message: &quot;The third toast&quot;<br>  }<br>];</pre><pre>const App = () =&gt; {<br>  return(<br>    &lt;div&gt;<br>      &lt;Button btnText={&#39;Demo button&#39;}/&gt;<br>      &lt;Button btnText={&#39;Alternate button&#39;} type={&#39;alter&#39;}/&gt;<br>      &lt;ToastRack toasts={dummyToasts} /&gt;<br>   &lt;/div&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>This gives us (drum roll, please) some ugly text of course, displayed in blocks under the existing buttons:</p><figure><img alt="Screenshot of three rows of plain text displayed under two buttons" src="https://cdn-images-1.medium.com/max/289/1*F2H_1z5YJl5qpLeyEk1eHA.png" /></figure><p>The stodgy dough balls of react components.</p><p><strong>Step 3: Make it pop, toast.scss</strong></p><p>The initial stylesheet is below:</p><pre>.toast-rack{<br>  position: fixed;<br>  min-width: 100vw;<br>  z-index: 1001;<br>  top: 2vh;<br>  left: 2vw;<br>  margin: 0px;<br>  padding: 0px;<br>  font-family: &#39;sans-serif&#39;;<br>  background-color: rgba(255, 255, 255, 0);<br>  pointer-events: none;<br>}</pre><pre>.toast-slice{<br>  pointer-events: all;<br>  position: relative;<br>  display: block;<br>  min-height: 50px;<br>  max-height: 30vh;<br>  width: 20rem;<br>  margin: 5px;<br>  padding: 10px;<br>  background-color: rgba(255, 255, 255, 0.9);<br>  border: 0px;<br>  border-radius: 0.5rem;<br>  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);<br>  color: rgba(40, 40, 40, 0.8);<br>}</pre><p>The essential parts being:</p><p>toast-rack : The holder should have position:fixed so that, wherever you decide to put it, it stays exactly there, no matter what else is going on and should have z-index set to an arbitrarily high number, so that it’s contents float “above” the rest of your app.</p><p>I’ve also set pointer-events: none so that, since this component will potentially cover everything else on screen, any pointer events will be allowed to pass through to the rest of the app regardless.</p><p>toast-slice : The toast itself will have pointer-events turned back to all to allow interactivity. I’m setting position:relative so that, when I add other elements to the component, I can use position:absolute to position them precisely.</p><p>I’ve set display:block to ensure these stack one per line and the rest of this is just colouring and shaping into a rounded, slightly translucent white toast which doesn’t sound tasty but looks pretty good:</p><figure><img alt="Screenshot of improved toast components rendered above existing buttons." src="https://cdn-images-1.medium.com/max/669/1*uxM7rP12QbHKxHc0-5wQpg.png" /></figure><p><strong>Pointless Diversion: Just to see some action</strong></p><p>This code won’t be useful in the component library, but just for fun and to see toasts created and dismissed as you’d expect, I updated App.js to create and remove toasts from an array with useState() and passed that state to the ToastRack component:</p><pre>const App = () =&gt; {<br>  <br>  const [toasts, setToasts] = useState([]);</pre><pre>  const handleAdd = () =&gt; {<br>    const ts = [...toasts];<br>    ts.push({<br>      id: toasts.length,<br>      message: `This id system is unsustainable: ${toasts.length}`<br>    });<br>    setToasts(ts);<br>  }</pre><pre>const handleRemove = () =&gt; {<br>  let ts = [...toasts];<br>  ts.pop();<br>  setToasts(ts);<br>  console.log(toasts);<br>}</pre><pre>return(<br>  &lt;div&gt;<br>    &lt;Button btnText={&#39;Add toast&#39;} onClick={handleAdd}/&gt;<br>    &lt;Button btnText={&#39;Remove toast&#39;} type={&#39;alter&#39;} <br>      onClick={handleRemove}/&gt;<br>    &lt;ToastRack toasts={toasts} /&gt;<br>   &lt;/div&gt;<br>  );<br>}</pre><p>In the next article, we’ll develop a system for the toast library to take care of it’s own state.</p><p><strong>Conclusion:</strong></p><p>This guide stepped coding and styling a beautiful but dumb toast notification component. The <a href="https://medium.com/@arfi720/custom-usestore-hook-6727d7b00ba3">next article</a> will move the create and remove logic from the demo app to the library, using custom hooks.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4a9b87a785fc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[3 ways to style a reactjs component package [3/3]]]></title>
            <link>https://medium.com/@arfi720/3-ways-to-style-a-reactjs-component-package-b42ba28d4f0f?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/b42ba28d4f0f</guid>
            <category><![CDATA[react-component-library]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[sass]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[reactjs]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Sun, 17 Apr 2022 18:01:19 GMT</pubDate>
            <atom:updated>2022-04-24T14:01:17.513Z</atom:updated>
            <content:encoded><![CDATA[<p>Having created a simple <a href="https://medium.com/@arfi720/package-react-components-for-npm-d22cd2f23b8">component package</a> and a <a href="https://medium.com/@arfi720/demo-app-for-development-of-react-component-library-8ec9f4a5531b">demo app</a> to test it with, this guide will show you some options for building styles into your component.</p><h3><strong>Option 1: CSS</strong></h3><p><em>Get the finished code for this option </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/3.1-css-loader"><em>on Github</em></a>.</p><p><em>To code-along from the same project, </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/2-npm-package-demo-app"><em>clone this</em></a><em> to start.</em></p><p><strong>Step 1: Add a .css file, code it and import it</strong></p><p>The most obvious option is to put our styles in .css files and import them into our components. I decided to move my Button component into it’s own directory and create a dedicated .css file in there called button.css, just to keep everything related to a particular component in one place.</p><figure><img alt="Screenshot of new file structure with component, button directory" src="https://cdn-images-1.medium.com/max/290/1*JEKLHMnCHdZ9h9pYSYwPyg.png" /></figure><p>For the content of the css file, I’m creating a buttclass for colouring and shaping the button and a shade class to add shadow. Both of these have hover and active pseudo-classes implemented to add interactivity.</p><pre>.butt {<br>  padding: 12px;<br>  background-color: rgb(240, 240, 240);<br>  border: 1px solid rgb(180, 180, 180);<br>  color: rgb(80, 80, 80);<br>  border-radius: 0.5vh;<br>  cursor: pointer&#39;<br>}</pre><pre>.butt:hover{<br>  transform: scale(1.02);<br>}</pre><pre>.butt:active{<br>  transform: scale(1);<br>}</pre><pre>.shade {<br>  box-shadow: 1px 1px 3px;<br>}</pre><pre>.shade:hover{<br>  box-shadow: 2px 2px 5px;<br>}</pre><pre>.shade:active{<br>  box-shadow: 0px 0px;<br>}</pre><p>To use these styles in my Button component, I’ve imported it and used the two classes as the className prop in my button tag.</p><pre>import React from &#39;react&#39;;<br>import &#39;./button.css&#39;;</pre><pre>export const Button = ({btnText}) =&gt; {<br>  return (<br>    &lt;button<br>      className=&#39;butt shade&#39;<br>      onClick={() =&gt; {console.log(&quot;It worked!&quot;)}}<br>    &gt;<br>      {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p>Because I moved the Button.js file into it’s own directory, I’ve had to update the import statement in src/lib/index.js</p><pre>import { Button } from &#39;./components/button/Button&#39;;</pre><p>If you run npm run start right now, you’ll see your newly-styled button working like so:</p><figure><img alt="Screenshot of working button with new styling" src="https://cdn-images-1.medium.com/max/684/1*50_d46ke_uFrPs5XrzjSoA.png" /></figure><p>Unfortunately, if you run npm run prepublish to build the component library for publishing, you’ll get an error explaining that you might be missing a loader for certain file type.</p><p><strong>Step 2: css-loader, webpack.config, package.json</strong></p><p>In your config.module.rules, you should already have an array with one object, referring to ‘babel-loader’. You’ll need to add the following rule object to the same array:</p><pre>{<br>        test: /\.css$/,<br>        use: [<br>          &#39;style-loader&#39;,<br>          &#39;css-loader&#39;<br>        ]<br>      }<br>}</pre><p>(You can return to <a href="https://createapp.dev/webpack/">createapp.dev</a> any time to crib the code needed to add elements like this)</p><p>You’ll also need to intall style-loader and css-loader as dev dependencies:</p><pre>npm install --save-dev style-loader css-loader</pre><p>Now you can run npm run prepublish , followed by npm publish (after updating the version number in package.json!) to build and publish the package. Installing it in another app, you should now see the styling built into the button.</p><h3>Option 2: Styling the component directly</h3><p><em>Get the finished code for this option on </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/3.2-inline-styles"><em>Github</em></a><em>.</em></p><p><em>To code-along from the same project, </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/2-npm-package-demo-app"><em>clone this</em></a><em> to start.</em></p><p>To make your component as minimal as possible, you might want to put the styling directly into the component. This won’t require any extra loader but it can get pretty complex pretty quickly.</p><p>You can create a new file(s) to store your styles and import them like any other object to your component file but I’ve put my style objects in the Button.js file for the moment to show a minimal example.</p><p><strong>Step 1: Style objects</strong></p><p>First, I’m just adding objects equivalent to the basic classes from Option 1, without “hover” and “active” implementations and using those in the button tag’s style prop with style:{{...butt, ...(shade)}}:</p><pre>import React, { useState } from &#39;react&#39;;</pre><pre>export const Button = ({btnText}) =&gt; {<br>  <br>  const butt = {<br>    padding: &#39;12px&#39;,<br>    backgroundColor: &#39;rgb(240, 240, 240)&#39;,<br>    border: &#39;1px solid rgb(180, 180, 180)&#39;,<br>    color: &#39;rgb(80, 80, 80)&#39;,<br>    borderRadius: &#39;0.5vh&#39;,<br>    cursor: &#39;pointer&#39;,<br>  }</pre><pre>const shade = {<br>    boxShadow: &#39;1px 1px 3px&#39;,<br>  }</pre><pre>return(<br>    &lt;button<br>      style={{...butt, ...(shade)}}<br>      onClick={() =&gt; {console.log(&quot;It worked!&quot;)}}<br>    &gt;<br>       {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p>You can more-or-less use any CSS property here by changing the syntax from background-color to backgroundColor for the property names and putting all property values between quotes (also separate with commas, not semi-colons because these are javascript objects).</p><p><strong>Step 2: Style logic</strong></p><p>While the css method of adding hover and active psuedo-classes is completely standardised and very simple, I had to go looking for ideas about how to implement this with jsx style objects. <a href="https://stackoverflow.com/questions/28365233/inline-css-styles-in-react-how-to-implement-ahover">This SO question</a> has a few solutions and I’ve implemented one below:</p><pre>import React, { useState } from &#39;react&#39;;</pre><pre>export const Button = ({btnText}) =&gt; {</pre><pre>  const [state, setState] = useState(0);<br>  <br>  const butt = {<br>    padding: &#39;12px&#39;,<br>    backgroundColor: &#39;rgb(240, 240, 240)&#39;,<br>    border: &#39;1px solid rgb(180, 180, 180)&#39;,<br>    color: &#39;rgb(80, 80, 80)&#39;,<br>    borderRadius: &#39;0.5vh&#39;,<br>    cursor: &#39;pointer&#39;,<br>  }</pre><pre>  const buttHover = {<br>    transform: &#39;scale(1.02)&#39;<br>  }</pre><pre>  const buttActive = {<br>    transform: &#39;scale(1)&#39;<br>  }</pre><pre>  const shade = {<br>    boxShadow: &#39;1px 1px 3px&#39;,<br>  }</pre><pre>  const shadeHover = {<br>    boxShadow: &#39;2px 2px 5px&#39;<br>  }</pre><pre>  const shadeActive = {<br>    boxShadow: &#39;0px 0px&#39;<br>  }</pre><pre>  return(<br>    &lt;button<br>      onMouseEnter={() =&gt; setState(1)}<br>      onMouseLeave={() =&gt; setState(0)}<br>      onMouseDown={() =&gt; setState(2)}<br>      style={{...butt, ...(shade),<br>        ...(state === 1) <br>          ? buttHover <br>          : (state === 2) <br>            ? buttActive <br>            : null,<br>        ...(state === 1) <br>          ? shadeHover <br>          : (state === 2) <br>            ? shadeActive <br>            : null<br>      }}<br>      onClick={() =&gt; {console.log(&quot;It worked!&quot;)}}<br>    &gt;<br>       {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p>Here, I’m using useState()to hold a value indicating whether the mouse is over the button, or not, or has been pressed; triggered by onMouseEnter / onMouseLeave / onMouseDown events.</p><p>Then I’m adding the relevant style objects to the style prop, depending on the value of that state.</p><p>Running npm run start should show you exactly the same result now as the CSS solution and running npm run prebublish to build it won’t show any errors because no extra loaders are required.</p><p>It’s pretty clear though that the component code, even if I move the style objects into their own file, has gotten pretty complicated for something that was achieved in css using .my-class:hover . I might use some of this kind of implementation for specific use-cases but in general, using and importing .css files makes a lot more sense if my component needs much styling built in.</p><h3>Option 3: Sass loader</h3><p><em>Get the finished code for this option on </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/3.3-sass-loader"><em>Github</em></a><em>.</em></p><p><em>To code-along from the same project, </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/3.1-css-loader"><em>clone this</em></a><em> to start, or continue where you finished Option 1.</em></p><p>If you want to use a Sass pre-compiler for your style sheets, you can pick up where we left off with the CSS-Loader section and just use Sass instead.</p><p><strong>Step 1: Change your .css files to .scss</strong></p><figure><img alt="Screenshot of new file extension changed to .scss" src="https://cdn-images-1.medium.com/max/281/1*jDbFM5kXG_15WmhfJNxWtg.png" /></figure><p>I’ve just got one .css file from before, so I’ve changed the name button.scss and updated the reference to it in Button.js to</p><pre>import &#39;./button.scss&#39;</pre><p><strong>Step 2: Sass-Loader, webpack.config.js, package.json</strong></p><p>If you have the css-loader rule object in your webpack.config.js file, replace it with a new rule below:</p><pre>{<br>  test: /\.scss$/,<br>  use: [<br>    &#39;style-loader&#39;,<br>    &#39;css-loader&#39;,<br>    &#39;sass-loader&#39;<br>  ]<br>}</pre><p>Or add that rule if you’re using sass from the start.</p><p>You’ll also need to install sass-loader and sass packages (and style-loader and css-loader if you’re starting from scratch).</p><p>Always with the dev dependencies:</p><pre>npm install --save-dev sass-loader sass</pre><p>I saw other guides recommending node-sass instead of sass here but I had conflict issues with it, so used sass package.</p><p>And that’s it in terms of migrating what we had with the CSS option. You can run this in the test app, build it, publish it, import it to a new project and it will work exactly the same as the other options.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*50_d46ke_uFrPs5XrzjSoA.png" /></figure><p><strong>Step 3: Why bother with Sass?</strong></p><p><a href="https://sass-lang.com/">Sass</a> is a pre-processor for CSS that is rich in features for abstracting and maintaining complex style sheet functionality. We’ll implement one feature now just to show why this can be a better option for more complex use-cases.</p><p><strong><em>Step 3.1: Creating variables, _colours.scss</em></strong></p><p>A quick way to leverage Sass is to store some colour variables in another file and reference them throughout a project.</p><p>I created a new directory /src/lib/sass/ with a file _colours.scss (it’s convention to include that underscore at the beginning of the file name when creating partial files like these. Sass will recognise these as modules).</p><p>In _colours.css , I declared some variables with $ symbol at the beginning of variable names:</p><pre>$bg-standard: rgb(240, 240, 240);<br>$brd-standard: rgb(180, 180, 180);<br>$txt-standard: rgb(80, 80, 80);</pre><pre>$bg-alter: rgb(80, 80, 80);<br>$brd-alter: rgb(140, 140, 140);<br>$txt-alter: rgb(240, 240, 240);</pre><p>These describe colours I want to use for “standard” button type and an alternate type.</p><p><strong><em>Step 3.2: Using variables, button.scss</em></strong></p><p>In my button.scss file, I need to tell it to use the colours file by adding this at the beginning of the file:</p><pre>@use &#39;../../sass/colours&#39;;</pre><p>Then, anywhere I want to use one of the declared colour variables, I can do so like this (syntax: module.$var-name):</p><pre>...<br>  background-color: colours.$bg-standard<br>...</pre><p>I updated my butt class with the “standard” variables, and added a new alter class with the alternate variables:</p><pre>.butt {<br>  margin:0.2vh;<br>  padding: 12px;<br>  background-color: colours.$bg-standard;<br>  border: 1px solid colours.$brd-standard;<br>  color: colours.$txt-standard;<br>  border-radius: 0.5vh;<br>}</pre><pre>.alter {<br>  background-color: colours.$bg-alter;<br>  border: 1px solid colours.$brd-alter;<br>  color: colours.$txt-alter;<br>}</pre><p><strong><em>Step 3.3: Implementing variations</em></strong></p><p>Of course, we could code a new button now that uses the alter class but lets implement a way to produce as many variants as we want with minimal code.</p><p>I’ve changed the signature of the Button component to take a new prop type :</p><pre>export const Button = ({btnText, type}) =&gt; {</pre><p>Then I’ve updated the className prop value in button tag to use the type value:</p><pre>className={`butt shade ${type}`}</pre><p>For flavour, I’ve updated the button’s onClick function to use the type value as well, just to print the type to console:</p><pre>onClick={() =&gt; {<br>  console.log(`It worked! (${<br>    type<br>    ? type<br>    : &#39;standard&#39;})`<br>  )<br>}}</pre><p>So the whole component code now looks like this:</p><pre>import React from &#39;react&#39;;<br>import &#39;./button.scss&#39;;</pre><pre>export const Button = ({btnText, type}) =&gt; {<br>  return (<br>    &lt;button<br>      className={`butt shade ${type}`}<br>      onClick={() =&gt; {<br>        console.log(`It worked! (${<br>          type<br>          ? type<br>          : &#39;standard&#39;})`<br>        )<br>      }}<br>    &gt;<br>      {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p><strong>Step 3.4: Using the variations</strong></p><p>If we update our demo app’s App.js, adding another button and supplying the prop type={&#39;alter&#39;} it will look something like this:</p><pre>import React from &quot;react&quot;;<br>import { MyButton } from &#39;./lib&#39;;</pre><pre>const App = () =&gt; {<br>  return(<br>    &lt;div&gt;<br>      &lt;MyButton btnText={&#39;Demo button&#39;}/&gt;<br>      &lt;MyButton btnText={&#39;Alternate button&#39;} type={&#39;alter&#39;}/&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>And running the demo app, npm run start , we should be able to test the two variants like so:</p><figure><img alt="Screenshot of standard and alternate button, with visual difference and different console.log results" src="https://cdn-images-1.medium.com/max/687/1*n-I-qirZy8k9U3h-76vd7A.png" /></figure><p>A little wrinkle came up here though — the shadow has disappeared from the alternate button.</p><p>The reason for this is that the colour for the box-shadow css property defaults to the color property already applied using the alter class. To fix this, we can specify the colour like so:</p><pre>box-shadow: 1px 1px 3px colours.$txt-standard</pre><h3>Conclusion</h3><p>In this article we tried CSS, inline styles, and finally Sass to get style into our component package. I definitely feel like I got more bang for my line of code using Sass, so if you’re following along, I’ll be continuing to build this component library from where I’ve left off with the Sass solution.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b42ba28d4f0f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Demo app for development of React component library [2/3]]]></title>
            <link>https://medium.com/@arfi720/demo-app-for-development-of-react-component-library-8ec9f4a5531b?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/8ec9f4a5531b</guid>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[packaging]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Wed, 13 Apr 2022 22:44:54 GMT</pubDate>
            <atom:updated>2022-04-24T14:02:19.201Z</atom:updated>
            <content:encoded><![CDATA[<p>In a <a href="https://medium.com/@arfi720/package-react-components-for-npm-d22cd2f23b8">previous article</a> we built and published a simple npm package containing a reusable React component. Having to publish the package, then update it in another app to test it would obviously be a little silly, so let’s flesh out our minimal setup with a demo app where we can test the package components locally as they are developed.</p><p><em>You can get the completed code for this article on </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/2-npm-package-demo-app"><em>github</em></a><em>.</em></p><p><em>Or to code-along from end of the previous article, </em><a href="https://github.com/aroomforimprovement/react-comp-pack/tree/1-tiny-npm-component-package"><em>clone this</em></a><em> to start.</em></p><p><strong>Step 1: Going public</strong></p><figure><img alt="Screenshot of React app file structure, including public directory" src="https://cdn-images-1.medium.com/max/166/1*sVCDIFYvEDfW6SkRSnBvzA.png" /></figure><p>To start a running app, I created a public/ directory to house my index.html file. I’ve also created manifest.json and robots.txt , although these aren’t really necessary because I’m not planning on running this app anywhere except locally but I’m copying the basic structure of a create-react-app, so keeping these for completeness.</p><p>Here’s the content of index.html (It’s a stripped down copy of the one from a create-react-app)</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html lang=&quot;en&quot;&gt;<br>  &lt;head&gt;<br>    &lt;meta charset=&quot;utf-8&quot; /&gt;<br>    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&gt;<br>    &lt;meta name=&quot;theme-color&quot; content=&quot;#000000&quot; /&gt;<br>    &lt;meta<br>      name=&quot;description&quot;<br>      content=&quot;Library test site&quot;<br>    /&gt;<br>    &lt;link rel=&quot;manifest&quot; href=&quot;%PUBLIC_URL%/manifest.json&quot; /&gt;<br>    &lt;title&gt;react-comp-pack&lt;/title&gt;<br>  &lt;/head&gt;<br>  &lt;body&gt;<br>    &lt;noscript&gt;You need to enable JavaScript to run this app.&lt;/noscript&gt;<br>    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;<br>  &lt;/body&gt;<br>&lt;/html&gt;</pre><p>For argument’s sake, here’s the content of manifest.json</p><pre>{<br>  &quot;short_name&quot;: &quot;react-comp-pack&quot;,<br>  &quot;name&quot;: &quot;React Component Package demo app&quot;,<br>  &quot;start_url&quot;: &quot;.&quot;,<br>  &quot;display&quot;: &quot;standalone&quot;,<br>  &quot;theme_color&quot;: &quot;#000000&quot;,<br>  &quot;background_color&quot;: &quot;#ffffff&quot;<br>}</pre><p>And robots.txt</p><pre># <a href="https://www.robotstxt.org/robotstxt.html">https://www.robotstxt.org/robotstxt.html</a><br>User-agent: *<br>Disallow:</pre><p><strong>Step 2: Coding the app</strong></p><p>The project created in the previous article already has index.js and App.js files in src/but I first want to swap out the content of index.js to render the root element declared in public/index.html .</p><p>Here’s the content:</p><pre>import React from &quot;react&quot;;<br>import ReactDOM from &quot;react-dom&quot;;<br>import App from &quot;./App&quot;;</pre><pre>ReactDOM.render(<br>  &lt;React.StrictMode&gt;<br>    &lt;App /&gt;<br>  &lt;/React.StrictMode&gt;,<br>  document.getElementById(&#39;root&#39;)<br>);</pre><p>In App.js , I’m just going to import my library component and render it:</p><pre>import React from &quot;react&quot;;<br>import { MyButton } from &#39;./lib&#39;;</pre><pre>const App = () =&gt; {<br>  return(<br>    &lt;div&gt;<br>      &lt;MyButton btnText={&#39;Demo button&#39;}/&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>The only kink here was to import the component from ./lib , which is interpreted as whatever is exported from lib/index.js because the exports are declared as such in package.json.</p><p><strong>Step 3: Running the app</strong></p><p>I decided to install react-scripts as a quick way to get the app running, but only installing it as devDependency :</p><pre>npm install --save-dev react-scripts</pre><p>Once intalled, you can change the value of scripts.start to call react-scripts’ start command:</p><pre>&quot;scripts&quot;:{<br>  ...<br>  &quot;start&quot;: &quot;npx react-scripts start&quot;<br>}</pre><p>And that should be it, you can run the demo app with</p><pre>npm run start</pre><p>If you’ve never used / installed npx before, you’ll be prompted to install it.</p><p>You’ll also be prompted to allow react-scripts to add default values for browserlist in package.json. Approve that and you can see afterward that the following will be added to package.json:</p><pre>&quot;browserslist&quot;: {<br>  &quot;production&quot;: [<br>    &quot;&gt;0.2%&quot;,<br>    &quot;not dead&quot;,<br>    &quot;not op_mini all&quot;<br>  ],<br>  &quot;development&quot;: [<br>    &quot;last 1 chrome version&quot;,<br>    &quot;last 1 firefox version&quot;,<br>    &quot;last 1 safari version&quot;<br>  ]<br>}</pre><p><em>NOTE: At time of writing, installing react-scripts will throw up a dozen vulnerability warnings but, since I’m only running this app locally, I chose this as the quickest way to get up and running.</em></p><p><strong>Conclusion:</strong></p><p>And boom, you can see and test the library component without needing to publish / import over and over:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/772/1*_LrsZtPkXcycA5Ha34uuKg.png" /></figure><p>In the next article, we’ll expand the library a little and explore options for <a href="https://medium.com/@arfi720/3-ways-to-style-a-reactjs-component-package-b42ba28d4f0f">adding styling to the build</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8ec9f4a5531b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Package React components for npm [1/3]]]></title>
            <link>https://medium.com/@arfi720/package-react-components-for-npm-d22cd2f23b8?source=rss-93b90d2ddd14------2</link>
            <guid isPermaLink="false">https://medium.com/p/d22cd2f23b8</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[npm-publish]]></category>
            <category><![CDATA[react-components]]></category>
            <dc:creator><![CDATA[arfi720]]></dc:creator>
            <pubDate>Wed, 13 Apr 2022 01:20:46 GMT</pubDate>
            <atom:updated>2022-05-01T12:43:24.785Z</atom:updated>
            <content:encoded><![CDATA[<p>A guide to packaging React components for private publication to npm for subsequent re-use in your projects.</p><p><em>Having created a few apps with Create-React-App, then wrestling with upgrades and alternatives to that and react-scripts when moving from webpack v4 to v5, I realised I needed a better understanding of webpack and decided to build up a package of Reactjs components as way to learn more about the build process.</em></p><p>The final code for this guide is on <a href="https://github.com/aroomforimprovement/react-comp-pack/tree/1-tiny-npm-component-package">github</a>:</p><p><strong>Step 1: The easy part</strong></p><p>Webpack recommends a visit to <a href="https://createapp.dev/webpack/">https://createapp.dev/webpack/</a>, a handy online tool that lets you not only generate a webpack.config.js for various purposes, but also provides minimal boiler-plate project files.</p><figure><img alt="Screenshot of createapp.dev interface with React and Babel selected, generating a basic webpack.config.js" src="https://cdn-images-1.medium.com/max/810/1*Zz8SPZn0LTtl1BGdf23_bA.png" /></figure><p>I selected React as my main library, which auto-checked Babel as my transpiler (great, I kept that) and react-hot-loader under the section React (I unchecked react-hot-loader because I’m making a library, not an app and I want to keep it tiny).</p><p>That’s it - download the project like this, extract it to your project directory and open the directory in your favourite IDE (I’m using Visual Code and called my project react-comp-pack)</p><figure><img alt="Screenshot of initial file structure after download from createapp.dev" src="https://cdn-images-1.medium.com/max/165/1*aZDNH1zaGyMhOiczl5fuiA.png" /></figure><p><strong>Step 2: Basic info, package.json</strong></p><p>Let’s edit the basic details of package.json. ( * = important bits)</p><pre>&quot;name&quot;: &quot;react-comp-pack&quot;,<br>&quot;version&quot;: &quot;1.0.6&quot;,<br>&quot;description&quot;: &quot;A package of react components&quot;,<br>&quot;main&quot;: &quot;dist/index.js&quot;,<br>&quot;module&quot;: &quot;dist/index.js&quot;,<br>&quot;files&quot;:[<br>  &quot;dist&quot;,<br>  &quot;README.md&quot;<br>],<br>&quot;keywords&quot;: [<br>  &quot;react&quot;,<br>  &quot;toast&quot;,<br>  &quot;components&quot;<br>],<br>&quot;author&quot;: &quot;arfi720&quot;,<br>&quot;license&quot;: &quot;ISC&quot;,</pre><p>Name it whatever you are naming your package.<br>*Provide a version number (you’ll need to update this each time you want to publish)<br>*Provide main and module entry points (we will change main in a follow up article but I’m setting both to dist/index.js for now)<br>*Provide files array: I only want to include whatever is in the dist directory and the README file.<br>Keywords are more relevant to a publicly published package but why not include some.<br>Author and license are up to you.</p><p><strong>Step 3: Dependencies, (or lack there-of), package.json</strong></p><p>Sticking with package.json but moving swiftly passed the scripts section, I renamed the dependencies object (currently only containing react and react-dom ) to peerDependencies . This means that we don’t want to bundle react up with our build like we would with an app, but we would like whoever is using our package to have react and react-dom as a dependency in their app.</p><pre>&quot;peerDependencies&quot;: {<br>  &quot;react&quot;: &quot;^17.0.0&quot;,<br>  &quot;react-dom&quot;: &quot;^17.0.2&quot;<br>}</pre><p>I lowered the versions to 17 from the auto-generated v18 because I’m just not ready for that yet.</p><p>I’m also adding these same two dependencies to devDependencies so that I can depend on them while developing. With the generated webpack and babel devDependencies, we have this:</p><pre>&quot;devDependencies&quot;: {<br>  &quot;webpack&quot;: &quot;^5.72.0&quot;,<br>  &quot;webpack-cli&quot;: &quot;^4.9.2&quot;,<br>  &quot;@babel/preset-react&quot;: &quot;^7.16.7&quot;,<br>  &quot;babel-loader&quot;: &quot;^8.2.4&quot;,<br>  &quot;@babel/core&quot;: &quot;^7.17.9&quot;,<br>  &quot;@babel/preset-env&quot;: &quot;^7.16.11&quot;,<br>  &quot;react&quot;: &quot;^17.0.0&quot;,<br>  &quot;react-dom&quot;: &quot;^17.0.2&quot;<br>}</pre><p><strong>Step 4: Entry and Output (oh my), webpack.config.js</strong></p><p>In terms of trying to build a package, not an app, this is probably the most important part. Paths are arbitrary but it’s best to keep to standard practice, which seems to be having an entry point ./src/lib/index.js , because we’re going to put everything we want to export inside src/lib/ .</p><p>The output object should contain path , filename (I changed mine from bundle.js to index.js because my package.json’s module value is going to look for src/dist/index.js ), library (I’ve included one component name, you can include an array of multiple as well), libraryTarget , and publicPath — mostly self-explanatory.</p><pre>entry: &#39;./src/lib/index.js&#39;,<br>output: {<br>  path: path.resolve(__dirname, &#39;dist&#39;),<br>  filename: &#39;index.js&#39;,<br>  library: &#39;MyButton&#39;,<br>  libraryTarget: &#39;umd&#39;,<br>  publicPath: &#39;/dist&#39;<br>},</pre><p>While we’re here, the only other things I’m adding to webpack.config.js are the externals and resolve.alias objects that help the build know to look for react and react-dom.</p><pre>externals: {<br>  react: {<br>    commonjs: &quot;react&quot;,<br>    commonjs2: &quot;react&quot;,<br>    amd: &quot;React&quot;,<br>    root: &quot;React&quot;<br>  },<br>  &quot;react-dom&quot;: {<br>    commonjs: &quot;react-dom&quot;,<br>    commonjs2: &quot;react-dom&quot;,<br>    amd: &quot;ReactDOM&quot;,<br>    root: &quot;ReactDOM&quot;<br>  }<br>},<br>resolve: {<br>  alias: {<br>    &#39;react&#39;: path.resolve(__dirname, &#39;./node_modules/react&#39;),<br>    &#39;react-dom&#39;: path.resolve(__dirname, &#39;./node_modules/react-dom&#39;),<br>  }<br>},</pre><p><strong>Step 5: Ignorance is bliss, .npmignore / .gitignore</strong></p><p>If you don’t include an .npmignore file, npm will use your .gitignore, so best to include one — here’s the content of mine:</p><pre>webpack.config.js<br>.eslintrc<br>.gitignore<br>.babelrc</pre><p>Come to think of it, the auto-generated .gitignore is pretty bare, so you might want to update that, assuming you’re creating a repository for your package project (you should definitely be doing that)</p><p>The main thing I wanted to change was</p><pre>dist/*<br>!dist/index.html</pre><p>to</p><p>dist/</p><p>Just because I won’t be having and index html in there.</p><p><strong>Step 6: Shouldn’t we have some code to build?</strong></p><p>Fair.</p><p>We’ve declared src/lib/index.js as our entry point already, so I created that directory and file for a start.</p><p>Then I created a directory src/lib/components/ with a file called Button.js</p><p>Here’s the content:</p><pre>import React from &#39;react&#39;;</pre><pre>export const Button = ({btnText}) =&gt; {<br>  return(<br>    &lt;button onClick={() =&gt; {console.log(&quot;It worked!&quot;)}}&gt;<br>      {btnText}<br>    &lt;/button&gt;<br>  )<br>}</pre><p>Inspirational stuff. Here’s the content of src/lib/index.js</p><pre>import { Button } from &#39;./components/Button&#39;;<br>export const MyButton = Button;</pre><p>Here, we’re simply exporting and aliasing the components we want to be available to the module users. (Remember the output.library property from Step 4? That’s where the alias comes in)</p><p><strong>Step 7: Building the thing, package.json</strong></p><p>Before put the finishing touches on package.json, because I’m on a Windows machine and most scripts you find online are Unix flavoured, I added another devDependency to help with this:</p><p>npm install --save-dev run-script-os</p><p>Then I added the following prepublish and buildcommands to the scripts object in package.json</p><pre>&quot;prepublish&quot;: &quot;run-script-os&quot;,<br>&quot;prepublish:darwin:linux&quot;: &quot;rm -rf ./dist &amp;&amp; npm run build&quot;,<br>&quot;prepublish:win32&quot;: &quot;rmdir /s dist &amp;&amp; npm run build&quot;,<br>&quot;build&quot;: &quot;webpack --mode development&quot;,</pre><p>The run-script-os library just takes care of running either the powershell or unix shell version of the same rm command, before running the build command. I’m building in development mode because I’m in development but you can change this according to your needs.</p><p><strong>Step 7 and a half: Darn it</strong></p><p>I thought I was done but because I lowered the versions of react and react-dom at the beginning from the auto-generated v18, down to v17, the code the auto-generated App.js had errors on build, so I’ve just replace the contents with:</p><pre>import React from &quot;react&quot;;<br>const App = () =&gt; {<br>}<br>export default App;</pre><p>The next article will implement a demo app with this file which is why I’m leaving it here at all.</p><p><strong>Step 8: Actually building the thing</strong></p><p>Run the prepublish command to build the libary:</p><p>npm run prepublish</p><p>Then run</p><pre>npm publish --tag beta<br>#you can remove --tag beta when you are ready to go public</pre><p>At this point, you may get an error because you don’t have an account with npm — create an account and try again. That should do it.</p><p><strong>Step 9: omg omg omg, testing</strong></p><p>Open or create another, working react app and install your new component libary</p><p>npm install react-comp-pack@1.0.0</p><p>or</p><p>yarn add react-comp-pack@1.0.0</p><p>I’ve imported and used my button component like this:</p><pre>import { MyButton } from &#39;react-comp-pack&#39;<br>export const App = () =&gt; {<br>  return(<br>    &lt;div&gt;<br>      &lt;MyButton btnText={&quot;My New Button&quot;}/&gt;<br>    &lt;/div&gt;<br>  )<br>}</pre><p>Running the new app, I get a button. When I click the button, it works. <br>I know it works because it tells me so:</p><figure><img alt="Screenshot of working button and console log" src="https://cdn-images-1.medium.com/proxy/1*bh3wOTr6xgvGlm9_jRWXUQ.png" /></figure><p><strong>Conclusion:</strong></p><p>This guide showed you how to privately publish a super-simple react component library. In further articles we’ll go through <a href="https://medium.com/@arfi720/demo-app-for-development-of-react-component-library-8ec9f4a5531b">adding a demo app to the same project</a>, so you can actually test without constantly publishing a new version and, later, how to add further elements to the build, like <a href="https://medium.com/@arfi720/3-ways-to-style-a-reactjs-component-package-b42ba28d4f0f">options for styling</a> and some more complex functionality.</p><p>References:</p><p><a href="https://docs.npmjs.com/creating-node-js-modules"><strong>Creating Node.js modules | npm Docs</strong><br><em>Node.js modules are a type of package that can be published to npm. Create a package.json file Create the file that…</em>docs.npmjs.com</a></p><p><a href="https://itnext.io/how-to-package-your-react-component-for-distribution-via-npm-d32d4bf71b4f"><strong>How to package your React Component for distribution via NPM</strong><br><em>I wrote a React component, transpiling using Babel, bundling and building using Webpack. I wanted to use it in another…</em>itnext.io</a></p><p><a href="https://levelup.gitconnected.com/publish-react-components-as-an-npm-package-7a671a2fb7f"><strong>Publish React components as an npm package</strong><br><em>This article will review how to publish React components as an npm package with Babel 7 (the latest version at the time…</em>levelup.gitconnected.com</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d22cd2f23b8" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>