@blakesteve/roster 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -292,6 +292,41 @@ Server Component it typechecks and then throws at render — use `/utils` there.
292
292
  | `useCountdown` | Countdown timer logic without the UI |
293
293
  | `useKeySequence` | Fires a callback when a sequence of keys is typed in order. Ships `KONAMI_CODE` |
294
294
 
295
+ ## Authoring components: the `rst:` prefix
296
+
297
+ Every class Roster emits carries an `rst:` prefix — `rst:flex`, `rst:bg-white`,
298
+ `rst:dark:bg-gray-950`, `rst:group-data-[checked]:translate-x-5`. **Consumers do
299
+ not write the prefix and never see it.** It exists to stop a host app from
300
+ overriding Roster by accident.
301
+
302
+ Roster's stylesheet deliberately sits in a layer *below* the host's `utilities`
303
+ so a consumer's `className` can override a component. Without a prefix that also
304
+ means the host wins any class-name *collision* — including on Roster's own
305
+ internal elements, which the consumer never touches:
306
+
307
+ - an app that used `bg-white` anywhere defeated the Textarea's
308
+ `dark:bg-gray-950`, rendering a white field on a dark page
309
+ - an app that used `translate-x-0` defeated the Switch's
310
+ `group-data-[checked]:translate-x-5`, so the thumb never moved
311
+
312
+ Neither app referenced those elements. Both bugs are invisible in this repo,
313
+ because Storybook is the only consumer here and it cannot collide with itself.
314
+
315
+ When adding or editing a component, write classes with the prefix. The codemod
316
+ that performed the original migration can also fix a file you forget:
317
+
318
+ ```bash
319
+ node scripts/prefix-classes.mjs src/components/atoms/Thing/Thing.tsx # dry run
320
+ APPLY=1 node scripts/prefix-classes.mjs src/components/atoms/Thing/Thing.tsx
321
+ ```
322
+
323
+ Two things are deliberately never prefixed. `dark` is the *consuming document's*
324
+ theme class, which Roster's own `@custom-variant dark` matches by name — Button
325
+ applies it directly for `surface="dark"`. And any class a consumer passes in,
326
+ such as `AvatarStrip`'s `ringClass`, stays exactly as they wrote it.
327
+
328
+ `npm run build` fails if any unprefixed class reaches `dist/roster.css`.
329
+
295
330
  ## Development
296
331
 
297
332
  Storybook is the component playground. Each component has dedicated stories covering all variants, props, and light/dark mode.
@@ -313,8 +348,25 @@ npm run test
313
348
 
314
349
  # Storybook interaction tests (Vitest + Playwright)
315
350
  npx vitest run --project storybook
351
+
352
+ # Every emitted class carries the rst: prefix (runs as part of the build)
353
+ npm run check:prefix
316
354
  ```
317
355
 
356
+ Two guards are worth knowing about, because the bug they catch cannot be
357
+ reproduced from inside this repo.
358
+
359
+ `check:prefix` reads `dist/roster.css` and fails on any unprefixed class
360
+ selector. The collision it prevents only appears in an app with its own Tailwind
361
+ build, so asserting on a rendered component here would never see it — the check
362
+ has to be on the artifact.
363
+
364
+ `src/lib/utils.test.ts` pins `cn`. `tailwind-merge` has to be configured with the
365
+ prefix or it stops recognising Roster's classes as utilities and silently
366
+ degrades to concatenation: conflicting classes both survive and the winner falls
367
+ back to stylesheet order. The class string still *contains* what you asked for,
368
+ so a snapshot passes while the browser is wrong.
369
+
318
370
  ## Building
319
371
 
320
372
  ```bash