<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Artemy</title>
    <description>The latest articles on DEV Community by Artemy (@tanella).</description>
    <link>https://dev.to/tanella</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2928127%2Fe5dea178-b256-4b3e-a24c-528c305407d1.jpeg</url>
      <title>DEV Community: Artemy</title>
      <link>https://dev.to/tanella</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tanella"/>
    <language>en</language>
    <item>
      <title>I shipped my first npm package with AI — and it's already in production</title>
      <dc:creator>Artemy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 10:13:27 +0000</pubDate>
      <link>https://dev.to/tanella/i-shipped-my-first-npm-package-with-ai-and-its-already-in-production-2cl9</link>
      <guid>https://dev.to/tanella/i-shipped-my-first-npm-package-with-ai-and-its-already-in-production-2cl9</guid>
      <description>&lt;p&gt;I'm a frontend developer with about three years of experience. Until a few months ago, "publish an npm package" lived on my someday list — the kind of thing you assume requires a deeper relationship with build tooling than you actually have. Then I built one. It's called &lt;a href="https://github.com/artemydottech/daterly" rel="noopener noreferrer"&gt;daterly&lt;/a&gt;, it's a React date picker, and it's already running in internal projects at the company I work for.&lt;/p&gt;

&lt;p&gt;The twist: I wrote most of it with AI — specifically Claude Code and the wider Claude toolset. This is the honest version of how that went. Not "AI built my startup overnight," but a real account of where the AI carried me, where it slowed me down, and what I'd actually keep from the experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why build &lt;em&gt;another&lt;/em&gt; date picker
&lt;/h2&gt;

&lt;p&gt;The internet does not need another React date picker. I know. But we needed &lt;em&gt;this&lt;/em&gt; one.&lt;/p&gt;

&lt;p&gt;At work (sima-land) we lean on &lt;a href="https://react-hook-form.com/" rel="noopener noreferrer"&gt;react-hook-form&lt;/a&gt; everywhere. It's the backbone of how we handle forms across projects. The date picker we were using — react-datepicker — kept getting in the way of that. Two things drove us up the wall:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Styling was a fight.&lt;/strong&gt; Overriding its look to match our design system always felt like wrestling specificity rather than setting a few variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The react-hook-form integration was awkward.&lt;/strong&gt; Wiring it into RHF cleanly took more glue code than it should have, every single time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the same papercut shows up in project after project, it stops being a papercut. We use one tech stack on purpose — a shared, repeatable way of building things so any of us can move between projects without relearning the basics. A date picker that fought both our styling approach and our form library was a crack in that consistency.&lt;/p&gt;

&lt;p&gt;So the real motivation wasn't "wouldn't it be cool to publish a package." It was: &lt;strong&gt;we want one tool that speaks our stack fluently.&lt;/strong&gt; First-class RHF support, styling that bends without a struggle, and the locale/format behavior we actually need (Russian market: &lt;code&gt;ru&lt;/code&gt; locale, &lt;code&gt;dd.MM.yyyy&lt;/code&gt; by default). That's the takeaway I keep coming back to — the package exists to protect a way of working, not to chase npm downloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it ended up being
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/daterly" rel="noopener noreferrer"&gt;daterly&lt;/a&gt; is built on &lt;a href="https://daypicker.dev/" rel="noopener noreferrer"&gt;react-day-picker v9&lt;/a&gt; (headless) and &lt;a href="https://date-fns.org/" rel="noopener noreferrer"&gt;date-fns v4&lt;/a&gt;. The headline features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single date &lt;strong&gt;and&lt;/strong&gt; range picking, controlled or uncontrolled&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;masked text input&lt;/strong&gt; so people can type a date instead of only clicking a calendar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arbitrary locales and formats&lt;/strong&gt; via props — the input mask regenerates itself from the &lt;code&gt;dateFormat&lt;/code&gt; you pass&lt;/li&gt;
&lt;li&gt;Optional time selection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-overhead react-hook-form integration&lt;/strong&gt; via a separate &lt;code&gt;daterly/rhf&lt;/code&gt; entry point — if you don't use RHF, you don't pay for it&lt;/li&gt;
&lt;li&gt;Styling through &lt;code&gt;--daterly-*&lt;/code&gt; CSS variables and &lt;code&gt;data-*&lt;/code&gt; state attributes, so you can theme it without touching JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The RHF wrappers are generic over your form's value type, so &lt;code&gt;name&lt;/code&gt; gets autocomplete and type-safety:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RHFDatePicker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;daterly/rhf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RHFDatePicker&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BookingFormValues&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkIn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Check-in date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pick a date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That snippet is the whole reason the project exists, honestly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6347bqynjjyixqpuoex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh6347bqynjjyixqpuoex.png" alt="Two daterly import paths: core DatePicker with no form library, and an opt-in daterly/rhf entry point that only enters your bundle when you use it" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it with AI: the good parts
&lt;/h2&gt;

&lt;p&gt;I worked almost entirely inside Claude Code, with Claude Design for the visual side. The parts where the AI genuinely shone were the fiddly, self-contained algorithms — the stuff that's annoying to write by hand but easy to specify.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;input mask&lt;/strong&gt; is the best example. We implemented our own digit-only mask instead of pulling in a masking library, and there's real subtlety in it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rebuild the masked string from raw digits on every keystroke.&lt;/li&gt;
&lt;li&gt;Restore the cursor position with &lt;code&gt;requestAnimationFrame&lt;/code&gt; after React re-renders the input — otherwise the caret jumps to the end and typing feels broken.&lt;/li&gt;
&lt;li&gt;Skip over separators when you press Backspace on one.&lt;/li&gt;
&lt;li&gt;Strip non-digits on paste before masking.&lt;/li&gt;
&lt;li&gt;Validate via a &lt;strong&gt;round-trip check&lt;/strong&gt;: &lt;code&gt;format(parse(masked)) === masked&lt;/code&gt;. That elegantly catches things like &lt;code&gt;32.01.2024&lt;/code&gt; — it parses, but it doesn't format back to the same string, so you know it's invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That round-trip trick is the kind of thing the AI proposed that made me go "oh, that's nice." Describing the edge cases in plain language and getting a working first pass back was a real accelerator. Same with boilerplate-heavy work: dual ESM/CJS build config, TypeScript declaration setup, test scaffolding. Tedious to set up from scratch, quick to generate and then review.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feecdsjt7135i497n46m6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feecdsjt7135i497n46m6.png" alt="Round-trip validation of the masked date input: 12.05.2026 formats back to itself and is valid, while 32.01.2024 formats to a different string and is rejected" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it with AI: the not-so-good parts
&lt;/h2&gt;

&lt;p&gt;It wasn't magic, and pretending otherwise would be dishonest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The limits and the lag.&lt;/strong&gt; I was on the Pro plan, and I hit usage limits more than once mid-flow — exactly when you've built momentum and don't want to stop. On top of that, it noticeably slowed down on a larger context, which broke the rhythm. If you're going to lean on AI for a real project, budget for the friction of &lt;em&gt;waiting&lt;/em&gt; and &lt;em&gt;rationing&lt;/em&gt;, not just the writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It needs a driver, not a passenger.&lt;/strong&gt; The AI is great at producing a plausible chunk of code. Whether that chunk is &lt;em&gt;correct&lt;/em&gt;, fits the existing patterns, and doesn't quietly reinvent something three files over — that's still on me. The most valuable skill wasn't prompting; it was reading every diff like a code reviewer who doesn't trust the author. A junior who can't evaluate the output would have shipped subtly broken behavior here.&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F55w4dpqyxk7cl3t02mme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F55w4dpqyxk7cl3t02mme.png" alt="What AI compresses versus what stays on the developer: it handles the mask algorithm, build config, type declarations and boilerplate, while correctness, fit and diff review remain the human's job" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From "it works on my machine" to an actual package
&lt;/h2&gt;

&lt;p&gt;This is the part I underestimated, and the part I'm most glad I didn't skip. Going from a working component to something installable and maintainable is a whole second project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dual ESM + CJS output&lt;/strong&gt; with proper type declarations, built via &lt;a href="https://github.com/egoist/tsup" rel="noopener noreferrer"&gt;tsup&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning with &lt;a href="https://github.com/changesets/changesets" rel="noopener noreferrer"&gt;Changesets&lt;/a&gt;&lt;/strong&gt;, so every change is intentional and the changelog writes itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI&lt;/strong&gt;, code coverage, and a &lt;strong&gt;bundle-size budget&lt;/strong&gt; (&lt;code&gt;size-limit&lt;/code&gt;) so the thing doesn't quietly balloon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component tests&lt;/strong&gt; with Playwright and Vitest — a masked input has enough edge cases that you really want them locked down.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is glamorous, but it's the difference between a gist and a package other people can depend on.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzhs34htkbjhjscn5vak3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzhs34htkbjhjscn5vak3.png" alt="The component took days, the packaging took longer: ESM plus CJS build, Changesets versioning, CI and coverage, size-limit budget, Playwright and Vitest tests, docs" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 0.4.0 incident
&lt;/h2&gt;

&lt;p&gt;A small, very human lesson. Early on, I ran the Changesets CLI interactively and — distracted — picked &lt;code&gt;minor&lt;/code&gt; instead of &lt;code&gt;patch&lt;/code&gt;. The version jumped to &lt;code&gt;0.4.0&lt;/code&gt; instead of &lt;code&gt;0.3.1&lt;/code&gt;. No undo on a published version; you just live with the gap.&lt;/p&gt;

&lt;p&gt;The fix was a process change I now recommend to anyone: &lt;strong&gt;don't bump versions interactively.&lt;/strong&gt; I have it written into the project's instructions for the AI too — create the changeset file by hand, decide the bump deliberately (&lt;code&gt;patch&lt;/code&gt; for fixes, &lt;code&gt;minor&lt;/code&gt; for new backwards-compatible props, &lt;code&gt;major&lt;/code&gt; for breaking changes), and only then publish. A thirty-second mistake taught me more about release discipline than any tutorial.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnnfij8xqj5x99u9mdz4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnnfij8xqj5x99u9mdz4m.png" alt="A distracted interactive version bump jumped daterly from 0.3.0 straight to 0.4.0 instead of the expected 0.3.1 patch, with no undo on a published version" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd actually take away
&lt;/h2&gt;

&lt;p&gt;If you're a frontend dev sitting where I was, three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build for your stack, not for the stars.&lt;/strong&gt; The best reason to make a library is that it removes friction you hit every day. daterly's whole job is to make our standard stack — react-hook-form, our styling approach, our locale defaults — feel native. The npm badge is a side effect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI compresses the boring parts, not the judgment.&lt;/strong&gt; It wrote a lot of correct code fast. It also needed me to catch what it got wrong, ration limited usage, and wait out the slow moments. Treat it as a fast junior pair, not an autopilot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The packaging is the real work.&lt;/strong&gt; The component took days. The build config, versioning, CI, tests, and docs took longer — and that's what makes it usable by anyone other than me.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;daterly is MIT-licensed and on &lt;a href="https://www.npmjs.com/package/daterly" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. Code and docs are on &lt;a href="https://github.com/artemydottech/daterly" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you're fighting your date picker's styling or RHF integration, give it a look — and if you build your own thing instead, even better. That's the point.&lt;/p&gt;




&lt;p&gt;I'm also open to freelance work and collaboration. If you've got something you're building and want a hand, or you just want to see what else I've made, it's all at &lt;a href="https://artemy.tech" rel="noopener noreferrer"&gt;artemy.tech&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>react</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
