<?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0" 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" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
    <channel>
      <title>Leon Radley</title>
      <description>Articles by Leon Radley</description>
      <link>https://leonradley.com</link>
      <atom:link href="https://leonradley.com/rss.xml" rel="self" type="application/rss+xml" />
      <language>en</language>
      <sy:updatePeriod>weekly</sy:updatePeriod>
      <lastBuildDate>Wed, 16 Jul 2025 06:08:40 GMT</lastBuildDate>
      <item>
      <guid>https://leonradley.com/articles/svelte/2025-07-font-awesome-icons</guid>
      <link>https://leonradley.com/articles/svelte/2025-07-font-awesome-icons</link>
      <title>Svelte &amp; Font Awesome Icons</title>
      <pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate>
      <category>svelte</category>
      <description><![CDATA[How to best integrate Font Awesome icons with Svelte.]]></description>
      <content><![CDATA[<!--[--><p>I needed a way to use Font Awesome with Svelte / SvelteKit.</p> <p>The Font Awesome docs did not have a Svelte example, so I set out to build my own.</p> <p>The criteria I wanted for the implementation were:</p> <ul><li>One-line import for icons</li> <li>Compatible with Tailwind</li> <li>Easily extendable</li> <li>Should work with both free and pro versions</li></ul> <h3>Dependencies</h3> <p>To start out, we need Font Awesome.
You can add whatever Font Awesome icon packs you want.</p> <pre class="language-bash"><!----><code class="language-bash"><span class="token function">pnpm</span> <span class="token function">add</span> @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/free-brands-svg-icons</code><!----></pre> <h3>Font Component</h3> <p>The Svelte component below uses <code>@fortawesome/fontawesome-svg-core</code> to render SVG icons, removes the default Font Awesome CSS, and passes Tailwind classes to the SVG element.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// lib/icon/icon.svelte</span>

<span class="token operator">&lt;</span>svelte<span class="token operator">:</span>options namespace<span class="token operator">=</span><span class="token string">"svg"</span> <span class="token operator">/</span><span class="token operator">></span>

<span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span> module<span class="token operator">></span>
	<span class="token comment">// Configure font awesome</span>
	<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> config<span class="token punctuation">,</span> <span class="token keyword">type</span> <span class="token class-name">IconDefinition</span> <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'@fortawesome/fontawesome-svg-core'</span><span class="token punctuation">;</span>
	config<span class="token punctuation">.</span>autoAddCss <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
	config<span class="token punctuation">.</span>keepOriginalSource <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
	config<span class="token punctuation">.</span>showMissingIcons <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
	<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> icon <span class="token keyword">as</span> iconRender <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'@fortawesome/fontawesome-svg-core'</span><span class="token punctuation">;</span>

	<span class="token keyword">interface</span> <span class="token class-name">IconProps</span> <span class="token punctuation">&#123;</span>
		icon<span class="token operator">:</span> IconDefinition<span class="token punctuation">;</span>
		<span class="token keyword">class</span><span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
	<span class="token punctuation">&#125;</span>
	<span class="token keyword">let</span> <span class="token punctuation">&#123;</span> icon<span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token operator">:</span> className <span class="token punctuation">&#125;</span><span class="token operator">:</span> IconProps <span class="token operator">=</span> <span class="token function">$props</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">let</span> iconRendered <span class="token operator">=</span> <span class="token function">$derived</span><span class="token punctuation">(</span>
		<span class="token function">iconRender</span><span class="token punctuation">(</span>icon<span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
			classes<span class="token operator">:</span> className <span class="token operator">?</span> <span class="token punctuation">[</span>className<span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
		<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span>html
	<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> eslint<span class="token operator">-</span>disable svelte<span class="token operator">/</span>no<span class="token operator">-</span>at<span class="token operator">-</span>html<span class="token operator">-</span>tags <span class="token operator">--</span><span class="token operator">></span>
<span class="token punctuation">&#123;</span><span class="token decorator"><span class="token at operator">@</span><span class="token function">html</span></span> iconRendered<span class="token punctuation">&#125;</span>
</code><!----></pre> <p>We then need a tiny bit of css to set the defaults.</p> <pre class="language-css"><!----><code class="language-css">// lib/icon/icon.css

<span class="token atrule"><span class="token rule">@layer</span> base</span> <span class="token punctuation">&#123;</span>
  <span class="token selector">.svg-inline--fa</span> <span class="token punctuation">&#123;</span>
    <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span>
    <span class="token property">overflow</span><span class="token punctuation">:</span> visible<span class="token punctuation">;</span>
    <span class="token property">vertical-align</span><span class="token punctuation">:</span> -0.125em<span class="token punctuation">;</span>
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span></code><!----></pre> <pre class="language-css"><!----><code class="language-css">// app.css
<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'tailwindcss'</span><span class="token punctuation">;</span></span>
<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'./lib/icon/icon.css'</span><span class="token punctuation">;</span></span></code><!----></pre> <h2>The export file</h2> <p>An <code>index.ts</code> file exports all the icons you want to have available, as well as the <code>icon.svelte</code> component created above.</p> <p>I will also explain below why we export the <code>IconDefinition</code> type.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// /lib/icon/index.ts</span>

<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">&#123;</span> IconDefinition <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'@fortawesome/fontawesome-svg-core'</span>
<span class="token keyword">export</span> <span class="token keyword">type</span> <span class="token punctuation">&#123;</span> IconDefinition <span class="token punctuation">&#125;</span>

<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">'@fortawesome/free-solid-svg-icons'</span>

<span class="token keyword">export</span> <span class="token punctuation">&#123;</span>
  faFacebook<span class="token punctuation">,</span>
  faInstagram<span class="token punctuation">,</span>
  faLinkedin<span class="token punctuation">,</span>
  faVimeo<span class="token punctuation">,</span>
  faYoutube<span class="token punctuation">,</span>
<span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'@fortawesome/free-brands-svg-icons'</span>

<span class="token keyword">export</span> <span class="token punctuation">&#123;</span> <span class="token keyword">default</span> <span class="token keyword">as</span> Icon <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'./icon.svelte'</span></code><!----></pre> <h2>How to use it</h2> <p>Since we have exported all the free icons plus a few from the brands, we only need a single import from <code>$lib/icon</code>:</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
	<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> Icon<span class="token punctuation">,</span> faGrimace<span class="token punctuation">,</span> faLaughWink<span class="token punctuation">,</span> faSmile <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'$lib/icon'</span><span class="token punctuation">;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>Icon icon<span class="token operator">=</span><span class="token punctuation">&#123;</span>faSmile<span class="token punctuation">&#125;</span> <span class="token operator">/</span><span class="token operator">></span> The simplest icon will use the inherited font size<span class="token punctuation">.</span>
<span class="token operator">&lt;</span>Icon <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"text-2xl"</span> icon<span class="token operator">=</span><span class="token punctuation">&#123;</span>faGrimace<span class="token punctuation">&#125;</span> <span class="token operator">/</span><span class="token operator">></span> Use Tailwind to override the font size<span class="token punctuation">,</span> making it bigger<span class="token punctuation">.</span>
<span class="token operator">&lt;</span>Icon <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"text-[48px] text-red-600"</span> icon<span class="token operator">=</span><span class="token punctuation">&#123;</span>faLaughWink<span class="token punctuation">&#125;</span> <span class="token operator">/</span><span class="token operator">></span> Set a specific size and color<span class="token punctuation">.</span>
</code><!----></pre> <h2>How to pass icons as props</h2> <p>By typing a prop as <code>IconDefinition</code>, we can pass the exported icons to it.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// lib/icon-button.svelte</span>

<span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
  <span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">&#123;</span> Snippet <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'svelte'</span>
  <span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">&#123;</span> HTMLButtonAttributes <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'svelte/elements'</span>
  <span class="token keyword">import</span> <span class="token punctuation">&#123;</span> Icon<span class="token punctuation">,</span> <span class="token keyword">type</span> <span class="token class-name">IconDefinition</span> <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'$lib/icon'</span>

  <span class="token keyword">interface</span> <span class="token class-name">IconButtonProps</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLButtonAttributes</span> <span class="token punctuation">&#123;</span>
    icon<span class="token operator">:</span> IconDefinition
    children<span class="token operator">:</span> Snippet
  <span class="token punctuation">&#125;</span>
  <span class="token keyword">let</span> <span class="token punctuation">&#123;</span> icon<span class="token punctuation">,</span> children<span class="token punctuation">,</span> <span class="token keyword">class</span><span class="token operator">:</span> className<span class="token punctuation">,</span> <span class="token operator">...</span>props <span class="token punctuation">&#125;</span><span class="token operator">:</span> IconButtonProps <span class="token operator">=</span> <span class="token function">$props</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>button
  type<span class="token operator">=</span><span class="token string">"button"</span>
  <span class="token punctuation">&#123;</span><span class="token operator">...</span>props<span class="token punctuation">&#125;</span>
  <span class="token keyword">class</span><span class="token operator">=</span><span class="token punctuation">[</span>
		<span class="token string">'flex items-center justify-between gap-2'</span><span class="token punctuation">,</span>
		<span class="token string">'rounded-lg bg-neutral-200 px-4 py-2 hover:bg-neutral-300'</span><span class="token punctuation">,</span>
		className
	<span class="token punctuation">]</span>
<span class="token operator">></span>
  <span class="token operator">&lt;</span>Icon <span class="token punctuation">&#123;</span>icon<span class="token punctuation">&#125;</span> <span class="token operator">/</span><span class="token operator">></span>
  <span class="token punctuation">&#123;</span><span class="token decorator"><span class="token at operator">@</span><span class="token function">render</span></span> <span class="token function">children</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span>
</code><!----></pre> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// routes/+page.svelte</span>

<span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
  <span class="token keyword">import</span> IconButton <span class="token keyword">from</span> <span class="token string">'$lib/icon-button.svelte'</span><span class="token punctuation">;</span>
  <span class="token keyword">import</span> <span class="token punctuation">&#123;</span> faSmile <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'$lib/icon'</span><span class="token punctuation">;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>IconButton icon<span class="token operator">=</span><span class="token punctuation">&#123;</span>faSmile<span class="token punctuation">&#125;</span><span class="token operator">></span>My Button<span class="token operator">&lt;</span><span class="token operator">/</span>IconButton<span class="token operator">></span></code><!----></pre> <h2>Demo</h2> <p>I have created a demo to showcase how it works:</p> <p><a href="https://github.com/leon/blog-svelte-fontawesome-icons" rel="nofollow">https://github.com/leon/blog-svelte-fontawesome-icons</a></p> <h2>Font Awesome 7</h2> <p>Font Awesome 7 is going to be released in July 2025, bringing many new icons and improved designs.
All SVGs are now square (512x512), ensuring consistent spacing and alignment.
Keep an eye out here: <a href="https://fontawesome.com/" rel="nofollow">https://fontawesome.com/</a></p><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/svelte/2025-07-prevent-default-util</guid>
      <link>https://leonradley.com/articles/svelte/2025-07-prevent-default-util</link>
      <title>event.preventDefault utility</title>
      <pubDate>Sun, 06 Jul 2025 00:00:00 GMT</pubDate>
      <category>svelte</category>
      <description><![CDATA[for less boilerplate in your event handlers and reusable functions.]]></description>
      <content><![CDATA[<!--[--><p>Having a way to wrap your event handlers in some code can come in handy when you want to:</p> <ul><li>preventDefault</li> <li>Add logging</li> <li>Send metrics</li></ul> <pre class="language-ts"><!----><code class="language-ts"><span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
  <span class="token keyword">const</span> preventDefault <span class="token operator">=</span> <span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">Event</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token function-variable function">handler</span><span class="token operator">:</span> <span class="token punctuation">(</span>event<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>event<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
      event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token function">handler</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">onClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span>event<span class="token operator">:</span> MouseEvent<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
    <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Button clicked!'</span><span class="token punctuation">,</span> event<span class="token punctuation">)</span>
  <span class="token punctuation">&#125;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>button onclick<span class="token operator">=</span><span class="token punctuation">&#123;</span><span class="token function">preventDefault</span><span class="token punctuation">(</span>onClick<span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span class="token operator">></span>Button<span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">></span></code><!----></pre><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/svelte/2025-07-svelte-breadcrumbs</guid>
      <link>https://leonradley.com/articles/svelte/2025-07-svelte-breadcrumbs</link>
      <title>SvelteKit Breadcrumbs</title>
      <pubDate>Sun, 06 Jul 2025 00:00:00 GMT</pubDate>
      <category>svelte</category><category>sveltekit</category>
      <description><![CDATA[How to implement breadcrumbs in sveltekit.]]></description>
      <content><![CDATA[<!--[--><p>I needed a simple way to have breadcrumbs in sveltekit.</p> <p>SvelteKit is very simple in its routing, and does not store the whole router tree, which makes the job of creating a solid breadcrumb implementation a bit more challenging.</p> <p>I chose to implement this as simple as possible. Which ended up being a method you call in the <code>+layout.svelte</code> and <code>+page.svelte</code> files you want to add to your breadcrumbs.</p> <p>The downside of this implementation is that it only works clientside because it uses <code>$effect</code> to track when a breadcrumb should be added and removed.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// lib/breadcrumb-state.svelte.ts</span>

<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> SvelteMap <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'svelte/reactivity'</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">Breadcrumb</span> <span class="token punctuation">&#123;</span>
  path<span class="token operator">:</span> <span class="token builtin">string</span>
  name<span class="token operator">:</span> <span class="token builtin">string</span>
<span class="token punctuation">&#125;</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">BreadcrumbInternal</span> <span class="token keyword">extends</span> <span class="token class-name">Breadcrumb</span> <span class="token punctuation">&#123;</span>
  count<span class="token operator">:</span> <span class="token builtin">number</span>
<span class="token punctuation">&#125;</span>

<span class="token keyword">const</span> breadcrumbMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SvelteMap<span class="token operator">&lt;</span><span class="token builtin">string</span><span class="token punctuation">,</span> BreadcrumbInternal<span class="token operator">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> breadcrumbs<span class="token operator">:</span> Breadcrumb<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> $derived<span class="token punctuation">.</span><span class="token function">by</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span>
  <span class="token builtin">Array</span><span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>breadcrumbMap<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toSorted</span><span class="token punctuation">(</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token operator">=></span> a<span class="token punctuation">.</span>count <span class="token operator">-</span> b<span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> getBreadcrumbs <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Breadcrumb<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=></span> breadcrumbs

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">setBreadcrumb</span><span class="token punctuation">(</span>item<span class="token operator">:</span> Breadcrumb<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
  <span class="token function">$effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
    breadcrumbMap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>path<span class="token punctuation">,</span> <span class="token punctuation">&#123;</span> <span class="token operator">...</span>item<span class="token punctuation">,</span> count<span class="token operator">:</span> item<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
      breadcrumbMap<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>path<span class="token punctuation">)</span>
    <span class="token punctuation">&#125;</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span></code><!----></pre> <p>The magic happens in the <code>setBreadcrumb</code> function.
We create a child effect which will get disposed of when the component that calls setBreadcrumb is destroyed.</p> <h3>They way we use it</h3> <pre class="language-ts"><!----><code class="language-ts"><span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
  <span class="token keyword">import</span> <span class="token punctuation">&#123;</span> setBreadcrumb <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'$lib/breadcrumb-state.svelte'</span>
  <span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">&#123;</span> LayoutProps <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'./$types'</span>

  <span class="token keyword">const</span> <span class="token punctuation">&#123;</span> children <span class="token punctuation">&#125;</span><span class="token operator">:</span> LayoutProps <span class="token operator">=</span> <span class="token function">$props</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token function">setBreadcrumb</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
    name<span class="token operator">:</span> <span class="token string">'Level 1'</span><span class="token punctuation">,</span>
    path<span class="token operator">:</span> <span class="token string">'/level-1/'</span><span class="token punctuation">,</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token punctuation">&#123;</span><span class="token decorator"><span class="token at operator">@</span><span class="token function">render</span></span> <span class="token function">children</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#125;</span></code><!----></pre> <h3>And to render the breadcrumbs</h3> <pre class="language-ts"><!----><code class="language-ts"><span class="token operator">&lt;</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
  <span class="token keyword">import</span> <span class="token punctuation">&#123;</span> getBreadcrumbs <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'./breadcrumb-state.svelte'</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">></span>

<span class="token operator">&lt;</span>nav <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"breadcrumbs text-sm"</span><span class="token operator">></span>
  <span class="token operator">&lt;</span>ul<span class="token operator">></span>
    <span class="token punctuation">&#123;</span>#each <span class="token function">getBreadcrumbs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token function">breadcrumb</span> <span class="token punctuation">(</span>breadcrumb<span class="token punctuation">.</span>path<span class="token punctuation">)</span><span class="token punctuation">&#125;</span>
      <span class="token operator">&lt;</span>li<span class="token operator">></span><span class="token operator">&lt;</span>a href<span class="token operator">=</span><span class="token punctuation">&#123;</span>breadcrumb<span class="token punctuation">.</span>path<span class="token punctuation">&#125;</span><span class="token operator">></span><span class="token punctuation">&#123;</span>breadcrumb<span class="token punctuation">.</span>name<span class="token punctuation">&#125;</span><span class="token operator">&lt;</span><span class="token operator">/</span>a<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span>li<span class="token operator">></span>
    <span class="token punctuation">&#123;</span><span class="token operator">/</span>each<span class="token punctuation">&#125;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>ul<span class="token operator">></span>
<span class="token operator">&lt;</span><span class="token operator">/</span>nav<span class="token operator">></span>
</code><!----></pre> <p>I have created a demo to showcase how it works here:</p> <p><a href="https://github.com/leon/blog-sveltekit-breadcrumbs" rel="nofollow">https://github.com/leon/blog-sveltekit-breadcrumbs</a></p><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/rxjs/2025-07-global-rate-limit</guid>
      <link>https://leonradley.com/articles/rxjs/2025-07-global-rate-limit</link>
      <title>RxJS Global Rate Limit</title>
      <pubDate>Sat, 05 Jul 2025 00:00:00 GMT</pubDate>
      <category>rxjs</category><category>typescript</category>
      <description><![CDATA[How to implement a global rate limit operator using rxjs.]]></description>
      <content><![CDATA[<!--[--><h3>RxJS Global Rate Limit</h3> <p>At work we are building an integration against a third party API that has a rate limit of 200 requests per minute.
The API was paginated and the response did not contain all data, so a request to each item was required.</p> <p>The following code will show you how this could be solved using rxjs.</p> <p>Lets get started!</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">&#123;</span>
  BehaviorSubject<span class="token punctuation">,</span>
  filter<span class="token punctuation">,</span>
  map<span class="token punctuation">,</span>
  mergeMap<span class="token punctuation">,</span>
  MonoTypeOperatorFunction<span class="token punctuation">,</span>
  Observable<span class="token punctuation">,</span>
  take<span class="token punctuation">,</span>
  timer<span class="token punctuation">,</span>
<span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'rxjs'</span>

<span class="token comment">// global variables</span>
<span class="token keyword">let</span> tokens <span class="token operator">=</span> <span class="token number">200</span>
<span class="token keyword">let</span> slidingWindowTime <span class="token operator">=</span> <span class="token number">60_000</span>
<span class="token keyword">let</span> tokenChangedSubject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BehaviorSubject</span><span class="token punctuation">(</span>tokens<span class="token punctuation">)</span>

<span class="token comment">/**
 * Rate limit observable to x number of requests withing the slidingWindowTime
 *
 * @param parallel number of requests to run in parallel
 * @param slidingWindowTime time in milliseconds for how many requests can be run within
 * @returns rate limited observable
 */</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token generic-function"><span class="token function">globalRateLimit</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">></span></span></span><span class="token punctuation">(</span>setOptions<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">&#123;</span>
  parallel<span class="token operator">:</span> <span class="token builtin">number</span>
  slidingWindowTime<span class="token operator">:</span> <span class="token builtin">number</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token operator">:</span> MonoTypeOperatorFunction<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">></span> <span class="token punctuation">&#123;</span>
  <span class="token comment">// initialize at first or at options reset</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>setOptions<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    tokens <span class="token operator">=</span> parallel <span class="token operator">??</span> <span class="token number">200</span>
    slidingWindowTime <span class="token operator">=</span> setOptions<span class="token punctuation">.</span>slidingWindowTime <span class="token operator">??</span> <span class="token number">60_000</span>
    tokenChangedSubject<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>tokens<span class="token punctuation">)</span>
  <span class="token punctuation">&#125;</span>

  <span class="token keyword">const</span> <span class="token function-variable function">consumeToken</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> tokenChangedSubject<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token operator">--</span>tokens<span class="token punctuation">)</span>
  <span class="token keyword">const</span> <span class="token function-variable function">renewToken</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> tokenChangedSubject<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token operator">++</span>tokens<span class="token punctuation">)</span>
  <span class="token keyword">const</span> availableTokens <span class="token operator">=</span> tokenChangedSubject<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> tokens <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token keyword">return</span> <span class="token generic-function"><span class="token function">mergeMap</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token punctuation">,</span> Observable<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">>></span></span></span><span class="token punctuation">(</span><span class="token punctuation">(</span>value<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    availableTokens<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
      <span class="token function">take</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
        <span class="token function">consumeToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token function">timer</span><span class="token punctuation">(</span>slidingWindowTime<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>renewToken<span class="token punctuation">)</span>
        <span class="token keyword">return</span> value
      <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span></code><!----></pre> <h2>How to use it</h2> <pre class="language-ts"><!----><code class="language-ts"><span class="token keyword">const</span> source$ <span class="token operator">=</span> <span class="token keyword">of</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span>
source$
  <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">globalRateLimit</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> parallel<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> slidingWindowTime<span class="token operator">:</span> <span class="token number">1000</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token comment">// output</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
<span class="token comment">// wait for 1000ms</span>
<span class="token comment">// 3</span>
<span class="token comment">// 4</span>
<span class="token comment">// wait for 1000ms</span>
<span class="token comment">// 5</span>
<span class="token comment">// 6</span>
<span class="token comment">// complete</span></code><!----></pre> <h2>What good does it do having it as a global rate limit?</h2> <p>Because if you have multiple observable streams that both need to listen to the same limit, you can in the first call configure the limit,
and in subsequent calls just use the pipe.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token keyword">interface</span> <span class="token class-name">Page</span> <span class="token punctuation">&#123;</span>
  page<span class="token operator">:</span> <span class="token builtin">number</span>
  totalPages<span class="token operator">:</span> <span class="token builtin">number</span>
  items<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">const</span> pageRequest <span class="token operator">=</span> <span class="token punctuation">(</span>page<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span>Page<span class="token operator">></span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
  <span class="token keyword">return</span> <span class="token keyword">of</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
    page<span class="token punctuation">,</span>
    totalPages<span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span>
    items<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
    <span class="token comment">// the page requests should be rate limited</span>
    <span class="token function">globalRateLimit</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> parallel<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> slidingWindowTime<span class="token operator">:</span> <span class="token number">1000</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">// a stream of page responses, where we comply to the rate limit</span>
<span class="token keyword">const</span> pages$ <span class="token operator">=</span> <span class="token function">pageRequest</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
  <span class="token function">expand</span><span class="token punctuation">(</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token operator">=></span>
    response<span class="token punctuation">.</span>page <span class="token operator">&lt;</span> response<span class="token punctuation">.</span>totalPages <span class="token operator">?</span> <span class="token function">pageRequest</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>page <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token constant">EMPTY</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>

<span class="token comment">// now we want a stream of all items in the pages</span>
<span class="token comment">// so we flatten the page.items into a stream of items</span>
<span class="token keyword">const</span> items$ <span class="token operator">=</span> pages$<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">concatMap</span><span class="token punctuation">(</span><span class="token punctuation">(</span>page<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">from</span><span class="token punctuation">(</span>page<span class="token punctuation">.</span>items<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token comment">// now we want to call the api and get each item and still keep to the rate limit</span>
<span class="token keyword">interface</span> <span class="token class-name">Item</span> <span class="token punctuation">&#123;</span>
  id<span class="token operator">:</span> <span class="token builtin">number</span>
  name<span class="token operator">:</span> <span class="token builtin">string</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">const</span> itemRequest <span class="token operator">=</span> <span class="token punctuation">(</span>item<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span>Item<span class="token operator">></span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
  <span class="token comment">// fake api call that simulates taking 50ms to complete</span>
  <span class="token keyword">return</span> <span class="token keyword">of</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
    id<span class="token operator">:</span> item<span class="token punctuation">,</span>
    name<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">&#96;</span><span class="token string">item </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">$&#123;</span>item<span class="token interpolation-punctuation punctuation">&#125;</span></span><span class="token template-punctuation string">&#96;</span></span><span class="token punctuation">,</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">delay</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span>

<span class="token keyword">const</span> items$ <span class="token operator">=</span> items$<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
  <span class="token function">globalRateLimit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token function">concatMap</span><span class="token punctuation">(</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">itemRequest</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>

<span class="token comment">// will get all pages, then call itemRequest for each item in page.items</span>
<span class="token comment">// and all of this will be rate limited to 200 requests per minute</span>
items$<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span></code><!----></pre> <h2>Conclusion</h2> <p>There are a lot of complex situations that can be solved with rxjs.
I hope this might help someone in the same situation.</p> <p>Happy coding!</p><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/web-components/2022-02-vite-lit-storybook</guid>
      <link>https://leonradley.com/articles/web-components/2022-02-vite-lit-storybook</link>
      <title>Vite, Lit and Storybook</title>
      <pubDate>Sun, 13 Feb 2022 00:00:00 GMT</pubDate>
      <category>web-components</category><category>vite</category><category>lit</category><category>storybook</category>
      <description><![CDATA[How to use Vite, Lit and Storybook to build stand alone web components and publish them to NPM]]></description>
      <content><![CDATA[<!--[--><p>At work we wanted to build some simple web components to publish to NPM.</p> <p>I was thinking about writing plain web components, but there is a lot of boiler plate, therefor I chose <a href="https://lib.dev" rel="nofollow">Lit</a> for the job. And <a href="https://vitejs.dev" rel="nofollow">Vite</a> for development and packaging.</p> <h3>Setup new Vite project</h3> <p>We start by setting up a new Vite project.</p> <pre class="language-bash"><!----><code class="language-bash"><span class="token function">npm</span> create vite@latest my-webcomponents -- <span class="token parameter variable">--template</span> lit-ts</code><!----></pre> <h3>Install Storybook</h3> <pre class="language-bash"><!----><code class="language-bash">npx sb@latest init <span class="token parameter variable">--builder</span> storybook-builder-vite</code><!----></pre> <h3>Vite config changes</h3> <p>In our case we wanted to be able to use the web components as a stand alone package. the default config externalizes <code>lit</code>. so we have to comment that out.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// vite.config.js</span>
<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> defineConfig <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'vite'</span>

<span class="token comment">// https://vitejs.dev/config/</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
  build<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
    lib<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      entry<span class="token operator">:</span> <span class="token string">'src/my-element.ts'</span><span class="token punctuation">,</span>
      formats<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'es'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
    rollupOptions<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
      <span class="token comment">// If we want to publish standalone components we don't externalize lit,</span>
      <span class="token comment">// if you are going to use lit in your own project, you can make it a dep instead.</span>
      <span class="token comment">// external: /^lit/, &lt;-- comment this line</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span></code><!----></pre> <h3>Typescript config changes</h3> <p>Because we have added storybook we need to exclude <code>.stories.ts</code> files from the typescript compilation, otherwise when we publish to NPM they will be included.</p> <pre class="language-json"><!----><code class="language-json"><span class="token comment">// tsconfig.json</span>
<span class="token punctuation">&#123;</span>
  <span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">&#123;</span>
    <span class="token property">"module"</span><span class="token operator">:</span> <span class="token string">"esnext"</span><span class="token punctuation">,</span>
    <span class="token property">"lib"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"es2017"</span><span class="token punctuation">,</span> <span class="token string">"dom"</span><span class="token punctuation">,</span> <span class="token string">"dom.iterable"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"declaration"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"emitDeclarationOnly"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"outDir"</span><span class="token operator">:</span> <span class="token string">"./types"</span><span class="token punctuation">,</span>
    <span class="token property">"strict"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"noUnusedLocals"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"noUnusedParameters"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"noImplicitReturns"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"noFallthroughCasesInSwitch"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"moduleResolution"</span><span class="token operator">:</span> <span class="token string">"node"</span><span class="token punctuation">,</span>
    <span class="token property">"allowSyntheticDefaultImports"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"experimentalDecorators"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"forceConsistentCasingInFileNames"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"useDefineForClassFields"</span><span class="token operator">:</span> <span class="token boolean">false</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
  <span class="token property">"include"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"src/**/*.ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token property">"exclude"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"src/**/*.stories.ts"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// &lt;-- this is the line we need to add</span>
  <span class="token property">"references"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">&#123;</span> <span class="token property">"path"</span><span class="token operator">:</span> <span class="token string">"./tsconfig.node.json"</span> <span class="token punctuation">&#125;</span><span class="token punctuation">]</span>
<span class="token punctuation">&#125;</span></code><!----></pre> <h3>Storybook config changes</h3> <p>The storybook config needs to tweak the vite config for <code>storybook-builder-vite</code> to work.
We need to include and exclude some packages from the vite config.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token comment">// .storybook/main.js</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">&#123;</span>
  stories<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'../src/**/*.stories.mdx'</span><span class="token punctuation">,</span> <span class="token string">'../src/**/*.stories.@(js|jsx|ts|tsx)'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  addons<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'@storybook/addon-links'</span><span class="token punctuation">,</span> <span class="token string">'@storybook/addon-essentials'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  framework<span class="token operator">:</span> <span class="token string">'@storybook/web-components'</span><span class="token punctuation">,</span>
  core<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
    builder<span class="token operator">:</span> <span class="token string">'storybook-builder-vite'</span><span class="token punctuation">,</span>
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
  <span class="token keyword">async</span> <span class="token function">viteFinal</span><span class="token punctuation">(</span>config<span class="token punctuation">,</span> <span class="token punctuation">&#123;</span> configType <span class="token punctuation">&#125;</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// customize the Vite config here</span>
    config<span class="token punctuation">.</span>optimizeDeps<span class="token punctuation">.</span>include <span class="token operator">=</span> <span class="token punctuation">[</span>
      <span class="token operator">...</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>optimizeDeps<span class="token operator">?.</span>include <span class="token operator">??</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token string">'@storybook/web-components'</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span>
    config<span class="token punctuation">.</span>optimizeDeps<span class="token punctuation">.</span>exclude <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>optimizeDeps<span class="token operator">?.</span>exclude <span class="token operator">??</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'lit'</span><span class="token punctuation">,</span> <span class="token string">'lit-html'</span><span class="token punctuation">]</span>

    <span class="token comment">// return the customized config</span>
    <span class="token keyword">return</span> config
  <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>
<span class="token punctuation">&#125;</span></code><!----></pre> <h3>Now we have a working Storybook</h3> <p>There is a downside to using web components (lit) with storybook, and that is that it does not support hot reload.
so each change will cause Storybook to do a full reload.
Hopefully this will be mitigated in the future.</p> <h3>Publish to NPM</h3> <p>This section covers the steps needed to publish to NPM, if you are not planning to publish to NPM, you can skip this section.</p> <p>First off, depending if you want to publish standalone web components you will need to move <code>lit</code> to become a devDependency in your <code>package.json</code>.</p> <ul><li>Also instead of only exporting the single <code>dist/my-element.es.js</code> file we will change it so we have a barrel file that exports all components.</li> <li>and change both <code>index.html</code> and <code>vite.config.js</code> to point <code>src/index.ts</code></li> <li>We then also need to change <code>package.json</code> to export the correct files.</li> <li>And we also want to make the package public by removing <code>"private": true</code> and choosing a name and license.</li></ul> <p>after this we should be good to go by running</p> <pre class="language-bash"><!----><code class="language-bash"><span class="token function">npm</span> run build</code><!----></pre> <p>then checking <code>/dist/</code> to see that the correct files are there, and that our <code>package.json</code> points to these files.</p> <p>then we can run</p> <pre class="language-bash"><!----><code class="language-bash"><span class="token function">npm</span> publish</code><!----></pre> <p>If all has gone well you should be able to use your new package by importing it</p> <pre class="language-html"><!----><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>module<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.skypack.dev/my-element<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>my-element</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Lit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>my-element</span><span class="token punctuation">></span></span></code><!----></pre> <h2>Example Repo</h2> <p>If you don’t want to copy paste everything, I’ve created a demo project on github.
you can find it here <a href="https://github.com/leon/blog-vite-lit-storybook" rel="nofollow">https://github.com/leon/blog-vite-lit-storybook</a></p><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/news/2022-01-hello-world</guid>
      <link>https://leonradley.com/articles/news/2022-01-hello-world</link>
      <title>Hello World again?</title>
      <pubDate>Sun, 23 Jan 2022 00:00:00 GMT</pubDate>
      <category>news</category>
      <description><![CDATA[Time for something new]]></description>
      <content><![CDATA[<!--[--><h3>Well, better late than never</h3> <p>I don’t know why it seems to be so hard to create a new homepage for myself.</p> <p>Since it’s my day job to create stuff I guess I’m to hard on myself and never feel that the page I create is good enough.</p> <p>But as a new years resolution for 2022, I was determined to create a new page where I could share things with the world.</p> <p>It has taken longer than I thought to get everything working as I want to.</p> <p>I first wrote it in next.js, but then when <a href="https://remix.run" rel="nofollow">Remix</a> got released, I found it so much easier to work with so I had to rewrite everything.</p> <p>It might not be 100% complete, but I really need to get something out there, so you will have to bear with me until I’ve polished some things.</p> <p>Here’s hoping for a more productive 2022 🚀</p><!----><!--]-->]]></content>
    </item><item>
      <guid>https://leonradley.com/articles/react/2021-05-react-and-typescript</guid>
      <link>https://leonradley.com/articles/react/2021-05-react-and-typescript</link>
      <title>React and Typescript</title>
      <pubDate>Sat, 15 May 2021 00:00:00 GMT</pubDate>
      <category>react</category><category>typescript</category>
      <description><![CDATA[How to write typescript React Components]]></description>
      <content><![CDATA[<!--[--><p>I do not use the built in functional component type <code>React.FC</code> because it forces you to always have the prop <code>children</code>.
Instead I like to be explicit about what props go into each component, that way <code>VS Code</code> will give me a hard time if I try to add a child to a component that does not support it.</p> <h3>Transform or Format Components</h3> <p>When you only want to style some input or transform it.</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token keyword">import</span> formatISO <span class="token keyword">from</span> <span class="token string">'date-fns/formatISO'</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">DateProps</span> <span class="token punctuation">&#123;</span>
	date<span class="token operator">:</span> <span class="token builtin">string</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">Date</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> date <span class="token punctuation">&#125;</span><span class="token operator">:</span> DateProps<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>date<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
		<span class="token keyword">return</span> <span class="token keyword">null</span>
	<span class="token punctuation">&#125;</span>
	<span class="token keyword">const</span> formatted <span class="token operator">=</span> <span class="token function">formatISO</span><span class="token punctuation">(</span>date<span class="token punctuation">,</span> <span class="token punctuation">&#123;</span> representation<span class="token operator">:</span> <span class="token string">'date'</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token operator">&lt;</span>time dateTime<span class="token operator">=</span><span class="token punctuation">&#123;</span>formatted<span class="token punctuation">&#125;</span><span class="token operator">></span><span class="token punctuation">&#123;</span>formatted<span class="token punctuation">&#125;</span><span class="token operator">&lt;</span><span class="token operator">/</span>time<span class="token operator">></span>
<span class="token punctuation">&#125;</span></code><!----></pre> <h3>Wrappers</h3> <p>When you want to create a wrapper element that always will have children</p> <pre class="language-ts"><!----><code class="language-ts"><span class="token keyword">import</span> clsx <span class="token keyword">from</span> <span class="token string">'clsx'</span>
<span class="token keyword">import</span> <span class="token punctuation">&#123;</span> ReactNode <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'react'</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">GridProps</span> <span class="token punctuation">&#123;</span>
	children<span class="token operator">:</span> ReactNode <span class="token comment">// VS Code will warn you if you use this component without children</span>
	className<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token comment">// optional posibility to add additional classes to grid</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">Grid</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> children<span class="token punctuation">,</span> className <span class="token punctuation">&#125;</span><span class="token operator">:</span> GridProps<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
	<span class="token keyword">const</span> mobileLayout <span class="token operator">=</span> <span class="token string">'grid gap-4 grid-cols-1'</span>
	<span class="token keyword">const</span> desktopLayout <span class="token operator">=</span> <span class="token string">'md:gap-8 md:grid-cols-2'</span>

	<span class="token keyword">return</span> <span class="token operator">&lt;</span>div className<span class="token operator">=</span><span class="token punctuation">&#123;</span><span class="token function">clsx</span><span class="token punctuation">(</span><span class="token string">'grid'</span><span class="token punctuation">,</span> mobileLayout<span class="token punctuation">,</span> desktopLayout<span class="token punctuation">,</span> className<span class="token punctuation">)</span><span class="token punctuation">&#125;</span><span class="token operator">></span><span class="token punctuation">&#123;</span>children<span class="token punctuation">&#125;</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token punctuation">&#125;</span></code><!----></pre> <mark>I'm using <a href="https://tailwindcss.com/">Tailwind CSS in the above example</a></mark><!----><!--]-->]]></content>
    </item>
    </channel>
    </rss>